【问题标题】:Fastest Algorithm to scale down 32Bit RGB IMAGE缩小 32 位 RGB 图像的最快算法
【发布时间】:2010-12-16 07:05:44
【问题描述】:

使用哪种算法将 32 位 RGB 图像按比例缩小到自定义分辨率?算法应该平均像素。

例如,如果我有 100x100 的图像并且我想要大小为 20x50 的新图像。第一个源行的前五个像素的平均值将给出目标的第一个像素,第一源列的前两个像素的平均值将给出第一个目标列的像素。

目前我所做的是首先缩小 X 分辨率,然后缩小 Y 分辨率。在这个方法中我需要一个临时缓冲区。

有没有你知道的优化方法?

【问题讨论】:

  • 哪种方式?更少的比特或更少的像素?还是以其他方式?

标签: algorithm image-processing image-scaling


【解决方案1】:

您要查找的术语是“重采样”。在您的情况下,您需要图像重采样。您似乎已经在进行线性插值,这应该是最快的。这里有 6 种基本算法。如果您真的想深入研究该主题,请查看“重采样内核”。

【讨论】:

    【解决方案2】:

    在您进行标准 C 优化(指针算术、定点数学等...)之后 还有一些更聪明的优化。 (非常)很久以前,我看到了一个缩放器实现,它首先缩放了 X 方向。在写出水平缩放图像的过程中,它在内存中将图像旋转了 90 度。这样做是为了在读取 Y 方向刻度时,内存中的数据会更好地缓存对齐。

    这种技术在很大程度上取决于它将运行的处理器。

    【讨论】:

    • 哇,非常好的技术,谢谢你的回答。
    【解决方案3】:

    这会平均适当的像素。

     w_ratio = src.w / dest.w
     h_ratio = src.h / dest.h
    
     dest[x,y] = 
        AVG( src[x * w_ratio + xi, y * h_ratio + yi] ) 
          where
               xi in range (0, w_ratio - 1), inc by 1
               yi in range (0, h_ratio - 1), inc by 1
    

    对于边界条件,做一个单独的循环(没有 if's in loop)。

    这是一个更像 C 的代码:

    src 和 dest 是位图:
    * 像素属性 src[x,y]
    * 宽度的属性 src.w
    * 高度的属性 src.h

    像素已被定义,因此

    添加

    p1 = p1 + p2     
    is same as
    p1.r = p1.r + p2.r
    p1.g = p1.g + p2.g
    ...
    

    部门

    p1 = p1 / c
    p1.r = p1.r / c
    p1.g = p1.g / c
    

    用常数 0 计算

    p1 = 0
    p1.r = 0
    p1.g = 0
    ...
    

    为了简单起见,我不会考虑像素分量整数溢出时的问题...

    float w_ratio = src.w / dest.w;
    float h_ratio = src.h / dest.h;
    int w_ratio_i = floor(w_ratio);
    int h_ratio_i = floor(h_ratio);
    
    wxh = w_ratio*h_ratio;
    
    for (y = 0; y < dest.w; y++)
    for (x = 0; x < dest.h; x++){
        pixel temp = 0;     
    
        int srcx, srcy;
        // we have to use here the floating point value w_ratio, h_ratio
        // otherwise towards the end it can get a little wrong
        // this multiplication can be optimized similarly to Bresenham's line
        srcx = floor(x * w_ratio);
        srcy = floor(y * h_ratio);
    
        // here we use floored value otherwise it might overflow src bitmap
        for(yi = 0; yi < h_ratio_i; yi++)
        for(xi = 0; xi < w_ratio_i; xi++)
                temp += src[srcx + xi, srcy + yi];
        dest[x,y] = temp / wxh;
    }
    

    Bresenham's line optimization

    【讨论】:

    • 我无法理解你,但看起来你的方法很有希望。请问可以用c语言写吗?
    【解决方案4】:

    您忘记提及问题中最重要的方面:您对质量的关注程度。如果您不关心源像素的值是如何被拼凑在一起以创建目标像素的,那么最快(至少在几乎所有情况下)产生最差质量的像素。

    如果您想以“仍然产生非常好的质量的最快算法”作为回应,那么您基本上已经涵盖了仅处理图像采样/调整大小的整个算法领域。

    您已经概述了您对该算法的初步想法:

    前五个像素的平均值 源行将给出第一个像素 目的地,

    计算源像素上每个通道的平均值可能被视为微不足道,您是否正在寻找执行此操作的示例代码?

    或者您是否正在寻找一个人来挑战您的算法初稿以更快的速度?

    【讨论】:

    • 我已经为我所描述的逻辑编写了代码。我想要更快的东西,在我目前的方法中,当我想在 x 和 y 中缩小图像时。我必须分开做。我首先在临时缓冲区中缩小 X 中的图像,然后从那个临时缓冲区中缩小 Y 中的图像。之后我得到了高质量的图像,但我不喜欢临时缓冲区的想法。我想要没有临时缓冲区的高质量stretchBlt,有什么方法吗?
    【解决方案5】:

    如果您正在寻找冗长的解释,我发现 this article 会很有帮助。另一方面,如果你更多地处理数学公式,有一种快速图像缩小的方法解释了here

    【讨论】:

      【解决方案6】:

      这确实是速度/质量的权衡。

      首先,你是正确的,做一个维度然后另一个维度比它必须的要慢。太多的内存读写。

      您最大的选择是是否支持小数像素。您的示例是 100x100 到 20x50。所以 10 像素映射到 1。如果你要从 100x100 到 21x49 怎么办?您愿意在源像素边界处进行操作,还是想要将小数像素拉入? 100x100 到 99x99 你会怎么做?

      您必须先告诉我们您愿意接受什么,然后我们才能说出什么是最快的。

      并告诉我们收缩的可能极端情况。源和目的地之间的差异可能有多少个数量级?在某些时候,对源内的代表性像素进行采样不会比平均所有像素差多少。但是你必须小心选择有代表性的像素,否则你会得到许多常见模式的锯齿。

      【讨论】:

        【解决方案7】:

        你在做什么优化的方法。唯一更快的称为最近邻,您只需抓住范围的中间像素而不尝试对其中任何一个进行平均。如果原始图像中有任何细节,则质量会明显变差,但如果原始图像简单,则可能可以接受。

        【讨论】:

        • 我第一次写了这个版本,但是当我用文字拉伸图像时,文字变得不可读,所以我用像素平均实现了新功能。但是带有像素平均值的stretchBlt 比普通的要多花300% 的时间。我已经为它编写了优化的程序集。我想要更快的质量,并希望消除我对临时缓冲区的需求。
        • 不,他的方法不是最快的。他在做一个维度,然后是另一个维度。一次完成所有操作会更快,因为它的内存操作更少。
        • 按照他的方式执行是 7 个内存操作,一次执行所有操作是 10 个。这是 O(n) 与 O(n^2),因此差异会随着收缩因子的增加而增加.
        猜你喜欢
        • 1970-01-01
        • 2019-09-20
        • 2012-03-23
        • 2014-08-05
        • 1970-01-01
        • 2023-03-25
        • 2020-05-23
        相关资源
        最近更新 更多