Estrazione dei coefficienti DCT da immagini e video codificati

C’è un modo per estrarre facilmente i coefficienti DCT (e i parametri di quantizzazione) dalle immagini e dai video codificati? Qualsiasi software decodificatore deve utilizzarli per decodificare immagini e video con codifica DCT a blocchi. Quindi sono abbastanza sicuro che il decodificatore sappia cosa sono. C’è un modo per esporli a chi sta usando il decoder?

Sto implementando alcuni algoritmi di valutazione della qualità video che funzionano direttamente nel dominio DCT. Attualmente, la maggior parte del mio codice utilizza OpenCV, quindi sarebbe fantastico se qualcuno fosse a conoscenza di una soluzione che utilizza tale framework. Non mi dispiace usare altre librerie (forse libjpeg, ma sembra essere solo per immagini statiche), ma la mia preoccupazione principale è di fare il più piccolo lavoro specifico per il formato (non voglio reinventare la ruota e scrivere i miei decodificatori). Voglio poter aprire qualsiasi video / immagine (H.264, MPEG, JPEG, ecc.) Che OpenCV può aprire, e se è un blocco codificato DCT, per ottenere i coefficienti DCT.

Nel peggiore dei casi, so che posso scrivere il mio codice DCT a blocchi, eseguire i frame / le immagini decompresse e poi tornerò nel dominio DCT. Non è certo una soluzione elegante, e spero di poter fare meglio.

Attualmente utilizzo la piastra di cottura OpenCV piuttosto comune per aprire le immagini:

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

Il codice che sto usando per il video è ugualmente banale:

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

In entrambi i casi, ottengo un IplImage a 3 canali in formato BGR. C’è un modo per ottenere i coefficienti DCT?

Bene, ho fatto un po ‘di lettura e la mia domanda iniziale sembra essere un’istanza di pio desiderio.

Fondamentalmente, non è ansible ottenere i coefficienti DCT dai frame video H.264 per il semplice motivo che H.264 non usa DCT . Usa una diversa trasformazione (trasformazione intera). Successivamente, i coefficienti per quella trasformazione non cambiano necessariamente su una base fotogramma per fotogramma – H.264 è più intelligente perché divide i fotogrammi in sezioni. Dovrebbe essere ansible ottenere questi coefficienti attraverso un decodificatore speciale, ma dubito che OpenCV lo esponga per l’utente.

Per JPEG, le cose sono un po ‘più positive. Come sospettavo, libjpeg espone per te i coefficienti DCT. Ho scritto una piccola app per dimostrare che funziona (fonte alla fine). Crea una nuova immagine usando il termine DC di ogni blocco. Poiché il termine DC è uguale alla media del blocco (dopo il corretto ridimensionamento), le immagini CC sono versioni sottocampionate dell’immagine JPEG di input.

EDIT: ridimensionamento fisso nella fonte

Immagine originale (512 x 512):

immagine jpeg

Immagini DC (64×64): luma Cr Cb RGB

DC lumaDC CbDC CrDC RGB

Fonte (C ++):

 #include  #include  #include  #include  extern "C" { #include "jpeglib.h" #include  } #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 (%dx %d blocks) sampling: (%dx %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; } 

Puoi usare, libjpeg per estrarre i dati dct del tuo file jpeg, ma per il file video h.264 , non riesco a trovare alcun codice open source che ti dia dati dct (actully Integer dct data). Ma puoi usare il software open source h.264 come JM , JSVM o x264 . In questi due file sorgente, devi trovare la loro funzione specifica che utilizza la funzione dct e cambiarla nella forma desiderata per ottenere i dati dct di output.

Per Image: usa il seguente codice, e dopo read_jpeg_file( infilename, v, quant_tbl ) , v e quant_tbl avranno rispettivamente dct data e quantization table della tua immagine jpeg.

Ho usato Qvector per memorizzare i miei dati di output, cambiandoli nella lista di array c ++ preferita.


 #include  #include  #include  #include  #include  #include  #include  int read_jpeg_file( char *filename, QVector > &dct_coeff, QVector &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 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 > v; QVector 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; }