如何为JPEG压缩指定比特率?

时间:2011-01-13 06:55:26

标签: image-processing compression opencv imagemagick jpeg

有没有办法以特定的比特率编码JPEG?

目前,我正在使用imagemagick的convert

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

比特率随着质量的提高而增加,但它是非线性的。我想明确地控制比特率。它不一定非常精确,但我希望它合理地接近(在指定设置的0.1 bpp内)。

那里是否有任何编码器允许以特定的比特率编码图像?它不一定是imagemagick,我会采取任何工作(最好在Linux上)。

这样做的一个愚蠢的方法是使用小数值到-quality参数,直到接近目标比特率出现,但我希望有一个更优雅的解决方案。

修改

所以我感到无聊,决定以快速(但很愚蠢)的方式做事。

首先,这是imagemagick的-quality与比特率的图表:

alt text

BTW,这是我用的图像:

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
misha@misha-desktop:~/co/cpp$ ./jpeg-bitrate.out Lenna-gray.png test.jpeg 0.53
wrote test.jpeg at 88% quality, 0.55bpp

2 个答案:

答案 0 :(得分:4)

我知道在控制JPEG编码器的输出比特率方面存在很多工作(例如1st paper; 2nd paper),并且这些控制存在于JPEG2000中。不幸的是,我不确定任何类型的比特率控制是针对JPEG标准化的,还是在公共库中实现的。您可能必须编写自己的方法,例如使用某种二进制搜索...

但是,我可能也错了 - 如果是的话,我很想知道这样的图书馆。

出于好奇,你用的是哪种语言?

答案 1 :(得分:2)

JPG中的比特率质量比很大程度上取决于内容。如果你想以特定的比特率编码,我建议你做两遍:  1.以固定的品质因数编码(更接近目标比特率更好,可以基于您的图表)  2.根据尺寸,以更高或更低的质量重新编码原件。同样,这可以基于您的图表或类似的东西。

您也可以无限期地重复最后一步,以获得所需的精确比特率。

我会用各种极端情况对其进行测试,例如非常嘈杂/繁忙的图像,黑色矩形或平滑渐变。