Ask Your Question
0

How to get stats from image segmented with watershed?

asked 2019-05-16 08:55:03 -0600

updated 2019-05-16 09:50:01 -0600

berak gravatar image

It appears that connectedComponents does not separate components that are divided by a single pixel dividing line.

This is an issue when trying to obtain region stats from an image segmented with the watershed method (ultimately I want to use connectedComponentsWithStats). Since connectedComponents does not handle already labeled images, I binarize the image by setting the background and dividing lines as 0 and the labeled regions as 255. The resulting binary image (segmented_bin) has regions separated by a single-pixel-wide line.

CoinsSegmented

Running connectedComponents on this image returns only 2 regions: the background and an aggregate of the foreground regions.

Steps to reproduce

Here is a sample code to reproduce the issue

import cv2

[...] # Prepare markers as in https://docs.opencv.org/3.4/d3/db4/tutorial_py_watershed.html

segmented = cv2.watershed(img,markers)

segmented_bin = segmented.copy()
segmented_bin[segmented < 2] = 0 # -1 is dividing regions, no 0s, 1 is background
segmented_bin[segmented > 1] = 255 # all above 1 are distinct regions
num_labels, label_image = cv2.connectedComponents(segmented_bin.astype('uint8'), 8, cv2.CV_16U, cv2.CCL_GRANA)

Executing this code returns num_labels = 2 instead of 27.

edit retag flag offensive close merge delete

Comments

did you try num_labels, label_image = cv2.connectedComponents(segmented_bin.astype('uint8'), 4, cv2.CV_16U, cv2.CCL_GRANA)

sturkmen gravatar imagesturkmen ( 2019-05-16 10:12:09 -0600 )edit

Indeed I tried both 4 and 8-way connectivity and also tried all 3 algorithms offered: wu, default, and grana

hlgirard gravatar imagehlgirard ( 2019-05-16 10:18:44 -0600 )edit

Would this help? I opened the above image as mono, did one iteration of erosion with 3x3 Rect kernel, did a threshold at 200. Then findContours was able to find 24 different shapes:

15:30:37: contour 0: ctr<177.58 288.50> area(1464.50) aspectratio(0.98)

15:30:37: contour 1: ctr<130.71 287.16> area(1479.00) aspectratio(1.00)

15:30:37: contour 2: ctr<49.81 273.77> area(1549.50) aspectratio(1.02)

15:30:37: contour 3: ctr<91.87 260.40> area(1449.50) aspectratio(1.00)

15:30:37: contour 4: ctr<175.53 241.93> area(1278.50) aspectratio(0.95) ...

15:30:37: contour 22: ctr<134.28 52.93> area(1462.00) aspectratio(1.02)

15:30:37: contour 23: ctr<63.94 37.95> area(1497.00) aspectratio(0.98)

Chris gravatar imageChris ( 2019-05-16 14:36:19 -0600 )edit

That definitely works to solve the problem. However, it adds an erosion step which modifies the boundaries found by the watershed algorithm. I would like to understand why connectedComponents does not give the correct answer.

hlgirard gravatar imagehlgirard ( 2019-05-21 15:33:48 -0600 )edit

After finding all the contours, if you take each one alone and dilate it with the same kernel, you should get a boundary very close to the original.

Chris gravatar imageChris ( 2019-05-24 14:18:00 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2019-05-24 14:37:19 -0600

Agreed thank you for the suggestion. I ended up going with skimage.regionprops for my application since I had already imported scikit-image in the package and it ends up being pretty fast.

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2019-05-16 08:55:03 -0600

Seen: 900 times

Last updated: May 16 '19