Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matching values from a matrix in a 3-D array

I am trying to match RGB values in an image.

         % R  G   B
RGBset = [ 3  9  12;
           4  8  13;
          11 13  13;
           8  3   2]

img(:,:,1) = [1   2   3
              6   5   4
              7   9   8
             10  11  12];

img(:,:,2) = [3  4  8;
              6  7  8;
             11 10  9;
             12 13 14];

img(:,:,3)= [3  7  2;
             4  9 10;
             5 11 12;
             6 13 14]

In this image, only one RGB value matches from the RGBset which is [11,13,13], so the expected output is:

[0  0  0;
 0  0  0;
 0  0  0;
 0  1  0]; % reshape(img(4,2,:),1,3) = [11, 13 13] is available in RGBset
           % no other RGB value is present in the image

I have made this code but it is very slow for larger images.

matched= zeros(img(:,:,1));
for r=1:size(img(:,:,1),1)
    for c=1:size(img(:,:,2),2)
     matched(r,c)=ismember(reshape(img(r,c,:),1,3),RGBset,'rows');
    end
end

What will be the solution with more speed?

like image 937
Likeunknown Avatar asked Jan 29 '23 17:01

Likeunknown


2 Answers

We can reduce each RGB triplet into a scalar each and we will do this for both RGBset and img. This would reduce them to 2D and 1D matrices respectively. We are calling this as dimensionality-reduction. With this reduced data, we are achieving memory efficiency and that hopefully should lead to performance boost.

Thus, a solution with those bases covered would look something like this -

% Scaling array for dim reduction
s = [256^2, 256, 1].';

% Reduce dims for RGBset and img
RGBset1D = RGBset*s;
img1D = reshape(img,[],3)*s;

% Finally use find membership and reshape to 2D
out = reshape(ismember(img1D, RGBset1D), size(img,1), []);

Benchmarking for the vectorized solutions

Benchmarking code -

         % R  G   B
RGBset = [ 3  9  12;
           4  8  13;
          11 13  13;
           8  3   2]

% Setup inputs
img = randi(255, 2000, 2000, 3);
img(3,2,:) = RGBset(4,:);

% Luis's soln
disp('--------------------- Reshape + Permute ------------------')
tic
img2 = reshape(permute(img, [3 1 2]), 3, []).';
matched = ismember(img2, RGBset, 'rows');
matched = reshape(matched, size(img,1), []);
toc

% Proposed in this post
disp('--------------------- Dim reduction ------------------')
tic
s = [256^2, 256, 1].';
RGBset1D = RGBset*s;
img1D = reshape(img,[],3)*s;
out = reshape(ismember(img1D, RGBset1D), size(img,1), []);
toc

Benchmarking output -

--------------------- Reshape + Permute ------------------
Elapsed time is 3.101870 seconds.
--------------------- Dim reduction ------------------
Elapsed time is 0.031589 seconds.
like image 99
Divakar Avatar answered Feb 05 '23 19:02

Divakar


You can replace the loops by permute and reshape:

img2 = reshape(permute(img, [3 1 2]), 3, []).';
matched = ismember(img2, RGBset, 'rows');
matched = reshape(matched, size(img,1), []);

This creates a 3-column matrix img2 in which each row corresponds to one pixel from img. That way ismember(..., 'rows') can be applied in a vectorized manner. The obtained result is then reshaped as needed.

like image 24
Luis Mendo Avatar answered Feb 05 '23 18:02

Luis Mendo