【问题标题】:Fast computation of a gradient of an image in matlab在matlab中快速计算图像的梯度
【发布时间】:2013-09-24 03:23:25
【问题描述】:

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

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 中的梯度算子明显较慢,并且可以通过使用移位和减法以及稀疏矩阵来加速。

我不了解稀疏矩阵。但是我确实尝试使用移位和减法方法来做到这一点。但是我很确定我的代码是错误的。请任何人都可以澄清一下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

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

【问题讨论】:

  • 你试过只使用diff吗? mathworks.com/help/matlab/ref/diff.html
  • diff 适用于 1D 数组,我正在处理 2D 或 3D 图像。请解释 diff 如何适用于我的情况?
  • diff(I,1,2) 列之间的差异,即与您的dx1 相同。请阅读我发布的文档链接,差异不仅适用于一维数组。
  • 感谢您的帮助。我会通过它让你知道
  • @Dan 请检查我的答案并告诉我

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


【解决方案1】:

感谢您的所有回答和有用的建议。我采纳了 pseudoDustHuguesDimaHigh Performance Mark 的建议,编写了自己的代码。我的代码如下:

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 梯度函数快得多。

我的代码是否正确?请各位大侠仔细看看。请给出您的反馈。我实际上是 matlab 的新手,对这个结果感到非常惊讶。请检查我所做的是否正确?

【讨论】:

    【解决方案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 个相邻位置(左右或顶部和底部),除了边缘,它取值和相邻位置之间的差异。

    【讨论】:

    • 我正在尝试编写一个梯度函数,该函数的作用与 matlab 中的梯度命令完全相同,但速度明显更快。这就是我尝试的原因。您的命令提供了一些其他值。
    • 您好,您能否再次查看您的代码。我试过了,但答案不正确。请检查并告诉我
    • 请检查我的答案并告诉我
    【解决方案3】:

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

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

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

    gradient 函数使用中心差异,[- 1 0 1] 在 x 方向。

    每个运算符的数值结果会有些不同。

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

    考虑看看imgradient

    【讨论】:

    • 嗨。感谢您的回复。你能告诉我普通渐变命令和imgradient命令有什么区别吗?
    • mathworks.se/help/matlab/ref/gradient.htmlmathworks.se/help/images/ref/imgradient.html 。基本上你在基本选项中没有任何选择。 im 版本可以让你选择你的内核,是否使用 GPU 等等。
    • 谢谢。是的,我阅读了文档。不幸的是,它仅在 R2013 中可用,我正在使用 R2012。但是你能告诉我,如果我在 imgradient 命令中使用默认情况,它们会给出相同的答案吗?由于我没有 Matlab 2013A 我无法检查。
    • 不,答案会有所不同,我确实写过。你有图像处理工具箱吗?然后你可以将imfilter 与Sobel 运算符一起使用并进行比较。
    • 你说得对,我在 2012/2013 年混了一点。我的答案已更新(尝试中心差异)。我这里没有安装 Matlab,但这些细节的答案在代码中!
    【解决方案4】:

    如果您有最新版本的 Matlab(R2012b 及更高版本,IIRC)和图像处理工具箱,则可以使用 imgradient 函数。

    【讨论】:

    • imgradient 在 2012a 中不可用
    • 是的。但是 2013a 刚刚问世。
    • @roni,好吧,生活就是这样。如果你没有更新的版本,那么你应该使用imfilterfspecial 来计算你的梯度。所以还不错。 :)
    猜你喜欢
    • 2015-04-27
    • 1970-01-01
    • 1970-01-01
    • 2014-04-02
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 2018-04-13
    相关资源
    最近更新 更多