Domanda

:

C'è un modo per estrarre facilmente i coefficienti DCT (e dei parametri di quantizzazione) dalle immagini codificate e video? Qualsiasi software decodificatore deve essere li utilizzano per decodificare blocco DCT codificati immagini e video. Quindi sono abbastanza sicuro che il decoder sa cosa siano. Esiste un modo per esporre loro a chi sta usando il decoder?

sto implementando alcuni algoritmi di valutazione della qualità video che lavorano direttamente nel dominio DCT. Attualmente, la maggior parte del mio codice usa OpenCV, quindi sarebbe bello se qualcuno sa di una soluzione che utilizza tale contesto. Non mi dispiace usare altre librerie (forse libjpeg, ma che sembra essere per le immagini ancora solo), ma la mia principale preoccupazione è quella di fare il meno lavoro formato-specifico possibile (io non voglio reinventare la ruota e la scrittura i miei decoder). Voglio essere in grado di aprire qualsiasi video / immagine (H.264 MPEG, JPEG, ecc) che OpenCV in grado di aprire, e se si tratta di blocco DCT-codificato, per ottenere i coefficienti DCT.

Nel peggiore dei casi, so che posso scrivere il mio proprio blocco di codice DCT, eseguire il frames / immagini decompressi attraverso di essa e poi sarei tornato nel dominio DCT. Non è certo una soluzione elegante, e spero di poter fare meglio.

Al momento, io uso il boilerplate OpenCV abbastanza comune per aprire le immagini:

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

Il codice che sto utilizzando per il video è altrettanto banale:

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

In entrambi i casi, ho un IplImage 3 canali in formato BGR. C'è un modo per ottenere i coefficienti DCT così?

È stato utile?

Soluzione

Bene, ho fatto un po 'di lettura e la mia domanda iniziale sembra essere un esempio di un pio desiderio.

In sostanza, non è possibile ottenere i coefficienti DCT da fotogrammi video H.264 per la semplice ragione che H.264 non usa DCT . Si utilizza un diverso trasformata (integer trasformata). Successivamente, i coefficienti per trasformare che non necessariamente cambiare su una base fotogramma per fotogramma - H.264 è più intelligente perche 'divide fotogrammi a fette. Dovrebbe essere possibile ottenere tali coefficienti attraverso un decodificatore speciale, ma dubito OpenCV espone per l'utente.

Per JPEG, le cose sono un po 'più positivo. Come sospettavo, libjpeg espone i coefficienti DCT per voi. Ho scritto una piccola applicazione per dimostrare che funziona (fonte alla fine). Si effettua una nuova immagine usando il termine CC da ciascun blocco. Poiché il termine CD è pari alla media blocco (dopo opportuna scala), le immagini DC sono ricampionate versioni del foto dell'ingresso JPEG.

Modifica di scala fissata in origine

Immagine originale (512 x 512):

immagine jpeg

immagini cc (64x64): luma Cr Cb RGB

DC luma DC Cb DC Cr DC RGB

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

Altri suggerimenti

È possibile utilizzare, libjpeg per estrarre i dati DCT del file jpeg, ma per h.264 di file video, non riesco a trovare alcun codice open source che danno si DCT dati (actully Integer DCT dati). Ma è possibile utilizzare H.264 software open source come JM , JSVM o x264 . In questi due file di origine, è necessario trovare la loro funzione specifica che fanno uso della funzione DCT, e modificarlo a vostro modulo desiderio, per ottenere l'output DCT di dati.

:

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

ho usato Qvector per memorizzare i miei dati in uscita, modificarlo a vostro c lista di array preferito ++.


#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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top