2010-12-17 7 views
16

¿Hay alguna manera de extraer fácilmente los coeficientes DCT (y los parámetros de cuantificación) de las imágenes codificadas y del video? 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?Extracción de coeficientes DCT a partir de imágenes codificadas y video

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 estaría de regreso en el dominio DCT. Esa no es una solución elegante, y espero poder hacerlo mejor.

Actualmente, utilizo el texto modelo OpenCV bastante común para abrir imágenes:

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

El código que estoy usando para el vídeo 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, aparece un 3 canales IplImage en formato BGR. ¿Hay alguna forma en que pueda obtener los coeficientes DCT también?

Respuesta

18

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

Básicamente, no es posible obtener los coeficientes DCT de cuadros de video H.264 por la sencilla razón de que H.264 doesn't use 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.

EDIT: escala fija de fuente

Imagen original (512 x 512):

jpeg image

imágenes DC (64x64): luma Cr Cb RGB

DC luma DC Cb DC Cr DC 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; 
} 
+0

¿qué es esto DC_SIZE y de dónde viene. Cuando compilé su fuente, recibí un error main_read.c: 85: 48: error: 'DC_SIZE' no se declaró en este ámbito –

+1

Creo que es un error tipográfico. Si echas un vistazo al historial de edición, verás que fue DCTSIZE en la edición anterior. No tengo la oportunidad de confirmarlo ahora, pero cuando lo haga, actualizaré mi respuesta. Gracias por señalar este problema. – misha

+2

DCTSIZE es el correcto en realidad. Lo puedo confirmar después de algunas pruebas. –

0

que puede utilizar, libjpeg DCT para extraer los datos de su archivo JPEG, pero para H.264 archivo de vídeo, no se encuentra ninguna abierto código fuente que le da datos dct (datos Intelt dct entero). Pero puede utilizar 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 cámbiela a su forma de deseo para obtener sus datos de salida de datos.

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

que utilizan Qvector para almacenar mis datos de salida, cambiar a su C++ lista de arreglo preferido.


#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 esto no funciona para todas las imágenes JPEG esta es la versión simple de la función, necesita buscar más filas que una basada en factores de muestra a veces – AngryDuck

Cuestiones relacionadas