OpenCVを使用した固有ベクトル計算
-
13-09-2019 - |
質問
画像のピクセル強度の類似性を表す行列 A があります。例えば:を考えてみましょう 10 x 10
画像。この場合の行列 A は次の次元になります。 100 x 100
, 、要素 A(i,j) は 0 ~ 1 の範囲の値を持ち、ピクセル i と j の強度の類似性を表します。
画像処理には OpenCV を使用しており、開発環境は Linux 上の C です。
目的は行列 A の固有ベクトルを計算することであり、次のアプローチを使用しました。
static CvMat mat, *eigenVec, *eigenVal;
static double A[100][100]={}, Ain1D[10000]={};
int cnt=0;
//Converting matrix A into a one dimensional array
//Reason: That is how cvMat requires it
for(i = 0;i < affnDim;i++){
for(j = 0;j < affnDim;j++){
Ain1D[cnt++] = A[i][j];
}
}
mat = cvMat(100, 100, CV_32FC1, Ain1D);
cvEigenVV(&mat, eigenVec, eigenVal, 1e-300);
for(i=0;i < 100;i++){
val1 = cvmGet(eigenVal,i,0); //Fetching Eigen Value
for(j=0;j < 100;j++){
matX[i][j] = cvmGet(eigenVec,i,j); //Fetching each component of Eigenvector i
}
}
問題: 実行後、すべての固有ベクトルのほぼすべての成分がゼロになります。さまざまな画像を試し、A に 0 から 1 までのランダムな値を入力してみましたが、結果は同じでした。
返される上位固有値のいくつかは次のようになります。
9805401476911479666115491135488.000000
-9805401476911479666115491135488.000000
-89222871725331592641813413888.000000
89222862280598626902522986496.000000
5255391142666987110400.000000
私は今、使用するラインについて考えています cvSVD() これにより、実浮動小数点行列の特異値分解が実行され、固有ベクトルが得られる可能性があります。でもその前にここで質問してみようと思いました。私の現在のアプローチに何か不合理な点はありますか?正しい API を使用していますか? cvEigenVV() 正しい入力行列の場合 (行列 A は浮動小数点行列です)?
乾杯
解決
読者への注意:この投稿は一見本題と無関係に見えるかもしれませんが、上記のコメントの議論を参照してください。
以下は私の実装の試みです スペクトルクラスタリング 画像ピクセルに適用されるアルゴリズム MATLAB. 。私はまさにそれに従った 紙 @Andriyevによって言及されました:
アンドリュー・ン、マイケル・ジョーダン、ヤイール・ワイス (2002)。スペクトルクラスタリングについて:分析とアルゴリズム。Tで。ディーテリッヒ、S.ベッカーと Z.Ghahramani(編)、神経情報処理システムの進歩14。MITプレス
コード:
%# parameters to tune
SIGMA = 2e-3; %# controls Gaussian kernel width
NUM_CLUSTERS = 4; %# specify number of clusters
%% Loading and preparing a sample image
%# read RGB image, and make it smaller for fast processing
I0 = im2double(imread('house.png'));
I0 = imresize(I0, 0.1);
[r,c,~] = size(I0);
%# reshape into one row per-pixel: r*c-by-3
%# (with pixels traversed in columwise-order)
I = reshape(I0, [r*c 3]);
%% 1) Compute affinity matrix
%# for each pair of pixels, apply a Gaussian kernel
%# to obtain a measure of similarity
A = exp(-SIGMA * squareform(pdist(I,'euclidean')).^2);
%# and we plot the matrix obtained
imagesc(A)
axis xy; colorbar; colormap(hot)
%% 2) Compute the Laplacian matrix L
D = diag( 1 ./ sqrt(sum(A,2)) );
L = D*A*D;
%% 3) perform an eigen decomposition of the laplacian marix L
[V,d] = eig(L);
%# Sort the eigenvalues and the eigenvectors in descending order.
[d,order] = sort(real(diag(d)), 'descend');
V = V(:,order);
%# kepp only the largest k eigenvectors
%# In this case 4 vectors are enough to explain 99.999% of the variance
NUM_VECTORS = sum(cumsum(d)./sum(d) < 0.99999) + 1;
V = V(:, 1:NUM_VECTORS);
%% 4) renormalize rows of V to unit length
VV = bsxfun(@rdivide, V, sqrt(sum(V.^2,2)));
%% 5) cluster rows of VV using K-Means
opts = statset('MaxIter',100, 'Display','iter');
[clustIDX,clusters] = kmeans(VV, NUM_CLUSTERS, 'options',opts, ...
'distance','sqEuclidean', 'EmptyAction','singleton');
%% 6) assign pixels to cluster and show the results
%# assign for each pixel the color of the cluster it belongs to
clr = lines(NUM_CLUSTERS);
J = reshape(clr(clustIDX,:), [r c 3]);
%# show results
figure('Name',sprintf('Clustering into K=%d clusters',NUM_CLUSTERS))
subplot(121), imshow(I0), title('original image')
subplot(122), imshow(J), title({'clustered pixels' '(color-coded classes)'})
...ペイントで描いたシンプルな家の画像を使用すると、次のような結果が得られました。
ちなみに、使用された最初の 4 つの固有値は次のとおりです。
1.0000
0.0014
0.0004
0.0002
および対応する固有ベクトル [長さ r*c=400 の列]:
-0.0500 0.0572 -0.0112 -0.0200
-0.0500 0.0553 0.0275 0.0135
-0.0500 0.0560 0.0130 0.0009
-0.0500 0.0572 -0.0122 -0.0209
-0.0500 0.0570 -0.0101 -0.0191
-0.0500 0.0562 -0.0094 -0.0184
......
質問で言及されていない上記で実行されたステップがあることに注意してください(ラプラシアン行列とその行の正規化)
他のヒント
これをお勧めします 記事. 。著者は顔認識のためにEigenfacesを実装しています。4 ページでは、cvCalcEigenObjects を使用して画像から固有ベクトルを生成していることがわかります。この記事では、この計算に必要な前処理ステップ全体が示されています。
あまり役に立たない答えは次のとおりです。
理論 (または紙に走り書きした数学) は、固有ベクトルがどうあるべきかを教えてくれますか?約。
別のライブラリは固有ベクトルがどうあるべきかを教えてくれますか?理想的には、Mathematica や Maple などのシステム (任意の精度まで計算できる) は、固有ベクトルがどうあるべきかを教えてくれますか?実稼働用の問題ではないとしても、少なくともテストサイズの問題では。
私は画像処理の専門家ではないので、これ以上お役に立てるわけではありませんが、科学者たちと多くの時間を過ごしており、経験から、最初にいくつかの計算を行って次のようなことを行うことで、多くの涙や怒りを回避できることが分かりました。なぜあちこちに 0 が表示されるのか疑問に思う前に、どのような結果が得られるのかを予想します。確かに、それはアルゴリズムの実装におけるエラーである可能性があり、精度の損失またはその他の数値上の問題である可能性があります。しかし、あなたはまだ知りませんし、これらの問い合わせを追跡するべきではありません。
よろしく
マーク