Извлечение коэффициентов DCT из кодированных изображений и видео

StackOverflow https://stackoverflow.com/questions/4470107

Вопрос

Есть ли способ легко извлечь коэффициенты DCT (и параметры квантования) из кодированных изображений и видео? Любое программное обеспечение для декодера должно использовать их для декодирования кодированных изображений Block-DCT и видео. Так что я уверен, что декодер знает, что они есть. Есть ли способ разоблачить их тому, кто использует декодер?

Я внедряю некоторые алгоритмы оценки качества видео, которые работают непосредственно в домене DCT. В настоящее время большая часть моего кода использует OpenCV, поэтому было бы здорово, если бы кто -то знал о решении, использующем эту структуру. Я не против использовать другие библиотеки (возможно, Libjpeg, но, похоже, это только для неподвижных изображений), но моя главная проблема-выполнять как можно меньше, чтобы сделать работу, насколько это возможно (я не хочу изобретать колесо и писать мои собственные декодеры). Я хочу иметь возможность открыть любое видео/изображение (H.264, MPEG, JPEG и т. Д.)

В худшем случае я знаю, что могу написать свой собственный код DCT Block, запустить декомпрессированные рамки/изображения через него, а затем я вернусь в домен DCT. Это вряд ли элегантное решение, и я надеюсь, что смогу сделать лучше.

В настоящее время я использую довольно распространенный шваров OpenCV для открытия изображений:

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

Код, который я использую для видео, одинаково тривиальный:

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

В обоих случаях я получаю 3-канальный IplImage в формате BGR. Есть ли способ, которым я могу получить коэффициенты DCT?

Это было полезно?

Решение

Ну, я немного прочитал, и мой первоначальный вопрос, кажется, является примером желаемого мышления.

По сути, невозможно получить коэффициенты DCT из видео кадров H.264 по той простой причине, что H.264 не использует DCT. Анкет Он использует другое преобразование (целочисленное преобразование). Далее, коэффициенты для этого преобразования не обязательно меняются на основе рамы-H.264 более умнее, потому что он разбивает рамки на ломтики. Должно быть возможно получить эти коэффициенты через специальный декодер, но я сомневаюсь, что OpenCV раскрывает его для пользователя.

Для JPEG все немного более позитивно. Как я подозревал, libjpeg разоблачает коэффициенты DCT для вас. Я написал небольшое приложение, чтобы показать, что оно работает (источник в конце). Он делает новое изображение, используя термин постоянного тока из каждого блока. Поскольку термин постоянного тока равен среднему блоку (после надлежащего масштабирования), изображения DC являются пониженными версиями входного изображения JPEG.

РЕДАКТИРОВАТЬ: Фиксированное масштабирование в источнике

Исходное изображение (512 x 512):

jpeg image

Изображения DC (64x64): Luma CR CB RGB

DC luma DC Cb DC Cr DC RGB

Источник (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;
}

Другие советы

Вы можете использовать, libjpeg для извлечения данных DCT вашего файла JPEG, но для H.264 Видеофайл, я не могу найти какой -либо открытый исходный код, который дает вам данные DCT (Actully Integer DCT Data). Но вы можете использовать программное обеспечение с открытым исходным кодом H.264 JM, JSVM или же x264. Анкет В этих двух исходных файлах вы должны найти их конкретную функцию, которая использует функцию DCT, и изменить ее на форму желания, чтобы получить данные о выводе DCT.

Для изображения:Используйте следующий код и после read_jpeg_file( infilename, v, quant_tbl ), v а также quant_tbl буду иметь dct data а также quantization table вашего изображения JPEG соответственно.

я использовал QVector Чтобы сохранить мои выходные данные, измените их на свой предпочтительный список массивов 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;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top