【发布时间】:2016-07-25 12:21:18
【问题描述】:
上下文
我正在实现seam carving 算法。
我将图片中的像素表示为一维数组
private int[] picture;
每个int代表像素的RGB。
要访问像素,我使用辅助方法,例如:
private int pixelToIndex(int x, int y) {return (y * width()) + x;}
另一种方法是存储在二维数组中:
private int[][] picture;
接缝雕刻算法有两个部分。
首先,它会进行一些图像处理,找到能量最低的水平或垂直连接接缝。在这里,像素访问会跨行跳跃一点。
其次,它会移除这个相连的接缝。
对于垂直接缝,我用-1 标记要删除的像素并创建一个新的图片数组,像这样跳过删除的像素:
int i = 0, j = 0;
while (i < temp.length) {
if (picture[j] != -1) {
temp[i++] = picture[j];
}
j++;
}
picture = temp;
对于水平接缝,给定一个特定的列,我将该列的已删除像素之后的所有像素向上移动一行,如下所示:
for (int i = 0; i < temp.length; i++) {
int row = indexToY(i);
int col = indexToX(i);
int deletedCell = seam[col];
if (row >= deletedCell) temp[i] = picture[i + width()];
else temp[i] = picture[i];
}
picture = temp;
问题
显然,由于每个子数组的开销,一维数组使用较少的物理内存,但考虑到我迭代矩阵的方式,二维数组是否会更有效地被 CPU 缓存,从而更高效?
这些数组在加载到 CPU 缓存和 RAM 中的方式有何不同?一维数组的一部分会进入一级缓存吗?一维和二维数组如何加载到内存中?它会取决于数组的大小吗?
【问题讨论】:
-
为什么不隔离
createMatrix()、set(m, x, y)和get(m, x, y)后面的所有更改——并对这两个选项(2D 与 1D)进行计时,看看哪个更快?在几分钟内删除此代码以获得最高效的定时替代方案将是微不足道的,并且您可以确定您的选择,因为您可以引用适用于您的用例的实际数据。 -
你应该考虑一下tucuxi所说的:将它隐藏在某个界面后面。除此之外,还有一个重要提示:布局(1D 与 2D)可能会影响性能,但与 迭代顺序 所暗示的差异相比,这可能可以忽略不计。到目前为止,比“1D vs 2D”更重要的是确保嵌套循环,如
for(y) for(x) { { pixelToIndex(x,y); }}(而不是for(x) for(y) ...,参考你建议的pixelToIndex实现!)。 -
另一个提示,关于一维数组的优势:它们可以很容易地复制到 GPU。 Seam Carving 似乎是可以在 GPU 上很好地实现的任务,如果你想要这个,一维数组更容易处理。 (可能有点牵强,但想提一下)
-
对每个像素查找使用函数调用 pixelToIndex 的开销将大大超过选择 1D 而不是 2D 可能获得的任何好处。
-
你确定@bhspencer 吗?
标签: java arrays memory heap-memory seam-carving