6

Próbowałem zoptymalizować mój kod i odkryłem, że jeden z moich kodów jest wąskim gardłem. Mój kod to:Szybkie obliczanie gradientu obrazu w 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 

Próbowałem uruchomić go tak: wszystko jasne; blisko wszystkich;

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

okazało się, że największa ilość czasu spożywane przez operatora gradientu rachunku (około 60%) do całkowitego czasu. Więc to dało mi do myślenia jak mogę dalej zoptymalizować kod ....

I konsultacje kilka miejsc jak: Dgradient i http://regularize.wordpress.com/2013/06/19/how-fast-can-you-calculate-the-gradient-of-an-image-in-matlab/

Jednak Dgradient plik jest MEX i nie chcę go używać. Chciałem napisać własną funkcję gradientu. Czytałem na blogach, że operator gradientu w Matlab jest znacznie wolniejszy i można go przyspieszyć za pomocą odejmowanej i rzadkiej macierzy przesunięcia.

Nie mam wiedzy na temat macierzy rzadkiej. Jednak próbowałem to zrobić, używając metody shift i substract. Jednak Jestem pewien, że mój kod jest nieprawidłowy. Czy ktoś mógłby wyjaśnić, jakiego rodzaju różnica używa matlab do obliczenia gradientu? I pokaż mi, jak to zrobić w moim kodzie?

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 

Proszę spojrzeć na kod i zasugerować, jak go poprawnie zastosować? Albo wskazujesz mi, jak to zrobić, używając rzadkiej matrycy?

+1

Czy próbowałeś używać 'diff'? http://www.mathworks.com/help/matlab/ref/diff.html – Dan

+0

diff działa z tablicą 1D i pracuję nad obrazem 2D lub 3D. Proszę wyjaśnić, w jaki sposób różnica ma zastosowanie w moim przypadku? – roni

+1

'diff (I, 1,2)' różnica między kolumnami, tj. Taka sama jak twoja 'dx1'. Przeczytaj przeczytany link do dokumentu, diff nie dotyczy tylko tablic 1D. – Dan

Odpowiedz

3

Dzięki wszystkim odpowiedziom i pomocnym sugestiom. Wziąłem sugestie pseudoDust, Hugues, Dima i High Performance Mark i napisałem swój własny kod. Mój kod jest podany poniżej:

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) 

mój Podstawową ideą było to, że: Gradient uśrednia 2 sąsiadujące pozycje (lewy i prawy lub górny i dolny), z wyjątkiem krawędzi, gdzie przybiera ona różnicę między wartością a sąsiednia pozycja. Następnie sprawdziłem generowaną przeze mnie matrycę (dx1, dy1) za pomocą macierzy generowanej przez funkcję gradientu matlab (dx, dy).

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

Wierzę, że mój kod jest poprawny. Również wyniki czasowe były co najmniej zaskakujące. Następnie wyliczyłem mój kod z matlab dla różnych rozmiarów obrazów.

mam to wyniki:


%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. 

Więc mój wniosek był następujący: Dla rozmiaru obrazu upto 1024x1024 mój kod był szybszy niż wbudowane polecenia gradientu w programie MATLAB.

Edycja: I aktualizowany moją odpowiedź i dodał ten wykres:

To wyraźnie pokazuje, że dla mniejszego rozmiaru tablicy mój kod jest znacznie szybsza niż funkcja Matlab gradientu.

enter image description here

Czy mój kod jest prawidłowy? Faceci, proszę przejrzyj to i sprawdź. Przekaż swoją opinię. Jestem dosłownie nowicjuszem w matlab i jestem bardzo zaskoczony tym wynikiem. Sprawdź, czy to, co robię, jest poprawne, czy nie?

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; 

powinien działać średnie gradientu z 2 sąsiednie pozycje (w lewo i w prawo lub w górnej i dolnej), z wyjątkiem krawędzi, gdzie odbywa się różnicę między wartością z przyległym położeniu.

+0

Próbuję napisać funkcję gradientu, który robi dokładnie tak, jak polecenie gradient w matlab, ale znacznie szybciej. Właśnie dlatego próbuję tego. Twoje polecenie podaje inne wartości. – roni

+0

Witam ponownie, możesz ponownie przejrzeć swój kod. Próbowałem, ale odpowiedź nie nadejdzie. Proszę sprawdzić i daj mi znać – roni

+0

Proszę sprawdzić moją odpowiedź i daj mi znać – roni

1

Fajnie, że chcesz napisać własną funkcję gradientu, a jak wspomniano na blogach, niektóre metody są lepsze od innych. Jednak wpis w blogu porównuje zagnieżdżone pętle for do przesunięcia i odejścia oraz rzadkiej macierzy; nigdzie nie mówi się, że gradient jest powolny lub niezoptymalizowany. Zwykle funkcje Matlab są implementowane w C++ i korzystają z bibliotek BLAS i LAPACK. Powinni pokonać dowolne techniki, które sugerujesz, ale śmiało, sprawdź to dla nas :-)

Jeśli chodzi o twój kod, wątpię, czy chcesz zmienić rozmiar obrazu na [4 4]! W przeciwnym razie kod jest poprawny.

Masz niejawnie używany operator Robert dla gradientu (dI/dx = I(x+1) - I(x))

Funkcja gradient wykorzystuje różnice centralnych, [- 1 0 1] w kierunku x.

Wyniki liczbowe dla każdego operatora będą nieco inne.

Należy zauważyć, że w Matlab R2013a funkcja imgradient używa operatora Sobel, [1 0 -1; 2 0 -2;1 0 -1] w kierunku X.

Rozważmy przyjrzeniu imgradient

+0

Witam. Dzięki za odpowiedź. Czy możesz mi powiedzieć, jaka jest różnica między poleceniem normalnego gradientu a poleceniem imgradient? – roni

+1

http: //www.mathworks.se/help/matlab/ref/gradient.html i http://www.mathworks.se/help/images/ref/imgradient.html. Zasadniczo nie masz żadnej opcji w podstawowej. Wersja im pozwala ci wybrać jądro, czy użyć GPU, itp. –

+0

Dzięki. Tak, czytam dokumentację. Niestety jest dostępna tylko w R2013 i używam R2012. Ale czy możesz mi powiedzieć, że obaj dają tę samą odpowiedź, jeśli użyję domyślnego przypadku w poleceniu imgradient? Ponieważ nie mam Matlab 2013A, nie jestem w stanie sprawdzić. – roni

0

Jeśli masz najnowszą wersję programu Matlab (R2012b i UP, IIRC) i obraz Processing Toolbox, można użyć funkcji imgradient.

+0

imgradient nie jest dostępny w 2012a – roni

+0

Prawda. Ale 2013a właśnie wyszedł. – Dima

+0

nie fair :(:(naprawdę – roni