OpenCV / C ++ conecta contornos cercanos en función de la distancia entre ellos

15

Tengo que conectar contornos cercanos en una imagen basada en la distancia entre ellos que especifica si los contornos se van a conectar.

Ahora hay una pregunta sobre el mismo problema aquí /programming/8973017/opencv-c-obj-c-connect-nearby-contours pero aquí combina todos los contornos en uno solo. Esto no lo quiero. No creo que haya alguna función en opencv para esto, pero puede sugerir un algoritmo para eso. Mi aplicación es así:

Estoy detectando manos, así que utilicé un algoritmo de detección de piel para determinarlas, pero dado que mi piel no es blanca y tal vez debido a las condiciones de aclaración en algún momento el contorno se rompe en el codo. Por lo tanto, quiero que se conecten los contornos cercanos, pero no todos (porque ambas manos estarán allí en contornos). (Por manos quiero decir desde el hombro hasta la palma).

Además, creo que al usar alguna detección de bordes, obtendré los límites de mis manos y detectaré si parte de este parche dentro de este límite se detecta como piel, entonces toda la región dentro de este límite se detectará como piel, pero no estoy seguro de cómo hacer esto parte.

Cualquier ayuda será apreciada. Gracias por adelantado

Imagen de muestra:

ingrese la descripción de la imagen aquí

En esta imagen quiero conectar puntos (8 conectividad) que son menos de 40 píxeles de distancia para que pueda obtener mi mano izquierda como un solo contorno

Mi objetivo es obtener solo el contorno de la mano (no me importa ninguna otra región)

Isla Roney
fuente
por manos en realidad te refieres a los brazos. ¿no podrías simplemente ajustar el tono que usas para detectar la piel para que coincida con el color de tu piel?
waspinator
Lo he hecho y da un buen resultado (cuando mi piel está iluminada). Entonces, durante la noche, viene como se muestra. De todos modos, pensé que podría haber algún método para conectar blobs cercanos.
Roney Island
Relacionado con dsp.stackexchange.com/q/2588/590
Chris
Bienvenido a stack exchange. ¡SE no es un foro! Esta no es una respuesta a la pregunta. Si tiene una pregunta sobre la pregunta, póngala como comentario.
Dipan Mehta
¿Cómo se detecta la piel?
nkint

Respuestas:

10

Si no le preocupa la velocidad o el contorno exacto de la mano, a continuación encontrará una solución simple.

El método es así: toma cada contorno y encuentra la distancia a otros contornos. Si la distancia es inferior a 50, están cerca y los juntas. Si no, se ponen como diferentes.

Por lo tanto, verificar la distancia a cada contorno es un proceso lento. Toma unos segundos Así que no puedes hacerlo en tiempo real.

Además, para unir contornos, los puse en un solo conjunto y dibujé un casco convexo para ese conjunto. Entonces, el resultado que está obteniendo es en realidad un casco de mano convexo, no una mano real.

A continuación se muestra mi código en OpenCV-Python. No he elegido ninguna optimización, solo quería que funcionara, eso es todo. Si resuelve su problema, vaya a la optimización.

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)

A continuación se muestran los resultados que obtuve:

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Abid Rahman K
fuente
¿Cómo se puede hacer esto en c ++? Tengo hasta la parte findContour, pero después de eso parece que no puedo hacer que los contornos se envuelvan en un polígono como se muestra arriba (a diferencia de un rectángulo delimitador).
Elionardo Feliciano
Aprecio su enfoque e intenté aplicarlo a mi caso, pero desafortunadamente es extremadamente lento en Python (aunque mi computadora portátil tiene Core i7QM y 8GB de RAM). Utilizo MSER para detectar regiones y ahora necesito determinar qué par de regiones son "adyacentes". Probé su algoritmo con el umbral 10 ... Lleva años devolver las regiones adyacentes.
Jim Raynor
4

Para solucionar el problema de conectividad, puede intentar una operación de cierre:

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

Dudo que esto produzca los resultados que desea, pero puede intentarlo.

bjoernz
fuente
2

Parece que estás "segmentando en exceso" tu imagen. Las operaciones morfológicas, como ha sugerido bjnoernz, ayudarían. En particular, un enfoque de cuenca hidrográfica debería acercarse más a lo que desea que simplemente verificar la distancia (como en el ejemplo de Python anterior). Ver http://cmm.ensmp.fr/~beucher/wtshed.html .

Profano
fuente