我正在编写一个可以生成图像的程序。我想要的一个衡量标准是图像中“自相似”的数量。我编写了以下代码,用于查找图片中每个sizeWindow * sizeWindow窗口的countBest-th最佳匹配:
double Pattern::selfSimilar(int sizeWindow, int countBest) {
std::vector<int> *pvecount;
double similarity;
int match;
int x1;
int x2;
int xWindow;
int y1;
int y2;
int yWindow;
similarity = 0.0;
// (x1, y1) is the original that's looking for matches.
for (x1 = 0; x1 < k_maxX - sizeWindow; x1++) {
for (y1 = 0; y1 < k_maxY - sizeWindow; y1++) {
pvecount = new std::vector<int>();
// (x2, y2) is the possible match.
for (x2 = 0; x2 < k_maxX - sizeWindow; x2++) {
for (y2 = 0; y2 < k_maxY - sizeWindow; y2++) {
// Testing...
match = 0;
for (xWindow = 0; xWindow < sizeWindow; xWindow++) {
for (yWindow = 0; yWindow < sizeWindow; yWindow++) {
if (m_color[x1 + xWindow][y1 + yWindow] == m_color[x2 + xWindow][y2 + yWindow]) {
match++;
}
}
}
pvecount->push_back(match);
}
}
nth_element(pvecount->begin(), pvecount->end()-countBest, pvecount->end());
similarity += (1.0 / ((k_maxX - sizeWindow) * (k_maxY - sizeWindow))) *
(*(pvecount->end()-countBest) / (double) (sizeWindow * sizeWindow));
delete pvecount;
}
}
return similarity;
}
好消息是算法按照我想要的方式执行:它将返回一个从0.0到1.0的值,关于图片的“自相似”。
坏消息 - 我确信你已经注意到了 - 这个算法非常慢。运行需要(k_maxX - sizeWindow) * (k_maxY - sizeWindow) * (k_maxX - sizeWindow) * (k_maxY - sizeWindow) * sizeWindow * sizeWindow
个步骤。
变量的一些典型值:
k_maxX = 1280
k_maxY = 1024
sizeWindow = between 5 and 25
countBest = 3, 4, or 5
m_color[x][y] is defined as short m_color[k_maxX][k_maxY] with values between 0 and 3 (but may increase in the future.)
现在,我不担心pvecount占用的内存占用量。之后,我可以使用一个排序数据集,当它小于countBest时不会添加另一个元素。我只担心算法速度。
如何加快速度?
答案 0 :(得分:2)
好的,首先,这种方法根本不稳定。如果向图像添加随机噪声,则会大大降低两幅图像之间的相似度。更重要的是,从图像处理的角度来看,它效率不高或特别好。我建议另一种方法;例如,使用基于小波的方法。如果您在图像上执行了2d DWT几个级别并比较了缩放系数,则可能会获得更好的结果。另外,离散小波变换是O(n)。
缺点是小波是一个高级数学主题。关于小波和滤波器组的一些很好的OpenCourseWare注释here。
答案 1 :(得分:1)
您的问题强烈提醒我必须在视频压缩中对motion compensation进行计算。也许你应该仔细看看在那个领域做了些什么。
正如rlbond已经指出的那样,计算颜色完全匹配的窗口中的点数不是比较图片时通常所做的。概念上比使用离散余弦或小波变换更简单的方法是添加差值的平方
diff = (m_color[x1 + xWindow][y1 + yWindow] - m_color[x2 + xWindow][y2 + yWindow]);
sum += diff*diff;
并使用 sum 而不是 match 作为相似度的标准(现在更小意味着更好)。
回到你真正问的问题:我认为可以通过因子2 / sizeWindow减少运行时间(可能是平方?),但它有点乱。这是基于以下事实:当你将y1递增1时,你比较的某些方块几乎保持不变。如果偏移xOff = x2-x1和yOff = y2-y1是相同的,只有顶部(rsp。bottom)垂直条纹正方形不再是(现在,但不是之前)匹配的。如果在由偏移xOff = x2-x1和yOff = y2-y1索引的二维数组中保留您为匹配计算的值,则可以计算y1的匹配[xOff] [yOff]的新值增加1和x1通过2 * sizeWindow比较保持不变:
for (int x = x1; x < x1 + sizeWindow; x++) {
if (m_color[x][y1] == m_color[x + xOff][y1 + yOff]) {
match[xOff][yOff]--; // top stripes no longer compared
}
if (m_color[x][y1+sizeWindow] == m_color[x + xOff][y1 + sizeWindow + yOff]) {
match[xOff][yOff]++; // bottom stripe compared not, but wasn't before
}
}
(因为yOff的可能值改变 - 通过递增y1 - 从区间[y2-y1,k_maxY-sizeWindow-y1-1]到区间[y2-y1-1,k_maxY-sizeWindow-y1-2]你可以用第二个索引丢弃匹配yOff = k_maxY - sizeWindow - y1 - 1并且必须以不同的方式计算与第二个索引yOff = y2 - y1 - 1的匹配。也许你也可以保持数值在数组循环期间增加/减少匹配[] []的数量,以获得另一个2 / sizeWindow加速。