Approximating polygons is a high approximation of contours, but sometimes, we wish to simplify it using the convex hull of a polygon.
A convex hull is similar to an approximating polygon, except that it is the outermost "convex" polygon of an object. A convex hull refers to a polygon that completely contains the original contour and is only composed of points on the contour. Every part of the convex hull is convex, that is, the straight line connecting any two points in the convex hull is inside the convex hull. In a convex hull, the interior angle of any three consecutive points is less than 180°.
For example, in Figure 12-25, the outermost polygon is the convex hull of the manipulator, and the part between the edge of the manipulator and the convex hull is called a convex defect (Convexity Defect), which can be used to deal with gesture recognition and other issues .
get convex hull
OpenCV provides 函数 cv2.convexHull()
a convex hull for obtaining contours. The syntax of this function is:
hull = cv2.convexHull( points[, clockwise[, returnPoints]] )
The return value hull in the formula is the corner point of the convex hull.
The parameters in the formula are as follows:
- points: outline.
- clockwise: Boolean value. When the value is True, the corners of the convex hull will be arranged in a clockwise direction; when the value is False, the corners of the convex hull will be arranged in a counterclockwise direction.
- returnPoints: Boolean value. The default value is True, the function returns the x/y axis coordinates of the corners of the convex hull; when it is False, the function returns the indices of the corners of the convex hull in the contour.
Example: observe the use of the parameter returnPoints in the function cv2.convexHull()
code show as below:
import cv2
o = cv2.imread('contours.bmp')
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
hull = cv2.convexHull(contours[0]) # 返回坐标值
print("returnPoints 为默认值 True 时返回值 hull 的值:\n",hull)
hull2 = cv2.convexHull(contours[0], returnPoints=False) # 返回索引值
print("returnPoints 为 False 时返回值 hull 的值:\n",hull2)
operation result:
returnPoints 为默认值 True 时返回值 hull 的值:
[[[195 270]]
[[195 383]]
[[ 79 383]]
[[ 79 270]]]
returnPoints 为 False 时返回值 hull 的值:
[[3]
[2]
[1]
[0]]
As can be seen from the program running results, the optional parameter returnPoints of the function cv2.convexHull():
- When the default value is True, the function returns the x/y axis coordinates of the corner points of the convex hull. In this example, the coordinate values of 4 contours are returned.
- When False, the function returns the indices of the corner points of the convex hull in the contour, in this case 4 index values of the contour are returned.
Example 2: Use the function cv2.convexHull() to obtain the convex hull of a contour.
code show as below:
import cv2
# --------------读取并绘制原始图像------------------
o = cv2.imread('hand.bmp')
cv2.imshow("original",o)
# --------------提取轮廓------------------
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
# --------------寻找凸包,得到凸包的角点------------------
hull = cv2.convexHull(contours[0])
# --------------绘制凸包------------------
cv2.polylines(o, [hull], True, (0, 255, 0), 2)
# --------------显示凸包------------------
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()
convex defect
The part between the convex hull and the contour is called a convex defect. cv2.convexityDefects()
Get convex defects using function in OpenCV . Its syntax format is as follows:
convexityDefects = cv2.convexityDefects( contour, convexhull )
The return value convexityDefects in the formula is the set of convex defect points. It is an array, and each row contains the values [start point, end point, point on the contour furthest from the convex hull, approximate distance from the furthest point to the convex hull].
需要注意的是,返回结果中[起点,终点,轮廓上距离凸包最远的点
, the approximate distance from the furthest point to the convex hull] The first three values are the indexes of the contour points, so you need to find them in the contour points.
The parameters in the formula are as follows:
- contour is the contour.
- convexhull is the convex hull.
It should be noted that when calculating convex defects with cv2.convexityDefects(), the convex hull should be used as a parameter. When looking for the convex hull, the value of the parameter returnPoints of the function cv2.convexHull() used must be False.
In order to allow everyone to observe the convex defect point set more intuitively, we try to display the convex defect point set in a picture. The implementation method is to connect the starting point and the ending point with a line, and draw a circle at the farthest point. Below we use an example to demonstrate the above operation.
Example 2: Calculate convex defects using the function cv2.convexityDefects().
code show as below:
import cv2
#----------------原图--------------------------
img = cv2.imread('hand.bmp')
cv2.imshow('original',img)
#----------------构造轮廓--------------------------
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255,0)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_TREE,
cv2.CHAIN_APPROX_SIMPLE)
#----------------凸包--------------------------
cnt = contours[0]
hull = cv2.convexHull(cnt,returnPoints = False)
defects = cv2.convexityDefects(cnt,hull)
print("defects=\n",defects)
#----------------构造凸缺陷--------------------------
for i in range(defects.shape[0]):
s,e,f,d = defects[i,0]
start = tuple(cnt[s][0])
end = tuple(cnt[e][0])
far = tuple(cnt[f][0])
cv2.line(img,start,end,[0,0,255],2)
cv2.circle(img,far,5,[255,0,0],-1)
#----------------显示结果,释放图像--------------------------
cv2.imshow('result',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
operation result:
defects=
[[[ 0 102 51 21878]]
[[ 103 184 150 13876]]
[[ 185 233 220 4168]]
[[ 233 238 235 256]]
[[ 238 240 239 247]]
[[ 240 294 255 2715]]
[[ 294 302 295 281]]
[[ 302 304 303 217]]
[[ 305 311 306 114]]
[[ 311 385 342 13666]]
[[ 385 389 386 395]]
[[ 389 489 435 20327]]]
Determine if the contour is convex
In OpenCV, the function cv2.isContourConvex() can be used to determine whether the contour is convex, and its syntax format is:
retval = cv2.isContourConvex( contour )
In the formula:
- The return value retval is a Boolean value. When True, the contour is convex; otherwise, it is not.
- The parameter contour is the contour to be judged.
Example: Use the function cv2.isContourConvex() to determine whether the contour is convex.
code show as below:
import cv2
o = cv2.imread('hand.bmp')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE)
#--------------凸包----------------------
image1=o.copy()
hull = cv2.convexHull(contours[0])
cv2.polylines(image1, [hull], True, (0, 255, 0), 2)
print("使用函数 cv2.convexHull()构造的多边形是否是凸形的:",
cv2.isContourConvex(hull))
cv2.imshow("result1",image1)
#------------逼近多边形--------------------
image2=o.copy()
epsilon = 0.01*cv2.arcLength(contours[0],True)
approx = cv2.approxPolyDP(contours[0],epsilon,True)
image2=cv2.drawContours(image2,[approx],0,(0,0,255),2)
print("使用函数 cv2.approxPolyDP()构造的多边形是否是凸形的:",
cv2.isContourConvex(approx))
cv2.imshow("result2",image2)
#------------释放窗口--------------------
cv2.waitKey()
cv2.destroyAllWindows()
operation result:
使用函数 cv2.convexHull()构造的多边形是否是凸形的: True
使用函数 cv2.approxPolyDP()构造的多边形是否是凸形的: False
From the above running results, it can be seen that:
- After using the function cv2.contourContourConvex() to construct a convex hull, use the function cv2.isContourContourConvex() to judge the drawn convex hull. The return value is True, indicating that the contour is convex.
- After using the function cv2.approxPolyDP() to construct the approximate polygon, use the function cv2.isContourConvex() to judge the drawn approximate polygon, and the return value is False, indicating that the contour (polygon) is not convex.
The original picture of the experiment: