傅里叶形状描述符

时间:2015-01-21 12:54:06

标签: image fourier-descriptors

我正在看一篇名为“使用通用傅立叶描述符的基于形状的图像检索”的论文,但只有傅立叶描述符的基本知识。我试图在论文的第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]);
				}

1 个答案:

答案 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