What is the algorithm used in OpenCV function convexityDefects()
to calculate the convexity defects of a contour?
Please, describe and illustrate the high-level operation of the algorithm, along with its inputs and outputs.
What is the algorithm used in OpenCV function convexityDefects()
to calculate the convexity defects of a contour?
Please, describe and illustrate the high-level operation of the algorithm, along with its inputs and outputs.
Based on the documentation, the input are two lists of coordinates:
contour
defining the original contour (red on the image below)convexhull
defining the convex hull corresponding to that contour (blue on the image below)The algorithm works in the following manner:
If the contour or the hull contain 3 or less points, then the contour is always convex, and no more processing is needed. The algorithm assures that both the contour and the hull are accessed in the same orientation.
N.B.: In further explanation I assume they are in the same orientation, and ignore the details regarding representation of the floating point depth as an integer.
Then for each pair of adjacent hull points (
H[i]
,H[i+1]
), defining one edge of the convex hull, calculate the distance from the edge for each point on the contourC[n]
that lies betweenH[i]
andH[i+1]
(excludingC[n] == H[i+1]
). If the distance is greater than zero, then a defect is present. When a defect is present, recordi
,i+1
, the maximum distance and the index (n
) of the contour point where the maximum located.Distance is calculated in the following manner:
It may be easier to visualize in terms of vectors:
C
: defect vector fromH[i]
toC[n]
H
: hull edge vector fromH[i]
toH[i+1]
H_rot
: hull edge vectorH
rotated 90 degreesU_rot
: unit vector in direction ofH_rot
H
components are[dx0, dy0]
, so rotating 90 degrees gives[-dy0, dx0]
.scale
is used to findU_rot
fromH_rot
, but because divisions are more computationally expensive than multiplications, the inverse is used as an optimization. It's also pre-calculated before the loop overC[n]
to avoid recomputing each iteration.|
H
| = sqrt(dx0 * dx0 + dy0 * dy0)U_rot
=H_rot
/ |H
| =H_rot
*scale
Then, a dot product between
C
andU_rot
gives the perpendicular distance from the defect point to the hull edge, andabs()
is used to get a positive magnitude in any orientation.distance = abs(
U_rot
.C
) = abs(-dy0 * dx + dx0 * dy) * scaleIn the scenario depicted on the above image, in first iteration, the edge is defined by
H[0]
andH[1]
. The contour points tho examine for this edge areC[0]
,C[1]
, andC[2]
(sinceC[3] == H[1]
).There are defects at
C[1]
andC[2]
. The defect atC[1]
is the deepest, so the algorithm will record(0, 1, 1, 50)
.The next edge is defined by
H[1]
andH[2]
, and corresponding contour pointC[3]
. No defect is present, so nothing is recorded.The next edge is defined by
H[2]
andH[3]
, and corresponding contour pointC[4]
. No defect is present, so nothing is recorded.Since
C[5] == H[3]
, the last contour point can be ignored -- there can't be a defect there.