【问题标题】:eigenvalue decomposition of structure tensor in matlabmatlab中结构张量的特征值分解
【发布时间】:2018-07-07 08:13:25
【问题描述】:

我有一个合成图像。为了某些边缘检测目的,我想对其局部结构张量(LST)进行特征值分解。我使用LST的特征值l1l2和特征向量e1e2为图像的每个像素生成一个自适应椭圆。不幸的是,我得到不相等的特征值 l1l2 ,因此对于我的图形的均匀区域,椭圆的半轴长度不相等:

但是,对于一个简单的测试图像,我得到了很好的响应:

我不知道我的代码有什么问题:

function [H,e1,e2,l1,l2] = LST_eig(I,sigma1,rw)

%  LST_eig - compute the structure tensor and its eigen
% value decomposition
%
%   H = LST_eig(I,sigma1,rw);
%
%   sigma1 is pre smoothing width (in pixels).
%   rw is filter bandwidth radius for tensor smoothing (in pixels).
%


n = size(I,1);
m = size(I,2);
if nargin<2
    sigma1 = 0.5;
end
if nargin<3
    rw = 0.001;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pre smoothing
J = imgaussfilt(I,sigma1);
% compute gradient using Sobel operator
Sch = [-3 0 3;-10 0 10;-3 0 3];
%h = fspecial('sobel');
gx = imfilter(J,Sch,'replicate');
gy = imfilter(J,Sch','replicate');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute tensors

gx2 = gx.^2;
gy2 = gy.^2;
gxy = gx.*gy;

% smooth
gx2_sm = imgaussfilt(gx2,rw); %rw/sqrt(2*log(2))
gy2_sm = imgaussfilt(gy2,rw);
gxy_sm = imgaussfilt(gxy,rw);
H = zeros(n,m,2,2);
H(:,:,1,1) = gx2_sm; 
H(:,:,2,2) = gy2_sm; 
H(:,:,1,2) = gxy_sm; 
H(:,:,2,1) = gxy_sm; 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% eigen decomposition
l1 = zeros(n,m);
l2 = zeros(n,m);
e1 = zeros(n,m,2);
e2 = zeros(n,m,2);
for i = 1:n
    for j = 1:m
        Hmat = zeros(2);
        Hmat(:,:) = H(i,j,:,:);
        [V,D] = eigs(Hmat);
        D = abs(D);
        l1(i,j) = D(1,1); % eigen values
        l2(i,j) = D(2,2); 
        e1(i,j,:) = V(:,1); % eigen vectors
        e2(i,j,:) = V(:,2); 
    end
end

感谢任何帮助。

这是我的椭圆绘制代码:

% determining ellipse parameteres from eigen value decomposition of LST

M = input('Enter the maximum allowed semi-major axes length: ');
I = input('Enter the input data: ');

row = size(I,1);
col = size(I,2);
a = zeros(row,col);
b = zeros(row,col);
cos_phi = zeros(row,col);
sin_phi = zeros(row,col);


for m = 1:row
  for n = 1:col

    a(m,n) = (l2(m,n)+eps)/(l1(m,n)+l2(m,n)+2*eps)*M;
    b(m,n) = (l1(m,n)+eps)/(l1(m,n)+l2(m,n)+2*eps)*M;

    cos_phi1 = e1(m,n,1);
    sin_phi1 = e1(m,n,2);
    len = hypot(cos_phi1,sin_phi1);           
    cos_phi(m,n) = cos_phi1/len;
    sin_phi(m,n) = sin_phi1/len;

  end
end

%% plot elliptic structuring elements using parametric equation and superimpose on the image 


figure; imagesc(I); colorbar; hold on

t = linspace(0,2*pi,50);

for i = 10:10:row-10
  for j = 10:10:col-10
    x0 = j;
    y0 = i;

    x = a(i,j)/2*cos(t)*cos_phi(i,j)-b(i,j)/2*sin(t)*sin_phi(i,j)+x0;
    y = a(i,j)/2*cos(t)*sin_phi(i,j)+b(i,j)/2*sin(t)*cos_phi(i,j)+y0;

    plot(x,y,'r','linewidth',1);
    hold on
  end
end 

这是我使用高斯导数内核的新结果:

这是axis equal的新情节:

【问题讨论】:

  • @Cris Luengo:谢谢。我为rw 测试了 0.5、1、5、8,但我没有得到好的结果。是的,它不是 Sobel 过滤器,而是 Scharr 过滤器。你确定高斯导数更好吗?你知道,那些椭圆是我用于我的目的的结构元素,我画它们是为了理解它们是否足够适应?我想我应该使用 eigs 作为张量。
  • 我用eig代替eigs,但结果没有改变,只是运行时间减少了。 matlab中的高斯导数函数是什么?
  • 查看您的图像,我注意到您的 x 和 y 轴的缩放方式不同。这是故意的吗? axis equal 将它们的缩放设置相同。这或许可以解释为什么其中一些椭圆与图像中的结构不一致。
  • 我觉得我的椭圆绘制代码是对的。我将它添加到问题中。我使用高斯导数内核运行代码,得到了更可接受的答案。我也将新情节添加到问题中。
  • 看起来不错。同样,使用axis equal,您将获得更好的椭圆表示,它们比您在图像中看到的更圆。你仍然有一条沿着图像中间向下延伸的高各向同性带,但也许这在数据中?在曲线水平的地方,我看到垂直拉长的椭圆,也不知道为什么会这样。在测试图像上运行您的代码,我得到了很好的结果(即使使用 Scharr 过滤器和eigs)。

标签: matlab image-processing structure tensor eigenvalue


【解决方案1】:

我创建了一个类似于你的测试图像(可能不太复杂),如下所示:

pos = yy([400,500]) + 100 * sin(xx(400)/400*2*pi);
img = gaussianlineclip(pos+50,7) + gaussianlineclip(pos-50,7);
I = double(stretch(img));

(这需要DIPimage 才能运行)

然后在上面运行你的LST_eigsigma1=1rw=3)和绘制椭圆的代码(两者都没有变化,除了添加axis equal),得到了这个结果:

我怀疑图像的某些蓝色区域存在不均匀性,这会导致出现非常小的渐变。使用椭圆时定义椭圆的问题在于,对于足够定向的模式,即使该模式难以察觉,您也会得到一条线。您可以通过如下定义椭圆轴长度来解决此问题:

a = repmat(M,size(l2)); % longest axis is always the same
b = M ./ (l2+1); % shortest axis is shorter the more important the largest eigenvalue is 

最小特征值l1在梯度强但方向不明确的区域较高。上面没有考虑到这一点。一种选择是使a 依赖于能量和各向异性测量,而b 仅依赖于能量:

T = 1000; % some threshold
r = M ./ max(l1+l2-T,1); % circle radius, smaller for higher energy
d = (l2-l1) ./ (l1+l2+eps); % anisotropy measure in range [0,1]
a = M*d + r.*(1-d); % use `M` length for high anisotropy, use `r` length for high isotropy (circle)
b = r; % use `r` width always

这样,如果有强梯度但没有明确的方向,整个椭圆会缩小,而当只有弱梯度或没有梯度时,它会保持大而圆形。阈值T取决于图像强度,根据需要调整。

您可能还应该考虑取特征值的平方根,因为它们对应于方差。

一些建议:

  1. 你可以写

    a = (l2+eps)./(l1+l2+2*eps) * M;
    b = (l1+eps)./(l1+l2+2*eps) * M;
    cos_phi = e1(:,:,1);
    sin_phi = e1(:,:,2);
    

    没有循环。注意e1是按定义归一化的,不需要再归一化。

  2. 使用 Gaussian gradients 代替高斯平滑,然后使用 Sobel 或 Schaar 滤波器。请参阅here 了解一些 MATLAB 实现细节。

  3. 当您需要所有特征值时,使用eig,而不是eigs。尤其是这么小的矩阵,使用eigs没有任何优势。 eig 似乎产生了更一致的结果。无需取特征值 (D = abs(D)) 的绝对值,因为它们根据定义是非负的。

  4. 您的默认值 rw = 0.001 太小了,该大小的 sigma 对图像没有影响。这种平滑的目标是平均局部邻域中的梯度。我用rw=3 效果很好。

  5. 使用 DIP 图像。有一个structuretensor 函数、高斯梯度和更多有用的东西。 The 3.0 version (still in development) 是一个重大改写,显着改进了处理向量和矩阵值图像。我可以把你所有的LST_eig写成如下:

    I = dip_image(I);
    g = gradient(I, sigma1);
    H = gaussf(g*g.', rw);
    [e,l] = eig(H);
    % Equivalences with your outputs:
    l1 = l{2};
    l2 = l{1};
    e1 = e{2,:};
    e2 = e{1,:};
    

【讨论】:

  • 亲爱的博士。 Luengo:我非常感谢您的大力帮助。你的建议总是对我有帮助。
  • 我有一些连接问题。还有一点:我使用 DIPimage 创建了您的测试图像。整个图像都是0,而不仅仅是曲线。所以它的特征值l1, l2 在同质区域是0。但是我的图像在整个图像中都有0.188075529030993 值,并且在某处有`1.493765725651963e-05`,在曲线中这个0.008912427070687 附近的值和在曲线旁边这个0.736702531715232 附近的值。我认为我的数据很复杂。
  • @bahar:是的,确实,我的测试图像非常简单。在使方法变得更复杂之前,使用简单的测试图像测试方法总是好的。正如我所说,如果局部有明确的方向,该方法会绘制直线而不是椭圆,即使它是由非常低的强度波动引起的。这就是为什么我建议替代 ab 计算,它们应该忽略那些小的波动。
  • 非常感谢。抱歉,还有 2 个问题:1. 我用 DIPimage 运行了你的简短 LST_eig 代码,但我收到了这个错误:Error using dip_image/eig (line 52) Tensor must be 2x2 or 3x3。我认为您代码中的 H 不是张量。它是一个 500*500 的矩阵。 2.你对使用bilateral过滤器代替高斯平滑有什么想法吗?它是边缘保留过滤器。
  • @bahar:输入图像I 应该是dip_image 对象,抱歉我忘了提。关于平滑——我不知道这是否可行和有用,如果你当然可以尝试看看它是否适合你。输出将显示各向异性,因为在同位素区域中,您平均会超过更少的像素。您必须注意平均在每个张量组件中获得相同的内核,如果您将过滤器分别应用于每个通道,则输出将不正确。您需要在本地对完整张量进行平均。
猜你喜欢
  • 1970-01-01
  • 2011-10-02
  • 1970-01-01
  • 2018-12-30
  • 2011-03-18
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 2018-09-20
相关资源
最近更新 更多