Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to specify bitrate for JPEG compression?
    text
    copied!<p>Is there a way to encode JPEG at a specific bitrate?</p> <p>Presently, I'm using imagemagick's <code>convert</code>:</p> <pre><code>convert Lenna-gray-100.jpeg -quality 1.1111 test.jpeg </code></pre> <p>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).</p> <p>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).</p> <p>A dumb way to do this would be to play around with fractional values to the <code>-quality</code> parameter until something close to the target bitrate comes out, but I'm hoping for a more elegant solution.</p> <p><strong>EDIT:</strong></p> <p>So I got bored and decided to do things the quick (but stupid) way.</p> <p>First, here's a graph of imagemagick's <code>-quality</code> vs bitrate:</p> <p><img src="https://i.stack.imgur.com/byOaY.png" alt="alt text"></p> <p>BTW, here's the image I used:</p> <p><img src="https://i.stack.imgur.com/Ay3s2.png" alt="alt text"></p> <p>So the change in bitrate is quite fine for lower quality values, but becomes coarse after about 80.</p> <p>Here's some sample code to encode an image at some target bitrate. I used OpenCV cause it allows for in-memory 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++.</p> <p>Lastly, I was thinking of using linear interpolation on the quality to get closer to the target bitrate, but since <code>cv::imencode</code> 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 <code>convert</code> didn't work well.</p> <p>This means that the output bitrate isn't equal to the target bitrate, especially at higher bitrates ( > 1). But it's close.</p> <p>Can anyone suggest something better?</p> <p>Code:</p> <pre><code>#include &lt;stdio.h&gt; #include &lt;cv.h&gt; #include &lt;highgui.h&gt; #include &lt;assert.h&gt; #include &lt;vector&gt; 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", &amp;target); Mat orig = cv::imread(fname_in); int pixels = orig.size().width * orig.size().height * orig.channels(); vector&lt;unsigned char&gt; buf; vector&lt;int&gt; params = vector&lt;int&gt;(2); params[0] = CV_IMWRITE_JPEG_QUALITY; int q; double bpp = 0.0; for (q = 1; q &lt; QUALITY_UBOUND; ++q) { params[1] = q; cv::imencode(IMENCODE_FMT, orig, buf, params); bpp = (double)buf.size() * BITS_PER_BYTE / pixels; if (bpp &gt; target) break; } cv::imwrite(fname_out, orig, params); printf("wrote %s at %d%% quality, %.2fbpp\n", fname_out, q, bpp); return 0; } </code></pre> <p>Compile and run using:</p> <pre><code>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 </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload