我有2张图像,它们具有相同的形状,但排列在不同的地方。我想正确匹配这些图像。
获取最小值作为匹配。
def modified_hausdorff(A,B):
D = cdist(A,B) #euclidean distance
fhd = np.mean(np.min(D,axis=0))
rhd = np.mean(np.min(D,axis=1))
return max(fhd,rhd)
源图片。
目标图片。
答案 0 :(得分:1)
这是一项双向任务。
<强> 1。翻译强>
对于每个轮廓,计算其moment。然后对于该轮廓中的每个点,将其转换为即contour.point[i] = contour.point[i] - contour.moment[i]
的时刻。这会将所有轮廓点移动到原点。
PS:您需要跟踪每个轮廓的生成时刻,因为它将在下一部分中使用
<强> 2。旋转强>
使用新翻译的点,计算他们的rotated rect。这将为您提供旋转角度。根据此角度,您可能希望计算要旋转此轮廓的新角度; this answer会有所帮助。
获得新角度后,计算rotation matrix。请记住,您的中心位于原点,即(0, 0)
。在计算旋转矩阵时,我没有考虑缩放(这是金字塔发挥作用的地方)因此我通过了1。
PS:您需要跟踪每个轮廓的生成矩阵,因为它将在下一节中使用
使用此矩阵,您可以继续旋转轮廓中的每个点,如图here * 所示。
完成所有这些操作后,您可以继续计算Hausdorff距离并找到超过设定阈值的轮廓。
第一部分完成的所有操作都必须撤消,以便我们在相机Feed中绘制有效的轮廓。
<强> 1。旋转强>
回想一下,每个检测到的轮廓产生一个旋转矩阵。您想要撤消有效轮廓的旋转。只需使用inverse matrix执行相同的旋转。
For each valid contour and corresponding matrix
inverse_matrix = matrix[i].inv(cv2.DECOMP_SVD)
Use * to rotate the points but with inverse_matrix as parameter
PS:计算逆时,如果生成的矩阵不是正方形,则会失败。即使原始矩阵是非正方形,cv2.DECOMP_SVD
也会生成逆矩阵。
<强> 2。翻译强>
将有效轮廓点向后旋转,您只需撤消先前执行的转换。而不是减去,只需将时刻添加到每个点。
现在可以继续将这些轮廓绘制到相机输入中。
这是图像金字塔发挥作用。
您所要做的就是按照固定的尺寸/比例调整模板图像的大小,直到您想要的次数(称为图层)。教程发现here很好地解释了如何在OpenCV中执行此操作。
毫无疑问,您选择调整图像大小和图层数量的值将会对您的计划的稳健性起到重要作用。
模板图片操作
Create a pyramid consisting of n layers
For each layer in n
Find contours
Translate the contour points
Rotate the contour points
此操作只应执行一次,并且只存储旋转点的结果。
相机Feed操作
假设
让每个级别的模板图像的旋转轮廓存储在templ_contours
中。所以如果我说templ_contours[0]
,这将给我金字塔等级0的旋转轮廓。
让图片的翻译,旋转的轮廓和时刻分别存储在transCont
,rotCont
和moment
中。
image_contours = Find Contours
for each contour detected in image
moment = calculate moment
for each point in image_contours
transCont.thisPoint = forward_translate(image_contours.thisPoint)
rotCont.thisPoint = forward_rotate(transCont.thisPoint)
for each contour_layer in templ_contours
for each contour in rotCont
calculate Hausdorff Distance
valid_contours = contours_passing_distance_threshold
for each point in valid_contours
valid_point = backward_rotate(valid_point)
for each point in valid_contours
valid_point = backward_translate(valid_point)
drawContours(valid_contours, image)
起初可能会有点混乱,特别是跟踪每个轮廓的相应时刻和旋转矩阵,但是一旦你理解了正在发生的事情,它实际上是一个非常简单的算法。