Есть ли способ кодировать JPEG с определенным битрейтом?
В настоящее время я использую imagemagick's convert
:
convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg
Битрейт увеличивается с качеством, но это нелинейно.Я хочу явно контролировать битрейт.Оно не должно быть точным, но я хочу, чтобы оно было достаточно близко (в пределах, скажем, 0,1 bpp от заданного значения).
Есть ли там какой-либо кодер, который позволяет кодировать изображения с определенной скоростью передачи данных??Это не обязательно должно быть imagemagick, я возьму все, что работает (желательно в Linux).
Глупый способ сделать это - поэкспериментировать с дробными значениями параметра -quality
, пока что-то близкодо целевого битрейта выходит, но я надеюсь на более элегантное решение.
РЕДАКТИРОВАТЬ:
Так что мне стало скучно и я решил сделать вещи быстро (но глупо).
Во-первых, вот график -quality
против битрейта imagemagick:
Кстати, вот изображение, которое я использовал:
Таким образом, изменение битрейта вполне подходит для более низких значений качества, но становится грубым примерно после 80.
Вот пример кода для кодирования изображения с некоторой целевой скоростью передачи битов,Я использовал OpenCV, потому что он допускает кодирование JPEG в памяти (ввод / вывод не требуется).Хотя я изначально собирался смоделировать это с помощью Python, к сожалению, обертки Python OpenCV не предоставляют возможности кодирования в памяти.Поэтому я написал это на C ++.
Наконец, я думал об использовании линейной интерполяции по качеству, чтобы приблизиться к целевому битрейту, но так как cv::imencode
принимает только целочисленные параметры, невозможно установитьЦелое качество JPEG.Шкала качества между OpenCV и imagemagick, похоже, также несколько отличается, поэтому взятие интерполированного параметра качества из OpenCV и использование в convert
imagemagick не сработало.
Это означает, что битрейт на выходе неравно целевому битрейту, особенно при более высоких битрейтах (> 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