Быстрое вычисление градиента изображения в MATLAB

Я пытался оптимизировать свой код и обнаружил, что один из моих кодов является узким местом. Мой код :

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%) от общего времени. Поэтому я подумал, как я могу оптимизировать свой код дальше ....

я консультировал несколько сайтов, таких как:Dgradient и http://regularize.wordpress.com/2013/06/19/how-fast-can-you-calculate-the-gradient-of-an-image-in-matlab/

однако Dgradient-это файл MEX, и я не хочу его использовать. Я хотел написать свою собственную градиентную функцию. Я читал в блогах, что оператор градиента в matlab значительно медленнее и ускоряется с помощью shift & substract и разреженной матрицы.

у меня нет знаний о разреженной матрице. Однако я попытался сделать это с помощью shift и метод вычитания. Однако Я довольно уверен, что мой код неверен. Пожалуйста, кто-нибудь может уточнить, какую разницу 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 ответов


Спасибо за все ваши ответы и полезные советы . Я принял предложения pseudoDust, Гуго , Дима и Высокая Производительность 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 смежных положения (левое и правое или верхнее и нижнее), за исключением краев, где он принимает разницу между значением и смежным позиция. Затем я проверил матрицу, сгенерированную мной (dx1,dy1), с матрицей, сгенерированной градиентной функцией matlab (dx, dy).

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.

Edit: я обновил свой ответ и добавил этот график:

это ясно показывает что для меньшего размера массива мой код значительно быстрее, чем функция градиента matlab.

enter image description here

мой код правильный ? Ребята, пожалуйста, просмотрите его и проверить. Дайте свой отзыв. Я буквально новичок в matlab и очень удивлен этим результатом. Пожалуйста, проверьте, что я делать правильно или нет ?


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 смежных положения (левое и правое или верхнее и нижнее), за исключением краев, где он принимает разницу между значением и смежным положением.


приятно, что вы хотите написать свою собственную функцию градиента, и, как упоминалось в блогах, некоторые методы лучше других. Однако запись в блоге сравнивает вложенные for-loops со сдвигом и вычитанием и разреженной матрицей; нигде не говорится, что gradient медленно или не оптимизировано. Обычно функции Matlab реализованы на C++ и используют библиотеки BLAS и LAPACK. Они должны бить любой из методов, которые вы предлагаете, но идти вперед и, пожалуйста, проверьте это для нас :-)

что касается вашего кода, я сомневаюсь, что вы хотите изменить размер изображения для [4 4]! В противном случае ваш код правильный.

вы неявно использовали оператор Роберта для своего градиента (dI/dx = I(x+1) - I(x) )

на gradient функция использует центральные различия,[- 1 0 1] в x-направлении.

численные результаты для каждого оператора будут немного отличаться.

отметим, что в MATLAB R2013a, в imgradient функция использует оператор Sobel,[1 0 -1; 2 0 -2;1 0 -1] in X-направления.

рассмотрите возможность взглянуть на imgradient


Если у вас есть последняя версия Matlab (R2012b и выше, IIRC) и набор инструментов обработки изображений, то вы можете использовать imgradient