Lum Ramabaja
Lum Ramabaja

Reputation: 326

Filling "holes" of an image in python with cv2 not working

I am trying to fill the "holes" of red blood cells in an image after performing binary threshold. Almost all red blood cells have a black center when inverting the binary threshold. I want to remove them.

Example image:

Example image


This is my code:

import cv2 
from PIL import Image
import numpy as np
from scipy import ndimage
from skimage.feature import peak_local_max
from skimage.morphology import watershed

image = cv2.imread("blood_cells.jpg")

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
darker = cv2.equalizeHist(gray)
ret,thresh = cv2.threshold(darker,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
newimg = cv2.bitwise_not(thresh)

im2, contours, hierarchy = cv2.findContours(newimg,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
    cv2.drawContours(newimg,[cnt],0,255,-1)

And it worked. I filled the holes using findContours() and drawContours().

but when I try to compute the euclidean distance, for applying the watershed algorithm, I get only 52 unique segments, however there should be more. Here is the code, if it might be helpful:

D = ndimage.distance_transform_edt(newimg)
localMax = peak_local_max(D, indices=False, min_distance=20, labels=thresh)
markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) - 1))

I tried to segment each cell, but the results were quite off. Only the inside of the cells that had "holes" got segmented.

First image shows my result, second shows how it should roughly look like:

First image shows my result, second shows how it should roughly look like.

I then filled the holes manually, just to see if my code for segmentation works - and it works. The error should be somewhere between the part where I drew the contours, and the part where I calculated the euclidean distance.. Could anybody explain to me what could be wrong? I am clueless.

Upvotes: 5

Views: 8009

Answers (1)

Dan Mašek
Dan Mašek

Reputation: 19041

Your problem lies in the following line:

labels = watershed(-D, markers, mask=thresh)

You're passing as mask an inverted, uncorrected result from thresholding:

Bad mask

Giving you this bad segmentation:

bad result

Whereas you should be passing the corrected, filled in mask:

labels = watershed(-D, markers, mask=newimg)

Good mask

Giving you the result you probably expect:

good result

Upvotes: 6

Related Questions