开发者

How to specify bitrate for JPEG compression?

Is there a way to encode JPEG at a specific bitrate?

Presently, I'm using imagemagick's convert:

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

Bitrate increases with quality, but it's non-linear. I want to control the bitrate explicitly. It doesn't have to be exact, but I want it reasonably close (within, say 0.1 bpp of the specified setting).

Is there any encoder there that allows images to be encoded at a particular bit-rate? It doesn't have to be imagemagick, I'll take whatever works (preferably on Linux).

A dumb way to do this would be to play around with fractional values to the -quality parameter until something close to the target bitrate comes out, but I'm hoping for a more elegant solution.

EDIT:

So I got bored and decided to do things the quick (but stupid) way.

First, here's a graph of imagemagick's -quality vs bitrate:

How to specify bitrate for JPEG compression?

BTW, here's the image I used:

How to specify bitrate for JPEG compression?

So the change in bitrate is quite fine for lower quality values, but becomes coarse after about 80.

Here's some sample code to encode an image at some target bitrate. I used OpenCV cause it allows for in-memor开发者_如何学编程y JPEG encoding (no I/O necessary). While I originally was going to mock this up with Python, unfortunately the Python OpenCV wrappers don't expose the in-memory encoding functionality. So I wrote it in C++.

Lastly, I was thinking of using linear interpolation on the quality to get closer to the target bitrate, but since cv::imencode only accepts integer parameters, it's not possible to set a non-integer JPEG quality. The quality scale between OpenCV and imagemagick seems to differ somewhat as well, so taking the interpolated quality parameter from OpenCV and using in imagemagick's convert didn't work well.

This means that the output bitrate isn't equal to the target bitrate, especially at higher bitrates ( > 1). But it's close.

Can anyone suggest something better?

Code:

#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;
}

Compile and run using:

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


I know a lot of work exist on controlling the output bitrate of a JPEG encoder (e.g. 1st paper ; 2nd paper), and that such controls exist in JPEG2000. Unfortunately, I'm not sure any kind of bitrate control is standardized for JPEG, or implemented in common libraries. You may have to code your own method, using some kind of binary search for instance...

But again, I may be mistaken - and if so, I'd love to hear about such a library.

Just out of curiosity, what language are you using ?


The bitrate-quality ratio in JPG is quite dependant on content. If you want to encode at a specific bitrate, I suggest you do it two passes: 1. Encode at a fixed quality factor (closer to your target bitrate is better, could be based on your graph) 2. Based on its size, reencode the original at a greater or lower quality. Again this can be based on your graph or something similar.

You could also repeat the last step indefinitely to get the EXACT bitrate you need.

I'd test this with various extreme cases, like a very noisy/busy image, a black rectangle, or a smooth gradient.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜