2011-01-13 14 views
8

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:

alt text

BTW, ecco l'immagine che ho usato:

alt text

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 
+1

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

+0

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

risposta

4

Conosco un sacco di lavoro esiste sul controllo del bitrate di uscita di un codificatore JPEG (ad esempio 1st paper; 2nd paper), e che tali controlli esistono in JPEG2000. Sfortunatamente, non sono sicuro che nessun tipo di controllo del bitrate sia standardizzato per JPEG o implementato in librerie comuni.Potrebbe essere necessario codificare il proprio metodo, usando una sorta di ricerca binaria per esempio ...

Ma ancora, potrei sbagliarmi - e se è così, mi piacerebbe sentire parlare di una tale biblioteca.

Solo per curiosità, che lingua stai usando?

+0

Grazie per la risposta e i collegamenti. La mia uni non si iscrive a SpringerLink, sfortunatamente, ma ho letto il secondo documento. Per rispondere alla tua domanda: per un lavoro serio sulle immagini uso C/C++, ma se finisco per codificare il mio metodo per questo, probabilmente userò Python/Bash perché sono pigro. – misha

+0

E anche quello sarebbe molto più semplice. Ad ogni modo - fateci sapere se vi imbattete in una buona soluzione per questo particolare problema :) – BlueCookie

+0

Ho aggiornato la domanda con il codice di esempio. Non la definirei una * buona * soluzione, ma è l'unica che ho al momento. – misha

2

Il rapporto qualità bitrate in JPG dipende in gran parte dal contenuto. Se vuoi codificare a un bitrate specifico, ti suggerisco di farlo due passaggi: 1. Codifica con un fattore di qualità fisso (più vicino al bitrate di destinazione è migliore, potrebbe essere basato sul grafico) 2. In base alla sua dimensione , reencode l'originale con una qualità maggiore o minore. Anche questo può essere basato sul tuo grafico o qualcosa di simile.

È anche possibile ripetere l'ultimo passaggio a tempo indeterminato per ottenere il bitrate EXACT necessario.

Provavo questo con vari casi estremi, come un'immagine molto disturbata/rumorosa, un rettangolo nero o una sfumatura uniforme.

Problemi correlati