# Use Parfor on a greenscreen picture

1 view (last 30 days)
Adnan Faek on 29 Apr 2021
Commented: Edric Ellis on 4 May 2021
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 ?
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.

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 CommentsShowHide 1 older comment
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.