基于矩阵窗口计算的Java代码优化
我有一个表示图像的矩阵,我需要遍历每个像素,对于其中的每一个,我必须计算其所有邻域的总和,即属于以像素为中心的半径基于矩阵窗口计算的Java代码优化,java,c++,algorithm,optimization,matrix,Java,C++,Algorithm,Optimization,Matrix,我有一个表示图像的矩阵,我需要遍历每个像素,对于其中的每一个,我必须计算其所有邻域的总和,即属于以像素为中心的半径rad窗口的像素 我想出了三个选择: 最简单的方法是为每个像素重新计算窗口 使用队列存储窗口列和并在矩阵列之间循环的更优化的方法通过添加新元素和删除旧元素来更新此队列 更优化的方法是不需要为每一行重新计算队列,而是增量地调整以前保存的队列 我在c++中实现了它们,第二种方法使用队列,第三种方法使用deques组合(我需要迭代它们的元素而不破坏它们),并对它们的时间进行评分,以查看
rad
窗口的像素
我想出了三个选择:
- 最简单的方法是为每个像素重新计算窗口
- 使用队列存储窗口列和并在矩阵列之间循环的更优化的方法通过添加新元素和删除旧元素来更新此队列
- 更优化的方法是不需要为每一行重新计算队列,而是增量地调整以前保存的队列
这里是C++中最简单的方法(我没有张贴java版本,因为它几乎是相同的):
LinkedList对于具有随机访问权限的列表来说是一个非常糟糕的选择。 对于每个
get(int)
扫描列表,直到达到请求索引get(1)
相当快,但是get(100)
比get(1)慢100倍,get(1000)
比get(1)慢1000倍
您应该将其更改为使用ArrayList,并使用预期的大小初始化ArrayList,以避免不必要地调整内部数组的大小
编辑虽然我关于get()和LinkedList的说法是正确的,但它们不适用于此上下文。我不知何故忽略了列表没有随机访问。使用
int[]
而不是列表
列出了需要从int
转换为Integer
并返回的存储对象。我确实为该例程实现了两个优化版本:
- 第一个,正如User216237所建议的,在算法逐列扫描图像时,使用
int
数组作为队列来缓存求和的列值
- 另一个实现了一个,通过四次访问该表(它与窗口半径无关),计算每个矩形面积的和
根据实现技术的特定领域,一种技术的速度可以任意快于另一种技术。在我的例子中,求和面积表必须计算几次,因此对于半径值小于20像素的情况,它的计算速度比第一种方法慢。关于代码计时:System.nanoTime()可以(据我所知,它使用的是操作系统计时器,所以我不认为你能做得更好),但是:
- 不要试图测量太短的任务,那么准确度就不太好了。我认为任何少于几毫秒的事情都会给你带来潜在的麻烦。有人推荐吗
- 多次测量,取测量值的中间值。外部效应会严重减慢执行速度,使您的估算毫无用处。取平均值效果不太好,因为它对这些异常值很敏感
很多JVM都有JIT编译器,在测量之前,你可能需要多次执行代码,这样编译器就不会在你测量中的某个地方踢,而你的一半的测量结果会比其他的快10倍。在虚拟机“预热”后进行更好的测量
,DeQE也不是C++中的太快。使用vector(带有.SaveVE()来减少在构建中的内存分配。)是的,你可能是对的,但是我不需要优化C++代码,我只是先写了它然后移植到爪哇,这是我必须使用的语言,在代码中不使用<代码>获取< /代码>。我只是在某些部分使用了getFirst
。我不需要随机访问,我只需要直接访问第一个和最后一个元素并遍历所有元素。对不起,我以为我看到了对列表的随机访问,但显然,这只是你使用的数组。即使更改为固定大小的ArrayList,相对于简单的第一种方法,代码也会有所改进,但它的计算时间仍然比第二种方法要长。我想,因为ArrayQue优化为从前面删除项,而ArrayList和LinkedList noI必须更正我的上一条语句,所以当列数和行数小于300且半径较小(4,5,6…)时,第一种方法在java中的性能总是更好,超过这些值会导致第二个方法速度最快。这并不能解释为什么第三个方法比第二个方法慢。事实上,第三个方法缓存了更多的整数。我现在可以理解你的观点,但当从前面删除值时,int[]
版本必须移动所有值。我应该使用一个非常大的数组,它的长度应该与列/行的数量相同,如果我想避免移位的话,没有必要移位任何东西,用int索引跟踪开始/结束。“超大数组”不会比ArrayList内部使用的数组大。
void normalWindowing(int mat[][MAX], int cols, int rows, int rad){
int i, j;
int h = 0;
for (i = 0; i < rows; ++i)
{
for (j = 0; j < cols; j++)
{
h = 0;
for (int ry =- rad; ry <= rad; ry++)
{
int y = i + ry;
if (y >= 0 && y < rows)
{
for (int rx =- rad; rx <= rad; rx++)
{
int x = j + rx;
if (x >= 0 && x < cols)
{
h += mat[y][x];
}
}
}
}
}
}
}
void opt1Windowing(int mat[][MAX], int cols, int rows, int rad){
int i, j, h, y, col;
queue<int>* q = NULL;
for (i = 0; i < rows; ++i)
{
if (q != NULL)
delete(q);
q = new queue<int>();
h = 0;
for (int rx = 0; rx <= rad; rx++)
{
if (rx < cols)
{
int mem = 0;
for (int ry =- rad; ry <= rad; ry++)
{
y = i + ry;
if (y >= 0 && y < rows)
{
mem += mat[y][rx];
}
}
q->push(mem);
h += mem;
}
}
for (j = 1; j < cols; j++)
{
col = j + rad;
if (j - rad > 0)
{
h -= q->front();
q->pop();
}
if (j + rad < cols)
{
int mem = 0;
for (int ry =- rad; ry <= rad; ry++)
{
y = i + ry;
if (y >= 0 && y < rows)
{
mem += mat[y][col];
}
}
q->push(mem);
h += mem;
}
}
}
}
public static void opt1Windowing(int [][] mat, int rad){
int i, j = 0, h, y, col;
int cols = mat[0].length;
int rows = mat.length;
ArrayDeque<Integer> q = null;
for (i = 0; i < rows; ++i)
{
q = new ArrayDeque<Integer>();
h = 0;
for (int rx = 0; rx <= rad; rx++)
{
if (rx < cols)
{
int mem = 0;
for (int ry =- rad; ry <= rad; ry++)
{
y = i + ry;
if (y >= 0 && y < rows)
{
mem += mat[y][rx];
}
}
q.addLast(mem);
h += mem;
}
}
j = 0;
for (j = 1; j < cols; j++)
{
col = j + rad;
if (j - rad > 0)
{
h -= q.peekFirst();
q.pop();
}
if (j + rad < cols)
{
int mem = 0;
for (int ry =- rad; ry <= rad; ry++)
{
y = i + ry;
if (y >= 0 && y < rows)
{
mem += mat[y][col];
}
}
q.addLast(mem);
h += mem;
}
}
}
}
void opt2Windowing(int mat[][MAX], int cols, int rows, int rad){
int i = 0;
int j = 0;
int h = 0;
int hh = 0;
deque< deque<int> *> * M = new deque< deque<int> *>();
for (int ry = 0; ry <= rad; ry++)
{
if (ry < rows)
{
deque<int> * q = new deque<int>();
M->push_back(q);
for (int rx = 0; rx <= rad; rx++)
{
if (rx < cols)
{
int val = mat[ry][rx];
q->push_back(val);
h += val;
}
}
}
}
deque<int> * C = new deque<int>(M->front()->size());
deque<int> * Q = new deque<int>(M->front()->size());
deque<int> * R = new deque<int>(M->size());
deque< deque<int> *>::iterator mit;
deque< deque<int> *>::iterator mstart = M->begin();
deque< deque<int> *>::iterator mend = M->end();
deque<int>::iterator rit;
deque<int>::iterator rstart = R->begin();
deque<int>::iterator rend = R->end();
deque<int>::iterator cit;
deque<int>::iterator cstart = C->begin();
deque<int>::iterator cend = C->end();
for (mit = mstart, rit = rstart; mit != mend, rit != rend; ++mit, ++rit)
{
deque<int>::iterator pit;
deque<int>::iterator pstart = (* mit)->begin();
deque<int>::iterator pend = (* mit)->end();
for(cit = cstart, pit = pstart; cit != cend && pit != pend; ++cit, ++pit)
{
(* cit) += (* pit);
(* rit) += (* pit);
}
}
for (i = 0; i < rows; ++i)
{
j = 0;
if (i - rad > 0)
{
deque<int>::iterator cit;
deque<int>::iterator cstart = C->begin();
deque<int>::iterator cend = C->end();
deque<int>::iterator pit;
deque<int>::iterator pstart = (M->front())->begin();
deque<int>::iterator pend = (M->front())->end();
for(cit = cstart, pit = pstart; cit != cend; ++cit, ++pit)
{
(* cit) -= (* pit);
}
deque<int> * k = M->front();
M->pop_front();
delete k;
h -= R->front();
R->pop_front();
}
int row = i + rad;
if (row < rows && i > 0)
{
deque<int> * newQ = new deque<int>();
M->push_back(newQ);
deque<int>::iterator cit;
deque<int>::iterator cstart = C->begin();
deque<int>::iterator cend = C->end();
int rx;
int tot = 0;
for (rx = 0, cit = cstart; rx <= rad; rx++, ++cit)
{
if (rx < cols)
{
int val = mat[row][rx];
newQ->push_back(val);
(* cit) += val;
tot += val;
}
}
R->push_back(tot);
h += tot;
}
hh = h;
copy(C->begin(), C->end(), Q->begin());
for (j = 1; j < cols; j++)
{
int col = j + rad;
if (j - rad > 0)
{
hh -= Q->front();
Q->pop_front();
}
if (j + rad < cols)
{
int val = 0;
for (int ry =- rad; ry <= rad; ry++)
{
int y = i + ry;
if (y >= 0 && y < rows)
{
val += mat[y][col];
}
}
hh += val;
Q->push_back(val);
}
}
}
}
public static void opt2Windowing(int [][] mat, int rad){
int cols = mat[0].length;
int rows = mat.length;
int i = 0;
int j = 0;
int h = 0;
int hh = 0;
LinkedList<LinkedList<Integer>> M = new LinkedList<LinkedList<Integer>>();
for (int ry = 0; ry <= rad; ry++)
{
if (ry < rows)
{
LinkedList<Integer> q = new LinkedList<Integer>();
M.addLast(q);
for (int rx = 0; rx <= rad; rx++)
{
if (rx < cols)
{
int val = mat[ry][rx];
q.addLast(val);
h += val;
}
}
}
}
int firstSize = M.getFirst().size();
int mSize = M.size();
LinkedList<Integer> C = new LinkedList<Integer>();
LinkedList<Integer> Q = null;
LinkedList<Integer> R = new LinkedList<Integer>();
for (int k = 0; k < firstSize; k++)
{
C.add(0);
}
for (int k = 0; k < mSize; k++)
{
R.add(0);
}
ListIterator<LinkedList<Integer>> mit;
ListIterator<Integer> rit;
ListIterator<Integer> cit;
ListIterator<Integer> pit;
for (mit = M.listIterator(), rit = R.listIterator(); mit.hasNext();)
{
Integer r = rit.next();
int rsum = 0;
for (cit = C.listIterator(), pit = (mit.next()).listIterator();
cit.hasNext();)
{
Integer c = cit.next();
Integer p = pit.next();
rsum += p;
cit.set(c + p);
}
rit.set(r + rsum);
}
for (i = 0; i < rows; ++i)
{
j = 0;
if (i - rad > 0)
{
for(cit = C.listIterator(), pit = M.getFirst().listIterator();
cit.hasNext();)
{
Integer c = cit.next();
Integer p = pit.next();
cit.set(c - p);
}
M.removeFirst();
h -= R.getFirst();
R.removeFirst();
}
int row = i + rad;
if (row < rows && i > 0)
{
LinkedList<Integer> newQ = new LinkedList<Integer>();
M.addLast(newQ);
int rx;
int tot = 0;
for (rx = 0, cit = C.listIterator(); rx <= rad; rx++)
{
if (rx < cols)
{
Integer c = cit.next();
int val = mat[row][rx];
newQ.addLast(val);
cit.set(c + val);
tot += val;
}
}
R.addLast(tot);
h += tot;
}
hh = h;
Q = new LinkedList<Integer>();
Q.addAll(C);
for (j = 1; j < cols; j++)
{
int col = j + rad;
if (j - rad > 0)
{
hh -= Q.getFirst();
Q.pop();
}
if (j + rad < cols)
{
int val = 0;
for (int ry =- rad; ry <= rad; ry++)
{
int y = i + ry;
if (y >= 0 && y < rows)
{
val += mat[y][col];
}
}
hh += val;
Q.addLast(val);
}
}
}
}
long start, end;
start = System.nanoTime();
simpleWindowing(mat, rad);
end = System.nanoTime();
System.out.println(end-start);
start = System.nanoTime();
opt1Windowing(mat, rad);
end = System.nanoTime();
System.out.println(end-start);
start = System.nanoTime();
opt2Windowing(mat, rad);
end = System.nanoTime();
System.out.println(end-start);