Как указать битрейт для сжатия JPEG?

Есть ли способ кодировать JPEG с определенным битрейтом?

В настоящее время я использую программу imagemagick convert :

convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg

Битрейт увеличивается с качеством, но он нелинейный. Я хочу явно контролировать битрейт. Это не обязательно должно быть точным, но я хочу, чтобы это было достаточно близко (скажем, в пределах 0,1 бит на пиксель от указанной настройки).

Есть ли какой-нибудь кодировщик, который позволяет кодировать изображения с определенной скоростью передачи данных? Это не обязательно должно быть imagemagick, я возьму все, что работает (желательно в Linux).

Тупой способ сделать это - поиграться с дробными значениями параметра -quality , пока выходит что-то близкое к целевому битрейту, но я надеюсь на более элегантное решение.

РЕДАКТИРОВАТЬ:

Мне стало скучно и я решил действовать быстро (но глупо).

Во-первых, вот график -качества imagemagick в зависимости от битрейта:

alt text

Кстати, вот изображение, которое я использовал:

alt text

Таким образом, изменение битрейта вполне нормально для значений более низкого качества, но становится грубым примерно после 80.

Вот пример кода для кодирования изображения с определенной целевой скоростью передачи битов. Я использовал OpenCV, потому что он позволяет кодировать JPEG в памяти (ввод-вывод не требуется). Хотя изначально я собирался смоделировать это с помощью Python, к сожалению, оболочки Python OpenCV не предоставляют функции кодирования в памяти. Поэтому я написал его на C ++.

Наконец, я думал об использовании линейной интерполяции качества, чтобы приблизиться к целевому битрейту, но поскольку cv :: imencode принимает только целочисленные параметры, это невозможно для установки качества JPEG, отличного от целого числа. Шкала качества между OpenCV и imagemagick, похоже, также несколько различается, поэтому использование интерполированного параметра качества из OpenCV и использование в imagemagick convert не сработало.

Это означает, что выходной битрейт не равен целевому битрейту, особенно при более высоких битрейтах (> 1). Но это близко.

Кто-нибудь может предложить что-нибудь получше?

Код:

#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <assert.h>
#include <vector>

using cv::Mat;
using std::vector;

#define IMENCODE_FMT   ".jpeg"
#define QUALITY_UBOUND 101
#define BITS_PER_BYTE  8

int
main(int argc, char **argv)
{
    if (argc != 4)
    {
        fprintf(stderr, "usage: %s in.png out.jpeg bpp\n", argv[0]);
        return 1;
    }

    char *fname_in = argv[1];
    char *fname_out = argv[2];
    float target;
    sscanf(argv[3], "%f", &target);

    Mat orig = cv::imread(fname_in);
    int pixels = orig.size().width * orig.size().height * orig.channels();

    vector<unsigned char> buf;
    vector<int> params = vector<int>(2);
    params[0] = CV_IMWRITE_JPEG_QUALITY;
    int q;
    double bpp = 0.0;

    for (q = 1; q < QUALITY_UBOUND; ++q)
    {
        params[1] = q;
        cv::imencode(IMENCODE_FMT, orig, buf, params);
        bpp = (double)buf.size() * BITS_PER_BYTE / pixels;
        if (bpp > target)
            break;
    }

    cv::imwrite(fname_out, orig, params);
    printf("wrote %s at %d%% quality, %.2fbpp\n", fname_out, q, bpp);

    return 0;
}

Скомпилировать и запустить, используя:

g++ -c -Wall -ggdb -I../c -I../blur `pkg-config --cflags opencv` -Wno-write-strings jpeg-bitrate.cpp -o jpeg-bitrate.o
g++ -I../c `pkg-config --cflags opencv` `pkg-config --libs opencv` -lboost_filesystem jpeg-bitrate.o -o jpeg-bitrate.out
rm jpeg-bitrate.o
misha@misha-desktop:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53
wrote test.jpeg at 88% quality, 0.55bpp
8
задан mpenkov 14 January 2011 в 07:59
поделиться