使用哪种算法将 32 位 RGB 图像按比例缩小到自定义分辨率?算法应该平均像素。
例如,如果我有 100x100 图像并且我想要大小为 20x50 的新图像。第一个源行的前五个像素的平均值将给出 dest 的第一个像素,第一个源列的前两个像素的平均值将给出第一个 dest 列的像素。
目前我所做的是首先缩小 X 分辨率,然后缩小 Y 分辨率。在这种方法中我需要一个临时缓冲区。
有没有你知道的优化方法?
使用哪种算法将 32 位 RGB 图像按比例缩小到自定义分辨率?算法应该平均像素。
例如,如果我有 100x100 图像并且我想要大小为 20x50 的新图像。第一个源行的前五个像素的平均值将给出 dest 的第一个像素,第一个源列的前两个像素的平均值将给出第一个 dest 列的像素。
目前我所做的是首先缩小 X 分辨率,然后缩小 Y 分辨率。在这种方法中我需要一个临时缓冲区。
有没有你知道的优化方法?
在完成标准 C 优化(指针算术、定点数学等)之后,还有一些更聪明的优化。(非常)很久以前,我看到了一个缩放器实现,它首先缩放了 X 方向。在写出水平缩放图像的过程中,它在内存中将图像旋转了90度。这样做是为了在读取 Y 方向刻度时,内存中的数据会更好地与缓存对齐。
这种技术在很大程度上取决于它将运行的处理器。
您忘记提及问题中最重要的方面:您对质量的关心程度。如果您不关心源像素的值是如何被粉碎在一起以创建目标像素的,那么最快的是(至少在几乎所有情况下)产生最差质量的像素。
如果您想用“仍然产生非常好的质量的最快算法”来回应,那么您基本上已经涵盖了仅处理图像采样/调整大小的整个算法领域。
您已经概述了您对该算法的初步想法:
第一个源行的前五个像素的平均值将给出目标的第一个像素,
计算源像素上每个通道的平均值可能被视为微不足道,您是否正在寻找执行此操作的示例代码?
或者您是否正在寻找某人以更快的速度挑战您的算法初稿?
这会平均适当的像素。
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 循环)。
这是一个更像 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;
}
这确实是速度/质量的权衡。
首先,你是正确的,做一个维度然后另一个维度比它必须要慢。太多的内存读写。
您最大的选择是是否支持小数像素。您的示例是 100x100 到 20x50。所以 10 像素映射到 1。如果你要从 100x100 到 21x49 怎么办?您是否愿意在源像素边界处进行操作,或者您是否想要将小数像素拉入?你会为 100x100 到 99x99 做什么?
您必须先告诉我们您愿意接受什么,然后我们才能说出什么是最快的。
并告诉我们收缩的可能极端情况。源和目的地之间的差异可能有多少个数量级?在某些时候,对源内的代表性像素进行采样不会比平均所有像素差多少。但是你必须小心选择有代表性的像素,否则你会得到许多常见模式的混叠。
你正在做的是优化的方法。唯一更快的称为最近邻,您只需抓住范围的中间像素而不尝试平均它们中的任何一个。如果原始图像中有任何细节,则质量会明显变差,尽管如果原始图像很简单,这可能是可以接受的。