OpenCV / C ++ соединяет близлежащие контуры в зависимости от расстояния между ними

15

Я должен соединить близлежащие контуры в изображении на основе расстояния между ними, которое указывает, должны ли контуры быть соединены.

Теперь уже есть вопрос по той же проблеме здесь /programming/8973017/opencv-c-obj-c-connect-nearby-contours, но здесь он объединяет все контуры в один. Это я не хочу. Я не думаю, что для этого есть какая-то функция в opencv, но вы можете предложить алгоритм для этого. Мое приложение выглядит так:

Я обнаруживаю руки, поэтому я использовал алгоритм определения кожи, чтобы определить их, но так как моя кожа не белая и, возможно, из-за условий осветления иногда контуры ломаются в локте. Поэтому я хочу, чтобы соседние контуры были связаны, но не все (потому что обе мои руки будут в контурах). (Под руками я имею в виду от плеча до ладони.)

Более того, я думаю, что с помощью некоторого обнаружения краев я получу границы моих рук и обнаружу, если часть этого участка внутри этой границы обнаружена как кожа, тогда вся область в пределах этой границы будет определена как кожа, но я не уверен, как это сделать часть.

Любая помощь будет оценена. заранее спасибо

Образец изображения:

введите описание изображения здесь

В этом изображении я хочу соединить точки (8 соединений), которые имеют расстояние менее 40 пикселей, так что я получу левую руку в виде единого контура

Моя цель - получить только контур руки (мне плевать на любой другой регион)

Roney Island
источник
под руками вы на самом деле имеете в виду руки. Не могли бы вы просто отрегулировать оттенок, который вы используете для определения кожи в соответствии с вашим цветом кожи?
waspinator
Я сделал это, и это дает прекрасный результат (когда моя кожа освещена). Таким образом, в течение вечера, как показано В любом случае, я подумал, что может быть какой-то метод для подключения соседних блобов
Рони Айленд
Связано с dsp.stackexchange.com/q/2588/590
Крис
Добро пожаловать в стек обмена. SE это не форум! Это не ответ на вопрос. Если у вас есть вопрос по этому вопросу - оставьте это как комментарий.
Дипан Мехта
как вы обнаруживаете кожу?
nkint

Ответы:

10

Если вас не беспокоит скорость или точный контур руки, ниже приведено простое решение.

Метод такой: вы берете каждый контур и находите расстояние до других контуров. Если расстояние меньше 50, они рядом, и вы соединяете их вместе. Если нет, они ставятся как разные.

Таким образом, проверка расстояния до каждого контура занимает много времени. Занимает несколько секунд. Так что вы никак не можете сделать это в реальном времени.

Кроме того, чтобы соединить контуры, я поместил их в один набор и нарисовал выпуклый корпус для этого набора. Таким образом, в результате вы получаете выпуклую оболочку руки, а не настоящую руку.

Ниже мой кусок кода в OpenCV-Python. Я не пошел на какую-либо оптимизацию, просто хотел, чтобы она работала, вот и все. Если это решит вашу проблему, перейдите к оптимизации.

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)

Ниже приведены результаты, которые я получил:

введите описание изображения здесь

введите описание изображения здесь

Абид Рахман К
источник
Как это можно сделать в C ++? У меня есть до части findContour, но после этого я не могу получить контуры, чтобы обернуть в многоугольник, как показано выше (в отличие от ограничивающего прямоугольника).
Элионардо Фелисиано
Я ценю ваш подход и пытался применить его к моему делу, но, к сожалению, он очень медленный на Python (хотя у моего ноутбука Core i7QM и 8 ГБ ОЗУ). Я использую MSER для обнаружения регионов, и теперь мне нужно определить, какая пара регионов является «смежной», я попробовал ваш алгоритм с порогом 10 ... Требуются годы, чтобы вернуть соседние регионы.
Джим Рейнор
4

Чтобы исправить проблему с подключением, вы можете попробовать закрыть операцию:

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

Я сомневаюсь, что это даст результаты, которые вы хотите, но вы можете попробовать.

bjoernz
источник
2

Похоже, вы «чрезмерно сегментируете» свое изображение. Морфологические операции, как предположил bjnoernz, помогли бы. В частности, подход водораздела должен быть ближе к тому, что вы хотите, чем просто проверка расстояния (как в примере с Python выше). См. Http://cmm.ensmp.fr/~beucher/wtshed.html .

непосвященный
источник