How do I do high quality scaling of a image?

末鹿安然 提交于 2019-12-03 02:03:29

问题


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


回答1:


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".




回答2:


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




回答3:


Is it possible that OpenGL is doing the scaling in the vector domain? If so, there is no way that any pixel-based scaling is going to be near it in quality. This is the big advantage of vector based images.

The bicubic algorithm can be tuned for sharpness vs. artifacts - I'm trying to find a link, I'll edit it in when I do.

Edit: It was the Mitchell-Netravali work that I was thinking of, which is referenced at the bottom of this link:

http://www.cg.tuwien.ac.at/~theussl/DA/node11.html

You might also look into Lanczos resampling as an alternative to bicubic.




回答4:


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.




回答5:


CodeProject articles discussing and sharing source code for scaling images:

  • Two Pass Scaling using Filters
  • Matrix Transformation of Images in C#, using .NET GDI+
  • Resizing a Photographic image with GDI+ for .NET
  • Fast Dyadic Image Scaling with Haar Transform



回答6:


Try using the Adobe Generic Image Library ( http://opensource.adobe.com/wiki/display/gil/Downloads ) if you want something ready and not only an algorithm.


Extract from: http://www.catenary.com/howto/enlarge.html#c

Enlarge or Reduce - the C Source Code Requires Victor Image Processing Library for 32-bit Windows v 5.3 or higher.


int enlarge_or_reduce(imgdes *image1)
{
   imgdes timage;
   int dx, dy, rcode, pct = 83; // 83% percent of original size

   // Allocate space for the new image
   dx = (int)(((long)(image1->endx - image1->stx + 1)) * pct / 100);
   dy = (int)(((long)(image1->endy - image1->sty + 1)) * pct / 100);
   if((rcode = allocimage(&timage, dx, dy,
      image1->bmh->biBitCount)) == NO_ERROR) {
      // Resize Image into timage
      if((rcode = resizeex(image1, &timage, 1)) == NO_ERROR) {
         // Success, free source image
         freeimage(image1);
         // Assign timage to image1
         copyimgdes(&timage, image1);
         }
      else // Error in resizing image, release timage memory
         freeimage(&timage);
      }
   return(rcode);
}

This example resizes an image area and replaces the original image with the new image.




回答7:


Intel has IPP libraries which provide high speed interpolation algorithms optimized for Intel family processors. It is very good but it is not free though. Take a look at the following link:

Intel IPP




回答8:


A generic article from our beloved host: Better Image Resizing, discussing the relative qualities of various algorithms (and it links to another CodeProject article).




回答9:


It sounds like what you're really having difficulty understanding is the discrete -> continuous -> discrete flow involved in properly resampling an image. A good tech report that might help give you the insight into this that you need is Alvy Ray Smith's A Pixel Is Not A Little Square.




回答10:


Take a look at ImageMagick, which does all kinds of rescaling filters.




回答11:


As a follow up, Jeremy Rudd posted this article above. It implements filtered two pass resizing. The sources are C# but it looks clear enough that I can port it to give it a try. I found very similar C code yesterday that was much harder to understand (very bad variable names). I got it to sort-of-work, but it was very slow and did not produce good results which led me to believe there was an error in my adaptation. I may have better luck writing it from scratch with this as a reference, which I'll try.

But considering how the two pass algorithm works I wonder if there isn't a faster way of doing it, perhaps even in one pass?



来源:https://stackoverflow.com/questions/353039/how-do-i-do-high-quality-scaling-of-a-image

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!