C'è un modo per codificare JPEG ad un bitrate specifico?Come specificare il bitrate per la compressione JPEG?
Attualmente, sto usando ImageMagick di convert
:
convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg
aumenta bitrate di qualità, ma è non lineare. Voglio controllare il bitrate in modo esplicito. Non deve essere esatto, ma lo voglio ragionevolmente vicino (all'interno, diciamo 0.1 bpp delle impostazioni specificate).
C'è qualche encoder che consente di codificare le immagini con una particolare velocità in bit? Non deve essere imagemagick, prenderò qualsiasi cosa funzioni (preferibilmente su Linux).
Un modo stupido per farlo sarebbe quello di giocare con valori frazionari al parametro -quality
fino a quando non viene fuori qualcosa di vicino al bitrate di destinazione, ma spero in una soluzione più elegante.
EDIT:
Così mi sono annoiato e ha deciso di fare le cose nel modo veloce (ma stupido).
In primo luogo, ecco un grafico della di ImageMagick -quality
vs bitrate:
BTW, ecco l'immagine che ho usato:
Così il cambiamento di bitrate è abbastanza bene per valori di qualità inferiori, ma diventano grossolani dopo circa 80.
Ecco alcuni esempi di codice per codificare un'immagine con un bitrate di destinazione. Ho usato OpenCV perché consente la codifica JPEG in memoria (nessun I/O necessario). Mentre inizialmente stavo prendendo in giro questo con Python, sfortunatamente i wrapper OpenCV Python non espongono la funzionalità di codifica in memoria. Così l'ho scritto in C++.
Infine, stavo pensando di utilizzare l'interpolazione lineare sulla qualità per avvicinarmi al bitrate target, ma dal momento che cv::imencode
accetta solo i parametri interi, non è possibile impostare una qualità JPEG non intera. Anche la scala di qualità tra OpenCV e imagemagick sembra differire, quindi prendere il parametro di qualità interpolato da OpenCV e utilizzare in convert
di imagemagick non ha funzionato bene.
Ciò significa che il bitrate di uscita non è uguale al bitrate di destinazione, specialmente a bitrate superiori (> 1). Ma è vicino.
Qualcuno può suggerire qualcosa di meglio?
Codice:
#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;
}
compilare ed eseguire utilizzando:
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
Suggerimento: rimuovere il ciclo for, sostituirlo con la ricerca. Non posso credere che qualcuno vorrebbe un JPEG codificato con fattori di qualità negli intervalli di 1-> ~ 30 o ~ 99-> 100. Puoi anche creare il tuo grafico per una varietà di diversi tipi di immagine e calcolare un punto iniziale iniziale migliore per la ricerca. Tutto ciò è molto ingenuo perché non si considera nemmeno la qualità (ad es. PSNR); scegliere una tabella di quantizzazione diversa potrebbe farti ottenere il bitrate desiderato ma una qualità molto più elevata. – koan
Grazie per il suggerimento. La ricerca migliorerebbe l'efficienza del codice, ma al momento non è davvero una preoccupazione perché è abbastanza veloce come è. Hai ragione riguardo alla qualità - la maggior parte delle persone normali non ha bisogno di JPEG di qualità così bassa da sembrare spazzatura. Tuttavia, io stesso * sono * interessato a tali immagini, mentre sto studiando il degrado dell'immagine. Il punto sulle tabelle di quantizzazione è interessante - penso che lo esaminerò. Probabilmente sarà necessario spostarsi da OpenCV e usare qualcosa come ijg, perché OpenCV non sembra esporre le tabelle di quantizzazione. – misha