如何对图像进行高质量缩放?

时间:2008-12-09 15:05:50

标签: c++ c image image-manipulation image-scaling

我正在编写一些代码来扩展C / C ++中的32位RGBA图像。我已经写过一些有些成功的尝试,但它们很慢,最重要的是尺寸图像的质量是不可接受的。

我比较了由OpenGL(即我的视频卡)和我的例程缩放的相同图像,它的质量相差几英里。我已经搜索了Google代码,搜索了我认为可以解决一些问题的源代码树(SDL,Allegro,wxWidgets,CxImage,GD,ImageMagick等),但通常他们的代码要么是错综复杂的,要么遍布整个地方或者充满了各种各样的代码。汇编程序,很少或没有评论。我还阅读了维基百科和其他地方的多篇文章,我只是没有找到我需要的明确解释。我理解插值和采样的基本概念,但我很难让算法正确。我不想依赖外部库来完成一个例程,并且必须转换为它们的图像格式并返回。此外,无论如何,我想知道如何自己做。 :)

我之前看过一个关于堆栈溢出问题的类似问题,但它并没有真正以这种方式回答,但我希望那里的某些人可以帮助推动我朝着正确的方向前进。也许请指点一些文章或伪代码......任何可以帮助我学习和做的事。

这就是我要找的东西:

  1. 没有汇编程序(我正在为多种处理器类型编写非常可移植的代码)。
  2. 不依赖外部库。
  3. 我主要关注的是缩放DOWN,但是稍后还需要编写一个扩展例程。
  4. 结果的质量和算法的清晰度是最重要的(我可以稍后对其进行优化)。
  5. 我的例程基本上采用以下形式:

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

    谢谢!

    更新:为了澄清,我需要一些比盒子重新采样更高级的东西来缩小图像,这会使图像模糊不清。我怀疑我想要的是某种双三次(或其他)滤波器,它与双三次升频算法有些相反(即每个目标像素都是根据所有贡献源像素和加权算法计算得出的,这种算法可以保持锐利。

    实施例

    以下是我从wxWidgets BoxResample算法得到的内容与我想要的256x256位图缩放到55x55的示例。

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

    最后:

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

    原始256x256图像

11 个答案:

答案 0 :(得分:2)

我发现wxWidgets实现非常简单,可以根据需要进行修改。这是所有C ++所以没有可移植性的问题。唯一的区别是它们的实现与无符号字符数组(我发现无论如何最简单的处理图像的方式)一起工作,RGB字节顺序和单独数组中的alpha分量。

如果您参考wxWidgets源代码树中的“src / common / image.cpp”文件,则会有一个下采样器函数,该函数使用盒子采样方法“wxImage :: ResampleBox”和一个名为“up-scaler”的函数wxImage :: ResampleBicubic”。

答案 1 :(得分:2)

重新采样图像的一个相当简单和不错的算法是Bicubic interpolation,仅维基百科就拥有了实现这一目标所需的所有信息。

答案 2 :(得分:2)

OpenGL是否可能在矢量域中进行缩放?如果是这样,任何基于像素的缩放都无法在质量上接近它。这是基于矢量的图像的一大优势。

双三次算法可以针对锐度与工件进行调整 - 我正在尝试找到一个链接,我会在我做的时候编辑它。

编辑:我正在考虑的是Mitchell-Netravali的作品,在这个链接的底部引用:

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

您也可以将Lanczos resampling视为双三次的替代方法。

答案 3 :(得分:2)

现在我看到了原始图像,我认为OpenGL正在使用最近邻居算法。它不仅是最简单的调整大小的方法,而且也是最快的。唯一的缺点是,如果原始图像中有任何细节,它看起来非常粗糙。

我们的想法是从原始图像中采集均匀间隔的样本;在你的情况下,256个中的55个,或每4.6545中的一个。只需将数字四舍五入即可选择像素。

答案 4 :(得分:1)

答案 5 :(得分:1)

尝试使用 Adob​​e通用图片库http://opensource.adobe.com/wiki/display/gil/Downloads),如果您想要准备就绪而不仅仅是算法。


摘自:http://www.catenary.com/howto/enlarge.html#c

放大或缩小 - C源代码 需要适用于32位Windows v 5.3或更高版本的Victor Image Processing Library。


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

此示例调整图像区域的大小,并用新图像替换原始图像。

答案 6 :(得分:1)

来自我们心爱的主持人的通用文章:Better Image Resizing,讨论各种算法的相对质量(并链接到另一个CodeProject文章)。

答案 7 :(得分:1)

英特尔拥有IPP库,可提供针对英特尔系列处理器优化的高速插值算法。这是非常好的,但它不是免费的。请看以下链接:

Intel IPP

答案 8 :(得分:1)

听起来你真正难以理解的是离散的 - >连续 - >离散流程涉及正确重新取样图像。一份好的技术报告可能会让你深入了解你需要的是Alvy Ray Smith的A Pixel Is Not A Little Square

答案 9 :(得分:0)

查看ImageMagick,它会执行各种重新缩放过滤器。

答案 10 :(得分:0)

作为后续行动,杰里米·拉德在上面发布了this article。它实现了过滤的两次调整大小。源代码是C#,但它看起来很清楚,我可以移植它来试一试。昨天我发现了非常相似的C代码,这个代码更难理解(非常糟糕的变量名称)。我得到它的工作,但它很慢,并没有产生良好的结果,这使我相信我的改编有错误。我可能有更好的运气从头开始写这个作为参考,我会尝试。

但考虑到两遍算法是如何工作的,我想知道是否有更快的方法,甚至可能在一次通过中?