Image segmentation problem, need help
Show older comments
Hi Guys! I'm having a big trouble to solve this one. I have an RGB image with various signs. My main goal is to count the signs that are in contact with the image borders. I started by loading the image[Fig. 1], then converted it to grayscale and applied a median filter to get rid of some noise[Fig. 2]. Then I've binarized it with a threshold of 0.2, which resulted in Figure 3. At this time i got my binarized image, but the problem is that some parts that belong to the same sign are appearing in various regions, insthead of only one. Now my goal is to merge the regions that belong to the same object , so then I could use 'Bwlabel' to count how many signs are in the image, and use 'imclearborder' to get rid of the ones in the border, and use bwlabel again to get the diference between the two.
My aproach was to use 'bwmorph, 'Dilate' to dilate the objects and then try to fill them with 'imfill, 'holes'. But the problem is that if I dilate them in a small amount[Fig. 4], the 'imfill' doesnt seem to fill them, if I dilate them by a big amount[Fig 5] all the objects start to merge =(
Fig 1: http://dl.dropbox.com/u/5272012/1.png Fig 2: http://dl.dropbox.com/u/5272012/2.png Fig 3: http://dl.dropbox.com/u/5272012/3.png Fig 4: http://dl.dropbox.com/u/5272012/4.png Fig 5: http://dl.dropbox.com/u/5272012/5.png
Anyone have a sugestion to solve this one? There is a simpler way to do this? Any suggestions will be much appreciated!
img=im2double(imread('image.png')); figure, imshow(img)
img_gray=rgb2gray(img); imshow(img_gray);
img_mediana=medfilt2(img_gray, [3 3]); figure, imshow(img_mediana);
img_bin=im2bw(img_mediana, 0.2); imshow(img_bin)
img_dilate=bwmorph(img_bin, 'Dilate', 10); imshow(img_dilate)
img_fill=imfill(img_dilate, 'Holes'); figure, imshow(img_fill)
Answers (2)
Image Analyst
on 16 May 2012
0 votes
You might use imclose() to close up small gaps in the boundaries, but then it will join some signs that are close together. So then you fill the blobs (now that their boundaries are sealed) and then use watershed to split them apart again.
Geoff
on 16 May 2012
0 votes
That's a cool problem. I would tend towards a solution that involved filling the 'empty' region from your thresholded 3rd image with white, and then (starting from a white pixel) counting the number of contiguous black regions you get around the edge.
The only issue you'll have with this is that sign on the left that has its white border eaten away by the thresholding, and the recycle sign.
So you need a final filtering step that examines each detected 'edge' blob and either tries to determine whether to merge it with adjacent blobs or discards it based on some heuristics that could involve size, shape, closeness, overlap, colour, or any combination. But it looks to me like a simple locality tolerance of 10 pixels would be sufficient.
6 Comments
Geoff
on 16 May 2012
Just to clarify what I mean in that first paragraph... You want an image where all the pixels that would be filled are white, and the rest are black (or the other way round). You'll need to detect an appropriate point to fill at. To do that I would simply 'walk' along one edge (binary subdivision-style) and attempt to fill. Then stop as soon as some proportion of all available pixels were filled and use that particular image. You could detect this proportion as being at least half the number of total white pixels in your thresholded image.
Rui
on 16 May 2012
Geoff
on 16 May 2012
Um, okay. It's simpler than what you're doing now....
Start by testing proof of concept before getting complicated:
1) Threshold your image to get the result in your #3.
2) Turn your 2-colour image into a 3-colour image. That is: convert to uint8 (it will actually be 255-colour but we only need 3).
3) Find the longest continuous stretch of black along all edges, then choose a pixel from that stretch to do an imfill() with the value 2.
4) Now extract the image where all values are 2 (you could just set all pixels that are 1 to 0). You now have a background silhouette image where 0 is a sign, and non-zero is background.
5) Start again at the point you selected in (3) and extract the entire border of your image into a vector.
6) Count how many 'solid' non-zero regions exist in that vector, where 'solid' is based on a tolerance of up to 10 zero pixels between non-zero pixels.
I think this should work fine, and ought not to be conceptually difficult. =)
Geoff
on 16 May 2012
Sorry I mixed up 'zero' and 'non-zero' in step 6. You want to count the 'sign' regions, which are zero, allowing up to 10 non-zero pixels in a row before a new region is counted as a different sign.
Rui
on 16 May 2012
Geoff
on 16 May 2012
Why do any processing that requires more complicated algorithms to be useful? Don't you want to apply a series of filters that simplify the problem, rather than shifting the problem elsewhere? By flood-filling the background, you clean up just about all the image noise that is going on inside the signs. Then it's just a matter of working out whether two individual blobs belong to the same sign. I don't see how making your blobs less distinct will help you here.
Categories
Find more on Color Segmentation in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!