Senyokbalgul
Senyokbalgul

Reputation: 1102

How to remove connected components from an image while retaining some

Let's say I have 5 connected components (labelled objects) in an image called labelledImage from bwlabel. How can I manipulate labelledImage so that the objects that are labelled as 1 and 4 only display, while removing the objects that are labelled as 2, 3 and 5. Then, how can I manipulate the original RGB image so that the connected components that are labelled as 1 and 4 only display.

I know how to retain a single connected component by using this line of code below. However, I don't know how to do this for multiple labelled regions.

Works.

connectedComponent1 = (labelledImage == 1);
imshow(connectedComponent1)

Doesn't work.

connectedComponent1and4 = (labelledImage == [1 4]);
imshow(connectedComponent1and4)

Upvotes: 1

Views: 681

Answers (2)

rayryeng
rayryeng

Reputation: 104493

You can't do logical indexing that way. The simplest way is to perhaps use Boolean statements to combine things.

connectedCompoonent1and4 = labelledImage == 1 | labelledImage == 4;

In general, supposing you had a vector of elements that denote which components you want to keep, you could use bsxfun, permute and any to help you with that. Something like this should work:

components = [1 4];
connected = any(bsxfun(@eq, labelledImage, permute(components, [1 3 2])), 3);

The above code uses matrix broadcasting to create a temporary 3D matrix where each slice i contains the ith value of the vector components which contain the desired labels you want to keep. labelledImage is also replicated in the third dimension so the result using bsxfun creates a 3D matrix where each slice i segments out the ith object you want to keep. We then combine all of the objects together using any and looking in the third dimension.

If you don't like one-liners, you could even use a simple for loop:

components = [1 4];
connected = false(size(labelledImage, 1), size(labelledImage, 2));
for ind = 1 : numel(components)
    connected = connected | labelledImage == components(ind);
end

This creates an output image that is all false, then we loop through each value in the vector of components you want to keep and append those results on top of the result. The end will give you all of the components you want to keep.

Lastly, you could use also use ismember and determine those values in your matrix that can be found between the label matrix and the components vector and simply create your mask that way:

connected = ismember(labelledImage, components);

Now that you have a mask of objects you want to extract out, to use this on the original image, simply multiply each channel with the mask. Another use of bsxfun can do that for you. Assuming your image in RGB is called img, simply do the following:

outImg = bsxfun(@times, img, cast(connected, class(img)));

To perform element-wise multiplication, you must ensure that both matrices that are being multiplied have the same type. I convert the mask into the same class as whatever the input image is and perform the multiplication.

Upvotes: 1

user2261062
user2261062

Reputation:

Use ismember.

Ex:

A = randi(5,5);  % your connected component matrix
B = [1 4]        % list of components you want to keep

A =

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


A(~ismember(A,B)) = 0

A =

     4     0     1     0     0
     0     4     0     0     1
     0     4     0     1     4
     1     4     1     0     0
     4     0     0     1     0

Upvotes: 1

Related Questions