una transformada imagenes imagen discreta cuantificacion coseno compresion codigo image-processing opencv video-processing dct

image processing - transformada - Extracción de coeficientes DCT a partir de imágenes codificadas y video



cuantificacion de una imagen en matlab (2)

¿Hay alguna manera de extraer fácilmente los coeficientes DCT (y los parámetros de cuantificación) a partir de imágenes y videos codificados? Cualquier software de decodificador debe estar utilizándolos para decodificar imágenes y videos codificados DCT de bloque. Así que estoy bastante seguro de que el decodificador sabe lo que son. ¿Hay alguna forma de exponerlos a quien usa el decodificador?

Estoy implementando algunos algoritmos de evaluación de calidad de video que funcionan directamente en el dominio DCT. Actualmente, la mayoría de mi código usa OpenCV, por lo que sería genial si alguien sabe de una solución que utiliza ese marco. No me importa usar otras bibliotecas (quizás libjpeg, pero parece ser solo para imágenes fijas), pero mi principal preocupación es hacer el menor trabajo posible de formato (no quiero reinventar la rueda y escribir mis propios decodificadores). Quiero poder abrir cualquier video / imagen (H.264, MPEG, JPEG, etc.) que OpenCV pueda abrir, y si es un bloque DCT-encoded, para obtener los coeficientes DCT.

En el peor de los casos, sé que puedo escribir mi propio código DCT de bloque, ejecutar los cuadros / imágenes descomprimidos a través de él y luego volver al dominio DCT. Esa no es una solución elegante, y espero poder hacerlo mejor.

Actualmente, utilizo el estándar repetitivo de OpenCV para abrir imágenes:

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

El código que estoy usando para video es igualmente trivial:

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

En ambos casos, obtengo una IplImage 3 canales en formato BGR. ¿Hay alguna forma en que pueda obtener los coeficientes DCT también?


Bueno, leí un poco y mi pregunta original parece ser un ejemplo de ilusión.

Básicamente, no es posible obtener los coeficientes DCT de las tramas de video H.264 por la simple razón de que H.264 no usa DCT . Utiliza una transformación diferente (transformación de enteros). A continuación, los coeficientes para esa transformación no cambian necesariamente marco por cuadro: H.264 es más inteligente porque divide las tramas en segmentos. Debería ser posible obtener esos coeficientes a través de un decodificador especial, pero dudo que OpenCV lo exponga para el usuario.

Para JPEG, las cosas son un poco más positivas. Como sospechaba, libjpeg expone los coeficientes DCT por usted. Escribí una pequeña aplicación para mostrar que funciona (fuente al final). Hace una nueva imagen usando el término DC de cada bloque. Debido a que el término de DC es igual al promedio del bloque (después de la escala adecuada), las imágenes de CC son versiones sin muestreo de la imagen JPEG de entrada.

EDITAR: escala fija en fuente

Imagen original (512 x 512):

Imágenes de CC (64x64): luma Cr Cb RGB

Fuente (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; }


Puede usar libjpeg para extraer datos dct de su archivo jpeg, pero para el archivo de video h.264 , no puedo encontrar ningún código fuente abierto que le proporcione datos dct (datos Intelt dct entero). Pero puede usar el software de código abierto h.264 como JM , JSVM o x264 . En estos dos archivos fuente, debe encontrar su función específica que haga uso de la función dct y cambiarla a su forma de deseo para obtener sus datos de salida de datos.

Para la imagen: utilice el siguiente código, y después de read_jpeg_file( infilename, v, quant_tbl ) , v y quant_tbl tendrán dct data y quantization table de quantization table de su imagen JPEG, respectivamente.

Utilicé Qvector para almacenar mis datos de salida, cambiarlos a su lista preferida de matriz de 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; }