【问题标题】:Image downsampling algorithms图像下采样算法
【发布时间】:2011-09-02 07:13:09
【问题描述】:

我可以使用哪种最佳重采样算法将图像分成原始大小的一半。速度是最重要的,但它不应该降低质量太差。我基本上是在尝试生成图像金字塔。

我原本打算跳过像素。这是最好的方法吗?从我读到的像素跳跃产生的图像太锐利了。尝试过此评论的人可以。我的图像包含类似于 this.

的地图数据

【问题讨论】:

  • “原来大小的一半”是指每个维度减半,还是总面积减半?
  • 当您阅读时,跳过像素并不是一个好方法——有些文本一开始只有一个像素厚(例如“+”)...这样的字符可能会完全消失如果它落在“off-”行和列中。更一般地,请参阅stackoverflow.com/questions/158756/…
  • @caf- 每个维度的一半。这意味着 1000X1000 的图像将变为 500X500
  • @Tony 并不是真的在寻找图书馆。

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


【解决方案1】:

【讨论】:

  • 那是一篇非常酷的论文,但对他的申请来说太过分了。如果您还没有,请查看他提供的示例图片。
  • 这只是一组链接,而不是答案。
  • @Kirill:你希望我重新输入答案吗?此外,他甚至没有在 StackOverflow 上搜索以前提出的问题的答案。
  • @Seth Robertson,如果能对这些文章进行一些回顾,那就太好了 - 提供的内容,方法的优缺点。或者,如果是,您可以将问题标记为重复。
  • 在询问之前我确实浏览了 Perceptual Image Downsampling 帖子。我特别想知道它们是否是一种将图像减半的快速算法(我不需要其他分辨率)。我什至提供了一个示例图像,以表明我的图像不包含很多细节,而是包含不同颜色的块/区域。
【解决方案2】:

跳过像素会导致混叠,其中高频变化(例如交替的亮/暗带)将转换为低频(例如恒定亮或暗)。

在没有锯齿的情况下将尺寸缩小到一半的最快方法是将 2x2 像素平均为单个像素。使用更复杂的归约内核可以获得更好的结果,但会以牺牲速度为代价。

这里是目前讨论的一些技术示例。

跳过每隔一个像素 - 通过查看左侧的图例,您可以看到结果不是很好。几乎看不懂:

平均每 2x2 网格 - 文本现在清晰易读:

高斯模糊,正如R. 所建议的那样 - 有点模糊,但在某种程度上更具可读性。可以调整模糊量以给出不同的结果:

R. 关于影响结果的 Gamma 曲线也是正确的,但这应该只在最苛刻的应用程序中可见。我的示例是在没有伽马校正的情况下完成的。

编辑:下面是一个更复杂但速度较慢的内核示例,Lanczos-5 在线性(未经过伽马调整)色彩空间中执行。

字体中的对比度较低,可能是因为色彩空间的转换。但是看看海岸线细节。

【讨论】:

  • +1 喜欢这些例子。请注意,虽然面积平均法和高斯法都清晰易读,但高斯法的字体形状要正确得多。
  • @Mark Ransom:如果我有黑白图像怎么办?什么是黑白图像的好算法?
  • @SukhanovNiсkolay 颜色和黑白之间的唯一区别是您如何对像素进行算术运算。算法和结果是一样的。
  • @Mark Ransom 所以如果我有一个黑白(1 位颜色深度)平均算法就可以了?
  • @SukhanovNiсkolay,你可能想要一个灰度输出,所以将每个像素转换为 0/255,否则是的。如果您需要黑白输出,那么我不确定最好的算法是什么。
【解决方案3】:

NetPBM suite 包含一个名为 pamscale 的实用程序,它提供了一些下采样选项。它是开源的,因此您可以尝试各种选项,然后复制您最喜欢的算法(或者只使用 libnetpbm)。

【讨论】:

    【解决方案4】:

    对于缩小比例,面积平均(请参阅 Mark 的回答)接近您将获得的最佳值。

    另一个主要的竞争者是高斯,半径稍大。这会稍微增加模糊,这可能被视为一个缺点,但会使模糊更加均匀,而不是依赖于像素 mod 2 的对齐方式。

    如果我的意思不是很清楚,请考虑像素模式 0,0,2,2,0,0 和 0,0,0,2,2,0。使用区域平均,它们将分别缩小到 0,2,0 和 0,1,1 - 也就是说,一个会清晰明亮,而另一个会模糊和暗淡。使用更长的滤镜,两者都会变得模糊,但它们会显得更相似,这可能对人类观察者很重要。

    另一个需要考虑的问题是伽玛。除非 gamma 是线性的,否则两个像素强度 k 的总强度将远低于单个像素强度 2*k。如果您的过滤器执行了足够的模糊,它可能没那么重要,但对于普通的面积平均过滤器,它可能是一个主要问题。我知道的唯一解决方法是在缩放前后应用和反转伽马曲线...

    【讨论】:

      【解决方案5】:

      如前所述,如果速度是一个问题,我建议采用 2x2 块并计算平均值作为结果像素。质量不是可以达到的最好,而是接近。您可以激发该算法以显示其弱点,但在大多数图像上,您不会看到可以证明计算时间增加数倍的差异。 您也没有任何内存开销。 如果颜色分辨率可以降低到每通道 6 位,这是一种非常快速的方法,可以防止您分解 ARGB 通道(这里假设为 32 位 ARGB):

      destPixel[x,y] = ((sourcePixel[2*x  ,2*y  ]>>2)&0x3f3f3f3f) +
                       ((sourcePixel[2*x+1,2*y  ]>>2)&0x3f3f3f3f) +
                       ((sourcePixel[2*x  ,2*y+1]>>2)&0x3f3f3f3f) +
                       ((sourcePixel[2*x+1,2*y+1]>>2)&0x3f3f3f3f);
      

      这个算法的副作用是,如果保存为 PNG,文件大小会变小。 这是它的样子:

      【讨论】:

        【解决方案6】:

        我试图概括 Thilo Köhler 的解决方案(但在 Python 中):

        STRIDE = 2
        MASK = 0x3F3F3F3F
        color = 0
        for Δx, Δy in itertools.product(range(STRIDE), repeat=2):
            color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK
        

        这适用于缩放 2(四分之一大小结果),但不适用于缩放 3 或 4 或其他 int 值。可以概括一下吗?

        顺便说一句,对于非 Pythonistas,上面的 for 循环等效于这个(除了第一个版本可以通过更改 STRIDE 进行扩展):

        for Δx, Δy in [(0, 0), (0, 1), (1, 0), (1, 1)]:
            color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK
        

        我使用的是 32 位 ARGB 值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-04
          • 2019-01-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多