简体   繁体   中英

OpenCV contour detection

I have been trying to detect contours using OpenCV. I am trying to detect the nucleus of white blood cells. I tested it on other images of mine and it turned out to be okay except for images where the nuclei are too far away from each other. This is the result from the program I made: 结果图片

At the bottom part, the nucleus was not detected as one but they are detected as two because they are not conjoined or sticking together. How can I make the program to detect it as only one cell?

Here is my code:

import cv2
import numpy as np

limit_area = 1000   
x = 0   
y = 0   
w = 0   
h = 0   
nuclei = []   
count = 0   
number_name = 1   

img1 = cv2.imread('7.bmp')
img = cv2.add(img1, 0.70)
img_3 = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask1 = cv2.inRange(img_3, (90,140,0), (255,255,255))   
mask2 = cv2.inRange(img_3, (90,90,0), (255,255,255))   
mask1 = cv2.equalizeHist(mask1)
mask2 = cv2.equalizeHist(mask2)
mask = mask1 + mask2   
kernel = np.ones((1,4),np.uint8)   
mask = cv2.dilate(mask,kernel,iterations = 1)   
kernel_close = np.ones((3,3),np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel_close)   
blur2 = cv2.medianBlur(mask,7)   
canny = cv2.Canny(blur2, 100,200)   
im2, contours, hierarchy = cv2.findContours(canny,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)   

for cnt in contours:   
    if cv2.contourArea(cnt) >= limit_area:   
        nuclei.append(cnt)   
        print(cv2.contourArea(cnt))
        x, y, w, h = cv2.boundingRect(cnt)   
        roi = blur2[y:y+h, x:x+w]
        outfile = '%d.jpg' % number_name
        image_roi = cv2.resize(roi, (128,128), interpolation=cv2.INTER_AREA)
        image_roi = cv2.medianBlur(image_roi, 5)
        (T, thresh) = cv2.threshold(image_roi, 10, 255, cv2.THRESH_BINARY)
        _, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        contours = [i for i in contours if cv2.contourArea(i) <= 5000]
        cv2.fillPoly(thresh, contours, color=(0,0,0))
        image_roi = thresh
        cv2.imshow(outfile, image_roi)
        cv2.rectangle(img, (x, y), (x+w, y+h), (0,255,0), 7)  
        number_name += 1   

    count += 1   

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Here is the Original Image: 原始图像

One simple way can be to merge closely detected regions. There is a concept called Intersection over Union in Image Localization, in which two bounding boxes are merged if their IoU score is greater than a certain threshold. A psuedo cade will be like

xi1 = max(box1[0], box2[0])
yi1 = max(box1[1], box2[1])
xi2 = min(box1[2], box2[2])
yi2 = min(box1[3], box2[3])
inter_area = max((xi2 - xi1), 0) * max((yi2 - yi1), 0)
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
union_area = box1_area + box2_area - inter_area
iou = inter_area/union_area

Another approach you can try is the Flood Fill Algorithm , I think it should work fine as the nucleus is one entity after all (fully connected). Try this before dialation which probably is the reason your contours are breaking into two.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM