I am using Python 3.5 and OpenCV 3 to analyze pictures of cells in biology. My pictures look like this:
I want to be able to calculate a ratio of the area of th
# light purple color segmentation (to get cells)
cell_hsvmin = (110,40,145)
cell_hsvmax = (150,190,255)
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
color_thresh = cv2.inRange(hsv, cell_hsvmin, cell_hsvmax)
# masked = cv2.bitwise_and(frame,frame, mask=color_thresh)
# cv2.imshow('masked0', masked)
ksize = 5
open_thresh = cv2.morphologyEx(color_thresh, cv2.MORPH_OPEN, np.ones((ksize,ksize),'uint8'), iterations=1)
masked = cv2.bitwise_and(frame,frame, mask=open_thresh)
cv2.imshow('masked', masked)
# dark purple color segmentation (to get nucleus)
nucleus_hsvmin = (125,65,160)
nucleus_hsvmax = (150,190,255)
nucleus_color_thresh = cv2.inRange(hsv, nucleus_hsvmin, nucleus_hsvmax)
ksize = 3
nucleus_open_thresh = cv2.morphologyEx(nucleus_color_thresh, cv2.MORPH_OPEN, np.ones((ksize,ksize),'uint8'), iterations=1)
nucleus_masked = cv2.bitwise_and(masked,masked, mask=nucleus_open_thresh)
cv2.imshow('nucleus_masked', nucleus_masked)
"""
HULL APPROXIMATES THE CELLS TO A CIRCLE TO FILL IN GAPS CREATED BY THRESHOLDING AND CLOSING.
FOR NON-CIRCULAR CELLS LIKE IN YOUR SECOND IMAGE, THIS MIGHT CAUSE BAD AREA CALCULATIONS
"""
# doHULL = False
doHULL = True
cells = []
cells_ratio = []
minArea = frame.shape[0]*frame.shape[1]* 0.01
_, contours, _ = cv2.findContours(open_thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
area = cv2.contourArea(cnt)
if area >= minArea:
cells.append(cnt)
nucleus_mask = np.zeros(frame.shape[:2], 'uint8')
if doHULL:
hull = cv2.convexHull(cnt)
cv2.drawContours(nucleus_mask, [hull], -1, 255, -1);
else:
cv2.drawContours(nucleus_mask, [cnt], -1, 255, -1);
nucleus_mask = cv2.bitwise_and(nucleus_open_thresh, nucleus_mask)
nucleus_area = np.count_nonzero(nucleus_mask)
ratio = nucleus_area / area
cells_ratio.append(ratio)
# nucleus_img = cv2.bitwise_and(frame, frame, mask=nucleus_mask)
# cv2.imshow('nucleus_img', nucleus_img)
# cv2.waitKey(0)
doDRAWCELLS = False
# doDRAWCELLS = True
if doDRAWCELLS:
for cell_cnt in cells:
cells_mask = np.zeros(frame.shape[:2], 'uint8')
if doHULL:
hull = cv2.convexHull(cell_cnt)
cv2.drawContours(cells_mask, [hull], -1, 255, -1);
else:
cv2.drawContours(cells_mask, [cell_cnt], -1, 255, -1);
cells_img = cv2.bitwise_and(frame, frame, mask=cells_mask)
cv2.imshow('cells_img', cells_img)
cv2.waitKey(0)
this will only work for cells that are not connected. you can use this as a base to work with the watershed algorithm. Also, the color segmentation parameters have been tuned according to the 2 images you posted. other slides might deviate from the color range so you might have to adjust them. if adjusting them doesnt get you a good compromise, you might have to look into otsu binarization or adaptive thresholding to segment the colors.
Another option is to look at cv2.MORPH_GRADIENT which works like an edge detector. or
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
kernel = np.array([[1,1,1],[1,-8,1],[1,1,1]],dtype='float32')
laplace = cv2.filter2D(cv2.GaussianBlur(gray,(blur_ksize,blur_ksize),0), -1, kernel)
cv2.imshow('laplace', laplace)
and use the edges to segment the cells?