OpenCV обнаружение окружности / эллипса с размытым краем

Как найти зрачка (маленький кружок в глазном яблоке) на следующем рисунке и рассчитать площадь зрачка. Я пробовал обнаружение круга Хафа и подбор эллипса на контурах с различным порогом, но ни один из этих наивных подходов не работает очень хорошо.

В частности, обнаружение HoughCircle полностью теряется во многих шумах, а обнаружение эллипса с обрезкой часто приводит к большему кругу.

И я не уверен, как определить функциональный порог без ручной настройки на трекбар. Может кто-нибудь дать мне несколько советов о том, как точно это сделать?

Eyeball_sample

1 ответ

Простой процесс обработки изображений должен помочь вам достичь вашей цели.

Сначала загрузите изображение в оттенках серого. Я думаю, что пороговый метод Оцу достаточно надежен, чтобы извлечь область зрачка глаза. Дополнительный морфологический процесс требуется для удаления шума и незаполненных областей

Затем, используя анализ связанных компонентов, мы можем выделить область зрачка для дальнейшей обработки.

С этой областью мы можем получить край, вычитая расширенную область с исходной областью, как показано ниже.

Наконец, мы можем запустить алгоритм подгонки окружности или эллипса, чтобы получить соответствующую форму,

Подгонка круга показана красным, а эллипс - зеленым. Оба возвращают одну и ту же центральную позицию, хотя и слегка различную форму.

Вот код, используемый. Я уменьшаю изображение, чтобы ускорить процесс, но оно будет работать так же, используя оригинальный размер.

import cv2
import numpy as np

img = cv2.imread('eye.jpg',0)

small_img = cv2.resize(img,(0,0),fx = 0.25, fy = 0.25)
r,c = small_img.shape
# Threshold objs
_, thresh = cv2.threshold(small_img,0,255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# Morphological close process to cluster nearby objects
bin_img = cv2.dilate(thresh, None,iterations = 5)
bin_img = cv2.erode(bin_img, None,iterations = 5)

# Analyse connected components
num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(bin_img)

# Find circle center and radius
# Radius calculated by averaging the height and width of bounding box
bin_eye = np.zeros((r,c))
cnt_label = labels[r/2,c/2]
bin_eye[labels == cnt_label] = 255
area = stats[cnt_label][4]
radius = np.sqrt(area / np.pi)
cnt_pt = ((centroids[cnt_label][0]),(centroids[cnt_label][1]))

# fit ellipse
bin_eye_large = cv2.dilate(bin_eye, None,iterations = 1)

# Get ellipse edge
edge_eye = bin_eye_large - bin_eye

# extract location points for fitting
ellip_pts = np.where(edge_eye > 0)
ellip_pts = np.transpose(ellip_pts)
temp = np.copy(ellip_pts[:,0])
ellip_pts[:,0] = ellip_pts[:,1]
ellip_pts[:,1] = temp

# fit ellipse
ellip = cv2.fitEllipse(ellip_pts)


# Display final result
edges_color = cv2.cvtColor(small_img,cv2.COLOR_GRAY2BGR)
cv2.circle(edges_color,(int(cnt_pt[0]),int(cnt_pt[1])),int(radius),(0,0,255),1)
cv2.circle(edges_color,(int(cnt_pt[0]),int(cnt_pt[1])),5,(0,0,255),1)
cv2.ellipse(edges_color,ellip, (0,255,0))
cv2.circle(edges_color,(int(ellip[0][0]),int(ellip[0][1])),5,(0,255,0),1)

cv2.imshow('edges_color',edges_color)
cv2.imshow('bin_img',bin_img)
cv2.imshow('eye_label',bin_eye)
cv2.imshow('eye_edge',edge_eye)

cv2.waitKey(0)
Другие вопросы по тегам