matlab中结构张量的特征值分解
eigenvalue decomposition of structure tensor in matlab
我有一张合成图像。为了某些边缘检测的目的,我想对其局部结构张量 (LST) 进行特征值分解。我使用 LST 的特征值 l1
、 l2
和特征向量 e1
、e2
为图像的每个像素生成自适应椭圆。不幸的是,对于我的图形的同质区域,我得到不相等的特征值 l1
, l2
等椭圆的半轴长度不相等:
但是我得到了一个简单的测试图像的良好响应:
我不知道我的代码有什么问题:
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
的新情节:
我创建了一个类似于你的测试图像(可能不那么复杂)如下:
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_eig
在上面(sigma1=1
和 rw=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
取决于图像强度,根据需要进行调整。
您可能还应该考虑对特征值求平方根,因为它们对应于方差。
一些建议:
可以写
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
是定义归一化的,不需要再归一化
使用 Gaussian gradients instead of Gaussian smoothing followed by Sobel or Schaar filters. See here 了解一些 MATLAB 实现细节。
当您需要所有特征值时,请使用 eig
,而不是 eigs
。尤其是这么小的矩阵,用eigs
没有什么优势。 eig
似乎产生了更一致的结果。不需要取特征值的绝对值 (D = abs(D)
),因为根据定义它们是非负的。
您的默认值 rw = 0.001
太小了,那个大小的西格玛对图像没有影响。这种平滑的目标是平均局部邻域中的梯度。我用了rw=3
,效果不错。
使用 DIPimage。有一个 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,:};
我有一张合成图像。为了某些边缘检测的目的,我想对其局部结构张量 (LST) 进行特征值分解。我使用 LST 的特征值 l1
、 l2
和特征向量 e1
、e2
为图像的每个像素生成自适应椭圆。不幸的是,对于我的图形的同质区域,我得到不相等的特征值 l1
, l2
等椭圆的半轴长度不相等:
但是我得到了一个简单的测试图像的良好响应:
我不知道我的代码有什么问题:
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
的新情节:
我创建了一个类似于你的测试图像(可能不那么复杂)如下:
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_eig
在上面(sigma1=1
和 rw=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
取决于图像强度,根据需要进行调整。
您可能还应该考虑对特征值求平方根,因为它们对应于方差。
一些建议:
可以写
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
是定义归一化的,不需要再归一化使用 Gaussian gradients instead of Gaussian smoothing followed by Sobel or Schaar filters. See here 了解一些 MATLAB 实现细节。
当您需要所有特征值时,请使用
eig
,而不是eigs
。尤其是这么小的矩阵,用eigs
没有什么优势。eig
似乎产生了更一致的结果。不需要取特征值的绝对值 (D = abs(D)
),因为根据定义它们是非负的。您的默认值
rw = 0.001
太小了,那个大小的西格玛对图像没有影响。这种平滑的目标是平均局部邻域中的梯度。我用了rw=3
,效果不错。使用 DIPimage。有一个
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,:};