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])。如果距离大于零,则存在缺陷。当存在缺陷时,记录ii+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_rotH_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

然后,CU_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] 开始,可以忽略最后一个轮廓点 -- 那里不能有缺陷。