Nested For Loop! Long running Time

Hello Everybody, I have written a code to process Images. Images will be processed using nested for loop to change Pixel by pixel so that the running time for one Picture with 12MB is 7 min. Is there another possibility to do the same but within 2 or 3 sec? Thank you very much for your Help. This is my Code:
rgb = imread('Image.jpg');
figure;
imshow(rgb);
R=rgb(:,:,1); %red
G=rgb(:,:,2); %green
B=rgb(:,:,3); %blue
[x,y,z]=size(rgb);
for i=1:x
for j=1:y
if((R(i,j) < 0))
R(i,j) = 0;
G(i,j) = 0;
B(i,j) = 0;
elseif ( (R(i,j) >= 0) && (R(i,j) <=26) )
R(i,j) = 0;
G(i,j) = 97;
B(i,j) = 254;
elseif ( (R(i,j) > 26) && (R(i,j) <=51) )
R(i,j) = 0;
G(i,j) = 197;
B(i,j) = 254;
elseif ( (R(i,j) > 51) && (R(i,j) <=77) )
R(i,j) = 0;
G(i,j) = 250;
B(i,j) = 204;
elseif ( (R(i,j) > 77) && (R(i,j) <=102) )
R(i,j) = 0;
G(i,j) = 250;
B(i,j) = 104;
elseif ( (R(i,j) > 102) && (R(i,j) <=128) )
R(i,j) = 0;
G(i,j) = 250;
B(i,j) = 4;
elseif ( (R(i,j) > 128) && (R(i,j) <=153) )
R(i,j) = 96;
G(i,j) = 250;
B(i,j) = 0;
elseif ( (R(i,j) > 153) && (R(i,j) <=179) )
R(i,j) = 196;
G(i,j) = 250;
B(i,j) = 0;
elseif ( (R(i,j) > 179) && (R(i,j) <=204) )
R(i,j) = 254;
G(i,j) = 205;
B(i,j) = 0;
elseif ( (R(i,j) > 204) && (R(i,j) <=230) )
R(i,j) = 254;
G(i,j) = 105;
B(i,j) = 0;
elseif ( (R(i,j) > 230) && (R(i,j) <=255) )
R(i,j) = 254;
G(i,j) = 5;
B(i,j) = 0;
elseif ( (R(i,j) >= 255))
R(i,j) = 255;
G(i,j) = 255;
B(i,j) = 255;
end
end
end
for i=1:x
for j=1:y
blue(i,j,1) = R(i,j);
blue(i,j,2) = G(i,j);
blue(i,j,3) = B(i,j);
end
end
figure;
imshow(blue);

 Accepted Answer

Zoubeir - I'm noticing the same with your code for a 3744x5616 RGB image. It seems though that the bottleneck is with the "second" part of the code where you update the blue matrix. Since you haven't defined a size for it, it is constantly being resized on all subsequent iterations of your for loops. I suggest that you pre-size this matrix as
blue = zeros(x,y,3,'uint8');
for i=1:x
for j=1:y
blue(i,j,1) = R(i,j);
blue(i,j,2) = G(i,j);
blue(i,j,3) = B(i,j);
end
end
There may be some other optimizations to your first set of for loops but I would start with the pre-sizing of blue. (Note that with this modification, it took about five seconds to execute your code. With the previous version, I killed the processing after a couple of minutes.)

1 Comment

Thank you very much, Geoff. Can you tell me the other optimizations that I could do to my first set of for loops? Thank you again. Best Regards.

Sign in to comment.

More Answers (3)

Use discretize to discretize the red plane of your image, identifying the bin to which each element should belong. Use those bin numbers to index into the array of colors. For illustration purposes, I'll use a smaller matrix.
tic
% Generate sample data
sizeOfR = [10 10 3];
R = randi(intmax('uint8'), sizeOfR, 'uint8');
% Set up a bin & color matrix
binAndColors = uint8(...
[ 0 0 97 254;
26 0 197 254;
51 0 250 204;
77 0 250 104;
102 0 250 4;
128 96 250 0;
153 196 250 0;
179 254 205 0;
204 254 105 0;
230 254 5 0]);
% Bin the elements of the red plane of R
D = discretize(R(:, :, 1), [binAndColors(:, 1); 255], 'includedEdge', 'right');
% These are the colors associated with each bin
colors = binAndColors(:, 2:4);
% Use the bin numbers to index into the appropriate column of the colors array
red = reshape(colors(D, 1), sizeOfR(1:2));
green = reshape(colors(D, 2), sizeOfR(1:2));
blue = reshape(colors(D, 3), sizeOfR(1:2));
% Stack the three planes together
R2 = cat(3, red, green, blue);
toc
% To check, display the original array R and the new array R2 side-by-side
% I added a layer of three 1's between the two arrays to make it easier
% to distinguish the boundaries. I would have used NaN, but NaN is converted
% to 0 in a uint8 array.
cat(2, R, repmat(1, sizeOfR(1), 3, sizeOfR(3)), R2)
On my Windows machine with release R2016b, running all these commands ( except the last one, which would print a very large array in the Command Window ) for an R array of size [3744 5616 3] took less than 2 seconds. Note that the binAndColors array doesn't contain entries for the <0 or >255 cases; if your data is uint8 as I think most of us have assumed, those cases cannot occur because of the range of values that can be stored in a uint8 array.
rangeOfUint8DataType = [intmin('uint8') intmax('uint8')]

1 Comment

Jan
Jan on 16 Feb 2017
Edited: Jan on 20 Feb 2017
Compare this, especially the creation of the binAndColors table, with my two solutions: While typing my suggestions has been tedious and in consequence prone to typos, this is compact and neat. I even gave up writing the 2nd suggestions in between.
This is an excellent example for the efficient use of Matlab for writing clean code. +1

Sign in to comment.

Jan
Jan on 16 Feb 2017
Edited: Jan on 16 Feb 2017
For the first part: Instead of looping you can use "linear indexing": This can replace each ELSEIF branch:
R = rgb(:,:,1); %red
G = rgb(:,:,2); %green
B = rgb(:,:,3); %blue
RR = R; % Do not overwrite original values
index = (RR < 0)); % Is this possible at all???
R(index) = 0;
G(index) = 0;
B(index) = 0;
index = (RR >= 0) & (RR <= 26);
R(index) = 0;
G(index) = 97;
B(index) = 254;
index = (RR > 26) & (RR <=51);
R(index) = 0;
G(index) = 197;
B(index) = 254;
index = (RR > 51) & (RR <= 77);
R(index) = 0;
G(index) = 250;
B(index) = 204;
index = (RR > 77) & (RR <= 102);
R(index) = 0;
G(index) = 250;
B(index) = 104;
index = (RR > 102) & (RR <= 128);
R(index) = 0;
G(index) = 250;
B(index) = 4;
index = (RR > 128) & (RR <= 153);
R(index) = 96;
G(index) = 250;
B(index) = 0;
index = (RR > 153) & (RR <= 179);
R(index) = 196;
G(index) = 250;
B(index) = 0;
index = (RR > 179) & (RR <= 204);
R(index) = 254;
G(index) = 205;
B(index) = 0;
index = (RR > 204) & (RR <= 230);
R(index) = 254;
G(index) = 105;
B(index) = 0;
index = (RR > 230) & (R <= 255);
R(index) = 254;
G(index) = 5;
B(index) = 0;
index = (RR >= 255);
R(index) = 255;
G(index) = 255;
B(index) = 255;
Note that you could reuse e.g. (RR <= 204) to obtain (RR > 204) by a simple not() command. But this would make the code less clear, so I've omitted this.
Geoff's pre-allocation "zeros()" helps already. But you can try this also instead of the loop:
blue = cat(3, uint8(R), uint8(G), uint8(B));
And another apporach
R = rgb(:,:,1); %red
G = rgb(:,:,2); %green
B = rgb(:,:,3); %blue
G(R <= 0) = 0;
G(R > 0 & R < 26) = 97;
G(R > 26 & R <= 51) = 197;
G(R > 51 & R <= 204) = 250;
G(R > 204 & R <= 230) = 105;
G(R > 230) = 5;
B(R <= 0) = 0;
B(R > 0 & R <= 51) = 254;
B(R > 51 & R <= 77) = 204;
etc.
RR = R; % Do not overwrite the original data
...
This is even shorter than my other suggestion, but still tedious to type. So I leave this up to you.

4 Comments

Thank you very much, Simon. With this code, I could save 4 sec.
The runtime was 7 minutes and now it is 6:54? Oh, I hoped it is ways faster.
Zoubeir Afifi
Zoubeir Afifi on 16 Feb 2017
Edited: Zoubeir Afifi on 16 Feb 2017
No, I meant with the pre-sizing of Geoff was the runtime 7 sec. Now, it is only 3 sec
Vielen Dank, es ist erledigt.

Sign in to comment.

Asked:

on 15 Feb 2017

Edited:

Jan
on 20 Feb 2017

Community Treasure Hunt

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

Start Hunting!