Czy istnieje sposób kodowania plików JPEG o określonej szybkości transmisji?Jak określić bitrate dla kompresji JPEG?
Obecnie używam ImageMagick na convert
:
convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg
bitrate wzrasta z jakości, ale jest nieliniowa. Chcę wyraźnie kontrolować bitrate. Nie musi to być dokładne, ale chcę, aby było względnie blisko (w granicach, powiedzmy 0,1 bpp określonego ustawienia).
Czy jest tam jakiś koder, który umożliwia kodowanie obrazów przy określonej przepływności? To nie musi być imagemagick, wezmę wszystko, co się da (najlepiej na Linuksie).
Dymnym sposobem na zrobienie tego byłoby granie z wartościami ułamkowymi do parametru -quality
, dopóki nie pojawi się coś zbliżonego do docelowej przepływności, ale mam nadzieję na bardziej eleganckie rozwiązanie.
EDIT:
więc znudziło i postanowił robić rzeczy szybki (ale głupie) sposób.
pierwsze, oto wykres ImageMagick na -quality
vs bitrate:
BTW, oto obraz użyłem:
Więc zmiana bitrate jest dość dobre dla niższa jakość, ale staje się grubsza po około 80.
Oto przykładowy kod do zakodowania obrazu przy określonej docelowej przepływności. Użyłem OpenCV, ponieważ pozwala on na kodowanie JPEG w pamięci (bez I/O). O ile początkowo miałem to udawać za pomocą Pythona, o tyle opakowania Pythona OpenCV nie eksponują funkcjonalności kodowania w pamięci. Więc napisałem to w C++.
Wreszcie, myślałem o zastosowaniu interpolacji liniowej na jakości, aby zbliżyć się do docelowej przepływności, ale ponieważ cv::imencode
akceptuje tylko parametry całkowite, nie jest możliwe ustawienie niecałkowitej jakości JPEG. Skala jakości między OpenCV i imagemagick również wydaje się nieco różnić, więc zastosowanie parametru interpolowanej jakości z OpenCV i użycie w imagemagick's convert
nie działa dobrze.
Oznacza to, że wyjściowa szybkość transmisji bitów nie jest równa docelowej szybkości transmisji, szczególnie przy wyższych przepływnościach (> 1). Ale jest blisko.
Czy ktoś może zaproponować coś lepszego?
Kod:
#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;
}
skompilować i uruchomić za pomocą:
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
[email protected]:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53
wrote test.jpeg at 88% quality, 0.55bpp
Sugestia: Usuń pętlę for, zastąp ją wyszukiwaniem. Nie mogę uwierzyć, że ktokolwiek chciałby JPEG zakodowanego z czynnikami jakości w zakresie 1-> 30 lub ~ 99-> 100. Można również utworzyć wykres dla różnych typów obrazów i opracować lepszy początkowy punkt początkowy wyszukiwania. To wszystko jest bardzo naiwne, ponieważ nie bierzesz pod uwagę jakości (np. PSNR); wybór innej tabeli kwantyzacji może zapewnić Ci żądaną szybkość transmisji, ale o wiele wyższą jakość. – koan
Dzięki za sugestię. Wyszukiwanie poprawiłoby efektywność kodu, ale w tej chwili nie jest to problemem, ponieważ jest wystarczająco szybki. Masz rację co do jakości - większość normalnych ludzi nie potrzebuje plików JPEG o tak niskiej jakości, ponieważ wyglądają jak śmieci. Jednak ja sam * jestem * zainteresowany takimi obrazami, ponieważ badam degradację obrazu. Punkt dotyczący tabel kwantyzacji jest interesujący - myślę, że się nim zajrzę. Prawdopodobnie będzie to wymagało odejścia od OpenCV i użycia czegoś takiego jak ijg, ponieważ OpenCV nie wydaje się wystawiać tabel kwantyzacji. – misha