简体   繁体   English

如何使用opencv从皮肤图像中删除头发?

[英]How to remove hair from skin images using opencv?

I am working with recognition of skin spots. 我正在努力识别皮肤斑点。 For this, I work with a number of images with different noises. 为此,我使用了许多具有不同噪声的图像。 One of these noises are the hairs, because I have images with hairs over the area of ​​the stain (ROI). 这些噪音中的一个是毛发,因为我在污渍区域(ROI)上有毛发的图像。 How to decrease or remove these types of image noise? 如何减少或消除这些类型的图像噪声?

The code below decreases the area where hairs are, but does not remove hairs that are above the area of ​​interest (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()

在此输入图像描述

Exit: 出口: 在此输入图像描述

How can I remove hair from the top of my region of interest? 如何从我感兴趣的区域顶部去除头发?

Images used: 使用的图像: 在此输入图像描述

在此输入图像描述

在此输入图像描述

You can try the following steps, at least to get a road map to the proper solution implementation: 您可以尝试以下步骤,至少要获得正确解决方案实施的路线图:

  1. Find the hair region using adaptive local thresholding - Otsu's method or any other method. 使用自适应局部阈值 - Otsu方法或任何其他方法找到头发区域。 I think "local thresholding" or even "local histogram equalization and then global thresholding" will find the hair regions. 我认为“局部阈值”或甚至“局部直方图均衡然后全局阈值”将找到头发区域。
  2. To fill the hair regions, use "texture synthesis" to synthesize skin like texture for the hair region. 为了填充头发区域,使用“纹理合成”来合成头发区域的皮肤纹理。

One good and easy method for texture synthesis is described in "AA Efros and TK Leung, Texture synthesis by non-parametric sampling', In Proceedings of the International Conference on Computer Vision (ICCV), Kerkyra, Greece, 1999". 纹理合成的一种简单易用的方法描述于“AA Efros and TK Leung,Texture synthesis by non-parametric sampling',In Proceedings of the International Conference on Computer Vision(ICCV),Kerkyra,Greece,1999”。 Texture synthesis will give a better result than averaging or median filtering to estimate the pixels in the hair region. 纹理合成将提供比平均或中值滤波更好的结果来估计头发区域中的像素。

Also, take a look at this paper, it should help you a lot: 另外,看看这篇论文,它应该对你有很大的帮助:

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

I am responding to your tag on a related post. 我在相关帖子上回复您的标记。 As I understand you and another colege are working together on a project to locate the moles on the skin? 据我所知,你和另一个合作伙伴正在合作开展一项项目,以确定皮肤上的痣? Because I think I have already gave help to one or maybe both of you on similar questions and already mentioned that the removal of the hair is very tricky and difficult task. 因为我认为我已经在类似的问题上给了你们一个或两个人,但已经提到过去除头发是非常棘手和困难的任务。 If you remove the hair on the image you lose information and you can't replace that part of the image (no program or alghorithm can guess what is under the hair - but it can make an estimation). 如果你删除图像上的头发,你会失去信息,你不能替换图像的那一部分(没有程序或算法可以猜出头发下面的东西 - 但它可以做出估计)。 What you could do as I mentioned in other posts and I think that it would be the best approach is to learn about deep neural networks and make your own for the hair removal. 正如我在其他帖子中提到的那样你可以做什么,我认为最好的方法是学习深层神经网络,并为脱毛做出自己的想法。 You can google "watermark removal deep neural network" and see what I mean. 你可以谷歌“水印去除深度神经网络”,看看我的意思。 That being said, your code does not seem to extract all ROIs (the moles) you have given in the example image. 话虽这么说,您的代码似乎并没有提取您在示例图像中给出的所有ROI(摩尔)。 I have made another example on how you can better extract the moles. 我已经就如何更好地提取痣提出了另一个例子。 Basically you should perform closing before transforming to binary and you will get better results. 基本上你应该在转换为二进制之前执行关闭,你会得到更好的结果。

For the second part - hair removal, if you do not wish to make a neural network, I think that alternative solution could be, that you calculate the mean pixel intesity of the region that contains the mole. 对于第二部分 - 脱毛,如果你不想建立神经网络,我认为替代解决方案可能是,你计算包含痣的区域的平均像素强度。 Then iterate throug every pixel and make some sort of criteria on how much can the pixel differ from the mean. 然后迭代每个像素并制定一些标准,说明像素与平均值的差异程度。 Hair seem to be presented with pixels that are darker than the mole area. 头发似乎呈现出比痣区域更暗的像素。 So when you find the pixel, replace it with the neigbour pixel that does not fall in this criteria. 因此,当您找到像素时,请将其替换为不符合此条件的neigbour像素。 In the example I have made a simple logic which will not work with every image but it can serve as an example. 在这个例子中,我制作了一个简单的逻辑,它不适用于每个图像,但它可以作为一个例子。 To make a fully operational solution you should make a better, more complex alghorithm which I guess will take quite some time. 为了制定一个完全可操作的解决方案,你应该制作一个更好,更复杂的算法,我想这将需要相当长的时间。 Hope it helps a bit! 希望它有点帮助! Cheers! 干杯!

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()

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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