O OpenCV / C ++ conecta contornos próximos com base na distância entre eles

15

Eu tenho que conectar contornos próximos em uma imagem com base na distância entre eles, que especifica se os contornos devem ser conectados.

Agora, já existe uma pergunta sobre o mesmo problema aqui /programming/8973017/opencv-c-obj-c-connect-nearby-contours, mas aqui ele mescla todos os contornos em um único. Isso eu não quero. Eu não acho que exista alguma função no opencv para isso, mas você pode sugerir um algoritmo para isso. Minha aplicação é assim:

Estou detectando mãos, então usei um algoritmo de detecção de pele para determiná-las, mas como minha pele não é branca e talvez por causa de condições de iluminação, em algum momento o contorno quebra no cotovelo. Então, eu quero que os contornos próximos sejam conectados, mas não todos (porque ambas as minhas mãos estarão lá em contornos.) (Por mãos, quero dizer do ombro à palma da mão.)

Além disso, acho que, ao usar alguma detecção de borda, vou obter os limites das minhas mãos e detectar se parte desse adesivo dentro desse limite é detectado como pele, então toda a região dentro desse limite será detectada como pele, mas não tenho certeza de como fazer isso parte.

Qualquer ajuda será apreciada. desde já, obrigado

Imagem de exemplo:

insira a descrição da imagem aqui

Nesta imagem, quero conectar pontos (8 conectividade) com menos de 40 pixels de distância, para que eu ponha minha mão esquerda em um único contorno

Meu objetivo é obter apenas o contorno da mão (não me importo com nenhuma outra região)

Roney Island
fonte
pelas mãos você realmente quer dizer braços. você não pode simplesmente ajustar o tom usado para detectar a pele para combinar com a cor da pele?
Waspinator
Eu fiz isso e dá uma saída fina (quando minha pele está iluminada). Então, durante a noite, vem como mostrado. De qualquer forma, pensei que poderia haver algum método para conectar blobs próximos.
Roney Island
Relacionado a dsp.stackexchange.com/q/2588/590
Chris
Bem-vindo à pilha de troca. SE não é um fórum! Esta não é uma resposta para a pergunta. Se você tiver uma pergunta sobre a pergunta, faça isso como um comentário.
Dipan Mehta
como você detecta a pele?
Nkint 7/01

Respostas:

10

Se você não está preocupado com a velocidade ou o contorno exato da mão, abaixo está uma solução simples.

O método é o seguinte: você pega cada contorno e encontra distância de outros contornos. Se a distância for menor que 50, eles estão próximos e você os reúne. Caso contrário, eles são colocados como diferentes.

Portanto, verificar a distância de cada contorno é um processo demorado. Demora alguns segundos. Portanto, você não pode fazer isso em tempo real.

Além disso, para juntar contornos, coloquei-os em um único conjunto e desenhei um casco convexo para esse conjunto. Portanto, o resultado que você está obtendo é, na verdade, um casco convexo da mão, não uma mão real.

Abaixo está o meu pedaço de código no OpenCV-Python. Não busquei nenhuma otimização, só queria que funcionasse, só isso. Se resolver o seu problema, vá para a otimização.

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)

Abaixo estão os resultados que obtive:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Abid Rahman K
fonte
Como isso pode ser feito em c ++? Eu tenho até a parte findContour, mas depois disso não consigo obter os contornos para envolver em um polígono, como mostrado acima (em oposição a um retângulo delimitador).
Elionardo Feliciano
Agradeço sua abordagem e tentei aplicar ao meu caso, mas infelizmente é extremamente lento no Python (embora meu laptop tenha Core i7QM e 8 GB de RAM). Eu uso o MSER para detectar regiões e agora preciso determinar qual par de regiões é "adjacente", tentei seu algoritmo com limite 10 ... Demora anos para retornar as regiões adjacentes.
Jim Raynor
4

Para corrigir o problema de conectividade, você pode tentar uma operação fechada:

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

Duvido que isso produza os resultados desejados, mas você pode tentar.

bjoernz
fonte
2

Parece que você está "oversegmenting" sua imagem. Operações morfológicas, como bjnoernz sugeriu, ajudariam. Em particular, uma abordagem de captação de água deve se aproximar do que você deseja, além de apenas verificar a distância (como no exemplo de python acima). Veja http://cmm.ensmp.fr/~beucher/wtshed.html .

Profano
fonte