OpenCV中如何计算凸性缺陷?
How Convexity Defect is calculated in OpenCV?
OpenCV函数convexityDefects()
计算轮廓凸缺陷的算法是什么?
请描述并说明算法的高级操作及其输入和输出。
基于documentation,输入的是两个坐标列表:
contour
定义原始轮廓(下图红色)
convexhull
定义对应于该轮廓的凸包(下图中的蓝色)
algorithm 的工作方式如下:
如果轮廓或船体包含3个或更少的点,那么轮廓总是凸的,不需要更多的处理。该算法确保以相同的方向访问轮廓和外壳。
N.B.: 在进一步的解释中,我假设它们处于同一方向,并忽略有关浮点深度表示的细节作为整数。
然后对每一对相邻的包点(H[i]
,H[i+1]
),定义凸包的一条边,计算轮廓上每个点到边缘的距离C[n]
介于 H[i]
和 H[i+1]
之间(不包括 C[n] == H[i+1]
)。如果距离大于零,则存在缺陷。当存在缺陷时,记录i
、i+1
、最大距离和最大值所在轮廓点的索引(n
)。
距离的计算方式如下:
dx0 = H[i+1].x - H[i].x
dy0 = H[i+1].y - H[i].y
if (dx0 is 0) and (dy0 is 0) then
scale = 0
else
scale = 1 / sqrt(dx0 * dx0 + dy0 * dy0)
dx = C[n].x - H[i].x
dy = C[n].y - H[i].y
distance = abs(-dy0 * dx + dx0 * dy) * scale
用向量表示可能更容易:
C
:从H[i]
到C[n]
的缺陷向量
H
:从H[i]
到H[i+1]
的船体边缘矢量
H_rot
:船体边缘矢量H
旋转90度
U_rot
:H_rot
方向的单位向量
H
分量是 [dx0, dy0]
,所以旋转 90 度得到 [-dy0, dx0]
.
scale
用于从H_rot
中求出U_rot
,但是因为除法是比乘法更昂贵的计算,逆被用作优化。它也在循环之前预先计算 C[n]
以避免重新计算每次迭代。
|H
| = sqrt(dx0 * dx0 + dy0 * dy0)
U_rot
= H_rot
/ |H
| = H_rot
* scale
然后,C
和U_rot
之间的点积给出到缺陷点的垂直距离到船体边缘,abs()
用于在任何方向上获得正幅度。
distance = abs(U_rot
.C
) = abs(-dy0 * dx + dx0 * dy) * 规模
在上图所示的场景中,在第一次迭代中,边缘由 H[0]
和 H[1]
定义。检查此边缘的轮廓点是 C[0]
、C[1]
和 C[2]
(因为 C[3] == H[1]
)。
C[1]
和 C[2]
处存在缺陷。 C[1]
处的缺陷最深,所以算法会记录(0, 1, 1, 50)
.
下一条边由H[1]
和H[2]
定义,对应的轮廓点C[3]
。没有缺陷,所以没有记录。
下一条边由H[2]
和H[3]
定义,对应的轮廓点C[4]
。没有缺陷,所以没有记录。
从 C[5] == H[3]
开始,可以忽略最后一个轮廓点 -- 那里不能有缺陷。
OpenCV函数convexityDefects()
计算轮廓凸缺陷的算法是什么?
请描述并说明算法的高级操作及其输入和输出。
基于documentation,输入的是两个坐标列表:
contour
定义原始轮廓(下图红色)convexhull
定义对应于该轮廓的凸包(下图中的蓝色)
algorithm 的工作方式如下:
如果轮廓或船体包含3个或更少的点,那么轮廓总是凸的,不需要更多的处理。该算法确保以相同的方向访问轮廓和外壳。
N.B.: 在进一步的解释中,我假设它们处于同一方向,并忽略有关浮点深度表示的细节作为整数。
然后对每一对相邻的包点(H[i]
,H[i+1]
),定义凸包的一条边,计算轮廓上每个点到边缘的距离C[n]
介于 H[i]
和 H[i+1]
之间(不包括 C[n] == H[i+1]
)。如果距离大于零,则存在缺陷。当存在缺陷时,记录i
、i+1
、最大距离和最大值所在轮廓点的索引(n
)。
距离的计算方式如下:
dx0 = H[i+1].x - H[i].x
dy0 = H[i+1].y - H[i].y
if (dx0 is 0) and (dy0 is 0) then
scale = 0
else
scale = 1 / sqrt(dx0 * dx0 + dy0 * dy0)
dx = C[n].x - H[i].x
dy = C[n].y - H[i].y
distance = abs(-dy0 * dx + dx0 * dy) * scale
用向量表示可能更容易:
C
:从H[i]
到C[n]
的缺陷向量
H
:从H[i]
到H[i+1]
的船体边缘矢量
H_rot
:船体边缘矢量H
旋转90度U_rot
:H_rot
方向的单位向量
H
分量是 [dx0, dy0]
,所以旋转 90 度得到 [-dy0, dx0]
.
scale
用于从H_rot
中求出U_rot
,但是因为除法是比乘法更昂贵的计算,逆被用作优化。它也在循环之前预先计算 C[n]
以避免重新计算每次迭代。
|H
| = sqrt(dx0 * dx0 + dy0 * dy0)
U_rot
= H_rot
/ |H
| = H_rot
* scale
然后,C
和U_rot
之间的点积给出到缺陷点的垂直距离到船体边缘,abs()
用于在任何方向上获得正幅度。
distance = abs(U_rot
.C
) = abs(-dy0 * dx + dx0 * dy) * 规模
在上图所示的场景中,在第一次迭代中,边缘由 H[0]
和 H[1]
定义。检查此边缘的轮廓点是 C[0]
、C[1]
和 C[2]
(因为 C[3] == H[1]
)。
C[1]
和 C[2]
处存在缺陷。 C[1]
处的缺陷最深,所以算法会记录(0, 1, 1, 50)
.
下一条边由H[1]
和H[2]
定义,对应的轮廓点C[3]
。没有缺陷,所以没有记录。
下一条边由H[2]
和H[3]
定义,对应的轮廓点C[4]
。没有缺陷,所以没有记录。
从 C[5] == H[3]
开始,可以忽略最后一个轮廓点 -- 那里不能有缺陷。