OpenCV / C ++ łączy pobliskie kontury na podstawie odległości między nimi

15

Muszę połączyć pobliskie kontury na obrazie na podstawie odległości między nimi, która określa, czy kontury mają zostać połączone.

Teraz jest już pytanie dotyczące tego samego problemu tutaj /programming/8973017/opencv-c-obj-c-connect-nearby-contours, ale tutaj łączy wszystkie kontury w jeden. Tego nie chcę. Nie sądzę, że jest w tym jakaś funkcja w opencv, ale możesz zaproponować algorytm. Moja aplikacja wygląda następująco:

Wykrywałem dłonie, więc użyłem algorytmu wykrywania skóry, aby je określić, ale ponieważ moja skóra nie jest biała i może z powodu warunków oświetleniowych czasami kontur łamie się na łokciu. Chcę więc, aby pobliskie kontury były ze sobą połączone, ale nie wszystkie (ponieważ obie moje ręce będą tam w konturach.) (Przez ręce mam na myśli od ramienia do dłoni.)

Co więcej, myślę, że stosując pewne wykrywanie krawędzi, dostanę granice rąk i wykryję, czy część tej łatki wewnątrz tej granicy zostanie wykryta jako skóra, wtedy cały region w tej granicy zostanie wykryty jako skóra, ale nie jestem pewien, jak to zrobić część.

Każda pomoc będzie mile widziana. Z góry dziękuję

Przykładowy obraz:

wprowadź opis zdjęcia tutaj

Na tym obrazie chcę połączyć punkty (8 połączeń), które są mniej niż powiedzmy 40 pikseli odległości, aby uzyskać lewą rękę jako pojedynczy kontur

Moim celem jest uzyskanie tylko konturu dłoni (nie dbam o żaden inny region)

Wyspa Roney
źródło
przez ręce masz na myśli ręce. czy możesz nie tylko dostosować odcień, którego używasz do wykrywania skóry, aby pasowała do koloru skóry?
waspinator
Zrobiłem to i daje świetny efekt (gdy moja skóra jest rozświetlona). Więc wieczorem przychodzi jak pokazano. W każdym razie myślałem, że może być jakiś sposób na połączenie pobliskich obiektów blob.
Roney Island
Witamy w wymianie stosów. SE nie jest forum! To nie jest odpowiedź na pytanie. Jeśli masz pytanie dotyczące pytania - umieść je w komentarzu.
Dipan Mehta
jak wykrywasz skórę?
nkint

Odpowiedzi:

10

Jeśli nie martwisz się prędkością lub dokładnym konturem dłoni, poniżej znajdziesz proste rozwiązanie.

Metoda jest następująca: bierzesz każdy kontur i znajdujesz odległość od innych konturów. Jeśli odległość jest mniejsza niż 50, są w pobliżu, a ty je poskładasz. Jeśli nie, są one przedstawiane jako różne.

Sprawdzanie odległości do każdego konturu jest więc czasochłonne. Zajmuje kilka sekund. Więc nie ma mowy, abyś mógł to zrobić w czasie rzeczywistym.

Ponadto, aby połączyć kontury, umieściłem je w jednym zestawie i narysowałem wypukły kadłub dla tego zestawu. Tak więc otrzymujesz wynik wypukłego kadłuba dłoni, a nie prawdziwej dłoni.

Poniżej mój fragment kodu w OpenCV-Python. Nie poszedłem na żadną optymalizację, chciałem tylko, żeby działała, to wszystko. Jeśli to rozwiąże problem, przejdź do optymalizacji.

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)

Poniżej znajdują się wyniki, które otrzymałem:

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Abid Rahman K.
źródło
Jak można to zrobić w c ++? Mam do czynienia z częścią findContour, ale potem nie wydaje mi się, aby kontury zawijały się w wielokącie, jak pokazano powyżej (w przeciwieństwie do prostokąta ograniczającego).
Elionardo Feliciano,
Doceniam twoje podejście i starałem się zastosować w moim przypadku, ale niestety jest on bardzo wolny w Pythonie (chociaż mój laptop ma Core i7QM i 8 GB pamięci RAM). Używam MSER do wykrywania regionów i teraz muszę ustalić, która para regionów jest „sąsiadująca”, wypróbowałem twój algorytm z progiem 10 ... Zwrócenie sąsiednich regionów zajmuje lata.
Jim Raynor,
4

Aby rozwiązać problem z łącznością, możesz spróbować zamknąć operację:

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

Wątpię, aby przyniosło to pożądane rezultaty, ale możesz spróbować.

Bjoernz
źródło
2

Wygląda na to, że „przesadzasz” swój obraz. Pomogłyby operacje morfologiczne, jak sugerował bjnoernz. W szczególności podejście do zlewni powinno być bliżej tego, co chcesz, niż tylko sprawdzanie odległości (jak w powyższym przykładzie Pythona). Zobacz http://cmm.ensmp.fr/~beucher/wtshed.html .

Bezcześcić
źródło