How to get stats from image segmented with watershed?
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.
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.
did you try
num_labels, label_image = cv2.connectedComponents(segmented_bin.astype('uint8'), 4, cv2.CV_16U, cv2.CCL_GRANA)
Indeed I tried both 4 and 8-way connectivity and also tried all 3 algorithms offered: wu, default, and grana
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)
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.
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.