Physicist
Physicist

Reputation: 3048

how to mask the outline of an object in python

How to mask the object in an image, e.g. by outlining the shape of the object or store the array's index of all the pixels that are part of the object? Since I will do other further processing only in the regions with the object, I want to 'get rid of' / ignore the background and only focus on the object itself.

The two images (the objects are a metal ball and a light-scattering ball) are similar to what I will be working on. I will try to improve the contrast between the object and the background, and work on the supporting 'stand' that holds the object when I take any more images, but for the images given here, are there any ways to mask the object?

Originally, I wanted to threshold the image so that pixels that are 'brighter' than than a certain value will be kept, then use numpy.nonzero(threshold_image) to find out all the index of the pixels that are parts of the image. However, I find that it doesn't work well for such 'noisy' image.

thanks

metal ball scattering ball

Upvotes: 1

Views: 2743

Answers (2)

vzaguskin
vzaguskin

Reputation: 310

You can start with tresholding each of the color channels(r,g,b) of the input image. The object in the lower image should be separable in the green channel and for the top pictures even just the brightness could do good initial job.

The second step would be labeling connected components in the mask, perhaps using the function in the link above.

Finally, you can select the best component by size/shape.

If all your objects are circles, you can start with detecting them by shape - that would mean doing edge detection and then Hough Transfrom

Upvotes: 2

Jiby
Jiby

Reputation: 1885

Storing masks for arrays can theoretically be done with Numpy's masked arrays, but I wouldn't recommend it (performance-wise it's quite slow, I'll edit my post with timings later)

The most Pythonic way (thus coolest) is just storing a plain bool array of same size as image, and using the * operator to combine it (because numbers multiplied by False becomes 0, with the notable exception of NaN

# creates an array of bool of same shape as image
maskAboveThreshold = image > 30 

# Show a 'cropped' version on the image
from matplotlib import pyplot as plt
plt.imshow(image * maskAboveThreshold, cmap='gray')

Note that I assumed here that image is a 2D image in grayscale, but as long as your mask shape is identical to the image, it works in any dimension.

As for the separation of image, I don't know how familiar you are with Image Processing techniques, but in general, in the cases where you find noise to be bothersome, blurring your image a little before anything else is usually effective, as the implied averaging over small area means the noise (spikes) are smoothed.

Sidenote on iterating over ndarrays : you might not want to iterate over the np.nonzero() output, as the pixel positions it will give you might be unsorted, meaning you will end up accessing random places in the image instead of accessing contiguous (following each other) addresses, which is a common "memory access worst case" slowing execution down.

For binary image manipulation like removing small isolated group of pixels in the mask, do take a look at Binary Morphology

Upvotes: 3

Related Questions