1

I have this binary image in where each ‘curve' represents a hat from a pile of these objects. It was obtained by thresholding a region of the original image of stacked straw hats.

Binary Image

As you can see, these curves have many gaps and holes inside of its shapes, which dificults the use of a technique like cv.connectedcomponentes in order to obtain the amount of objects in the image, which is my goal.

I think if there was some technique to fill in these gaps and/or, mainly, the holes, in smaller parts of the original binary image, like the ones I'm showing bellow, maybe by connecting nearby elements or detecting and filling contours, would be possible to segment each curve as an individual element.

Smaller Region 1

Smaller Region 2

1 Answer 1

2

Not the most elegant way, but it should be simple enough.
Consider a vertical slice of with w (the same as the slices you posted in your question). If you sum the white pixels along the rows of the slice, you should get six nice "peaks" corresponding to the six rims of the hats:

enter image description here

However, since the rims are rounded, some vertical slices would be better than others for this sort of estimation.
Therefore, I suggest looking at all slices of width w and counting the peaks for each slice.
Here's a Matlab code that does this

img = imread('https://i.sstatic.net/69FfJ.jpg');  % read the image
bw = img(:,:,1)>128;  % convert to binary 

w = 75;  % width of slice
all_slices = imfilter(single(bw), ones(1,w)/w, 'symmetric')>.5;  % compute horizontal sum of all slices using filter
% a peak is a slice with more than 50% "white" pixels
peaks = diff( all_slices, 1, 1 ) > 0;  % detect the peaks using vertical diff
count_per_slice = sum( peaks, 1 );  % how many peaks each slice think it sees

Looking at the distribution of the count_per_slice:

enter image description here

You see that although many slices predict the wrong number of hats (between 4 to 9) the majority votes for the correct number 6:

num_hats = mode(count_per_slice);  % take the mode of the distribution.

A python code that does the same (assuming bw is a numpy array of shape (h,w) and of dtype bool):

from scipy import signal, stats
import numpy as np
w = 75;
all_slices = signal.convolve2d( bw.astype('f4'), np.ones((1,w),dtype='f4')/float(w), mode='same', boundary='symmetric')>0.5
peaks = np.diff( all_slices, n=1, axis=0 ) > 0
count_per_slice = peaks.sum( axis=0 )
num_hats = stats.mode( count_per_slice )
Sign up to request clarification or add additional context in comments.

3 Comments

To improve the stability you could first convolve (scipy.signal.convolve2d) the image with a small kernel (e.g. np.ones((n,n)), this will close the small gaps. This will first give you a array filled with integers, but you can convert it back into a boolean one with a right treshhold
@JürgMerlinSpaak indeed, playing with the filter shape and values may increas the robustness of the method. I only demonstrated here a minimal solution to be used as a baseline for further research and improvement
Thank you for the suggestions, guys! The approuch I'm using is similar to what you did, Shai. I'm slicing the binary image in many sections, like 250 to 300, then doing some enhancements (erosion, dilation and opening) in each one, and counting the white parts in all of them. My struggle in this method is to elimite some remaining holes inside of these white elementes in order to improve the accuracy of the couting (in a small section, one hole turns 1 hat into 2 by separating the white pixels), since, in fact, this image is just a region of the original one, that actuallly contains 85 hats.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.