图像处理通常是一项计算密集型的任务。当需要展示缩放后的图片时,使用GPU进行渲染(如OpenGL或DirectX)通常是更好的选择。然而,并非总是可以使用GPU,因此拥有一个替代方案是有益的。高质量的图像缩放(放大/缩小)对CPU要求极高,特别是在处理大图像时。此外,有时需要多次进行这种处理。为了减轻这种负担,可以应用不同的技巧。如果需要缩小(缩小尺寸)图片,可以应用类似于mip-maps的技巧。例如,如果想要缩小图片超过两倍(目标尺寸小于原始尺寸的一半),可以通过在实际缩放之前先进行一半的缩小来加速整个过程。2:1的缩小非常快,因为它使用的算法计算量更少。
例如,如果有一张1920x1024的图像,并且需要将其缩小到500x281,可以执行如下代码:
shrink(imageDst, imageSrc);
但可以通过先进行2:1的预缩小来优化这个过程:
shrinkHalf(imageHalf, imageSrc);
shrink(imageDst, imageHalf);
在一个项目中,当需要将3个显示器的图像缩放到生成预览时,结果如下:
这意味着,应用一次技巧,可以提高36%的速度。应用两次技巧,可以提高66%的速度。
演示应用程序有两个按钮:
左侧是原始图像。右侧是原始图像的灰度版本和缩小后的图像(或缩小的部分)的颜色版本。
当原始图像更新时,仅缩小图像的一部分是合适的,因为需要更新缩小后的副本。这可以节省大量的CPU和处理时间。
项目中包含一对文件:
要使用这些代码,只需要将这些文件放入项目中,并包含ShrinkHalf.h文件。
#include "ShrinkHalf.h"
这些文件包含了所有算法的实现。shrinkHalf函数有以下参数:
为了使用这些函数,应该执行以下操作:
shrinkHalf(dstPixels, srcPixels, srcWidth, srcHeight);
注意,目标不提供尺寸,因为它们是从源尺寸计算出来的。
可用的函数有:
void shrinkHalf(BYTE* target, const BYTE* source, int srcWidth, int srcHeight);
void shrinkHalfPart(BYTE* target, const BYTE* source, int srcWidth, int srcHeight, int x1, int y1, int x2, int y2);
第一个函数对整个图像进行2:1缩小。第二个函数对源图像中指定的矩形区域进行2:1缩小,计算目标图像中相应的矩形区域。如果使用这个,应该注意到可能需要对源矩形点进行+1/-1的校正,因为整数四舍五入。
这在需要应用大量更新时非常有用(例如,视频渲染)。
在shrinkHalf函数中,有一段注释掉的代码是可行的,但更倾向于保留对shrinkHalfPart的内部调用。
//static
void shrinkHalf(BYTE* target, const BYTE* source, int srcWidth, int srcHeight)
{
shrinkHalfPart(target, source, srcWidth, srcHeight, 0, 0, srcWidth-1, srcHeight-1);
//~~~~~
/*
int dstWidth = srcWidth / 2;
int dstHeight = srcHeight / 2;
int srcLineBytes = srcWidth * 3;
int dstLineBytes = dstWidth * 3;
int dstRows = dstHeight;
const BYTE* sl = source;
BYTE* tl = target;
const BYTE* te = target + srcHeight/2 * dstLineBytes;
while(tl < te)
{
BYTE* pt = tl;
const BYTE* p1 = sl;
const BYTE* p2 = p1 + srcLineBytes;
const BYTE* pe = sl + srcLineBytes;
while(p1 < pe)
{
*pt++ = (p1[0] + p1[3] + p2[0] + p2[3]) >> 2; // / 4; blue;
*pt++ = (p1[1] + p1[4] + p2[1] + p2[4]) >> 2; // / 4; green;
*pt++ = (p1[2] + p1[5] + p2[2] + p2[5]) >> 2; // / 4; red;
p1 += 6;//2*3;
p2 += 6;//2*3;
}
sl += srcLineBytes << 1; // Shift by 1 is equal to " * 2 "
tl += dstLineBytes;
}
*/
}