简体   繁体   English

如何在 OpenCV 中找到两个轮廓之间的最近点

[英]How to find nearest points between two contours in OpenCV

For two contours c1 and c2, How do I find the nearest points between the contours.对于两个轮廓 c1 和 c2,如何找到轮廓之间最近的点。

A solution could be to iterate over all the points, get euclidian distance and go with the minimum euclidian distance but that would have huge time complexity.一个解决方案可能是遍历所有点,获得欧几里得距离和 go 最小欧几里得距离,但这将具有巨大的时间复杂度。

I have used cv2.findContours to find the contours.我使用cv2.findContours来查找轮廓。

contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

在此处输入图像描述

I'd like to find the two points shown on blue between the two contours.我想找到两个轮廓之间以蓝色显示的两个点。

Using a double for loop can be time consuming.使用双for循环可能很耗时。 Based on Giovanni Tardini's comment and an answer from CodeReview.stackexchange , you can just iterate through the points of a single contour.根据 Giovanni Tardini 的评论和CodeReview.stackexchange 的回答,您可以迭代单个轮廓的点。 I have not done speed comparison, but the original author claims vectorization speeds up computation.我没有做过速度比较,但是原作者声称矢量化可以加快计算速度。

Code:代码:

# To draw the final result
img = cv2.imread('image_path', 1)

# grayscale to binary conversion -> find contours
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th = cv2.threshold(gray,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
contours, hierarchy = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# store the 2 contours
c1, c2 = contours[0], contours[1]

# Function to index and distance of the point closest to an array of points
# borrowed shamelessly from: https://codereview.stackexchange.com/questions/28207/finding-the-closest-point-to-a-list-of-points
def closest_point(point, array):
     diff = array - point
     distance = np.einsum('ij,ij->i', diff, diff)
     return np.argmin(distance), distance

# initialize some variables
min_dist = np.max(th.shape)
chosen_point_c2 = None
chosen_point_c1 = None

# iterate through each point in contour c1
for point in c1:
    t = point[0][0], point[0][1]
    index, dist = closest_point(t, c2[:,0])
    if dist[index] < min_dist :
        min_dist = dist[index]
        chosen_point_c2 = c2[index]
        chosen_point_c1 = t     

# draw the two points and save
cv2.circle(img,(chosen_point_c1), 4, (0,255,255), -1)
cv2.circle(img,tuple(chosen_point_c2[0]), 4, (0,255,255), -1)
cv2.imshow('Result', img)    

Result:结果:

在此处输入图像描述

(I used the image shared in the question. If you look closely, you will see a yellow dot in each of the contour.) (我使用了问题中共享的图像。如果仔细观察,您会在每个轮廓中看到一个黄点。)

This link provides other solutions of which KDtrees (proposed by Daniel F) is an option. 此链接提供了其他解决方案,其中 KDtrees(由 Daniel F 提出)是一个选项。

Can't test due to no test data in the question, but this should get you going.由于问题中没有测试数据而无法测试,但这应该会让你继续。 Using KDTree s.使用KDTree s。

from scipy.spatial import KDTree

max_distance = 10 #tune to your data

kd_trees = [KDTree(c) for c in contours]
out = {}
for i, j in zip(np.triu_indices((len(contours),)*2, 1)):
    coo = kd_trees[i].sparse_distance_matrix(kd_trees[j], 
                                             max_distance = max_distance,
                                             output_type = 'coo_matrix')
    ix = np.argmin(coo.data)
    out[(i, j)] = [contours[i][coo.row[ix]], contours[j][coo.col[ix]]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM