2017-09-28 4 views
0

Meine anfängliche Aufgabe war die Segmentierung von Kernen aus einem beschnittenen Bereich eines 40-fachen Vergrößerungs-Slidescan. Viele Kerne berühren sich, manche überlappen sich potentiell. Ich begann mit dem Watershed-Algorithmus mit fairen Ergebnissen. Was ich jetzt tun möchte, ist vollständig zu beseitigen alle Konturen, die eine Grenze mit anderen Konturen teilen. Im Grunde sind alles, was mich interessiert, Konturen, die vollständig isoliert sind. Ich weiß, dass dies den Zweck des Watershed-Algorithmus zunichte macht, aber ich bin gespannt, wie dies durchgeführt werden würde. Hier ist der Code, mit dem ich arbeite. Vieles davon wurde von einer PY-Bildersuche article ausgeliehen.OpenCV gibt nur Konturen zurück, die keine Umrandung mit anderen Konturen haben

# 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) 

Mit anderen Worten, ich möchte nur die Konturen Kreise in rot zurückgegeben werden:

Isolated nuclei image

Antwort

0

A nicht sehr intelligente Lösung von jedem Zentrum mit blauem füllen zu überfluten würde, dann laufen eine Kennzeichnung der angeschlossenen Komponenten. Jetzt markieren Sie für jedes Zentrum die verbundene Komponente, in die es fällt, besucht und wenn ein Zentrum in eine besuchte Komponente fällt, markieren Sie es als entfernen. Behalten Sie nur die besuchten und nicht entfernten verbundenen Komponenten.

Ich bin mir sicher, dass Sie es besser machen können, aber als schnelle und schmutzige Strategie sollte es funktionieren.