it-swarm.com.ru

Как удалить волосы с изображений кожи, используя opencv?

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

Приведенный ниже код уменьшает область, где находятся волосы, но не удаляет волосы, которые находятся выше области интереса (ROI).

import numpy as np
import cv2

IMD = 'IMD436'
# Read the image and perfrom an OTSU threshold
img = cv2.imread(IMD+'.bmp')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh =     cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# Remove hair with opening
kernel = np.ones((2,2),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)

# Combine surrounding noise with ROI
kernel = np.ones((6,6),np.uint8)
dilate = cv2.dilate(opening,kernel,iterations=3)

# Blur the image for smoother ROI
blur = cv2.blur(dilate,(15,15))

# Perform another OTSU threshold and search for biggest contour
ret, thresh =     cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
contours, hierarchy =     cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)

# Create a new mask for the result image
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)

# Draw the contour on the new mask and perform the bitwise operation
cv2.drawContours(mask, [cnt],-1, 255, -1)
res = cv2.bitwise_and(img, img, mask=mask)

# Display the result
cv2.imwrite(IMD+'.png', res)
cv2.imshow('img', res)
cv2.waitKey(0)
cv2.destroyAllWindows()

 enter image description here

Результат:  enter image description here

Как я могу удалить волосы с верхней части моей области интересов?

Используемые изображения:  enter image description here

 enter image description here

 enter image description here

6
Carlos Diego

Я отвечаю на ваш тег в соответствующем сообщении. Насколько я понимаю, вы и другая коллега работаете вместе над проектом по обнаружению родинок на коже? Потому что я думаю, что уже оказал помощь одному или, возможно, вам обоим по схожим вопросам и уже упомянул, что удаление волос является очень сложной и сложной задачей. Если вы удаляете волосы на изображении, вы теряете информацию, и вы не можете заменить эту часть изображения (никакая программа или алгоритм не могут угадать, что находится под волосами - но это может дать оценку). То, что вы могли бы сделать, как я упоминал в других постах, и я думаю, что это будет лучший подход, это узнать о глубоких нейронных сетях и сделать свои собственные для удаления волос. Вы можете погуглить "удаление водяных знаков в глубокой нейронной сети" и посмотреть, что я имею в виду. При этом ваш код, по-видимому, не извлекает все области интереса (родинки), которые вы указали в примере изображения. Я сделал еще один пример того, как вы можете лучше извлечь родинки. По сути, вы должны выполнить закрытие перед преобразованием в двоичный файл, и вы получите лучшие результаты.

Что касается второй части - удаления волос, если вы не хотите создавать нейронную сеть, я думаю, что альтернативное решение может состоять в том, чтобы вы вычислили среднюю интенсивность пикселей в области, в которой находится моль. Затем выполните итерацию каждого пикселя и определите критерии того, насколько пиксель может отличаться от среднего значения. Волосы, кажется, представлены с пикселями, которые темнее, чем область моль. Поэтому, когда вы найдете пиксель, замените его соседним пикселем, который не попадает под этот критерий. В примере я сделал простую логику, которая не будет работать с каждым изображением, но может служить примером. Чтобы сделать полностью работоспособное решение, вы должны сделать лучший, более сложный алгоритм, который, я думаю, займет довольно много времени. Надеюсь, это поможет немного! Ура!

import numpy as np
import cv2
from PIL import Image

# Read the image and perfrom an OTSU threshold
img = cv2.imread('skin2.png')
kernel = np.ones((15,15),np.uint8)

# Perform closing to remove hair and blur the image
closing = cv2.morphologyEx(img,cv2.MORPH_CLOSE,kernel, iterations = 2)
blur = cv2.blur(closing,(15,15))

# Binarize the image
gray = cv2.cvtColor(blur,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)


# Search for contours and select the biggest one
_, contours, hierarchy =     cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)

# Create a new mask for the result image
h, w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)

# Draw the contour on the new mask and perform the bitwise operation
cv2.drawContours(mask, [cnt],-1, 255, -1)
res = cv2.bitwise_and(img, img, mask=mask)

# Calculate the mean color of the contour
mean = cv2.mean(res, mask = mask)
print(mean)

# Make some sort of criterion as the ratio hair vs. skin color varies
# thus makes it hard to unify the threshold.
# NOTE that this is only for example and it will not work with all images!!!

if mean[2] >182:
    bp = mean[0]/100*35
    gp = mean[1]/100*35
    rp = mean[2]/100*35   

Elif 182 > mean[2] >160:
    bp = mean[0]/100*30
    gp = mean[1]/100*30
    rp = mean[2]/100*30

Elif 160>mean[2]>150:
    bp = mean[0]/100*50
    gp = mean[1]/100*50
    rp = mean[2]/100*50

Elif 150>mean[2]>120:
    bp = mean[0]/100*60
    gp = mean[1]/100*60
    rp = mean[2]/100*60

else:
    bp = mean[0]/100*53
    gp = mean[1]/100*53
    rp = mean[2]/100*53

# Write temporary image
cv2.imwrite('temp.png', res)

# Open the image with PIL and load it to RGB pixelpoints
mask2 = Image.open('temp.png')
pix = mask2.load()
x,y = mask2.size

# Itearate through the image and make some sort of logic to replace the pixels that
# differs from the mean of the image
# NOTE that this alghorithm is for example and it will not work with other images

for i in range(0,x):
    for j in range(0,y):
        if -1<pix[i,j][0]<bp or -1<pix[i,j][1]<gp or -1<pix[i,j][2]<rp:
            try:
                pix[i,j] = b,g,r
            except:
                pix[i,j] = (int(mean[0]),int(mean[1]),int(mean[2]))
        else:
            b,g,r = pix[i,j]

# Transform the image back to cv2 format and mask the result         
res = np.array(mask2)
res = res[:,:,::-1].copy()
final = cv2.bitwise_and(res, res, mask=mask)

# Display the result
cv2.imshow('img', final)
cv2.waitKey(0)
cv2.destroyAllWindows()

 enter image description here

 enter image description here

 enter image description here

 enter image description here

1
kavko

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

  1. Найдите область волос, используя адаптивный локальный порог - метод Оцу Или любой другой метод. Я думаю, что "локальное определение порога" или даже "Выравнивание локальной гистограммы и затем глобальное определение порога" Найдет области волос.
  2. Чтобы заполнить области волос, используйте «синтез текстуры», чтобы синтезировать кожу. Как текстуру для области волос.

Один хороший и простой метод для синтеза текстур описан в «AA Efros и TK Leung, Синтез текстур с помощью непараметрической выборки», В материалах Международной конференции по компьютерному зрению (ICCV), Керкира, Греция, 1999 ». Синтез текстуры даст лучший результат, чем усреднение или медианная фильтрация для оценки пикселей в области волос.

Кроме того, взгляните на этот документ, он вам очень поможет:

http://link.springer.com/article/10.1007%2Fs00521-012-1149-1?LI=true

2
Abdul Rehman