2011-01-13 144 views
8

有沒有辦法以特定比特率對JPEG進行編碼?如何指定JPEG壓縮的比特率?

目前,我使用ImageMagick的convert

convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg 

與質量的比特率的增加,但它是非線性的。我想明確控制比特率。它不一定是確切的,但我希望它合理地接近(在指定設置的0.1 bpp內)。

那裏有任何編碼器允許圖像以特定比特率編碼嗎?它不一定是imagemagick,我會採取任何作品(最好在Linux上)。

一個愚蠢的做法是將參數-quality的小數部分放在一起,直到接近目標比特率的東西出來,但我希望得到更優雅的解決方案。

編輯:

所以我覺得無聊,並決定做事情快(但愚蠢的)的方式。

首先,這裏ImageMagick的-quality的VS碼率圖:

alt text

順便說一句,這是我所使用的圖像:

alt text

所以在比特率的變化是相當精細較低的質量值,但在約80後變得粗糙。

以下是一些示例代碼,以某種目標比特率對圖像進行編碼。我使用了OpenCV,因爲它允許內存中的JPEG編碼(不需要I/O)。雖然我原本打算用Python進行模擬,但不幸的是,Python OpenCV包裝程序不公開內存編碼功能。所以我用C++寫了它。

最後,我在考慮在質量上使用線性插值以接近目標比特率,但由於cv::imencode只接受整數參數,因此無法設置非整數JPEG質量。 OpenCV和imagemagick之間的質量規模似乎也有所不同,所以從OpenCV獲取內插質量參數並在imagemagick的convert中使用效果不理想。

這意味着輸出比特率不等於目標比特率,特別是在較高比特率(> 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 
[email protected]:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53 
wrote test.jpeg at 88% quality, 0.55bpp 
+1

建議:刪除for循環,用搜索替換。我無法相信任何人都會想要一個質量因子編碼的JPEG,編碼範圍爲1->〜30或〜99-> 100。您還可以爲各種不同的圖像類型創建圖形,併爲搜索找到更好的初始起點。這是非常天真的,因爲你甚至不考慮質量(例如PSNR)。選擇一個不同的量化表可能會讓你想要的比特率,但質量更高。 – koan 2011-01-14 10:11:58

+0

感謝您的建議。搜索可以提高代碼的效率,但目前它並不是真正的問題,因爲它的速度足夠快。你的質量是正確的 - 大多數普通人不需要質量低下的JPEG,因爲他們看起來像垃圾。但是,我自己*對這些圖像感興趣,因爲我正在研究圖像降級。關於量化表的觀點很有趣 - 我想我會研究它。它可能需要離開OpenCV並使用像ijg這樣的東西,因爲OpenCV似乎沒有公開量化表。 – misha 2011-01-14 13:17:19

回答

4

我知道了很多工作,存在於控制JPEG編碼器的輸出比特率(如1st paper; 2nd paper),以及這些控件存在於JPEG2000中。不幸的是,我不確定任何類型的比特率控制是針對JPEG標準還是在通用庫中實現的。你可能必須編碼你自己的方法,使用某種二進制搜索的例子...

但是,我可能會誤會 - 如果是這樣,我很樂意聽到這樣一個圖書館。

出於好奇,你用什麼語言?

2

JPG中的比特率質量比完全取決於內容。如果你想以特定比特率進行編碼,我建議你做兩遍: 1.以固定的質量因子進行編碼(更接近目標比特率更好,可以根據你的圖表) 2.根據其大小以較高或較低的質量重新編碼原稿。再次,這可以基於您的圖表或類似的東西。

您也可以無限期地重複上一步以獲得您需要的EXACT比特率。

我會測試這與各種極端的情況下,像一個非常嘈雜/繁忙的圖像,黑色的矩形,或平滑的漸變。