web-dev-qa-db-fra.com

Comment enlever les poils des images de la peau en utilisant l'opencv?

Je travaille avec la reconnaissance des taches cutanées. Pour cela, je travaille avec plusieurs images avec des bruits différents. Un de ces bruits sont les poils, car j'ai des images avec des poils sur la zone de la tache (ROI). Comment diminuer ou supprimer ces types de bruit d'image?

Le code ci-dessous diminue la zone où se trouvent les cheveux, mais ne supprime pas les cheveux au-dessus de la zone d'intérêt (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

Sortie:  enter image description here

Comment puis-je enlever les poils du haut de ma région d'intérêt?

Images utilisées:  enter image description here

 enter image description here

 enter image description here

6
Carlos Diego

Je réponds à votre tag sur un post connexe. Si j'ai bien compris, vous et un autre collège travaillez ensemble à un projet visant à localiser les taupes sur la peau? Parce que je pense avoir déjà apporté de l'aide à l'un de vous ou peut-être à vous deux sur des questions similaires et déjà mentionné que le retrait des poils est une tâche très délicate et difficile. Si vous enlevez les cheveux de l'image, vous perdez des informations et vous ne pouvez pas remplacer cette partie de l'image (aucun programme ni aucun algorithme ne peut deviner ce qu'il y a sous les cheveux - mais cela peut donner une estimation). Ce que vous pourriez faire, comme je l’ai mentionné dans d’autres articles, et je pense que ce serait la meilleure approche, c’est d’apprendre sur les réseaux de neurones profonds et de créer le vôtre pour l’épilation. Vous pouvez google "suppression du filigrane réseau de neurones profonds" et voir ce que je veux dire. Cela étant dit, votre code ne semble pas extraire toutes les ROI (les taupes) que vous avez données dans l'exemple d'image. J'ai fait un autre exemple sur la façon dont vous pouvez mieux extraire les taupes. Fondamentalement, vous devriez effectuer la fermeture avant de passer au binaire et vous obtiendrez de meilleurs résultats.

Pour la deuxième partie - l'épilation, si vous ne souhaitez pas créer de réseau de neurones, je pense que cette solution alternative pourrait être de calculer l'intensité moyenne en pixels de la région contenant la taupe. Puis parcourez chaque pixel et définissez une sorte de critère sur la différence de pixel possible. Les cheveux semblent présenter des pixels plus sombres que la taupe. Ainsi, lorsque vous trouvez le pixel, remplacez-le par le pixel voisin qui ne correspond pas à ce critère. Dans l’exemple, j’ai établi une logique simple qui ne fonctionnera pas avec toutes les images mais qui peut servir d’exemple. Pour créer une solution pleinement opérationnelle, vous devez créer un algorithme meilleur et plus complexe, qui prendra probablement un certain temps. J'espère que ça aide un peu! À votre santé!

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

Vous pouvez essayer les étapes suivantes, au moins pour obtenir une feuille de route pour la mise en œuvre de la solution appropriée:

  1. Trouvez la région capillaire à l'aide du seuillage local adaptatif - méthode Otsu Ou de toute autre méthode. Je pense que "seuillage local" ou même "Égalisation d'histogramme local et puis seuillage global" va Trouver les régions de cheveux.
  2. Pour remplir les régions capillaires, utilisez la "synthèse de texture" pour synthétiser la peau. Une texture semblable à celle de la région capillaire.

Une méthode simple et efficace pour la synthèse de texture est décrite dans "AA Efros and TK Leung, Synthèse de texture par échantillonnage non paramétrique", In Actes de la Conférence internationale sur la vision par ordinateur (ICCV), Kerkyra, Grèce, 1999 .. ... La synthèse de texture donnera un meilleur résultat que la moyenne ou le filtrage médian pour estimer les pixels dans la région du cheveu.

Regardez aussi ce papier, il devrait vous aider beaucoup:

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

2
Abdul Rehman