Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do high quality scaling of a image?

I'm writing some code to scale a 32 bit RGBA image in C/C++. I have written a few attempts that have been somewhat successful, but they're slow and most importantly the quality of the sized image is not acceptable.

I compared the same image scaled by OpenGL (i.e. my video card) and my routine and it's miles apart in quality. I've Google Code Searched, scoured source trees of anything I thought would shed some light (SDL, Allegro, wxWidgets, CxImage, GD, ImageMagick, etc.) but usually their code is either convoluted and scattered all over the place or riddled with assembler and little or no comments. I've also read multiple articles on Wikipedia and elsewhere, and I'm just not finding a clear explanation of what I need. I understand the basic concepts of interpolation and sampling, but I'm struggling to get the algorithm right. I do NOT want to rely on an external library for one routine and have to convert to their image format and back. Besides, I'd like to know how to do it myself anyway. :)

I have seen a similar question asked on stack overflow before, but it wasn't really answered in this way, but I'm hoping there's someone out there who can help nudge me in the right direction. Maybe point me to some articles or pseudo code... anything to help me learn and do.

Here's what I'm looking for:

  1. No assembler (I'm writing very portable code for multiple processor types).
  2. No dependencies on external libraries.
  3. I am primarily concerned with scaling DOWN, but will also need to write a scale up routine later.
  4. Quality of the result and clarity of the algorithm is most important (I can optimize it later).

My routine essentially takes the following form:

DrawScaled(uint32 *src, uint32 *dst, 
      src_x, src_y, src_w, src_h, 
      dst_x, dst_y, dst_w, dst_h );

Thanks!

UPDATE: To clarify, I need something more advanced than a box resample for downscaling which blurs the image too much. I suspect what I want is some kind of bicubic (or other) filter that is somewhat the reverse to a bicubic upscaling algorithm (i.e. each destination pixel is computed from all contributing source pixels combined with a weighting algorithm that keeps things sharp.

Example

Here's an example of what I'm getting from the wxWidgets BoxResample algorithm vs. what I want on a 256x256 bitmap scaled to 55x55.

  • www.free_image_hosting.net/uploads/1a25434e0b.png

And finally:

  • www.free_image_hosting.net/uploads/eec3065e2f.png

the original 256x256 image

like image 263
Patrick Hogan Avatar asked Dec 09 '08 15:12

Patrick Hogan


People also ask

How can I scale an image without losing quality?

If you want to resize an image without losing quality, you need to make sure that the "Resample" checkbox is unchecked. This checkbox tells Paint to change the number of pixels in the image. When you uncheck this box, Paint will not change the number of pixels, and the quality of the image will not be reduced.

How do I resize a PNG without losing quality?

Go to Image, then Scale, where you can input your desired dimensions. Finally, under the Quality, choose Sinc as Interpolation and then click Scale. There you have it, an image resize with sustained quality.


3 Answers

I've found the wxWidgets implementation fairly straightforward to modify as required. It is all C++ so no problems with portability there. The only difference is that their implementation works with unsigned char arrays (which I find to be the easiest way to deal with images anyhow) with a byte order of RGB and the alpha component in a separate array.

If you refer to the "src/common/image.cpp" file in the wxWidgets source tree there is a down-sampler function which uses a box sampling method "wxImage::ResampleBox" and an up-scaler function called "wxImage::ResampleBicubic".

like image 74
Dan Avatar answered Oct 18 '22 23:10

Dan


A fairly simple and decent algorithm to resample images is Bicubic interpolation, wikipedia alone has all the info you need to get this implemented.

like image 34
Pieter Avatar answered Oct 18 '22 23:10

Pieter


Now that I see your original image, I think that OpenGL is using a nearest neighbor algorithm. Not only is it the simplest possible way to resize, but it's also the quickest. The only downside is that it looks very rough if there's any detail in your original image.

The idea is to take evenly spaced samples from your original image; in your case, 55 out of 256, or one out of every 4.6545. Just round the number to get the pixel to choose.

like image 2
Mark Ransom Avatar answered Oct 19 '22 00:10

Mark Ransom