凸包:在数学中,在实向量空间V中的一组点X的凸包或凸包络是包含X的最小凸集。来自Wikipedia。通俗的来说就是包围一组散点的最小凸边形。
在scipy.spatial 和opencv 分别有计算凸包的函数,scipy中convexHull输入的参数可以是m*2的点坐标。其返回值的属性.verticess是所有凸轮廓点在散点(m*2)中的索引值。
注意:属性.verticess绘制出来的轮廓点是按照逆时针排序
在opencv 中,cv2.convexHull可以得到凸包的坐标值/凸包在轮廓的索引值(取决于参数returnPoints=True/Fasle)。同时opencv中convexityDefects函数可计算凸缺陷,即使图像中所有的凹点。其函数返回值是m*4的数组,第一列是起点,第二列是终点,第三列是最远点,第四列是最远点到凸轮廓的距离。
图像的质心----利用图像矩,opencv--- cv2.moments(轮廓)
其中 cx = int(M['m10']/M['m00']);y = int(M['m01']/M['m00'])
Scipy 计算得到的凸包见下图:
Opencv计算凸包:
本次测试图为:
注意:本测试图阈值化的时候注意反转图像,牢记找轮廓是针对的“白像素”
反转和不反转后的图
寻找轮廓函数详解:
cv2.findContours(thresh,0,2)
参数:第一个输入的是binary_image
第二个参数:RetrievalModes
cv::RETR_EXTERNAL = 0, 外部轮廓用的比较多
cv::RETR_LIST= 1,
cv::RETR_CCOMP= 2,
cv::RETR_TREE= 3,
cv::RETR_FLOODFILL= 4
第三个参数:ContourApproximationModes
cv::CHAIN_APPROX_NONE = 1, 轮廓所有点
cv::CHAIN_APPROX_SIMPLE = 2, 只返回四角的点
cv::CHAIN_APPROX_TC89_L1= 3,
cv::CHAIN_APPROX_TC89_KCOS= 4
轮廓寻找完成后,找出轮廓面积最大的轮廓作为计算凸包的当前轮廓。注意:cnt_max的大小是m*1*2
最终结果图:----凸缺陷检测出来的点(红色点),有一处错误.
# -*- coding: utf-8 -*-
import cv2
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial import ConvexHull
##########scipy 凸包################
points = np.random.rand(30, 2)
hull = ConvexHull(points)
plt.plot(points[:,0], points[:,1], 'o')
# hull.vertices 得到凸轮廓坐标的索引值,逆时针画
hull1=hull.vertices.tolist()#要闭合必须再回到起点[0]
hull1.append(hull1[0])
plt.plot(points[hull1,0], points[hull1,1], 'r--^',lw=2)
for i in range(len(hull1)-1):
plt.text(points[hull1[i],0], points[hull1[i],1],str(i),fontsize=20)
########cv2#########
im=cv2.imread(r"C:\Users\Y\Desktop\star.jpg")
im_gray=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
_,thresh=cv2.threshold(im_gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
_,cnts,h=cv2.findContours(thresh,0,1)
area=[]
for c in cnts:
area.append(cv2.contourArea(c))
cnt_max=cnts[np.argsort(-np.array(area))[0]]
hull_cv=cv2.convexHull(cnt_max)
cv2.drawContours(im,[hull_cv],0,(0,0,255),2)
#####寻找凸缺陷********
hull_index=cv2.convexHull(cnt_max,returnPoints = False)
defects = cv2.convexityDefects(cnt_max,hull_index)
for i in range(defects.shape[0]):
s,e,f,d=defects[i,0]
far = tuple(cnt_max[f][0])
cv2.circle(im,far,5,(0,0,255),-1)
##########确定重心###########
#计算图像矩
M=cv2.moments(cnt_max)
cx=M["m10"]/M["m00"]
cy=M["m01"]/M["m00"]
cv2.circle(im,(np.float32(cx),np.float32(cy)),5,(255,0,0),-1)
cv2.putText(im,"center",(np.float32(cx),np.float32(cy)),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),3)
cv2.imshow("tu",im),cv2.waitKey(0)