0

我最初的任务是从放大 40 倍的全玻片扫描的裁剪区域执行细胞核分割。许多原子核是接触的,有些可能是重叠的。我开始使用具有公平结果的分水岭算法。我现在想做的是完全消除与其他轮廓共享边界的任何轮廓。本质上,我感兴趣的只是完全隔离的轮廓。我知道这违背了分水岭算法的目的,但我很好奇这将如何执行。这是我正在使用的代码。其中大部分内容是从 pyimagesearch文章中借来的。

# USAGE
# python watershed.py --image images/coins_01.png

import argparse

import cv2
import numpy as np
import tifffile as tiff
from scipy import ndimage
# import the necessary packages
from skimage.feature import peak_local_max
from skimage.morphology import watershed

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
                help="path to input image")
ap.add_argument("-m", "--min_distance", required=False, default=10, nargs="?", type=int,
                help="minimum distance used for distance transformation")
args = vars(ap.parse_args())

# load the image and perform pyramid mean shift filtering
# to aid the thresholding step
filename = args["image"]
minimum_distance = args["min_distance"]
print("minimum distance is " + str(minimum_distance))
if filename.lower().endswith('.tif'):
    image = tiff.imread(filename)
    image = np.uint8(image)
    image *= 1 / 256
else:
    image = cv2.imread(args["image"])
shifted = cv2.pyrMeanShiftFiltering(image, 21, 51)
cv2.imshow("Input", image)

# convert the mean shift image to grayscale, then apply
# Otsu's thresholding
gray = cv2.cvtColor(shifted, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
                       cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)

# compute the exact Euclidean distance from every binary
# pixel to the nearest zero pixel, then find peaks in this
# distance map
D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=minimum_distance,
                          labels=thresh)

# perform a connected component analysis on the local peaks,
# using 8-connectivity, then apply the Watershed algorithm
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))

# loop over the unique labels returned by the Watershed
# algorithm
for label in np.unique(labels):
    # if the label is zero, we are examining the 'background'
    # so simply ignore it
    if label == 0:
        continue

    # otherwise, allocate memory for the label region and draw
    # it on the mask
    mask = np.zeros(gray.shape, dtype="uint8")
    mask[labels == label] = 255

    # detect contours in the mask and grab the largest one
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
                            cv2.CHAIN_APPROX_SIMPLE)[-2]
    for idx, c in enumerate(cnts):
        # compute the center of the contour
        M = cv2.moments(c)
        area = cv2.contourArea(c)
        equi_diameter = np.sqrt(4 * area / np.pi)
        arc_length = cv2.arcLength(c, closed=1)
        perimeter_over_diameter = arc_length / equi_diameter
        ellipse = cv2.fitEllipse(c)
        center, axes, orientation = ellipse
        major_axis_length = max(axes)
        minor_axis_length = min(axes)
        eccentricity = np.sqrt(1 - (minor_axis_length / major_axis_length) ** 2)

        if 500 <= area <= 2000 and perimeter_over_diameter > 3.6 and eccentricity < 0.9:

            if M["m00"] == 0:
                M["m00"] = 1

            cX = int(M["m10"] / M["m00"])
            cY = int(M["m01"] / M["m00"])

            # draw the contour and center of the shape on the image
            cv2.drawContours(image, [c], -1, (255, 0, 0), 2)
            cv2.circle(image, (cX, cY), 3, (255, 255, 255), 1)

# show the output image
cv2.imwrite("dapi_segmented.png", image)
cv2.namedWindow("Output", cv2.WINDOW_NORMAL)
cv2.imshow("Output", image)
cv2.waitKey(0)

换句话说,我只希望返回红色的轮廓圆圈:

孤立的核图像

4

1 回答 1

0

一个不太聪明的解决方案是用蓝色填充每个中心的填充,然后运行连接的组件标签。现在,对于每个中心,将其所在的连接组件标记为已访问,如果中心位于已访问组件中,则将其标记为remove。仅保留已访问且未删除的连接组件。

我相信你可以做得比这更好,但作为一种快速而肮脏的策略,它应该有效。

于 2017-09-28T20:25:19.923 回答