簡體   English   中英

如何改進 Python 中異質結構的分水嶺分割?

[英]How can I improve Watershed segmentation of heterogenous structures in Python?

我正在使用 Python 中的分水嶺算法對細胞(顯微圖像)進行簡單分割。90% 的情況下我對結果感到滿意,但我有兩個主要問題:(i) 標記/輪廓確實“尖峰”和 (2) 當兩個單元格彼此靠近(即它們被分割在一起)時,算法有時會失敗。 你能給出一些改進的建議嗎?

這是我正在使用的代碼和顯示我的 2 個問題的 output 圖像。

# Adjustable parameters for a future function
img_file = NP_file
sigma = 9 # size of gaussian blur kernel; has to be an even number
alpha = 0.2 #scalling factor distance transform
clear_border = False
remove_small_objects = True

# read image and covert to gray scale 
im = cv2.imread(NP_file, 1)
im = enhanceContrast(im)
im_gray = cv2.cvtColor(im.copy(), cv2.COLOR_BGR2GRAY)

# Basic Median Filter
im_blur = cv2.medianBlur(im_gray, ksize = sigma)

# Threshold Image
th, im_seg = cv2.threshold(im_blur, im_blur.mean(), 255, cv2.THRESH_BINARY);

# filling holes in the segmented image
im_filled = binary_fill_holes(im_seg)

# discard cells touching the border
if clear_border == True: 
    im_filled = skimage.segmentation.clear_border(im_filled)

# filter small particles
if remove_small_objects == True: 
    im_filled = sk.morphology.remove_small_objects(im_filled, min_size = 5000)

# apply distance transform
# labels each pixel of the image with the distance to the nearest obstacle pixel.
# In this case, obstacle pixel is a boundary pixel in a binary image.

dist_transform = cv2.distanceTransform(img_as_ubyte(im_filled), cv2.DIST_L2, 3)

# get sure foreground area: region near to center of object
fg_val, sure_fg = cv2.threshold(dist_transform, alpha * dist_transform.max(), 255, 0)

# get sure background area: region much away from the object
sure_bg = cv2.dilate(img_as_ubyte(im_filled), np.ones((3,3),np.uint8), iterations = 6)
    
# The remaining regions (borders) are those which we don’t know if they are img or background
borders = cv2.subtract(sure_bg, np.uint8(sure_fg))

# use Connected Components labelling: 
# scans an image and groups its pixels into components based on pixel connectivity
# label background of the image with 0 and other objects with integers starting from 1.

n_markers, markers1 = cv2.connectedComponents(np.uint8(sure_fg))

# filter small particles again! (bc of segmentation artifacts)
if remove_small_objects == True: 
    markers1 = sk.morphology.remove_small_objects(markers1, min_size = 1000)
    
# Make sure the background is 1 and not 0; 
# and that borders are marked as 0
markers2 = markers1 + 1
markers2[borders == 255] = 0

# implement the watershed algorithm: connects markers with original image
# The label image will be modified and the marker in the border area will change to -1
im_out = im.copy()
markers3 = cv2.watershed(im_out, markers2)

# generate an extra image with color labels only for visuzalization
# color markers in BLUE (pixels = -1 after watershed algorithm)
im_out[markers3 == -1] = [0, 255, 255]

在此處輸入圖像描述

如果您想嘗試重現我的結果,您可以在此處找到 my.tif 文件: https://drive.google.com/file/d/13KfyUVyHodtEOP_yKAnfFCAhgyoY0BQL/view?usp=sharing

謝謝!

過去,我應用分水嶺算法的最佳方法是“僅在需要時”。 它是計算密集型的,圖像中的大多數細胞都不需要。 這是我在您的圖片中使用的代碼:

# Threshold your image
# This example worked very well with a threshold value of 1
tv, thresh = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 1, 255, cv2.THRESH_BINARY)

# Minimize the holes in the cells to facilitate finding contours
for i in range(5):
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, np.ones((3,3)))
    thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, np.ones((3,3)))

閾值圖像

# Find contours and keep the ones big enough to be a cell
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = [c for c in contours if cv2.contourArea(c) > 400]
output = np.zeros_like(thresh)
cv2.drawContours(output, contours, -1, 255, -1)
for i, contour in enumerate(contours):
    x, y, w, h = cv2.boundingRect(contour)
    cv2.putText(output, f"{i}", (x, y), cv2.FONT_HERSHEY_PLAIN, 1, 255, 2)

這段代碼的output就是這張圖: 找到輪廓 如您所見,只有一對單元格(輪廓#7)需要使用分水嶺算法進行拆分。 在該單元格上運行分水嶺算法非常快(可以使用較小的圖像),結果如下:

使用分水嶺算法拆分單元格

編輯一些可用於評估分水嶺算法是否應在圖像中的 object 上運行的細胞形態計算:

# area
area = cv2.contourArea(contour)
# perimeter, with the minimum value = 0.01 to avoid division by zero in other calculations
perimeter = max(0.01, cv2.arcLength(contour, True))
# circularity
circularity = (4 * math.pi * area) / (perimeter ** 2)
# Check if the cell is convex (not smoothly elliptical)
hull = cv2.convexHull(contour)
convexity = cv2.arcLength(hull, True) / perimeter
approx = cv2.approxPolyDP(contour, 0.1 * perimeter, True)
convex = cv2.isContourConvex(approx)

您需要找到項目中每個測量的閾值。 在我的項目中,細胞是橢圓形的,有一個大面積凸起的斑點通常意味着有 2 個或更多細胞聚集在一起。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM