2011-01-13 12 views
8

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:

alt text

BTW, oto obraz użyłem:

alt text

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

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

+0

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

Odpowiedz

4

wiem dużo pracy istnieje na kontrolowanie przepływności wyjściowego kodera JPEG (np 1st paper; 2nd paper) i że takie kontrole istnieją w JPEG2000. Niestety, nie jestem pewien, czy jakakolwiek kontrola bitrate jest standaryzowana dla JPEG lub implementowana w popularnych bibliotekach.Być może trzeba będzie zakodować własną metodę, używając na przykład jakiegoś wyszukiwania binarnego ...

Ale znowu mogę się mylić - a jeśli tak, to chciałbym usłyszeć o takiej bibliotece.

Po prostu z ciekawości, z jakiego języka korzystasz?

+0

Dzięki za odpowiedź i linki. Mój uniwersytet nie subskrybuje SpringerLink, niestety, ale przeczytałem drugi artykuł. Aby odpowiedzieć na twoje pytanie: do poważnej pracy z obrazem używam C/C++, ale jeśli skończę kodować własną metodę, prawdopodobnie użyję po prostu Pythona/Basha, bo jestem leniwy. – misha

+0

To też byłoby prostsze. W każdym razie - daj nam znać, jeśli natkniesz się na dobre rozwiązanie tego konkretnego problemu :) – BlueCookie

+0

Zaktualizowałem pytanie za pomocą przykładowego kodu. Nie nazwałbym tego * dobrym * rozwiązaniem, ale jest to jedyne, które mam w tej chwili. – misha

2

Współczynnik jakości bitrate w JPG jest całkowicie zależny od zawartości. Jeśli chcesz kodować z określoną szybkością transmisji, sugeruję wykonanie dwóch przebiegów: 1. Kodowanie ze stałym współczynnikiem jakości (bliższe do docelowej szybkości transmisji jest lepsze, może być oparte na twoim wykresie) 2. W oparciu o jego rozmiar , ponownie koduj oryginał w wyższej lub niższej jakości. Znowu może to być oparte na twoim wykresie lub czymś podobnym.

Można również powtarzać ostatni krok w nieskończoność, aby uzyskać dokładną szybkość transmisji, której potrzebujesz.

Testowałem to w różnych ekstremalnych przypadkach, takich jak bardzo głośny/zajęty obraz, czarny prostokąt lub płynny gradient.