【问题标题】:Eigenvector computation using OpenCV使用 OpenCV 进行特征向量计算
【发布时间】:2010-12-23 20:00:04
【问题描述】:

我有这个矩阵 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    
  }
}

问题: 执行后,所有特征向量的几乎所有分量都为零。我尝试了不同的图像,还尝试使用 0 到 1 之间的随机值填充 A,但结果相同。

返回的几个顶级特征值如下所示:

9805401476911479666115491135488.000000  
-9805401476911479666115491135488.000000  
-89222871725331592641813413888.000000  
89222862280598626902522986496.000000  
5255391142666987110400.000000

我现在正在考虑使用cvSVD() 的方法,它执行实浮点矩阵的奇异值分解,并可能产生特征向量。但在那之前,我想在这里问。我目前的方法有什么荒谬的吗?我是否使用了正确的 API,即 cvEigenVV() 用于正确的输入矩阵(我的矩阵 A 是浮点矩阵)?

干杯

【问题讨论】:

  • 在openCV中没有真正使用过eig/svd但是返回的特征值不是应该排序的吗?
  • 是的,没错。我刚刚提出了返回的前 5 个特征值,它们的大小是按顺序排列的(从大到小)。就符号而言,它们不是。但是这个符号只是表示向量的方向,所以我认为特征值是可以的。只关心特征向量。
  • 哦忘了这个标志!根据文档,epsilon 值 1e-15 就足够了(您使用的是 eps=1e-300)。这会导致问题吗?同样,我们通常可以期望只有前几个最大的特征向量占数据方差的大部分,这不是真的吗?
  • 好吧,我很想这样做,但显然我不知道 MATLAB。我正在使用高斯内核来计算相似度并参考 Andrew Ng 的光谱聚类算法。请在这里eprints.kfupm.edu.sa/54643/1/54643.pdf 找到它。第 2 页有算法。该算法的第 1 步提到了用于计算两个像素之间相似度的高斯核。我使用了 Si、Sj 的像素强度和分母的标准差,即 sigma^2。我在计算 sigma 时排除了像素 i 和 j 的强度。
  • 我对openCV一无所知,但看起来你正在将两个未初始化的指针(eigenVec 和 eigenVal)传递给 cvEigenVV()。但也许你为了简短而跳过了初始化代码。

标签: c image-processing opencv eigenvector


【解决方案1】:

读者注意:这篇文章乍一看可能与主题无关,但请参考上面cmets中的讨论。

以下是我尝试实现应用于MATLAB 中图像像素的Spectral Clustering 算法。我完全遵循了@Andriyev 提到的paper

Andrew Ng、Michael Jordan 和 Yair Weiss(2002 年)。 关于谱聚类:分析和算法。 在 T. Dietterich、S. Becker 和 Z. Ghahramani(编辑)中, 神经信息处理系统的进展 14. MIT Press

代码:

%# 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)'})

...并使用我在 Paint 中绘制的简单房屋图像,结果是:

顺便说一下,使用的前 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
......

请注意,上面执行了您在问题中未提及的步骤(拉普拉斯矩阵,并对其行进行规范化)

【讨论】:

  • 看起来棒极了。是的,我只是从我的问题中跳过了拉普拉斯算子和规范化步骤,只是为了保持重点。好吧,现在可能是我学习 MATLAB 的充分理由。感谢您的指导和努力。
  • 事实上,我自己也在阅读内核 PCA 的主题,这非常相似,我发现这是一个通过编码更好地理解它的机会。这是我喜欢的事情之一MATLAB;您可以相当快速地实现这样的算法,并且只需要几行代码! (与 C 中的编码相比)
【解决方案2】:

我会推荐这个article。作者实现了 Eigenfaces 进行人脸识别。在第 4 页上,您可以看到他使用 cvCalcEigenObjects 从图像生成特征向量。在文章中,显示了此计算所需的整个预处理步骤。

【讨论】:

  • 亲爱的 Janusz,我目前正在做一个类似的项目,在阅读了您的回答后,我查找了 forcvCalcEigenObjects 的文档。但是,当同时搜索 openCV 参考手册和 O'Reilly - Learning openCV 时,该功能并不存在。你可能知道它是否过时了?
【解决方案3】:

这是一个不太有用的答案:

理论(或写在纸上的数学)告诉你特征向量应该是什么?大约。

另一个库告诉你特征向量应该是什么?理想情况下,诸如 Mathematica 或 Maple 之类的系统(可以被说服以任意精度进行计算)告诉您特征向量应该是什么?如果不是针对生产型问题,至少针对测试型问题。

我不是图像处理方面的专家,所以我无法提供更多帮助,但我花了很多时间与科学家们相处,经验告诉我,做一些数学可以避免很多眼泪和愤怒首先,在想知道为什么到处都是 0 之前,先形成对应该得到什么结果的期望。当然,这可能是算法实现中的错误,可能是精度损失或其他一些数值问题。但是你不知道也不应该继续这些调查。

问候

标记

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    • 2015-06-26
    • 1970-01-01
    • 2015-07-19
    相关资源
    最近更新 更多