缩小32位RGB图像的最快算法

时间:2009-11-13 13:20:52

标签: algorithm image-processing image-scaling

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

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

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

您知道有任何优化方法吗?

7 个答案:

答案 0 :(得分:6)

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

答案 1 :(得分:2)

您忘记提及问题的最重要方面:您对质量的关注程度。如果您并不完全关心如何将源像素的值一起打碎以创建目标像素,则最快(至少在所有情况下)产生最差质量的像素。

如果你想用“仍然可以产生非常好的质量的最快算法”做出反应,你基本上已经覆盖了整个算法领域,只处理图像采样/调整大小。

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

  

首先是前五个像素的平均值   源行将给出第一个像素   DEST,

计算源像素上每个通道的平均值可以看作是微不足道的,您是否在寻找能够做到这一点的示例代码?

或者您是否正在寻找某人以更快的速度挑战您的初始算法草案?

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

平均合适的像素。

 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

对于边界条件,执行单独的循环(如果在循环中,则为no)。

这是一个更像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

答案 5 :(得分:1)

这真的是速度/质量的权衡。

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

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

在我们说出什么是最快的之前,你必须告诉我们你愿意接受什么。

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

答案 6 :(得分:0)

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