OpenCV / C ++ connecte les contours proches en fonction de la distance entre eux

15

Je dois connecter les contours voisins dans une image en fonction de la distance entre eux qui spécifie si les contours doivent être connectés.

Maintenant, il y a déjà une question sur le même problème ici /programming/8973017/opencv-c-obj-c-connect-nearby-contours mais ici, il fusionne tous les contours en un seul. Ça, je ne veux pas. Je ne pense pas qu'il y ait une fonction dans opencv pour cela, mais vous pouvez suggérer un algorithme pour cela. Ma candidature se présente comme suit:

Je détecte des mains, j'ai donc utilisé un algorithme de détection de la peau pour les déterminer, mais comme ma peau n'est pas blanche et peut-être à cause des conditions d'éclaircissement, parfois le contour se brise au niveau du coude. Je veux donc que les contours voisins soient connectés, mais pas tous (parce que mes deux mains seront là dans les contours.) (Par mains, je veux dire de l'épaule à la paume.)

De plus, je pense qu'en utilisant une détection de bord, je vais obtenir mes limites de mains et détecter si une partie de ce patch à l'intérieur de cette limite est détectée comme peau, alors toute la région à l'intérieur de cette limite sera détectée comme peau, mais je ne sais pas comment le faire partie.

Toute aide serait appréciée. Merci d'avance

Exemple d'image:

entrez la description de l'image ici

Dans cette image, je veux connecter des points (8 connectivités) qui sont inférieurs à 40 pixels de distance pour que je prenne ma main gauche comme un contour unique

Mon objectif est d'obtenir uniquement le contour de la main (je ne me soucie d'aucune autre région)

Roney Island
la source
par les mains, vous voulez dire les bras. ne pourriez-vous pas simplement ajuster la teinte que vous utilisez pour détecter la peau en fonction de votre couleur de peau?
waspinator
Je l'ai fait et cela donne une sortie fine (lorsque ma peau est illuminée). Donc, le soir, cela vient comme indiqué. Quoi qu'il en soit, je pensais qu'il pourrait y avoir une méthode pour connecter les blobs à proximité.
Roney Island
Bienvenue sur stack exchange. SE n'est pas un forum! Ce n'est pas une réponse à la question. Si vous avez une question sur la question - mettez-la en commentaire.
Dipan Mehta
comment détectez-vous la peau?
nkint

Réponses:

10

Si vous n'êtes pas inquiet de la vitesse ou du contour exact de la main, voici une solution simple.

La méthode est la suivante: vous prenez chaque contour et trouvez la distance par rapport aux autres contours. Si la distance est inférieure à 50, ils sont à proximité et vous les mettez ensemble. Sinon, ils sont mis comme différents.

La vérification de la distance à chaque contour est donc un processus long. Prend quelques secondes. Vous ne pouvez donc pas le faire en temps réel.

De plus, pour joindre les contours, je les ai mis dans un seul ensemble et j'ai dessiné une coque convexe pour cet ensemble. Ainsi, le résultat que vous obtenez est en fait une coque de main convexe, pas une vraie main.

Ci-dessous mon morceau de code en OpenCV-Python. Je n'ai opté pour aucune optimisation, je voulais juste que ça marche, c'est tout. Si cela résout votre problème, optez pour l'optimisation.

import cv2
import numpy as np

def find_if_close(cnt1,cnt2):
    row1,row2 = cnt1.shape[0],cnt2.shape[0]
    for i in xrange(row1):
        for j in xrange(row2):
            dist = np.linalg.norm(cnt1[i]-cnt2[j])
            if abs(dist) < 50 :
                return True
            elif i==row1-1 and j==row2-1:
                return False

img = cv2.imread('dspcnt.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray,127,255,0)
contours,hier = cv2.findContours(thresh,cv2.RETR_EXTERNAL,2)

LENGTH = len(contours)
status = np.zeros((LENGTH,1))

for i,cnt1 in enumerate(contours):
    x = i    
    if i != LENGTH-1:
        for j,cnt2 in enumerate(contours[i+1:]):
            x = x+1
            dist = find_if_close(cnt1,cnt2)
            if dist == True:
                val = min(status[i],status[x])
                status[x] = status[i] = val
            else:
                if status[x]==status[i]:
                    status[x] = i+1

unified = []
maximum = int(status.max())+1
for i in xrange(maximum):
    pos = np.where(status==i)[0]
    if pos.size != 0:
        cont = np.vstack(contours[i] for i in pos)
        hull = cv2.convexHull(cont)
        unified.append(hull)

cv2.drawContours(img,unified,-1,(0,255,0),2)
cv2.drawContours(thresh,unified,-1,255,-1)

Voici les résultats que j'ai obtenus:

entrez la description de l'image ici

entrez la description de l'image ici

Abid Rahman K
la source
Comment cela peut-il être fait en c ++? J'ai jusqu'à la partie findContour mais après cela, je n'arrive pas à obtenir les contours à encapsuler dans un polygone comme indiqué ci-dessus (par opposition à un rectangle englobant).
Elionardo Feliciano
J'apprécie votre approche et j'ai essayé de l'appliquer à mon cas, mais malheureusement, c'est extrêmement lent sur Python (bien que mon ordinateur portable dispose de Core i7QM et de 8 Go de RAM). J'utilise MSER pour détecter les régions et maintenant je dois déterminer quelle paire de régions est "adjacente", j'ai essayé votre algorithme avec le seuil 10 ... Il faut des années pour renvoyer les régions adjacentes.
Jim Raynor
4

Pour résoudre le problème de connectivité, vous pouvez essayer une opération de fermeture:

cv::Mat structuringElement = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(40, 40));
cv::morphologyEx( inputImage, outputImage, cv::MORPH_CLOSE, structuringElement );

Je doute que cela produise les résultats que vous souhaitez, mais vous pouvez l'essayer.

bjoernz
la source
2

Il semble que vous «surzégiez» votre image. Les opérations morphologiques, comme l'a suggéré bjnoernz, seraient utiles. En particulier, une approche par bassin versant devrait se rapprocher de ce que vous voulez plutôt que de simplement vérifier la distance (comme dans l'exemple python ci-dessus). Voir http://cmm.ensmp.fr/~beucher/wtshed.html .

Profane
la source