找到轮廓之后,怎么测量弧长面积多边形拟合,中心距等等
原点矩就是几何图形的重心;
中心矩反映几何图形上点的分布规律,相当于将坐标原点移到重心上,此时的原点矩。
二、相关函数
1、几何计算
(1)cv.contourArea(contour) 获取每个轮廓面积
(2)cv.boundingRect(contour) 获取轮廓的外接矩形
矩形边框(Bounding Rectangle)是说,用一个最小的矩形,把找到的形状包起来。还有一个带旋转的矩形,面积会更小,效果见下图
contour轮廓点的位置信息,是一个二值图;
返回四个值,分别是x,y,w,h;
x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
然后利用cv2.rectangle(img, (x,y), (x+w,y+h), (0,255,0), 2)画出矩形
参数解释
第一个参数:img是原图
第二个参数:(x,y)是矩阵的左上点坐标
第三个参数:(x+w,y+h)是矩阵的右下点坐标
第四个参数:(
0,255,0)是画线对应的rgb颜色
第五个参数:2是所画的线的宽度
(3)cv.moments(contour) 求取轮廓的图像矩
(4)cv.arcLength(contour,True) 求取轮廓的周长,指定闭合
2、approPolyDP轮廓逼近方法
def approxPolyDP(curve, epsilon, closed, approxCurve=None): # real signature unknown; restored from __doc__
第一个参数curve:输入的点集,直接使用轮廓点集contour
第二个参数epsilon:指定的精度,也即是原始曲线与近似曲线之间的最大距离
第三个参数closed:若为true,则说明近似曲线是闭合的,反之,若为false,则断开
第四个参数approxCurve:输出的点集,当前点集是能最小包容指定点集的。画出来即是一个多边形
-
输出的点集,当前点集是能最小包容指定点集的。画出来即是一个多边形
-
approxCurve = cv.approxPolyDP(contour,4,True) #4是与阈值的间隔大小,越小越易找出,True是是否找闭合图像 print(approxCurve) #打印每个轮廓的特征点 print(approxCurve.shape) #打印该点集的shape,第一个数是代表了点的个数,也就是边长连接逼近数
[[[138 208]] [[138 234]] [[265 234]] [[264 207]]] (4, 1, 2) #矩形,四个点逼近图像 [[[124 154]] [[124 183]] [[325 183]] [[325 154]]] (4, 1, 2) [[[ 61 125]] [[ 9 279]] [[114 280]]] (3, 1, 2) #3是三角形 [[[123 102]] [[111 118]] [[117 128]] [[129 131]] [[139 124]] [[141 114]] [[134 104]]] (7, 1, 2) #7,8,9都是圆形类 [[[303 78]] [[291 87]] [[289 99]] [[298 111]] [[310 113]] [[322 105]] [[324 91]] [[314 79]]] (8, 1, 2) [[[308 28]] [[298 35]] [[295 48]] [[303 59]] [[314 61]] [[325 54]] [[327 39]]] (7, 1, 2) [[[198 21]] [[165 38]] [[153 75]] [[170 107]] [[185 116]] [[210 119]] [[244 100]] [[254 63]] [[235 31]]] (9, 1, 2) [[[ 27 21]] [[ 27 87]] [[101 87]] [[101 21]]] (4, 1, 2) [[[418 15]] [[416 190]] [[454 192]] [[455 16]]] (4, 1, 2) [[[359 14]] [[346 58]] [[345 138]] [[356 190]] [[363 192]] [[374 156]] [[376 82]] [[369 24]]] (8, 1, 2)
三、获取图像外接矩形boundingRect和几何矩moments
1 import cv2 as cv 2 import numpy as np 3 4 def meaure(image): 5 gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) 6 #全局自适应阈值 参数0可改为任意数字但不起作用,gray是灰度图,像素值最大是255,所以写255 7 ret , binary = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU) 8 print('threshold value',ret) 9 cv.imshow('binary image',binary) 10 outimage,contours,hirachy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) 11 for i , contour in enumerate(contours): 12 area = cv.contourArea(contour) #获取每个轮廓的面积 13 x,y,w,h = cv.boundingRect(contour) 14 rate = min(w,h)/max(w,h) #获得外接矩形的宽高比,可以起到一定的筛选作用 15 print('rectangle rate: %s'%rate) 16 mm = cv.moments(contour) #求取轮廓的几何矩 17 print(type(mm)) 18 print(mm) 19 cx = mm['m10']/mm['m00'] #重心坐标 20 cy = mm['m01']/mm['m00'] #重心坐标 21 cv.circle(image,(np.int(cx),np.int(cy)),2,(0,255,255),-1) #半径是2,-1表示填充,画个圆点 22 cv.rectangle(image,(x,y),(x+w,y+h),(0,0,255),2) 23 print('contour area',area) 24 cv.imshow('measured_image',image) 25 img = cv.imread('contours.png') 26 cv.imshow('input_image',img) 27 meaure(img) 28 cv.waitKey(0) 29 cv.destroyAllWindows()
1 threshold value 55.0 2 rectangle rate: 0.7071290944123314 3 <class 'dict'> 4 {'nu21': 0.0, 'm00': 189588.0, 'mu02': 2116370844.0, 'm21': 3174612636832.0, 'm10': 49672056.0, 'mu12': 0.0, 'm20': 17253329548.0, 'm11': 9139658304.0, 'mu11': 0.0, 'nu03': 0.0, 'nu20': 0.11794171220400729, 'mu20': 4239250876.0, 'nu30': 0.0, 'nu11': 0.0, 'mu03': 0.0, 'nu12': 0.0, 'mu21': 0.0, 'm01': 34884192.0, 'm30': 6741739800600.0, 'm03': 2349275910240.0, 'mu30': 0.0, 'm02': 8535062172.0, 'nu02': 0.05888030888030888, 'm12': 2236186289064.0} 5 contour area 189588.0 6 rectangle rate: 0.2328767123287671 7 <class 'dict'> 8 {'nu21': 0.00012337159954486592, 'm00': 4638.5, 'mu02': 395646.24861073494, 'm21': 63361445232.433334, 'm10': 1068926.6666666665, 'mu12': -41552.704846039414, 'm20': 254451863.5833333, 'm11': 266174910.2083333, 'mu11': -657.9870841801167, 'nu03': -5.5731840906128935e-08, 'nu20': 0.3774605687931838, 'mu20': 8121321.660058409, 'nu30': 4.147758615136351e-05, 'nu11': -3.058174388962807e-05, 'mu03': -81.66712951660156, 'nu12': -2.835668094870454e-05, 'mu21': 180783.62808203697, 'm01': 1155042.1666666665, 'm30': 62380696103.3, 'm03': 71916234563.05, 'mu30': 60779.53545379639, 'm02': 288015007.4166666, 'nu02': 0.01838873822421945, 'm12': 66371716951.6} 9 contour area 4638.5 10 rectangle rate: 0.15555555555555556 11 <class 'dict'> 12 {'nu21': 3.8371793569830693e-05, 'm00': 2678.5, 'mu02': 89193.07461163402, 'm21': 36282586368.316666, 'm10': 616088.3333333333, 'mu12': 2005.2493966259062, 'm20': 145711489.91666666, 'm11': 153407428.875, 'mu11': 322.1481836140156, 'nu03': -8.185951318082867e-08, 'nu20': 0.5580295542656055, 'mu20': 4003506.1685074866, 'nu30': -3.5402871905680954e-06, 'nu11': 4.490269272561691e-05, 'mu03': -30.394729614257812, 'nu12': 5.40056587103005e-06, 'mu21': 14247.584001541138, 'm01': 666951.3333333333, 'm30': 35357167196.200005, 'm03': 41418876646.700005, 'mu30': -1314.5212783813477, 'm02': 166161278.5833333, 'nu02': 0.012432195574127027, 'm12': 38219324350.316666} 13 contour area 2678.5 14 rectangle rate: 0.1572052401746725 15 <class 'dict'> 16 {'nu21': -5.0325287139101995e-16, 'm00': 7978.0, 'mu02': 814035.5000000596, 'm21': 106182743120.5, 'm10': 2042368.0, 'mu12': -1.5228986740112305e-05, 'm20': 557389727.6666666, 'm11': 389071104.0, 'mu11': 5.960464477539063e-08, 'nu03': -2.68401531408544e-15, 'nu20': 0.5427233689755546, 'mu20': 34543519.66666669, 'nu30': 5.36803062817088e-15, 'nu11': 9.364660558983717e-16, 'mu03': -1.52587890625e-05, 'nu12': -2.6787730966751167e-15, 'mu21': -2.86102294921875e-06, 'm01': 1519809.0, 'm30': 160378052352.0, 'm03': 55619469850.5, 'mu30': 3.0517578125e-05, 'm02': 290337650.0, 'nu02': 0.012789550494243657, 'm12': 74326438400.0} 17 contour area 7978.0 18 rectangle rate: 0.6910112359550562 19 <class 'dict'> 20 {'nu21': 0.012773324262564329, 'm00': 11273.5, 'mu02': 20750773.8061198, 'm21': 17397875250.05, 'm10': 823135.1666666666, 'mu12': -351678.8153767586, 'm20': 67251828.58333333, 'm11': 210835642.2083333, 'mu11': -3017.880377650261, 'nu03': -0.03671091137116082, 'nu20': 0.05626305607377813, 'mu20': 7150573.196509272, 'nu30': -8.927214266694102e-06, 'nu11': -2.3745673003470692e-05, 'mu03': -495384129.6209717, 'nu12': -2.606149258816397e-05, 'mu21': 172365705.06794214, 'm01': 2887605.5, 'm30': 5954474083.55, 'm03': 204900612520.65002, 'mu30': -120465.55381679535, 'm02': 760384917.9166666, 'nu02': 0.1632738968112304, 'm12': 55517645149.51666} 21 contour area 11273.5 22 rectangle rate: 1.0 23 <class 'dict'> 24 {'nu21': -0.00012249343654428105, 'm00': 937.0, 'mu02': 71058.39887940139, 'm21': 2608467731.1666665, 'm10': 135997.16666666666, 'mu12': 5936.621304638684, 'm20': 19807560.666666664, 'm11': 17909800.0, 'mu11': -243.08831376582384, 'nu03': 0.00011619106641937682, 'nu20': 0.07834979461427596, 'mu20': 68788.69082770124, 'nu30': -0.00022638241437502373, 'nu11': -0.00027687573680371845, 'mu03': 3122.63853597641, 'nu12': 0.00022089728041426173, 'mu21': -3292.0149297602475, 'm01': 123397.5, 'm30': 2894852254.65, 'm03': 2168205818.75, 'mu30': -6084.034451007843, 'm02': 16321798.0, 'nu02': 0.08093497478772188, 'm12': 2368904858.633333} 25 contour area 937.0 26 rectangle rate: 0.9767441860465116 27 <class 'dict'> 28 {'nu21': 6.394444079962859e-05, 'm00': 1337.5, 'mu02': 143608.10929387622, 'm21': 17579855687.9, 'm10': 466171.8333333333, 'mu12': 2721.5148126482964, 'm20': 162620703.91666666, 'm11': 50394767.125, 'mu11': -5.531905494630337, 'nu03': -6.349478218615885e-05, 'nu20': 0.07899706959873945, 'mu20': 141318.35153687, 'nu30': -4.34086448861369e-05, 'nu11': -3.0923395201008077e-06, 'mu03': -4154.057602882385, 'nu12': 4.159836159363943e-05, 'mu21': 4183.47589077428, 'm01': 144588.3333333333, 'm30': 56778276750.950005, 'm03': 1736279429.2, 'mu30': -2839.9500732421875, 'm02': 15774102.416666666, 'nu02': 0.0802770459848727, 'm12': 5497902267.733334} 29 contour area 1337.5 30 rectangle rate: 1.0 31 <class 'dict'> 32 {'nu21': 0.00017643873342657596, 'm00': 1171.5, 'mu02': 108556.00897472398, 'm21': 7454198465.65, 'm10': 414346.8333333333, 'mu12': 11056.098625324667, 'm20': 146660034.25, 'm11': 21059689.791666664, 'mu11': 35.98085905984044, 'nu03': -0.00019657490281580083, 'nu20': 0.08019241081548555, 'mu20': 110057.04696020484, 'nu30': -0.0002541097288689007, 'nu11': 2.621723834062283e-05, 'mu03': -9233.870977252722, 'nu12': 0.00023536732516071226, 'mu21': 8287.998500894755, 'm01': 59542.83333333333, 'm30': 51949902144.450005, 'm03': 170360064.45000002, 'mu30': -11936.500625610352, 'm02': 3134888.9166666665, 'nu02': 0.07909868844053526, 'm12': 1108790894.15} 33 contour area 1171.5 34 rectangle rate: 0.9827586206896551 35 <class 'dict'> 36 {'nu21': -5.9617117618475176e-05, 'm00': 10188.0, 'mu02': 8080978.927321911, 'm21': 44361328538.15, 'm10': 2369605.833333333, 'mu12': 65883.69320464134, 'm20': 559585560.1666666, 'm11': 187859907.5833333, 'mu11': -6170.492562055588, 'nu03': 5.789763072450438e-05, 'nu20': 0.08135089273197578, 'mu20': 8443843.895822525, 'nu30': -6.649191036488463e-06, 'nu11': -5.944864503802395e-05, 'mu03': 606573.080696106, 'nu12': 6.288623516809079e-06, 'mu21': -624587.5391366482, 'm01': 807720.6666666666, 'm30': 134080649922.85, 'm03': 6999607777.200001, 'mu30': -69661.23208618164, 'm02': 72118344.0, 'nu02': 0.0778549269736214, 'm12': 16772943834.616667} 37 contour area 10188.0 38 rectangle rate: 0.9069767441860465 39 <class 'dict'> 40 {'nu21': 2.5029581296177077e-06, 'm00': 6468.0, 'mu02': 3195020.3257575743, 'm21': 2470652874.1666665, 'm10': 485015.3333333333, 'mu12': -51429.50591498613, 'm20': 40173096.0, 'm11': 29828671.666666664, 'mu11': -296.2417027428746, 'nu03': 3.7404301111953477e-06, 'nu20': 0.09091174159972219, 'mu20': 3803294.891706176, 'nu30': -7.103004931735946e-07, 'nu11': -7.081188784375375e-06, 'mu03': 12584.80737566948, 'nu12': -1.528577011835907e-05, 'mu21': 8421.289796680212, 'm01': 397789.0, 'm30': 3582848603.8, 'm03': 2094094606.5, 'mu30': -2389.830746650696, 'm02': 27659474.333333332, 'nu02': 0.07637190134652665, 'm12': 2074010642.2666667} 41 contour area 6468.0 42 rectangle rate: 0.22885572139303484 43 <class 'dict'> 44 {'nu21': 5.8846255461310086e-06, 'm00': 8996.5, 'mu02': 29965362.62111345, 'm21': 256564644068.48334, 'm10': 4439805.333333333, 'mu12': 212314.99474525452, 'm20': 2192577070.9166665, 'm11': 519527440.5416666, 'mu11': -3233.247374713421, 'nu03': -2.842289825086851e-06, 'nu20': 0.018743698111458488, 'mu20': 1517058.9236574173, 'nu30': -1.4152503746804512e-07, 'nu11': -3.9947698646528944e-05, 'mu03': -21819.87815475464, 'nu12': 2.765646741919632e-05, 'mu21': 45175.48184904456, 'm01': 1052739.3333333333, 'm30': 1083542072586.7001, 'm03': 24934332010.7, 'mu30': -1086.46875, 'm02': 153153280.5833333, 'nu02': 0.37023064958903834, 'm12': 75581154283.31667} 45 contour area 8996.5 46 rectangle rate: 0.19117647058823528 47 <class 'dict'> 48 {'nu21': 4.9640674350614795e-06, 'm00': 6161.5, 'mu02': 16228397.796561554, 'm21': 120405497566.23334, 'm10': 2520171.833333333, 'mu12': 189011.2604341507, 'm20': 1031361607.9166666, 'm11': 294213998.7916666, 'mu11': 1439.863492667675, 'nu03': -0.00013813884205259537, 'nu20': 0.014827896369745835, 'mu20': 562927.4773755074, 'nu30': -2.1518071719240386e-06, 'nu11': 3.7926993287653485e-05, 'mu03': -411653.62416648865, 'nu12': 6.342661674397237e-05, 'mu21': 14792.916459165514, 'm01': 719312.3333333333, 'm30': 422307195112.95, 'm03': 15486711827.2, 'mu30': -6412.3834228515625, 'm02': 100203117.08333333, 'nu02': 0.42746714354095977, 'm12': 40985524515.4} 49 contour area 6161.5
四、多边形逼近approxPolyDP
1 import cv2 as cv 2 import numpy as np 3 4 def measure(image): 5 #变成灰度图像,通过大律法得到二值图像 6 gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) 7 ret , binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) 8 cv.imshow('binary image',binary) 9 #将二值图像变成bgr,因为后面要用各种颜色画轮廓,所以需要变成BGR 10 dst = cv.cvtColor(binary,cv.COLOR_GRAY2BGR) 11 cv.imshow('binary_to_bgr',dst) 12 #寻找轮廓 13 outimage,contours,hireachy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) 14 for i,contour in enumerate(contours): 15 mm = cv.moments(contour) #求的是每个轮廓的几何矩 16 cx = mm['m10']/mm['m00'] #重心坐标x 17 cy = mm['m01']/mm['m00'] #重心坐标y 18 cv.circle(dst,(np.int(cx),np.int(cy)),2,(0,255,255),-1) #画重心点,填充的方法 19 #多边形逼近 20 #arg: 21 # 每个轮廓的位置信息contour 22 # 4是与阈值的间隔大小,越小就越容易找出,True是 是否找闭合图像 23 approxcure = cv.approxPolyDP(contour,4,True) 24 print(approxcure.shape) #每个轮廓的信息 25 26 if approxcure.shape[0] >= 7: #>=7 就都是圆了 27 cv.drawContours(dst,contours,i,(0,0,255),2) 28 elif approxcure.shape[0] == 4: #4说明有四个点,是矩形;3是三个点,三角形 29 cv.drawContours(dst,contours,i,(0,255,0),2) 30 else: 31 cv.drawContours(dst,contours,i,(255,0,0),2) 32 cv.imshow('measure_image',dst) 33 34 img = cv.imread('contours.png') 35 cv.imshow('input_image',img) 36 measure(img) 37 cv.waitKey(0) 38 cv.destroyAllWindows()
1 (4, 1, 2) 2 (4, 1, 2) 3 (4, 1, 2) 4 (3, 1, 2) 5 (7, 1, 2) 6 (8, 1, 2) 7 (8, 1, 2) 8 (13, 1, 2) 9 (4, 1, 2) 10 (4, 1, 2) 11 (9, 1, 2) 12 (4, 1, 2)