在matlab中快速计算图像的梯度

时间:2013-09-23 11:34:51

标签: matlab optimization image-processing gradient sparse-matrix

我试图优化我的代码,发现我的一个代码是瓶颈。我的代码是:

function [] = one(x)
I = imread('coins.png');
I = double(I);
I = imresize(I,[x x]);
sig=.8;    % scale parameter in Gaussian kernel
G=fspecial('gaussian',15,sig); % Caussian kernel
Img_smooth=conv2(I,G,'same');  % smooth image by Gaussiin convolution
[Ix,Iy]=gradient(Img_smooth);
f=Ix.^2+Iy.^2;
g=1./(1+f);  % edge indicator function.
end

我试图像这样运行它: 清除所有;关闭所有;

x=4000;N=1;
tic
for i=1:N
    one(x);
end
toc

我发现渐变运算符语句占用了最长的时间(约占总时间的60%)。所以它让我思考如何进一步优化我的代码......

我咨询了一些网站,例如:Dgradienthttp://regularize.wordpress.com/2013/06/19/how-fast-can-you-calculate-the-gradient-of-an-image-in-matlab/

然而,Dgradient是一个MEX文件,我不想使用它。我想写自己的渐变功能。我在博客中读到,matlab中的梯度算子明显变慢,并且使用shift& amp;减法和稀疏矩阵。

我不了解稀疏矩阵。但是我确实尝试使用shift和substract方法。但是我很确定我的代码是错误的。请问任何人都可以澄清matlab用于计算其梯度的差异是什么?并告诉我如何在我的代码中执行此操作?

clc;clear all;close all;
I = imread('coins.png');
I = double(I(:,:,1));
I = imresize(I,[4 4]);

tic
[dx dy] = gradient(I);
toc

tic
%//Doing forward difference on both directions
dx1 = [I(:,2:end) I(:,end)] - I;
dy1 = [I(2:end,:);I(end,:)] - I;
toc

请大家查看代码并建议我如何正确应用它?或者使用稀疏矩阵指导我如何做到这一点?

4 个答案:

答案 0 :(得分:4)

感谢您的所有答案和有用的建议。我接受了 pseudoDust Hugues Dima 高性能标记的建议,并编写了自己的代码。我的代码如下:

clc;clear all;close all;
x=32;
I = imread('coins.png');
I = imresize(I,[x x]);
I = double(I(:,:,1));

tic
[dx dy] = gradient(I);
toc

tic
[m,n]=size(I);
A = [I(:,2:end) zeros(m,1)];
B = [zeros(m,1) I(:,1:end-1)];
dx1 = [I(:,2)-I(:,1) (A(:,2:end-1)-B(:,2:end-1))./2 I(:,end)-I(:,end-1)];
A = [I(2:end,:) ; zeros(1,n)];
B = [zeros(1,n) ; I(1:end-1,:)];
dy1 = [I(2,:)-I(1,:) ; (A(2:end-1,:)-B(2:end-1,:))./2 ; I(end,:)-I(end-1,:)];
toc

nnz(dx-dx1)
nnz(dy-dy1)

我的基本想法是:渐变平均2个相邻位置(左侧和右侧或顶部和底部),除了它取值和相邻位置之间的差异的边缘。然后我用matlab梯度函数(dx,dy)生成的矩阵检查了我生成的矩阵(dx1,dy1)。

Elapsed time is 0.010232 seconds.
Elapsed time is 0.000066 seconds.
ans =
     0
ans =
     0

所以我相信我的代码是正确的。至少可以说,时间结果令人惊讶。然后我用matlab计算我的代码,用于不同大小的图像。

我得到了这个结果:


%x=16
Elapsed time is 0.010790 seconds.
Elapsed time is 0.000057 seconds.
%x=32
Elapsed time is 0.010564 seconds.
Elapsed time is 0.000069 seconds.
%x=64
Elapsed time is 0.010627 seconds.
Elapsed time is 0.000152 seconds.
%x=128
Elapsed time is 0.011346 seconds.
Elapsed time is 0.000669 seconds.
%x=256
Elapsed time is 0.017311 seconds.
Elapsed time is 0.004468 seconds.
%x=512
Elapsed time is 0.044148 seconds.
Elapsed time is 0.030435 seconds.
%x=1024
Elapsed time is 0.093386 seconds.
Elapsed time is 0.093029 seconds.
%x=2048
Elapsed time is 0.345423 seconds.
Elapsed time is 0.387762 seconds.

所以我的结论是这样的:对于高达1024X1024的图像大小,我的代码比matlab中内置的渐变命令更快。

编辑:我更新了我的答案并添加了这张图:

清楚地显示对于较小的数组大小,我的代码明显快于matlab渐变函数。

enter image description here

我的代码是否正确?伙计们请仔细检查并检查。请提供反馈。我实际上是matlab的新手,对这个结果非常惊讶。请检查我在做什么是否正确?

答案 1 :(得分:2)

dx1 = (I(:,[1:end end]) - I(:,[1 1:end]));
dx1(:,2:(end-1))=dx1(:,2:(end-1))*0.5;
dy1 = (I([1:end end],:) - I([1 1:end],:));
dy1(2:(end-1),:)=dy1(2:(end-1),:)*0.5;

应该工作,渐变平均2个相邻位置(左和右或顶部和底部),除了它取值和相邻位置之间的差异的边缘。

答案 2 :(得分:1)

很高兴您想要编写自己的渐变函数,并且正如博客中提到的,某些方法比其他方法更好。但是,博客条目将嵌套的for循环与shift和subtract以及稀疏矩阵进行比较;没有任何地方说gradient是缓慢的或未优化的。 Usualy Matlab函数在C ++中实现,并使用BLAS和LAPACK库。他们应该击败你建议的任何技术,但请继续,请为我们检查: - )

关于您的代码,我怀疑您要将图片大小调整为[4 4]! 否则你的代码是正确的。

您已隐式使用Robert运算符作为渐变(dI/dx = I(x+1) - I(x)

gradient函数使用x方向上的中心差异[- 1 0 1]

每个运营商的数值结果会有所不同。

请注意,在Matlab R2013a中,imgradient函数在x方向上使用Sobel算子[1 0 -1; 2 0 -2;1 0 -1]

考虑一下imgradient

答案 3 :(得分:0)

如果你有最新版本的Matlab(R2012b及更高版本,IIRC)和图像处理工具箱,那么你可以使用imgradient功能。