Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace multiple pixels value in an image with a certain value Matlab

I have an image 640x480 img, and I want to replace pixels having values not in this list or array x=[1, 2, 3, 4, 5] with a certain value 10, so that any pixel in img which doesn't have the any of the values in x will be replaced with 10. I already know how to replace only one value using img(img~=1)=10 or multiple values using this img(img~=1 & img~=2 & img~=3 & img~=4 & img~=5)=10 but I when I tried this img(img~=x)=10 it gave an error saying Matrix dimensions must agree. So if anyone could please advise.

like image 733
Tak Avatar asked Mar 17 '23 17:03

Tak


1 Answers

You can achieve this very easily with a combination of permute and bsxfun. We can create a 3D column vector that consists of the elements of [1,2,3,4,5], then use bsxfun with the not equals method (@ne) on your image (assuming grayscale) so that we thus create a 3D matrix of 5 slices. Each slice would tell you whether the locations in the image do not match an element in x. The first slice would give you the locations that don't match x = 1, the second slice would give you the locations that don't match x = 2, and so on.

Once you finish this, we can use an all call operating on the third dimension to consolidate the pixel locations that are not equal to all of 1, 2, 3, 4 or 5. The last step would be to take this logical map, which that tells you the locations that are none of 1, 2, 3, 4, or 5 and we'd set those locations to 10.

One thing we need to consider is that the image type and the vector x must be the same type. We can ensure this by casting the vector to be the same class as img.

As such, do something like this:

x = permute([1 2 3 4 5], [3 1 2]);
vals = bsxfun(@ne, img, cast(x, class(img)));
ind = all(vals, 3);
img(ind) = 10;

The advantage of the above method is that the list you want to use to check for the elements can be whatever you want. It prevents having messy logical indexing syntax, like img(img ~= 1 & img ~= 2 & ....). All you have to do is change the input list at the beginning line of the code, and bsxfun, permute and any should do the work for you.

Here's an example 5 x 5 image:

>> rng(123123);
>> img = randi(7, 5, 5)

img =

     3     4     3     6     5
     7     2     6     5     1
     3     1     6     1     7
     6     4     4     3     3
     6     2     4     1     3

By using the code above, the output we get is:

img =

     3     4     3    10     5
    10     2    10     5     1
     3     1    10     1    10
    10     4     4     3     3
    10     2     4     1     3

You can most certainly see that those elements that are neither 1, 2, 3, 4 or 5 get set to 10.

Aside

If you don't like the permute and bsxfun approach, one way would be to have a for loop and with an initially all true array, keep logical ANDing the final result with a logical map that consists of those locations which are not equal to each value in x. In the end, we will have a logical map where true are those locations that are neither equal to 1, 2, 3, 4 or 5.

Therefore, do something like this:

ind = true(size(img));
for idx = 1 : 5
    ind = ind & img ~= idx;
end
img(ind) = 10;

If you do this instead, you'll see that we get the same answer.

like image 112
rayryeng Avatar answered Apr 06 '23 21:04

rayryeng