我正在看一篇名为“使用通用傅立叶描述符的基于形状的图像检索”的论文,但只有傅立叶描述符的基本知识。我试图在论文的第12页上实现该算法,并且有一些我无法理解的结果。
如果我创建一个小图像,请计算图像的FD,并将FD与在x和y方向上由单个像素平移的相同图像进行比较,描述符完全不同,除了第一个条目 - 完全相同。首先,一个问题是,这两个图像之间是否应该完全相同(因为描述符显然是缩放,旋转和平移不变)?
其次,在论文中,它提到两个单独图像的描述符通过简单的欧几里德距离进行比较 - 因此,通过采用上述两个描述符之间的欧几里德距离,欧几里德距离显然为0。
我快速整理了一些Javascript代码来测试算法,如下所示。
有没有人有任何意见,想法,前进的方法?
谢谢, 保罗
var iShape = [
0, 0, 0, 0, 0,
0, 0, 255, 0, 0,
0, 255, 255, 255, 0,
0, 0, 255, 0, 0,
0, 0, 0, 0, 0
];
var ImageWidth = 5, ImageHeight = 5, MaxRFreq = 5, MaxAFreq = 5;
// Calculate centroid
var cX = 0, cY = 0, pCount = 0;
for (x = 0; x < ImageWidth; x++) {
for (y = 0; y < ImageHeight; y++) {
if (iShape[y * ImageWidth + x]) {
cX += x;
cY += y;
pCount++;
}
}
}
cX = cX / pCount;
cY = cY / pCount;
console.log("cX = " + cX + ", cY = " + cY);
// Calculate the maximum radius
var maxR = 0;
for (x = 0; x < ImageWidth; x++) {
for (y = 0; y < ImageHeight; y++) {
if (iShape[y * ImageWidth + x]) {
var r = Math.sqrt(Math.pow(x - cX, 2) + Math.pow(y - cY, 2));
if (r > maxR) {
maxR = r;
}
}
}
}
// Initialise real / imaginary table
var i;
var FR = [ ];
var FI = [ ];
for (r = 0; r < (MaxRFreq); r++) {
var rRow = [ ];
FR.push(rRow);
var aRow = [ ];
FI.push(aRow);
for (a = 0; a < (MaxAFreq); a++) {
rRow.push(0.0);
aRow.push(0.0);
}
}
var rFreq, aFreq, x, y;
for (rFreq = 0; rFreq < MaxRFreq; rFreq++) {
for (aFreq = 0; aFreq < MaxAFreq; aFreq++) {
for (x = 0; x < ImageWidth; x++) {
for (y = 0; y < ImageHeight; y++) {
var radius = Math.sqrt(Math.pow(x - maxR, 2) +
Math.pow(y - maxR, 2));
var theta = Math.atan2(y - maxR, x - maxR);
if (theta < 0.0) {
theta += (2 * Math.PI);
}
var iPixel = iShape[y * ImageWidth + x];
FR[rFreq][aFreq] += iPixel * Math.cos(2 * Math.PI * rFreq *
(radius / maxR) + aFreq * theta);
FI[rFreq][aFreq] -= iPixel * Math.sin(2 * Math.PI * rFreq *
(radius / maxR) + aFreq * theta);
}
}
}
}
// Initialise fourier descriptor table
var FD = [ ];
for (i = 0; i < (MaxRFreq * MaxAFreq); i++) {
FD.push(0.0);
}
// Calculate the fourier descriptor
for (rFreq = 0; rFreq < MaxRFreq; rFreq++) {
for (aFreq = 0; aFreq < MaxAFreq; aFreq++) {
if (rFreq == 0 && aFreq == 0) {
FD[0] = Math.sqrt(Math.pow(FR[0][0], 2) + Math.pow(FR[0][0], 2) /
(Math.PI * maxR * maxR));
} else {
FD[rFreq * MaxAFreq + aFreq] = Math.sqrt(Math.pow(FR[rFreq][aFreq], 2) +
Math.pow(FI[rFreq][aFreq], 2) / FD[0]);
}
}
}
for (i = 0; i < (MaxRFreq * MaxAFreq); i++) {
console.log(FD[i]);
}
答案 0 :(得分:1)
这里应用了三种单独的归一化技术,以使最终描述符不变为1)平移和2)缩放3)旋转。
对于平移不变部分,您需要找到形状的质心,并计算以质心为原点的每个轮廓点的矢量。这是通过分别从每个点的坐标减去质心的x和y坐标来完成的。所以在你的代码中,每个点的半径和θ应该按如下方式计算:
var radius = Math.sqrt(Math.pow(x - cX, 2) + Math.pow(y - cY, 2));
var theta = Math.atan2(y - cY, x - cX);
对于比例不变部分,您需要找到每个矢量的最大倍数(或所说的半径)(已经为转换不变性标准化),并将每个点的幅度除以最大幅度值。实现这一点的另一种方法是将每个傅里叶系数除以零频率系数(第一系数),因为在那里表示了比例信息。正如我在你的代码和论文中看到的那样,这是按照我描述的第二种方式实现的。
最后,通过仅保持傅里叶系数的大小来实现旋转不变性,如本文的伪代码的第6步所示。
除了所有这些之外,请记住,为了应用描述符比较的eucidean距离,每个形状的描述符长度必须相同。在FFT中,最终系数的数量取决于形状的轮廓点的数量。我发现的解决方案是在点之间进行插值,以便为每个形状达到固定数量的点。
希望我帮助过, Lazaros