凸包:在数学中,在实向量空间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)