0

I need to convert 24bppRGB to 16bppRGB, 8bppRGB, 4bppRGB, 8bpp grayscal and 4bpp grayscale. Any good link or other suggestions?

preferably using Windows/GDI+

[EDIT] speed is more critical than quality. source images are screenshots [EDIT1] color conversion is required to minimize space

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112
  • the RGB formats are just downscaling. the grayscale is more intricate if you want good results. for good results have to convert to lab or something like that – Cheers and hth. - Alf Feb 08 '11 at 00:29
  • Yeah, just loop over the the array, and write into another with down sampled color channels. – Arelius Feb 08 '11 at 00:31
  • @Arelius: as I understand, it's not so simple, because for bpp <= 8 I need to use indexed color (palette). I would highly appreciate any examples – Andriy Tylychko Feb 08 '11 at 00:45
  • @Andy: sorry about "just downscaling" comment, i forgot all about palettes (it's long ago). but still, note that for good results you need more than just averaging for the grayscale pics – Cheers and hth. - Alf Feb 08 '11 at 00:50
  • Indexed color is also simple, it's just a quick array lookup and then you have the color in beautiful 8bpp, continue from there. – Arelius Feb 08 '11 at 01:43
  • 1
    @Arelius, Indexed color is anything but simple. What method do you use to create the palette? How do you look up the closest color in the palette given an arbitrary 24bit color? Do you dither? Which algorithm? – Mark Ransom Feb 08 '11 at 02:11
  • @Mark, It's not quite as simple as some of the other conversions. But it's not an enormous task either. Those other choices depend greatly on your specific needs. The specific algorithms needed depend on the usage. – Arelius Feb 08 '11 at 06:25

4 Answers4

3

You're better off getting yourself a library, as others have suggested. Aside from ImageMagick, there are others, such as OpenCV. The benefits of leaving this to a library are:

  • Save yourself some time -- by cutting out dev and testing time for the algorithm
  • Speed. Most libraries out there are optimized to a level far greater than a standard developer (such as ourselves) could achieve
  • Standards compliance. There are many image formats out there, and using a library cuts the problem of standards compliance out of the equation.

If you're doing this yourself, then your problem can be divided into the following sub-problems:

  1. Simple color quantization. As @Alf P. Steinbach pointed out, this is just "downscaling" the number of colors. RGB24 has 8 bits per R, G, B channels, each. For RGB16 you can do a number of conversions:
    • Equal number of bits for each of R, G, B. This typically means 4 or 5 bits each.
    • Favor the green channel (human eyes are more sensitive to green) and give it 6 bits. R and B get 5 bits.
    • You can even do the same thing for RGB24 to RGB8, but the results won't be as pretty as a palletized image:
    • 4 bits green, 2 red, 2 blue.
    • 3 bits green, 5 bits between red and blue
  2. Palletization (indexed color). This is for going from RGB24 to RGB8 and RGB4. This is a hard problem to solve by yourself.
  3. Color to grayscale conversion. Very easy. Convert your RGB24 to YUV' color space, and keep the Y' channel. That will give you 8bpp grayscale. If you want 4bpp grayscale, then you either quantize or do palletization.
  4. Also be sure to check out chroma subsampling. Often, you can decrease the bitrate by a third without visible losses to image quality.

With that breakdown, you can divide and conquer. Problems 1 and 2 you can solve pretty quickly. That will allow you to see the quality you can get simply by doing coarser color quantization.

Whether or not you want to solve Problem 2 will depend on the result from above. You said that speed is more important, so if the quality of color quantization only is good enough, don't bother with palletization.

Finally, you never mentioned WHY you are doing this. If this is for reducing storage space, then you should be looking at image compression. Even lossless compression will give you better results than reducing the color depth alone.

EDIT

If you're set on using PNG as the final format, then your options are quite limited, because both RGB16 and RGB8 are not valid combinations in the PNG header.

So what this means is: regardless of bit depth, you will have to switch to index color if you want RGB color images below 24bpp (8 bits per channel). This means you will NOT be able to take advantage of the color quantization and chroma decimation that I mentioned above -- it's not supported in PNG. So this means you will have to solve Problem 2 -- palletization.

But before you think about that, some more questions:

  • What are the dimensions of your images?
  • What sort of ideal file-size are you after?
  • How close to that ideal file-size do you get with straight RBG24 + PNG compression?
  • What is the source of your images? You've mentioned screenshots, but since you're so concerned about disk space, I'm beginning to suspect that you might be dealing with image sequences (video). If this is so, then you could do better than PNG compression.

    Oh, and if you're serious about doing things with PNG, then definitely have a look at this library.

mpenkov
  • 21,621
  • 10
  • 84
  • 126
  • Good answer. Problem with OpenCV is that it does not support indexed files. So while you can use k-means and others to quantize the input, you cannot write the result to an image file. Maybe not necessary for the OP anyway. – ypnos Feb 08 '11 at 09:46
  • Thanks. You're absolutely right. Although you can't use OpenCV's `cvSaveImage` and `cv::imwrite` to save indexed color images, you can still write your own image I/O functions, e.g. http://stackoverflow.com/questions/2231518/how-to-read-a-frame-from-yuv-file-in-opencv. The problem is that standards compliance (and typically speed) go **flying out the window**... but it saves dev time, so it's better than nothing. Good point about k-means, too -- if the OP clarifies his question re **WHY**, it may be worth expanding on that. – mpenkov Feb 08 '11 at 10:01
  • @misha: +1 for detailed answer. color conversion is required to minimize image size. after that I'll compress them to PNG – Andriy Tylychko Feb 08 '11 at 13:29
  • @Andy T: if you're using PNG, a lot will change. Look at my updated answer. – mpenkov Feb 08 '11 at 13:56
  • @misha: 1) yeah, standard PNG doesn't support 16bpp color, only 16bpp grayscale, but in practice i didn't see an image application that cannot handle it; 2) different desktop resolutions; 3) the smaller size the better but speed is more important; 4) video encoding (involving inter-frame compression) is too heavy (in general) – Andriy Tylychko Feb 08 '11 at 16:23
  • @Andy T, even though PNG doesn't support 16bpp color, you may get better compression by reducing the number of colors contained in the 24bpp before saving it. I just tested one screen capture that went from 56K to 47K using this method; the result wasn't drastic because PNG already does a good job of compressing, the uncompressed file would have been over 3GB! – Mark Ransom Feb 08 '11 at 20:48
  • @Mark: not sure i got your point. it's why I was asking about color reduction from 24bpp to all these color modes, to reduce the image itself before compressing it by PNG. pls elaborate – Andriy Tylychko Feb 08 '11 at 22:50
1

Find your self a copy of the ImageMagick [sic] library. It's very configurable, so you can teach it about the details of some binary format that you need to process...

Sniggerfardimungus
  • 11,583
  • 10
  • 52
  • 97
  • ImageMagick will do the job, however it's a giant library, certainly overkill for this sort of job. – Arelius Feb 08 '11 at 01:45
  • @Arelius, nothing is overkill if you need color reduction to a palette - that's not something you can easily whip up yourself. – Mark Ransom Feb 08 '11 at 02:08
  • @Mark, well that depends on your needs of palettization. While the algorithms are less intuitive, very suitible palette reduction can be done in a rather trivial amount of time. Do note that at no point does he say he needs to reduce to palette. The smallest color format he lists is '4bppRGB' which is 16bit non-palettized color. Even in that case, I'd call ImageMagick greatly overkill. – Arelius Feb 08 '11 at 05:45
  • @Arelius: 4bppRGB = 16bit non-palettized color? why? I thought it's 4bit palettized (indexed) color – Andriy Tylychko Feb 08 '11 at 09:01
  • @user30997: cannot find such functionality in ImageMagick, can you provide any link that points to it please? – Andriy Tylychko Feb 10 '11 at 11:52
1

See: ImageMagick, which has a very practical license.

Keith
  • 6,756
  • 19
  • 23
0

I received acceptable results (preliminary) by GDI+, v.1.1 that is shipped with Vista and Win7. It allows conversion to 16bpp (I used PixelFormat16bppRGB565) and to 8bpp and 4bpp using standard palettes. Better quality could be received by "optimal palette" - GDI+ would calculate optimal palette for each screenshot, but it's two times slower conversion. Grayscale was received by specifying simple custom palette, e.g. as demonstrated here, except that I didn't need to modify pixels manually, Bitmap::ConvertFormat() did it for me.

[EDIT] results were really acceptable until I decided to check the solution on WinXP. Surprisingly, Microsoft decided to not ship GDI+ v.1.1 (required for Bitmap::ConvertFormat) to WinXP. Nice move! So I continue researching...

[EDIT] had to reimplement this on clean GDI hardcoding palettes from GDI+

Andriy Tylychko
  • 15,967
  • 6
  • 64
  • 112