3

I'm trying the following to get the mask out of this image, but unfortunately I fail.

import numpy as np import skimage.color import skimage.filters import skimage.io # get filename, sigma, and threshold value from command line filename = 'pathToImage' # read and display the original image image = skimage.io.imread(fname=filename) skimage.io.imshow(image) # blur and grayscale before thresholding blur = skimage.color.rgb2gray(image) blur = skimage.filters.gaussian(blur, sigma=2) # perform inverse binary thresholding mask = blur < 0.8 # use the mask to select the "interesting" part of the image sel = np.ones_like(image) sel[mask] = image[mask] # display the result skimage.io.imshow(sel) 

How can I obtain the mask?

enter image description here enter image description here

Is there a general approach that would work for this image as well. without custom fine-tuning and changing parameters? enter image description here

1
  • A possible approach is load image, convert to grayscale, Gaussian blur, threshold to obtain a binary image, morph open to remove small noise, find contours, and sort from largest to smallest contour area, the largest contour should be your desired object. Then simply draw this contour with white onto a black mask image to get your result Commented Sep 20, 2021 at 23:16

3 Answers 3

1
  1. Apply high contrast (maximum possible value)

s1

  1. convert to black & white image using high threshold (I've used 250)

s2

  1. min filter (value=8)

s3

  1. max filter (value=8)

s4

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

5 Comments

Is there a general approach that would work also for the other image (please see edit) without manually modifying parameters ?
if the object colors matches the background you will need different approach. why don't you put all the odd cases you want this to work correctly with, and then I will try to give you a general approach.
I think that all of my cases fall into these two categories.
Why don't you want to use OpenCV ?
My app cannot support it given the flow already inplace
1

Here is how you can get a rough mask using only the skimage library methods:

import numpy as np from skimage.io import imread, imsave from skimage.feature import canny from skimage.color import rgb2gray from skimage.filters import gaussian from skimage.morphology import dilation, erosion, selem from skimage.measure import find_contours from skimage.draw import polygon def get_mask(img): kernel = selem.rectangle(7, 6) dilate = dilation(canny(rgb2gray(img), 0), kernel) dilate = dilation(dilate, kernel) dilate = dilation(dilate, kernel) erode = erosion(dilate, kernel) mask = np.zeros_like(erode) rr, cc = polygon(*find_contours(erode)[0].T) mask[rr, cc] = 1 return gaussian(mask, 7) > 0.74 def save_img_masked(file): img = imread(file)[..., :3] mask = get_mask(img) result = np.zeros_like(img) result[mask] = img[mask] imsave("masked_" + file, result) save_img_masked('belt.png') save_img_masked('bottle.jpg') 

Resulting masked_belt.png:

enter image description here

Resulting masked_bottle.jpg:

enter image description here

Comments

0

One approach uses the fact that the background changes color only very slowly. Here I apply the gradient magnitude to each of the channels and compute the norm of the result, giving me an image highlighting the quicker changes in color. The watershed of this (with sufficient tolerance) should have one or more regions covering the background and touching the image edge. After identifying those regions, and doing a bit of cleanup we get these results (red line is the edge of the mask, overlaid on the input image):

case 1 output

case 2 output

I did have to adjust the tolerance, with a lower tolerance in the first case, more of the shadow is seen as object. I think it should be possible to find a way to set the tolerance based on the statistics of the gradient image, I have not tried.

There are no other parameters to tweak here, the minimum object area, 300, is quite safe; an alternative would be to keep only the one largest object.

This is the code, using DIPlib (disclaimer: I'm an author). out is the mask image, not the outline as displayed above.

import diplib as dip import numpy as np # Case 1: img = dip.ImageRead('Pa9DO.png') img = img[362:915, 45:877] # cut out actual image img = img(slice(0,2)) # remove alpha channel tol = 7 # Case 2: #img = dip.ImageRead('jTnVr.jpg') #tol = 1 # Compute gradient gm = dip.Norm(dip.GradientMagnitude(img)) # Compute watershed with tolerance lab = dip.Watershed(gm, connectivity=1, maxDepth=tol, flags={'correct','labels'}) # Identify regions touching the image edge ll = np.unique(np.concatenate(( np.unique(lab[:,0]), np.unique(lab[:,-1]), np.unique(lab[0,:]), np.unique(lab[-1,:])))) # Remove regions touching the image edge out = dip.Image(lab.Sizes(), dt='BIN') out.Fill(1) for l in ll: if l != 0: # label zero is for the watershed lines out = out - (lab == l) # Remove watershed lines out = dip.Opening(out, dip.SE(3, 'rectangular')) # Remove small regions out = dip.AreaOpening(out, filterSize=300) # Display dip.Overlay(img, dip.Dilation(out, 3) - out).Show() 

14 Comments

Hi Cris, is it necessary to cut the actual image? I would like to avoid that if possible
@azal That line is necessary because you posted a screen shot of the image displayed with Matplotlib, with a border and axes around it. It is cutting off these axes and border. I’m pretty sure that the image you posted is not the one you are actually processing. This was my way of approximating the actual image you need to process. You should leave that out.
could you elaborate/show a way to calc the tolerance if possible?
@azal I haven't had time to think about that yet. The shadow in that first image is quite sharp, it'll be hard to know if it's a sharp shadow or a product. I think a 2nd order derivative might be meaningful, but I would need to give that some thought to give a concrete idea.
was not able to install the library via pip install diplib
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.