In my code, arrayfun slower than for loop

2 views (last 30 days)
function Hist = hsv36(I)
[M,N,~] = size(I);
[H,S,V] = rgb2hsv(I);
H = H*360;
Hist = zeros(1,36);
for i = 1:M
for j = 1:N
h = H(i,j);
v = V(i,j);
s = S(i,j);
if(v>=0 && v<0.2)
l = 0+1;
Hist(l) = Hist(l)+1;
continue;
end;
if(s>=0 && s<=0.2)
if (v>=0.2 && v<=0.8)
l = floor((v-0.2)*10)+1+1;
Hist(l) = Hist(l)+1;
elseif (v>0.8 && v<=1)
l = 7+1;
Hist(l) = Hist(l)+1;
end
continue;
end
if((s>0.2 && s<=1)&&(v>=0.2 && v<=1))
if h<=22 || h>330
HF = 0;
elseif h>22 && h<=45
HF = 1;
elseif h>45 && h<=70
HF = 2;
elseif h>70 && h<=155
HF = 3;
elseif h>155 && h<=186
HF = 4;
elseif h>186 && h<=278
HF = 5;
elseif h>278 && h<=330
HF = 6;
end
if(s>0.2 && s<=0.65)
SF = 0;
elseif(s>0.65 && s<=1)
SF = 1;
end;
if(v>=0.2 && v<=0.7)
VF = 0;
elseif(v>0.7 && v<=1)
VF = 1;
end;
l = 4*HF + 2*SF + VF + 8 + 1;
Hist(l) = Hist(l) + 1;
end
end
end
%Hist = Hist/(M*N);
Hist = normr(Hist);
this is my fuction to get hsv color histogram, as you see in which have two for loops, which make code looks ugly, and matlab also doesn't recommend for loop. To make it better, i use arrafun instead of for loop, like that:
function Hist = hsv36_new(I)
[M,N,~] = size(I);
[H,S,V] = rgb2hsv(I);
H = H*360;
Hist = zeros(1,36);
function calHsvHist(i, j)
h = H(i,j);
v = V(i,j);
s = S(i,j);
if(v>=0 && v<0.2)
l = 0+1;
Hist(l) = Hist(l)+1;
return;
end;
if(s>=0 && s<=0.2)
if (v>=0.2 && v<=0.8)
l = floor((v-0.2)*10)+1+1;
Hist(l) = Hist(l)+1;
elseif (v>0.8 && v<=1)
l = 7+1;
Hist(l) = Hist(l)+1;
end
return;
end
if((s>0.2 && s<=1)&&(v>=0.2 && v<=1))
if h<=22 || h>330
HF = 0;
elseif h>22 && h<=45
HF = 1;
elseif h>45 && h<=70
HF = 2;
elseif h>70 && h<=155
HF = 3;
elseif h>155 && h<=186
HF = 4;
elseif h>186 && h<=278
HF = 5;
elseif h>278 && h<=330
HF = 6;
end
if(s>0.2 && s<=0.65)
SF = 0;
elseif(s>0.65 && s<=1)
SF = 1;
end;
if(v>=0.2 && v<=0.7)
VF = 0;
elseif(v>0.7 && v<=1)
VF = 1;
end;
l = 4*HF + 2*SF + VF + 8 + 1;
Hist(l) = Hist(l) + 1;
end
end
arrayfun(@(id1) arrayfun(@(id2) calHsvHist(id1, id2), 1:N), 1:M);
%Hist = Hist/(M*N);
Hist = normr(Hist);
end
In for loop case it juse take 0.06 second, but arrayfun case almost 2 second.. why this happen, could someone explain that to me? thank you.
  1 Comment
Sean de Wolski
Sean de Wolski on 5 Aug 2014
With the exception of being on a GPU, arrayfun will most likely often be slower than a for-loop and harder to read. It's just a less flexible more complex for-loop.
Personally, I'd recommend against it at all cost unless you're targeting a GPU.

Sign in to comment.

Accepted Answer

Chris Turnes
Chris Turnes on 5 Aug 2014
The arrayfun function simply applies a given function to each element of the array that you supply. In this sense, arrayfun is effectively looping through the input arrays and calling the supplied function on each input. Since there is some overhead involved with calling a function, this will not be faster than simply placing the loop inside of the function itself.
More specifically, the hsv36_new function given in the question uses arrayfun to call calHsvHist on each grid element. This results in a total of M*N separate calls to calHsvHist, and each of those calls introduces some overhead cost. In the end, both functions are essentially using the same looping, but the hsv36_new function is using a more expensive version since it involves the overhead of calling another function, as well.
If you do want to speed up your code, you should consider vectorizing it by replacing the for loops with matrix operations. You should be able to remove both for loops by making use of logical indexing. For example, you would be able to replace the lines
if(v>=0 && v<0.2)
l = 0+1;
Hist(l) = Hist(l)+1;
continue;
end;
with the single line
Hist(1) = nnz((v >= 0) && (v < 0.2));
The quantity (v >= 0) && (v < 0.2) is a logical matrix of the same size as v whose elements v(i,j) are true if the conditions v(i,j) >= 0 and v(i,j) < 0.2 are both satisfied and false otherwise. The function nnz is then used to count the number of non-zero elements ( i.e., the number of elements that are true).
You could apply similar logic to account for the other if conditions as well, and would then not need the nested for loops.

More Answers (1)

osman
osman on 8 Aug 2014
Thank your sir for your detailed answer, and I learn a new technique from you.

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!