我一直在编写一些用于进行粗略图像缩放的代码,但遇到了此性能问题。我最初的方法是创建从源图像到目标图像的像素索引的粗略映射,并将该映射存储在两个数组中,一个用于行,一个用于列,以便在预定大小之间重复缩放图像时快速访问。
这按预期工作,此时我决定创建另一种用于一次性缩放的方法,在该方法中,我将目标尺寸作为方法参数提供,而不是预先确定的目标大小,并即时计算映射。
我希望这种方法运行速度较慢-如果只使用一次,则可以节省计算初始映射的时间。但是,当我对这两种方法进行计时时,单次使用方法始终优于重复使用方法。
以下是相关的for循环:
重复使用,其中rowMap和columnMap是整数数组,用于存储与所需目标像素相对应的源像素的索引:
for (int r = 0; r < rowMap.length; ++r) {
for (int c = 0; c < columnMap.length; ++c) {
target.setRGB(
c,
r,
source.getRGB(
columnMap[c],
rowMap[r]
)
);
}
}
一次性使用,其中widthRatio和heightRatio由以下公式计算
private static double calculateRatio(int sourceValue, int targetValue) {
return (double)sourceValue / (double)targetValue;
}
和
private static int mapByRatio(int targetValue, double sourceToTargetRatio) {
return (int)Math.floor((double)targetValue * sourceToTargetRatio);
}
:
for (int r = 0; r < targetHeight; ++r) {
for (int c = 0; c < targetWidth; ++c) {
target.setRGB(
c,
r,
source.getRGB(
mapByRatio(c, widthRatio),
mapByRatio(r, heightRatio)
)
);
}
}
这是我的速度测试的示例输出-尽管确切的数字并不完全一致,但对于许多目标图像大小,方法运行时之间的比率是:
在13毫秒内设置地图。 具有预设地图的缩放图像在121毫秒内。 不带预设图的缩放图像在91毫秒内。 具有预设图的缩放图像在4443毫秒内反复出现。 没有预设映射的缩放图像会在3643毫秒内重复出现。
如果相关,在使用重复缩放方法之前,我会通过对此方法的调用来设置地图:
public static void setMaps(int sourceHeight, int sourceWidth, int targetHeight, int targetWidth) {
columnMap = new int[targetWidth];
rowMap = new int[targetHeight];
double heightRatio = calculateRatio(sourceHeight, targetHeight);
double widthRatio = calculateRatio(sourceWidth, targetWidth);
for (int h = 0; h < targetHeight; ++h) rowMap[h] = mapByRatio(h, heightRatio);
for (int w = 0; w < targetWidth; ++w) columnMap[w] = mapByRatio(w, widthRatio);
}
在我看来,这个结果似乎违反直觉-阵列访问几乎不需要花费任何时间,尽管对于现代CPU而言,单一使用方法中使用的计算并不是特别费力,但我仍然希望它们的运行速度比简单访问时慢预先计算的值。
如果我不得不猜测,我希望答案与Java或我的操作系统(Windows 10)如何分配和访问数组的内存有关。谁能对此提供进一步的见解?