Объединение нескольких контуров в opencvPython

Программы на Python
Anonymous
Объединение нескольких контуров в opencv

Сообщение Anonymous »

Я использую OpenCV-python версии 4.13.0.92 для расчета выпуклых оболочек, окружающих наборы точек. Я хочу использовать функцию convexityDefect, чтобы найти максимальное расстояние между корпусом и контуром, который он окружает. Когда я вызываю функцию convexityDefect, я получаю следующую ошибку:

Код: Выделить всё


cv2.error: OpenCV(4.13.0) /io/opencv/modules/imgproc/src/convhull.cpp:397: error: (-5:Bad argument) The convex hull indices are not monotonous, which can be in the case when the input contour contains self-intersections in function 'convexityDefects'
Это можно воспроизвести с помощью следующего кода:

Код: Выделить всё

import cv2
import numpy as np
import scipy.spatial.distance as sdistance
import scipy.cluster.hierarchy as hcluster
import math

def get_distance_between_vectors(v1, v2) -> float:
distances = []
for x1 in v1:
for x2 in v2:
# each pair of points is wrapped in an extra list
distances.append(math.dist(x1[0], x2[0]))

return min(distances)

def fast_distance_matrix(contours) -> np.array:
hull_list = []
for i in range(len(contours)):
hull = cv2.convexHull(contours[i])
hull_list.append(hull)

num_contours = len(contours)
distance_matrix = np.zeros((num_contours, num_contours))
for i in range(num_contours):
ci = hull_list[i]
for j in range(num_contours):
cj = hull_list[j]
distance_matrix[i][j] = get_distance_between_vectors(ci, cj)
return distance_matrix

def hierarchical_clustering(contours, threshold: int):
distance_matrix = fast_distance_matrix(contours)
condensed = sdistance.squareform(distance_matrix)
if len(condensed) == 0:
return []
linked = hcluster.linkage(condensed)
clusters = hcluster.fcluster(linked, threshold, criterion='distance')
contours_dict = {}
for i in range(len(contours)):
l = clusters[i]
if not l in contours_dict:
contours_dict[l] = []
contours_dict[l].append(contours[i])

hull_list = []
defect_list = []
for k,v in contours_dict.items():
cont = np.vstack([v[i] for i in range(len(v))])
hull = cv2.convexHull(cont, returnPoints=False)
defects = cv2.convexityDefects(cont, hull)
hull_list.append(hull)
defect_list.append(defects)
return hull_list, defect_list

def get_contours(image_path: str, low_threshold: int, high_threshold: int):
image = cv2.imread(image_path)

src_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
src_gray = cv2.blur(src_gray, (3, 3))

canny_output = cv2.Canny(src_gray, low_threshold, high_threshold)

contours, _ = cv2.findContours(canny_output, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

return contours, canny_output.shape

def get_convex_hull(image_path: str, low_threshold: int, high_threshold: int, clustering_threshold: int):
contours, shape = get_contours(image_path, low_threshold, high_threshold)

hull_list, defect_list = hierarchical_clustering(contours, clustering_threshold)
blank_image = np.full((shape[0], shape[1], 3), 255, dtype=np.uint8)
for i in range(len(hull_list)):
color = (0,0,255)
# draw hulls
cv2.drawContours(blank_image, hull_list, i, color, thickness=-1)
print(f'convexity defect: {defect_list[i]}')

if __name__ == '__main__':
get_convex_hull('9.png', 100, 200, 40)
Я считаю, что проблема связана с тем, что я объединяю несколько контуров, просто складывая их вместе. Я объединил несколько контуров в один массив, потому что хочу нарисовать вокруг них выпуклую оболочку. Общая цель состоит в том, чтобы взять рисунок, нарисованный человеком, который примерно обозначает область, заполнить пробелы и т. д., чтобы получить более удобное для компьютера представление отмеченной области. Я пытаюсь сделать это, рисуя выпуклую оболочку вокруг наборов контуров, которые я сгруппировал вместе, но это плохое приближение для определенных форм. Я пытаюсь количественно оценить, насколько это проблема в моем наборе данных, вычисляя дефект выпуклости между выпуклой оболочкой и фактическими контурами.
Правильно ли я, что мне нужно объединить несколько контуров в один, чтобы получить выпуклую оболочку и дефект выпуклости для набора контуров? Если да, то как лучше всего их объединить, учитывая, что они могут пересекаться, а могут и не пересекаться?
Изображение

Вернуться в «Python»