1

「汎用フーリエ記述子を使用した形状ベースの画像検索」という名前の論文を見ていますが、フーリエ記述子の基本的な知識しかありません。私はこの論文の 12 ページにあるアルゴリズムを実装しようとしていますが、あまり意味をなさない結果が得られました。

小さな画像を作成し、その画像の FD を計算し、その FD を x 方向と y 方向に 1 ピクセル分変換された同じ画像と比較すると、最初のエントリを除いて、記述子は完全に異なります -これはまったく同じです。まず、問題は、これらの記述子が 2 つの画像間でまったく同じであるべきかどうかです (記述子は明らかにスケール、回転、および平行移動に対して不変であるため)。

第二に、この論文では、2 つの別個の画像の記述子が単純なユークリッド距離によって比較されることに言及しています。したがって、上記の 2 つの記述子間のユークリッド距離をとることにより、ユークリッド距離は明らかに 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]);
				}

4

1 に答える 1

1

最終記述子を 1) 平行移動と 2) スケール 3) 回転に対して不変にするために、ここでは 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);

スケール不変性部分については、すべてのベクトル(並進不変性のためにすでに正規化されている)の最大マグニチュード(またはあなたが言うように半径)を見つけ、各ポイントの大きさを最大マグニチュード値で割る必要があります。これを実現する別の方法は、ゼロ周波数係数 (最初の係数) ですべてのフーリエ係数を除算することです。これは、スケール情報がそこに表されているためです。あなたのコードと論文でわかるように、これは私が説明した2番目の方法に従って実装されています。

最後に、論文の擬似コードのステップ 6 でわかるように、フーリエ係数の大きさを維持するだけで回転不変性が実現されます。

これらすべてに加えて、記述子の比較にユーシッド距離を適用するには、すべての形状の記述子の長さが同じでなければならないことに注意してください。FFT では、最終的な係数の数は形状の輪郭点の数に依存します。これに対する私が見つけた解決策は、すべての形状に対して固定数のポイントに到達するためにポイント間を補間することです。

お役に立てば幸いです、ラザロス

于 2015-02-23T12:48:17.580 に答える