代码之家  ›  专栏  ›  技术社区  ›  BenAlabaster

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

  •  18
  • BenAlabaster  · 技术社区  · 16 年前

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

    我比较了用OpenGL(即我的显卡)缩放的同一张图像和我的程序,它的质量相差几英里。我搜索过Google代码,搜索过任何我认为可以提供一些信息的源代码树(SDL、Allegro、wxWidgets、CxImage、GD、ImageMagick等),但通常它们的代码要么是复杂的,要么是散乱的,要么是塞满了汇编程序,几乎没有评论。我也读过维基百科和其他地方的多篇文章,我只是没有找到一个明确的解释,我需要什么。我了解插值和采样的基本概念,但我正在努力使算法正确。我不想依赖于一个外部库的一个例行程序,必须转换成他们的图像格式和回来。再说了,反正我也想知道怎么做。:)

    我以前在stack overflow上见过类似的问题,但并没有得到这样的回答,但我希望有人能帮助我朝正确的方向前进。也许可以给我指一些文章或伪代码。。。任何能帮助我学习和做的事。

    我要找的是:

    1. 不依赖外部库。
    2. 我主要关心的是缩小比例,但以后也需要编写一个放大的例程。
    3. 结果的质量和算法的清晰性是最重要的(我可以稍后对其进行优化)。

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

    谢谢!

    更新: 为了澄清这一点,我需要一个比盒子重采样更先进的方法来缩小图像,这样会使图像变得更模糊。我怀疑我想要的是某种双三次(或其他)滤波器,它与双三次放大算法有点相反(即,每个目标像素都是从所有有贡献的源像素中计算出来的,并与保持事物清晰的加权算法相结合)。

    下面是一个例子,我从wxWidgets的box重采样算法中得到了什么,而不是我想要的256x256位图缩放到55x55。

    最后:

    原图256x256

    11 回复  |  直到 7 年前
        1
  •  2
  •   Dan    16 年前

    我发现wxWidgets实现很容易根据需要进行修改。它都是C++的,所以在那里没有可移植性的问题。唯一的区别是,它们的实现使用无符号字符数组(我发现这是处理图像最简单的方法),字节顺序为RGB,alpha组件在单独的数组中。

    如果您引用wxWidgets源树中的“src/common/image.cpp”文件,则有一个down sampler函数,它使用一个box采样方法“wxImage::ResampleBox”和一个名为“wxImage::resamplebubic”的向上scaler函数。

        2
  •  2
  •   Pieter    16 年前

    一个相当简单和体面的图像重采样算法是 Bicubic interpolation

        3
  •  2
  •   Mark Ransom    16 年前

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

    编辑:我想的是米切尔·内特拉瓦利的作品,在这个链接的底部引用了它:

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

    你也可以调查一下 Lanczos resampling

        4
  •  2
  •   Mark Ransom    16 年前

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

    这样做的目的是从原始图像中提取均匀分布的样本;在您的情况下,256个样本中有55个,或者每4.6545个样本中就有一个样本。只需将数字四舍五入即可选择像素。

        6
  •  1
  •   berlindev    16 年前

    Adobe通用图像库 http://opensource.adobe.com/wiki/display/gil/Downloads )如果你想准备一些东西而不仅仅是一个算法。


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

    放大或缩小-C源代码 对于32位Windows 5.3或更高版本,需要Victor图像处理库。

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

        7
  •  1
  •   Naveen    16 年前

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

    Intel IPP

        8
  •  1
  •   genpfault    10 年前

    我们敬爱的主持人的一篇普通文章: Better Image Resizing

        9
  •  1
  •   genpfault    10 年前

    听起来,您真正难以理解的是正确重采样图像所涉及的离散-连续-离散流。一份好的技术报告可以帮助你了解你所需要的是阿尔维·雷·史密斯的 A Pixel Is Not A Little Square .

        10
  •  0
  •   derobert    16 年前

    看一看 ImageMagick ,它执行各种重新缩放筛选器。

        11
  •  0
  •   BenAlabaster    16 年前

    this article 上面。它实现了过滤的两次调整大小。资料来源是C#,但看起来很清楚,我可以把它移植过来试试。我昨天发现了非常相似的C代码,很难理解(非常糟糕的变量名)。我把它做了一些工作,但它很慢,没有产生好的结果,这使我相信我的适应有一个错误。我可能会有更好的运气从零开始写这个作为参考,我会尝试。

    但考虑到两次通过的算法是如何工作的,我想知道是否没有一种更快的方法来实现它,甚至在一次通过的情况下?