Как я могу извлечь ноготь из изображения пальцем? - PullRequest
1 голос
/ 04 октября 2019

Описание

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

Что я сделал до сих пор:

  1. загрузить изображение
  2. изменить размеризображение для меньших вычислительных усилий
  3. обработка его (размытие, удаление зеленого фона, преобразование в серую шкалу
  4. извлечение ногтя из изображения (как?)

IПопытка сделать обнаружение круга или обнаружение эллипса. Обнаружение круга с использованием грубого преобразования не распознает ноготь. То же самое для обнаружения эллипса (за исключением того, что это заняло 2 минуты и это слишком долго ждать). Теперь мойВопрос в том, существует ли простой способ решения проблемы и извлечения ногтя?

Я также использовал обнаружение краев / обнаружение контуров, чтобы извлечь ноготь, однако это было слишком неточно и бесполезно.

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


Важные фрагменты кода:

# imports

# helper functions
def remove_green(img):
    empty_img = np.zeros_like(img)
    RED, GREEN, BLUE = (2, 1, 0)
    reds = img[:, :, RED]
    greens = img[:, :, GREEN]
    blues = img[:, :, BLUE]
    # loop over the image, pixel by pixel
    tmpMask = (greens < 35) | (reds > greens) | (blues > greens)
    img[tmpMask == 0] = (0, 0, 0)  # remove background from original picture
    empty_img[tmpMask] = (255, 255, 255)  # mask with finger in white
    return img, empty_img

# main function
# load and process 
image = cv2.imread(imagePath, 1)  # load
image = cv2.resize(image, None, fx=0.3, fy=0.3)  # resize
image = cv2.GaussianBlur(image, (3, 3), 0)
no_green_image, mask_finger = remove_green(image)  # remove green
gray = cv2.cvtColor(no_green_image, cv2.COLOR_BGR2GRAY)  # gray scalEd
gray_mask_finger = cv2.cvtColor(mask_finger, cv2.COLOR_BGR2GRAY)

# refine edges
kernel = np.ones((5, 5), np.uint8)
gray_mask_finger = cv2.morphologyEx(gray_mask_finger, cv2.MORPH_GRADIENT, kernel)

detect_nail(gray_mask_finger)
# here I struggle

Изображения

Начальное изображение:

Starting image

Удалено зеленое и преобразовано в серое:

Processed image

Контуры:

Contours

1 Ответ

0 голосов
/ 04 октября 2019

Я думаю, что наилучшим подходом к решению этой проблемы, рассматриваемой как проблема семантической сегментации / сегментации, может быть использование архитектуры типа Encoder-Decoder (например, U-Net), поскольку решить эту проблему довольно сложно, используя традиционные методы обработки изображений,Тем не менее, я дам ему попробовать. В моем подходе я следовал ниже упомянутым шагам, чтобы обнаружить область ногтя (результат не идеален, но вы можете улучшить это):

  • Применение порога по сглаженному значению насыщенности к сегменту ROI
  • Градиентвычисление с использованием оператора Собеля с последующим применением порога для обнаружения краевой области (имеющего высокое значение градиента)
  • Обнаружение контура и сегментация ногтевой области
image = cv2.imread("finger.jpg")  # load image

hsv_img = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)  # BGR to HSV conversion
hsv_img = cv2.resize(hsv_img, (250, 250))

img_s = hsv_img[:, :, 1]  # Extracting Saturation channel on which we will work

img_s_blur = cv2.GaussianBlur(img_s, (7, 7), 0)  # smoothing before applying  threshold

img_s_binary = cv2.threshold(img_s_blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]  # Thresholding to generate binary image (ROI detection)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
img_s_binary = cv2.morphologyEx(img_s_binary, cv2.MORPH_OPEN, kernel, iterations=3)  # reduce some noise

img_croped = cv2.bitwise_and(img_s, img_s_binary) * 2  # ROI only image extraction & contrast enhancement, you can crop this region 

abs_grad_x = cv2.convertScaleAbs(cv2.Sobel(img_croped, cv2.CV_64F, 1, 0, ksize=3))
abs_grad_y = cv2.convertScaleAbs(cv2.Sobel(img_croped, cv2.CV_64F, 0, 1, ksize=3))
grad = cv2.addWeighted(abs_grad_x, .5, abs_grad_y, .5, 0)  # Gradient calculation
grad = cv2.medianBlur(grad, 13)

edges = cv2.threshold(grad, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

cnts = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # Contours Detection
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnt = None
max_area = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > max_area:  # Filtering contour
        max_area = area
        cnt = c

cv2.drawContours(hsv_img, [cnt], 0, (0, 255, 0), 3)

Пошаговый вывод: enter image description here

...