2010-12-17 14 views
16

क्या एन्कोडेड छवियों और वीडियो से डीसीटी गुणांक (और क्वांटिज़ेशन पैरामीटर) को आसानी से निकालने का कोई तरीका है? ब्लॉक-डीसीटी एन्कोडेड छवियों और वीडियो को डीकोड करने के लिए किसी भी डिकोडर सॉफ़्टवेयर का उपयोग करना चाहिए। तो मुझे पूरा यकीन है कि डिकोडर जानता है कि वे क्या हैं। क्या डिकोडर का उपयोग करने वाले किसी भी व्यक्ति को बेनकाब करने का कोई तरीका है?एन्कोडेड छवियों और वीडियो से डीसीटी गुणांक निकालने

मैं कुछ वीडियो गुणवत्ता मूल्यांकन एल्गोरिदम लागू कर रहा हूं जो सीधे डीसीटी डोमेन में काम करते हैं। वर्तमान में, मेरा अधिकांश कोड ओपनसीवी का उपयोग करता है, इसलिए अगर कोई उस ढांचे का उपयोग करके समाधान के बारे में जानता है तो यह बहुत अच्छा होगा। मुझे अन्य पुस्तकालयों का उपयोग करने में कोई फर्क नहीं पड़ता है (शायद libjpeg, लेकिन यह अभी भी छवियों के लिए प्रतीत होता है), लेकिन मेरी प्राथमिक चिंता जितनी संभव हो सके छोटे प्रारूप-विशिष्ट काम के रूप में करना है (मैं पहिया को फिर से लिखना और लिखना नहीं चाहता मेरे अपने डिकोडर्स)। मैं किसी भी वीडियो/छवि (एच .264, एमपीईजी, जेपीईजी, आदि) को खोलने में सक्षम होना चाहता हूं जो ओपनसीवी खोल सकता है, और यदि यह डीसीटी गुणांक प्राप्त करने के लिए डीसीटी-एन्कोडेड ब्लॉक करता है।

सबसे बुरे मामले में, मुझे पता है कि मैं अपना स्वयं का ब्लॉक डीसीटी कोड लिख सकता हूं, इसके माध्यम से डिकंप्रेस्ड फ्रेम/छवियों को चला सकता हूं और फिर मैं डीसीटी डोमेन में वापस आऊंगा। यह शायद ही एक सुरुचिपूर्ण समाधान है, और मुझे उम्मीद है कि मैं बेहतर कर सकता हूं। एक

CvCapture *capture = cvCaptureFromAVI(filename);  
while (cvGrabFrame(capture)) 
{ 
    IplImage *frame = cvRetrieveFrame(capture); 
    // Run quality assessment metric on frame 
} 
cvReleaseCapture(&capture); 

दोनों मामलों में, मैं:

वर्तमान में, मैं काफी आम OpenCV बॉयलरप्लेट का उपयोग छवियों को खोलने के लिए:

IplImage *image = cvLoadImage(filename); 
// Run quality assessment metric 

कोड मैं वीडियो के लिए उपयोग कर रहा हूँ उतना ही मामूली बात है बीजीआर प्रारूप में 3-चैनल IplImage। क्या कोई तरीका है कि मैं डीसीटी गुणांक भी प्राप्त कर सकता हूं?

उत्तर

18

ठीक है, मैंने कुछ पढ़ा और मेरा मूल प्रश्न इच्छापूर्ण सोच का एक उदाहरण प्रतीत होता है।

असल में, H.264 doesn't use DCT के सामान्य कारण के लिए H.264 वीडियो फ्रेम से डीसीटी गुणांक प्राप्त करना संभव नहीं है। यह एक अलग परिवर्तन (पूर्णांक परिवर्तन) का उपयोग करता है। इसके बाद, उस ट्रांसफॉर्म के लिए गुणांक फ्रेम-दर-फ्रेम आधार पर आवश्यक रूप से परिवर्तित नहीं होते हैं - एच .264 स्मार्ट है क्योंकि यह स्लाइस में फ्रेम को विभाजित करता है। उन गुणांक को एक विशेष डिकोडर के माध्यम से प्राप्त करना संभव होना चाहिए, लेकिन मुझे संदेह है कि ओपनसीवी उपयोगकर्ता के लिए इसे उजागर करता है।

जेपीईजी के लिए, चीजें थोड़ा अधिक सकारात्मक हैं। जैसा कि मुझे संदेह था, libjpeg आपके लिए डीसीटी गुणांक का खुलासा करता है। मैंने यह दिखाने के लिए एक छोटा ऐप लिखा था कि यह काम करता है (अंत में स्रोत)। यह प्रत्येक ब्लॉक से डीसी अवधि का उपयोग कर एक नई छवि बनाता है। चूंकि डीसी शब्द ब्लॉक औसत (उचित स्केलिंग के बाद) के बराबर है, डीसी छवियों इनपुट जेपीईजी छवि के downsampled संस्करण हैं।

संपादित करें: स्रोत में निश्चित स्केलिंग

मूल छवि (512 x 512):

jpeg image

डीसी छवियों (64x64): लुमा सीआर सीबी आरजीबी

DC luma DC Cb DC Cr DC RGB

स्रोत (C++):

#include <stdio.h> 
#include <assert.h> 

#include <cv.h>  
#include <highgui.h> 

extern "C" 
{ 
#include "jpeglib.h" 
#include <setjmp.h> 
} 

#define DEBUG 0 
#define OUTPUT_IMAGES 1 

/* 
* Extract the DC terms from the specified component. 
*/ 
IplImage * 
extract_dc(j_decompress_ptr cinfo, jvirt_barray_ptr *coeffs, int ci) 
{ 
    jpeg_component_info *ci_ptr = &cinfo->comp_info[ci]; 
    CvSize size = cvSize(ci_ptr->width_in_blocks, ci_ptr->height_in_blocks); 
    IplImage *dc = cvCreateImage(size, IPL_DEPTH_8U, 1); 
    assert(dc != NULL); 

    JQUANT_TBL *tbl = ci_ptr->quant_table; 
    UINT16 dc_quant = tbl->quantval[0]; 

#if DEBUG 
    printf("DCT method: %x\n", cinfo->dct_method); 
    printf 
    (
     "component: %d (%d x %d blocks) sampling: (%d x %d)\n", 
     ci, 
     ci_ptr->width_in_blocks, 
     ci_ptr->height_in_blocks, 
     ci_ptr->h_samp_factor, 
     ci_ptr->v_samp_factor 
    ); 

    printf("quantization table: %d\n", ci); 
    for (int i = 0; i < DCTSIZE2; ++i) 
    { 
     printf("% 4d ", (int)(tbl->quantval[i])); 
     if ((i + 1) % 8 == 0) 
      printf("\n"); 
    } 

    printf("raw DC coefficients:\n"); 
#endif 

    JBLOCKARRAY buf = 
    (cinfo->mem->access_virt_barray) 
    (
     (j_common_ptr)cinfo, 
     coeffs[ci], 
     0, 
     ci_ptr->v_samp_factor, 
     FALSE 
    ); 
    for (int sf = 0; (JDIMENSION)sf < ci_ptr->height_in_blocks; ++sf) 
    { 
     for (JDIMENSION b = 0; b < ci_ptr->width_in_blocks; ++b) 
     { 
      int intensity = 0; 

      intensity = buf[sf][b][0]*dc_quant/DCTSIZE + 128; 
      intensity = MAX(0, intensity); 
      intensity = MIN(255, intensity); 

      cvSet2D(dc, sf, (int)b, cvScalar(intensity)); 

#if DEBUG 
      printf("% 2d ", buf[sf][b][0]);       
#endif 
     } 
#if DEBUG 
     printf("\n"); 
#endif 
    } 

    return dc; 

} 

IplImage *upscale_chroma(IplImage *quarter, CvSize full_size) 
{ 
    IplImage *full = cvCreateImage(full_size, IPL_DEPTH_8U, 1); 
    cvResize(quarter, full, CV_INTER_NN); 
    return full; 
} 

GLOBAL(int) 
read_JPEG_file (char * filename, IplImage **dc) 
{ 
    /* This struct contains the JPEG decompression parameters and pointers to 
    * working space (which is allocated as needed by the JPEG library). 
    */ 
    struct jpeg_decompress_struct cinfo; 

    struct jpeg_error_mgr jerr; 
    /* More stuff */ 
    FILE * infile;  /* source file */ 

    /* In this example we want to open the input file before doing anything else, 
    * so that the setjmp() error recovery below can assume the file is open. 
    * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that 
    * requires it in order to read binary files. 
    */ 

    if ((infile = fopen(filename, "rb")) == NULL) { 
    fprintf(stderr, "can't open %s\n", filename); 
    return 0; 
    } 

    /* Step 1: allocate and initialize JPEG decompression object */ 

    cinfo.err = jpeg_std_error(&jerr); 

    /* Now we can initialize the JPEG decompression object. */ 
    jpeg_create_decompress(&cinfo); 

    /* Step 2: specify data source (eg, a file) */ 

    jpeg_stdio_src(&cinfo, infile); 

    /* Step 3: read file parameters with jpeg_read_header() */ 

    (void) jpeg_read_header(&cinfo, TRUE); 
    /* We can ignore the return value from jpeg_read_header since 
    * (a) suspension is not possible with the stdio data source, and 
    * (b) we passed TRUE to reject a tables-only JPEG file as an error. 
    * See libjpeg.txt for more info. 
    */ 

    /* Step 4: set parameters for decompression */ 

    /* In this example, we don't need to change any of the defaults set by 
    * jpeg_read_header(), so we do nothing here. 
    */ 

    jvirt_barray_ptr *coeffs = jpeg_read_coefficients(&cinfo); 

    IplImage *y = extract_dc(&cinfo, coeffs, 0); 
    IplImage *cb_q = extract_dc(&cinfo, coeffs, 1); 
    IplImage *cr_q = extract_dc(&cinfo, coeffs, 2); 

    IplImage *cb = upscale_chroma(cb_q, cvGetSize(y)); 
    IplImage *cr = upscale_chroma(cr_q, cvGetSize(y)); 

    cvReleaseImage(&cb_q); 
    cvReleaseImage(&cr_q); 

#if OUTPUT_IMAGES 
    cvSaveImage("y.png", y); 
    cvSaveImage("cb.png", cb); 
    cvSaveImage("cr.png", cr); 
#endif 

    *dc = cvCreateImage(cvGetSize(y), IPL_DEPTH_8U, 3); 
    assert(dc != NULL); 

    cvMerge(y, cr, cb, NULL, *dc); 

    cvReleaseImage(&y); 
    cvReleaseImage(&cb); 
    cvReleaseImage(&cr); 

    /* Step 7: Finish decompression */ 

    (void) jpeg_finish_decompress(&cinfo); 
    /* We can ignore the return value since suspension is not possible 
    * with the stdio data source. 
    */ 

    /* Step 8: Release JPEG decompression object */ 

    /* This is an important step since it will release a good deal of memory. */ 
    jpeg_destroy_decompress(&cinfo); 

    fclose(infile); 

    return 1; 
} 

int 
main(int argc, char **argv) 
{ 
    int ret = 0; 
    if (argc != 2) 
    { 
     fprintf(stderr, "usage: %s filename.jpg\n", argv[0]); 
     return 1; 
    } 
    IplImage *dc = NULL; 
    ret = read_JPEG_file(argv[1], &dc); 
    assert(dc != NULL); 

    IplImage *rgb = cvCreateImage(cvGetSize(dc), IPL_DEPTH_8U, 3); 
    cvCvtColor(dc, rgb, CV_YCrCb2RGB); 

#if OUTPUT_IMAGES 
    cvSaveImage("rgb.png", rgb); 
#else 
    cvNamedWindow("DC", CV_WINDOW_AUTOSIZE); 
    cvShowImage("DC", rgb); 
    cvWaitKey(0); 
#endif 

    cvReleaseImage(&dc); 
    cvReleaseImage(&rgb); 

    return 0; 
} 
+0

इस DC_SIZE क्या है और यह कहाँ से आता है। जब मैंने आपके स्रोत को संकलित किया तो मुझे एक त्रुटि मिली मुख्य_read.c: 85: 48: त्रुटि: इस क्षेत्र में 'DC_SIZE' घोषित नहीं किया गया था –

+1

मुझे लगता है कि यह एक टाइपो है। यदि आप संपादन इतिहास पर एक नज़र डालते हैं, तो आप पाएंगे कि यह पिछले संपादन में DCTSIZE था। मुझे अभी पुष्टि करने का मौका नहीं है, लेकिन जब मैं करता हूं, तो मैं अपना जवाब अपडेट कर दूंगा। इस समस्या को इंगित करने के लिए धन्यवाद। – misha

+2

डीसीटीएसआईएसईई वास्तव में उचित है। मैं कुछ परीक्षणों के बाद इसकी पुष्टि कर सकता हूं। –

0

आप उपयोग कर सकते हैं, libjpeg अपने jpeg फ़ाइल का डीसीटी डेटा निकालने के लिए, लेकिन h.264 वीडियो फ़ाइल के लिए, मैं किसी भी खुले नहीं मिल सकता है स्रोत कोड जो आपको डीटीसी डेटा देता है (एक्टुलली इंटीजर डीटीसी डेटा)। लेकिन आप H.264 ओपन सोर्स सॉफ़्टवेयर जैसे जेएम, JSVM या x264 का उपयोग कर सकते हैं। इन दो स्रोत फ़ाइल में, आपको अपना विशिष्ट फ़ंक्शन ढूंढना होगा जो डीटीसी फ़ंक्शन का उपयोग करे, और इसे अपने आउटपुट डीटीटी डेटा प्राप्त करने के लिए अपनी इच्छा फ़ॉर्म में बदल दें।

छवि: निम्नलिखित कोड का उपयोग करें, और read_jpeg_file(infilename, v, quant_tbl), v और quant_tbl के बाद क्रमश: dct data और अपने jpeg छवि की quantization table होगा।

मैं Qvector, मेरी उत्पादन डाटा स्टोर अपना पसंदीदा C++ सरणी सूची में इसे बदलने के लिए इस्तेमाल किया।


#include <iostream> 
#include <stdio.h> 
#include <jpeglib.h> 
#include <stdlib.h> 
#include <setjmp.h> 
#include <fstream> 

#include <QVector> 

int read_jpeg_file(char *filename, QVector<QVector<int> > &dct_coeff, QVector<unsigned short> &quant_tbl) 
{ 
    struct jpeg_decompress_struct cinfo; 
    struct jpeg_error_mgr jerr; 
    FILE * infile; 

    if ((infile = fopen(filename, "rb")) == NULL) { 
     fprintf(stderr, "can't open %s\n", filename); 
     return 0; 
    } 

    cinfo.err = jpeg_std_error(&jerr); 
    jpeg_create_decompress(&cinfo); 
    jpeg_stdio_src(&cinfo, infile); 
    (void) jpeg_read_header(&cinfo, TRUE); 

    jvirt_barray_ptr *coeffs_array = jpeg_read_coefficients(&cinfo); 
    for (int ci = 0; ci < 1; ci++) 
    { 
     JBLOCKARRAY buffer_one; 
     JCOEFPTR blockptr_one; 
     jpeg_component_info* compptr_one; 
     compptr_one = cinfo.comp_info + ci; 

     for (int by = 0; by < compptr_one->height_in_blocks; by++) 
     { 
      buffer_one = (cinfo.mem->access_virt_barray)((j_common_ptr)&cinfo, coeffs_array[ci], by, (JDIMENSION)1, FALSE); 
      for (int bx = 0; bx < compptr_one->width_in_blocks; bx++) 
      { 
       blockptr_one = buffer_one[0][bx]; 
       QVector<int> tmp; 
       for (int bi = 0; bi < 64; bi++) 
       { 
        tmp.append(blockptr_one[bi]); 
       } 
       dct_coeff.push_back(tmp); 
      } 
     } 
    } 


    // coantization table 
    j_decompress_ptr dec_cinfo = (j_decompress_ptr) &cinfo; 
    jpeg_component_info *ci_ptr = &dec_cinfo->comp_info[0]; 
    JQUANT_TBL *tbl = ci_ptr->quant_table; 

    for(int ci =0 ; ci < 64; ci++){ 
     quant_tbl.append(tbl->quantval[ci]); 
    } 

    return 1; 
} 

int main() 
{ 
    QVector<QVector<int> > v; 
    QVector<unsigned short> quant_tbl; 
    char *infilename = "your_image.jpg"; 

    std::ofstream out; 
    out.open("out_dct.txt"); 


    if(read_jpeg_file(infilename, v, quant_tbl) > 0){ 

     for(int j = 0; j < v.size(); j++){ 
       for (int i = 0; i < v[0].size(); ++i){ 
        out << v[j][i] << "\t"; 
      } 
      out << "---------------" << std::endl; 
     } 

     out << "\n\n\n" << std::string(10,'-') << std::endl; 
     out << "\nQauntization Table:" << std::endl; 
     for(int i = 0; i < quant_tbl.size(); i++){ 
      out << quant_tbl[i] << "\t"; 
     } 
    } 
    else{ 
     std::cout << "Can not read, Returned With Error"; 
     return -1; 
    } 

    out.close(); 

return 0; 
} 
+0

FYI यह सभी जेपीईजी छवियों के लिए काम नहीं करता है यह फ़ंक्शन का सरल संस्करण है, आपको कभी-कभी नमूना कारकों के आधार पर एक से अधिक पंक्तियां लाने की आवश्यकता होती है – AngryDuck

संबंधित मुद्दे