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

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

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

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

这是我正在寻找的:

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

我的例程基本上采用以下forms:

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

谢谢!

更新:为了澄清,我需要一些比盒子重新采样更先进的东西,用于降尺度,这会使图像模糊不清。 我怀疑我想要的是某种双三次(或其他)滤波器,它与双三次升频算法有些相反(即每个目标像素都是从所有贡献源像素计算得出的,并结合了保持锐利的加权算法。

这是我从wxWidgets BoxResample算法得到的例子与我想要的256×256位图缩放到55×55的例子。

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

最后:

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

原始的256×256图像

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

如果你在wxWidgets源代码树中引用“src / common / image.cpp”文件,那么有一个下采样器函数,它使用盒子采样方法“wxImage :: ResampleBox”和一个名为“wxImage ::”的向上扩展器函数。 ResampleBicubic”。

一个相当简单和体面的重新采样图像算法是双立方插值 ,仅维基百科就拥有了实现这一点所需的所有信息。

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

双三次算法可以针对锐度与工件进行调整 – 我正在尝试查找链接,我会在编辑时进行编辑。

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

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

您也可以将Lanczos重新取样作为双三次方的替代方案。

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

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

CodeProject文章讨论和共享缩放图像的源代码

  • 使用filter的两次通过缩放
  • 使用.NET GDI +在C#中对图像进行矩阵变换
  • 使用GDI + for .NET调整摄影图像大小
  • Haar变换的快速二元图像缩放

如果您想要准备好的东西而不仅仅是算法,请尝试使用Adobe通用图像库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); } 

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

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

英特尔IPP

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

听起来你真正难以理解的是离散 – >连续 – >离散流程,正确地重新取样图像。 一个好的技术报告可能会帮助你深入了解你需要的是Alvy Ray Smith的A Pixel 不是一个小广场 。

看看ImageMagick ,它可以完成各种重新缩放滤镜。

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

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