Use Parfor on a greenscreen picture

1 view (last 30 days)
I have this piece of code, which compares the pixels of a picture with a greenscreen background. If a pixel with a higher green value than the value of the threshold is found, the pixel has to be replaced with a pixel of another picture
function [outPic] = thresholdFilter(green_pic,background, threshold)
[m,n,p] = size(green_pic);
outPic = green_pic;
tic
for i = 1:m
for k = 1:n
if green_pic(i,k,2) >= threshold;
outPic(i,k,1) = background(i,k,1);
outPic(i,k,2) = background(i,k,2);
outPic(i,k,3) = background(i,k,3);
end
end
end
toc
end
Now, i'm trying to reduce the execution time by using parfor. However, when i display the picture, the background is still unedited and it only shows the greenscreen picture.
function [outPic] = thresholdFilter2_0(green_pic,background, threshold)
[m,n,p] = size(green_pic);
outPic = green_pic;
tic
parfor i = 1:m
pic = green_pic;
for k = 1:n
if green_pic(i,k,2) >= threshold;
pic(i,k,1) = background(i,k,1);
pic(i,k,2) = background(i,k,2);
pic(i,k,3) = background(i,k,3);
end
end
outPic = pic(i,:,:);
end
toc
end
How can i get the same results as the first example by using Parfor ?
  1 Comment
Daniel Pollard
Daniel Pollard on 29 Apr 2021
Is there any reason you can't reshape the array into a 1D array, do your thresholding process, then reshape it back to its original shape? That way you could vectorise the code, removing the need for loops at all, and be much cleaner and more efficient.
Also read up on logical indexing. You can get rid of that if statement pretty easily.

Sign in to comment.

Accepted Answer

Edric Ellis
Edric Ellis on 30 Apr 2021
The comment on your question by @Daniel Pollard is probably the most productive way forward. But to answer your parfor query specifically - the problem here is that inside the parfor loop, outPic is being treated as a "loop temporary variable". To make a value available after the parfor loop, it has to be either a sliced or a reduction output.
Your original for loop is very close to working as a parfor loop. The only tweak necessary is to make a single assignment into outPic to satisfy the constraints for a sliced output variable.
% Dummy data:
green_pic = rand(10,10,3);
background = rand(10,10,3);
threshold = 0.5;
% Very slightly modified code:
[m,n,p] = size(green_pic);
outPic = green_pic;
parfor i = 1:m
for k = 1:n
if green_pic(i,k,2) >= threshold;
% Make a single assignment into outPic so that
% it can be "sliced"
outPic(i,k,:) = background(i,k,:);
end
end
end
disp('Success!');
Success!
Of course, the vectorised way to do this is as follows:
% Dummy inputs
green_pic = rand(10,10,3);
background = rand(10,10,3);
threshold = 0.5;
[m,n,p] = size(green_pic);
% Starting point for outPic
outPic = green_pic;
% Find all locations where threshold is exceeded. exceedsThreshold will be
% m-by-n logical array.
exceedsThreshold = green_pic(:,:,2) > threshold;
% We want to copy all planes of "background" into "outPic", so we need
% to duplicate "exceedsThreshold" into the third dimension
exceedsThreshold = repmat(exceedsThreshold, 1, 1, p);
% Copy appropriate pieces of background
outPic(exceedsThreshold) = background(exceedsThreshold);
  2 Comments
Adnan Faek
Adnan Faek on 1 May 2021
Thank you very much!
However i was expecting a gain in comparison with the function that doesn't use parfor. Instead it takes longer to perform now(0.028239 seconds vs. 2.335178 seconds). I'll try to find a solution to this.
Edric Ellis
Edric Ellis on 4 May 2021
I'm not really surprised that parfor is slower than for in this case. There are overheads to running in parfor - specifically you have to transfer the data to different processes to operate on it, and then transfer it back. In this case, the work you're doing is much less time-consuming than the transfer. I suspect you will have more luck trying to use the vectorised approach.

Sign in to comment.

More Answers (0)

Community Treasure Hunt

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

Start Hunting!