Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Well, I did a bit of reading and my original question seems to be an instance of wishful thinking.</p> <p>Basically, it's not possible to get the DCT coefficients from H.264 video frames for the simple reason that H.264 <a href="http://en.wikipedia.org/wiki/H.264/MPEG-4_AVC#Features" rel="noreferrer">doesn't use DCT</a>. It uses a different transform (integer transform). Next, the coefficients for that transform don't necessarily change on a frame-by-frame basis -- H.264 is smarter cause it splits up frames into slices. It should be possible to get those coefficients through a special decoder, but I doubt OpenCV exposes it for the user.</p> <p>For JPEG, things are a bit more positive. As I suspected, <a href="http://www.ijg.org/" rel="noreferrer">libjpeg</a> exposes the DCT coefficients for you. I wrote a small app to show that it works (source at the end). It makes a new image using the DC term from each block. Because the DC term is equal to the block average (after proper scaling), the DC images are downsampled versions of the input JPEG image.</p> <p><strong>EDIT:</strong> fixed scaling in source</p> <p>Original image (512 x 512):</p> <p><img src="https://i.stack.imgur.com/MOxTO.jpg" alt="jpeg image"></p> <p>DC images (64x64): luma Cr Cb RGB</p> <p><img src="https://i.stack.imgur.com/6ZRPY.png" alt="DC luma"> <img src="https://i.stack.imgur.com/UcQdN.png" alt="DC Cb"> <img src="https://i.stack.imgur.com/Xd6S4.png" alt="DC Cr"> <img src="https://i.stack.imgur.com/JSRJW.png" alt="DC RGB"></p> <p>Source (C++):</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;assert.h&gt; #include &lt;cv.h&gt; #include &lt;highgui.h&gt; extern "C" { #include "jpeglib.h" #include &lt;setjmp.h&gt; } #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 = &amp;cinfo-&gt;comp_info[ci]; CvSize size = cvSize(ci_ptr-&gt;width_in_blocks, ci_ptr-&gt;height_in_blocks); IplImage *dc = cvCreateImage(size, IPL_DEPTH_8U, 1); assert(dc != NULL); JQUANT_TBL *tbl = ci_ptr-&gt;quant_table; UINT16 dc_quant = tbl-&gt;quantval[0]; #if DEBUG printf("DCT method: %x\n", cinfo-&gt;dct_method); printf ( "component: %d (%d x %d blocks) sampling: (%d x %d)\n", ci, ci_ptr-&gt;width_in_blocks, ci_ptr-&gt;height_in_blocks, ci_ptr-&gt;h_samp_factor, ci_ptr-&gt;v_samp_factor ); printf("quantization table: %d\n", ci); for (int i = 0; i &lt; DCTSIZE2; ++i) { printf("% 4d ", (int)(tbl-&gt;quantval[i])); if ((i + 1) % 8 == 0) printf("\n"); } printf("raw DC coefficients:\n"); #endif JBLOCKARRAY buf = (cinfo-&gt;mem-&gt;access_virt_barray) ( (j_common_ptr)cinfo, coeffs[ci], 0, ci_ptr-&gt;v_samp_factor, FALSE ); for (int sf = 0; (JDIMENSION)sf &lt; ci_ptr-&gt;height_in_blocks; ++sf) { for (JDIMENSION b = 0; b &lt; ci_ptr-&gt;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(&amp;jerr); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&amp;cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&amp;cinfo, infile); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&amp;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(&amp;cinfo); IplImage *y = extract_dc(&amp;cinfo, coeffs, 0); IplImage *cb_q = extract_dc(&amp;cinfo, coeffs, 1); IplImage *cr_q = extract_dc(&amp;cinfo, coeffs, 2); IplImage *cb = upscale_chroma(cb_q, cvGetSize(y)); IplImage *cr = upscale_chroma(cr_q, cvGetSize(y)); cvReleaseImage(&amp;cb_q); cvReleaseImage(&amp;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(&amp;y); cvReleaseImage(&amp;cb); cvReleaseImage(&amp;cr); /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&amp;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(&amp;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], &amp;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(&amp;dc); cvReleaseImage(&amp;rgb); return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload