Подгонка четырехугольника (тетрагона) к капле

После применения различных методов фильтрации и сегментации я получаю такое изображение:

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

У меня есть доступ к некоторым функциям обнаружения контуров, которые возвращают список точек на краю этого объекта или возвращают подогнанный многоугольник (хотя и со многими ребрами, гораздо больше, чем 4). Мне нужен способ подогнать четырехугольник к этой форме, поскольку я знаю, что это передняя сторона обувной коробки, которая должна быть четырехугольником. Из-за вида в перспективе параллельность не сохраняется, поэтому на данный момент у меня нет ограничений, и мне нужны только четыре отрезка, охватывающих этот прямоугольник.

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

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

Какие-нибудь известные подходы к решению такой проблемы?


person Mehdi    schedule 14.12.2016    source источник


Ответы (1)


Я рекомендую следующие шаги:

  1. threshold() изображение
  2. dilate() изображение — это удалит черную линию, разделяющую верхнюю и нижнюю части, а также более темные артефакты в нижней части
  3. findContours() с помощью настройки для извлечения только внешних контуров(RETR_EXTERNAL) и упрощения выход (CHAIN_APPROX_SIMPLE)
  4. обработайте контуры дальше

Шаг 1: порог

# threshold image
ret,thresh = cv2.threshold(img,127,255,0)
cv2.imshow('threshold ',thresh)

порог

Шаг 2: расширение

# dilate thresholded image - merges top/bottom 
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=3)
cv2.imshow('threshold dilated',dilated)

расширить

Шаг 3. Найдите контуры

# find contours
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, 0, (255,255,255), 3)
print "contours:",len(contours)
print "largest contour has ",len(contours[0]),"points"

контуры

Обратите внимание, что сначала расширение, а затем использование простых внешних контуров дает вам нужную форму, но это все еще довольно сложно (содержит 279 точек).

С этого момента вы можете продолжать обрабатывать контурные объекты. Есть несколько доступных вариантов, таких как:

a: получение мин. прямоугольник области

# minAreaRect
rect = cv2.minAreaRect(contours[0])
box = cv2.cv.BoxPoints(rect)
box = np.int0(box)
cv2.drawContours(img,[box],0,(255,255,255),3)

minAreaRect

Может быть полезно, но не совсем то, что вам нужно.

b: выпуклая оболочка

# convexHull
hull = cv2.convexHull(contours[0])
cv2.drawContours(img, [hull], 0, (255,255,255), 3)
print "convex hull has ",len(hull),"points"

выпуклый корпус

Лучше, но у вас все еще есть 22 точки, и это не так сложно, как могло бы быть.

c: упростить контуры

# simplify contours

epsilon = 0.1*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
cv2.drawContours(img, [approx], 0, (255,255,255), 3)
print "simplified contour has",len(approx),"points"

примерноПолиДП

Вероятно, это то, что вам нужно: всего 4 балла. Вы можете поиграть со значением эпсилон, если вам нужно больше очков.

Имейте в виду, теперь у вас есть четырехугольник, но картинка сплющена: нет информации о перспективе/3D-повороте.

Полный листинг кода OpenCV Python (комментируйте/раскомментируйте по мере необходимости, используйте ссылку для адаптации к С++/java/и т. д.):

import numpy as np
import cv2

img = cv2.imread('XwzWQ.png',0)

# threshold image
ret,thresh = cv2.threshold(img,127,255,0)
cv2.imshow('threshold ',thresh)

# dilate thresholded image - merges top/bottom 
kernel = np.ones((3,3), np.uint8)
dilated = cv2.dilate(thresh, kernel, iterations=3)
cv2.imshow('threshold dilated',dilated)

# find contours
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
# cv2.drawContours(img, contours, 0, (255,255,255), 3)
print "contours:",len(contours)
print "largest contour has ",len(contours[0]),"points"

# minAreaRect
# rect = cv2.minAreaRect(contours[0])
# box = cv2.cv.BoxPoints(rect)
# box = np.int0(box)
# cv2.drawContours(img,[box],0,(255,255,255),3)

# convexHull
# hull = cv2.convexHull(contours[0])
# cv2.drawContours(img, [hull], 0, (255,255,255), 3)
# print "convex hull has ",len(hull),"points"

# simplify contours
epsilon = 0.1*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
cv2.drawContours(img, [approx], 0, (255,255,255), 3)
print "simplified contour has",len(approx),"points"


# display output 
cv2.imshow('image',img)

cv2.waitKey(0)
cv2.destroyAllWindows()
person George Profenza    schedule 14.12.2016