我正在编写一些代码来扩展C / C ++中的32位RGBA图像。我已经写过一些有些成功的尝试,但它们很慢,最重要的是尺寸图像的质量是不可接受的。
我比较了由OpenGL(即我的视频卡)和我的例程缩放的相同图像,它的质量相差几英里。我已经搜索了Google代码,搜索了我认为可以解决一些问题的源代码树(SDL,Allegro,wxWidgets,CxImage,GD,ImageMagick等),但通常他们的代码要么是错综复杂的,要么遍布整个地方或者充满了各种各样的代码。汇编程序,很少或没有评论。我还阅读了维基百科和其他地方的多篇文章,我只是没有找到我需要的明确解释。我理解插值和采样的基本概念,但我很难让算法正确。我不想依赖外部库来完成一个例程,并且必须转换为它们的图像格式并返回。此外,无论如何,我想知道如何自己做。 :)
我之前看过一个关于堆栈溢出问题的类似问题,但它并没有真正以这种方式回答,但我希望那里的某些人可以帮助推动我朝着正确的方向前进。也许请指点一些文章或伪代码......任何可以帮助我学习和做的事。
这就是我要找的东西:
我的例程基本上采用以下形式:
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的示例。
最后:
原始256x256图像
答案 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)
CodeProject文章讨论和共享缩放图像的源代码:
答案 5 :(得分:1)
尝试使用 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);
}
此示例调整图像区域的大小,并用新图像替换原始图像。
答案 6 :(得分:1)
来自我们心爱的主持人的通用文章:Better Image Resizing,讨论各种算法的相对质量(并链接到另一个CodeProject文章)。
答案 7 :(得分:1)
英特尔拥有IPP库,可提供针对英特尔系列处理器优化的高速插值算法。这是非常好的,但它不是免费的。请看以下链接:
答案 8 :(得分:1)
听起来你真正难以理解的是离散的 - >连续 - >离散流程涉及正确重新取样图像。一份好的技术报告可能会让你深入了解你需要的是Alvy Ray Smith的A Pixel Is Not A Little Square。
答案 9 :(得分:0)
查看ImageMagick,它会执行各种重新缩放过滤器。
答案 10 :(得分:0)
作为后续行动,杰里米·拉德在上面发布了this article。它实现了过滤的两次调整大小。源代码是C#,但它看起来很清楚,我可以移植它来试一试。昨天我发现了非常相似的C代码,这个代码更难理解(非常糟糕的变量名称)。我得到它的工作,但它很慢,并没有产生良好的结果,这使我相信我的改编有错误。我可能有更好的运气从头开始写这个作为参考,我会尝试。
但考虑到两遍算法是如何工作的,我想知道是否有更快的方法,甚至可能在一次通过中?