1

Hi I have loaded an image, thus creating a 3D matrix.

img1 = imread('bluebird.jpg')

I know that for a vector, i can create another vector based on a logic test and use this other vector as index like this:

speeds = [20 77 55 90 87 65 67 72 55]
invalid = speed > 70
speeds(invalid) = 0

This will set all invalid speed in speeds to 0.

But I have not figured out how to do it with a 3D matrix (an image).

What I want to do is swap color components 1 (red) and 3 (blue) for every pixel where the blue component is at least 20% higher than the average of the three components (the gray scale).

I have tried this:

img1 = imread('bluebird.jpg');
img2 = img1;
m = mean(img1, 3);
blues = img1(:,:,3) > 1.2*m;
img2(blues, [3,2,1]) = img1(blues, [1,2,3]);

But that did not work. The variable blues successfully get the pixels I want (the ones with a dominant blue component), but I get a illegal syntax on the last line.

Is it possible to do what I want? If so, how?

Thanks in advance.

0

3 Answers 3

3

The issue is because your logical array is 2D (takes care of the first two dimensions) and your linear index is only applied to the third dimension. You can combine logical indices however you must have one array of either per-dimension.

data = magic(3);
data([true false, true], [1 3])

%   8   6
%   4   2

An easy way around this for your case is to reshape your input to an [M*N x 3] array and then you can do exactly what you want because your logical array will now be a column vector of length M*N.

img1 = imread('bluebird.jpg');

% Remember the original size
shape = size(img1);

% Reshape to (M*N x 3)
img2 = reshape(img1, [], 3);

isBlue = img2(:,3) > 1.2 * mean(img2, 2);
img2(isBlue, [3 2 1]) = img2(isBlue, [1 2 3]);

% Reshape it back to the original size
img2 = reshape(img2, shape);

Or rather than using indexing, you could simply call fliplr.

img1 = imread('bluebird.jpg');

% Remember the original size
shape = size(img1);

% Reshape to (M*N x 3)
img2 = reshape(img1, [], 3);

isBlue = img2(:,3) > 1.2 * mean(img2, 2);
img2(isBlue, :) = fliplr(img2(isBlue, :));

% Reshape it back to the original size
img2 = reshape(img2, shape);

This is going to be more performant than creating a 3D logical matrix because reshape commands are very cheap as they don't actually alter the underlying data.

Sign up to request clarification or add additional context in comments.

Comments

1

Logical indexing (using matrices) and indexing by integers cannot be mixed. Instead, you can construct full logical index matrices:

img2 = rand(2, 4, 3);
m = mean(img2, 3);
blues = img2(:,:,3) > 1.2*m;
f_ind = false(size(blues));
ind = cat(3, blues, f_ind, blues);
img2(ind) = cat(3, img2(cat(3, f_ind, f_ind, blues)), img2(cat(3, blues, f_ind, f_ind)));

Or, instead of the last two lines:

r_ind = cat(3, blues, f_ind, f_ind);
b_ind = cat(3, f_ind, f_ind, blues);
img2(b_ind) = img1(r_ind);
img2(r_ind) = img1(b_ind);

2 Comments

That first statement isn't actually true. You just can't combine logical matrices and integer-based indexing.
@Suever thanks for the clarification. And 'integer-based' is the correct term, too...
1

Use:

[Y,X] = find(blues);
inds1 = sub2ind(size(img1),Y,X,ones(length(Y),1));
inds2 = sub2ind(size(img1),Y,X,3*ones(length(Y),1));
img2([inds1,inds2]) = img1([inds2,inds1]);

2 Comments

Hi. I tried your code and the image displayed was identical to the original image.
Thanks for your comment, I fixed it (had a small typo)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.