-1

This question is kind of a follow-up to my 2 previous auestions: Python Image tutorial works, other images behaves differently (showing images with Pylab) and Detect objects on a white background in Python .

What I am trying to achieve is being able to programmatically count the number of individual objects on a white background. As seen in the other 2 posts I've been able to achieve this to some extent. At this moment I am able to count the number of objects when virtually no shadow is present on the image. The image I'm trying to analyse (bottom of this post) does have some shadows which causes objects to merge and be seen as one individual object.

I need some simple way of getting rid of the shadows, I already tried adaptive thresholding with scikit-image (http://scikit-image.org/docs/dev/auto_examples/plot_threshold_adaptive.html#example-plot-threshold-adaptive-py), but I stumbled upon some problems (https://imgur.com/uYnj6af). Is there any not too complicated way to get this to work? There's already a lot of code in my previous posts but please let me know if you want to see any additional code!

Thanks in advance.

enter image description here

Community
  • 1
  • 1
E. V. d. B.
  • 785
  • 1
  • 10
  • 29

1 Answers1

3

Perhaps it's easier to operate on a binary image. In the code below, I obtain such an image by computing the variance over a sliding window and thresholding it.

Binary threshold of variance map

from skimage import io, exposure, color, util
import matplotlib.pyplot as plt

image = color.rgb2gray(io.imread('tools.jpg'))

exposure.equalize_adapthist(image)
Z = util.view_as_windows(image, (5, 5))
Z = Z.reshape(Z.shape[0], Z.shape[1], -1)
variance_map = Z.var(axis=2)

plt.imshow(variance_map > 0.005, cmap='gray')
plt.savefig('tools_thresh.png')

plt.show()

Update:

enter image description here

This extended version of the code identifies the 8 tools.

from skimage import io, exposure, color, util, measure, morphology
from scipy import ndimage as ndi
import numpy as np
import matplotlib.pyplot as plt

image = color.rgb2gray(io.imread('tools.jpg'))

exposure.equalize_adapthist(image)
Z = util.view_as_windows(image, (5, 5))
Z = Z.reshape(Z.shape[0], Z.shape[1], -1)
variance_map = Z.var(axis=2)

tools_bw = variance_map > 0.005
tools_bw = morphology.binary_closing(tools_bw, np.ones((5, 5)))
tools_bw = ndi.binary_fill_holes(tools_bw)


labels = measure.label(tools_bw)
regions = measure.regionprops(labels)
regions = [r for r in regions if r.perimeter > 500 and r.major_axis_length > 200]

print(len(regions))

out = np.zeros_like(tools_bw, dtype=int)
for i, r in enumerate(regions):
    out[labels == r.label] = i + 1

plt.imshow(out, cmap='spectral')
plt.savefig('tools_identified.png', bbox_inches='tight')

plt.show()
Stefan van der Walt
  • 6,547
  • 1
  • 28
  • 34
  • It looks good because the sahdows are practically gone, but I think all the little white spots will be seen as seperate components and thus the count will not be right, will it? I'll try it out now though and report back – E. V. d. B. Jan 21 '15 at 13:36
  • As I suspected all the little parts are seen as objects and I get a count of 318 – E. V. d. B. Jan 21 '15 at 13:58
  • Well, of course--you'll have to do post-processing on the binary image to remove those. – Stefan van der Walt Jan 21 '15 at 17:02
  • Unfortunately my knowledge is too limited to be able to do that, never worked in Python before and never did anything to do with image analysis so it's all new to me, but thanks anyways for your help! – E. V. d. B. Jan 21 '15 at 18:37