转载请注明详细地址
本文简单介绍了图像常见几何特征的概念以及求解方法
本文介绍了Python和opencv求解几何特征的常用方法
目录
一、获得轮廓
二、面积
1、cv2.connectedComponentsWithStats()
stats参数解析
2、cv2.contourArea()函数
三、周长
1、cv2.arcLength(contours[0],True)
四、细长度
1、绘制外接矩形(cv2.rectangle()函数)
2、得到矩形的角点坐标和长宽cv2.boundingRect()函数
3、求解最小外接矩形(cv2.minAreaRect()函数)
4、绘制最小外接矩形:cv2.boxPoints()函数和cv2.polylines()函数
step1 角点坐标获得cv2.boxPoints()
step2 将角点坐标全部转换为整数
step3 依次连接起来cv2.polylines()
5、细长度的计算
五、区间占空比
六、重心
七、图像上添加文字cv2.putText()函数
八、完整代码
一、获得轮廓
在进行轮廓几何特征的提取之前,首先要做的就是得到轮廓,得到轮廓常用的函数有:
cv2.findcontours()
contours, hierarchy = cv.findContours( image, mode, method[, contours[, hierarchy[, offset]]] )
参数1:源图像
参数2:轮廓的检索方式,这篇文章主要讲解这个参数
参数3:一般用 cv.CHAIN_APPROX_SIMPLE,就表示用尽可能少的像素点表示轮廓
contours:图像轮廓坐标,是一个列表
hierarchy:[Next, Previous, First Child, Parent],文中有详细解释
具体可见:《【图像处理】——Python+opencv实现二值图像的轮廓边界跟踪以及轮廓面积周长的求解(findcontours函数和contourArea函数)》
二、面积
一般指的是轮廓内所包含的所有像素的个数,但是为了方便计算加快计算的速度,一般会采样一种近似地方法去估算面积,常用的有将轮廓近似成一个多边形,然后进行求解,在Python—opencv中,有两种方式可以对轮廓面积进行求解
1、cv2.connectedComponentsWithStats()
具体看见:《【图像处理】——实现二值图像的轮廓边界跟踪以及轮廓面积周长的求解(connectedComponentsWithStats()函数和connectedComponents()函数)》
retval, labels, stats, centroids =
connectedComponentsWithStats(image, labels=None, stats=None, centroids=None, connectivity=None, ltype=None)
这个函数返回值stats中的最后一个元素就是轮廓区域的面积,通过提取可以得到
stats参数解析
stats参数是一个numpy数组,每一行代表一个轮廓,每一行固定为5个参数,依次是:
CC_STAT_LEFT 组件的左上角点像素点坐标的X位置
CC_STAT_TOP 组件的左上角点像素点坐标的Y位置
CC_STAT_WIDTH 组件外接矩形的宽度,计算方式为用每一个轮廓中最右边的点的x坐标减去最左边的点的x坐标
CC_STAT_HEIGHT 组件外接矩形的高度,计算方式为用每一个轮廓中最下边的点的y坐标减去最上边的点的y坐标
CC_STAT_AREA 当前连通组件的面积(像素单位),这里统计的是轮廓所包含的像素点的个数,不是外接矩形的面积
所以stats的shape为:mx5,m是轮廓的个数,第一个轮廓是背景轮廓,前两个参数为0,0
2、cv2.contourArea()函数
这个函数可以针对每一个轮廓求得近似的面积,返回的是一个常数
contours,layer_num = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#面积1
area1 = cv2.contourArea(contours[0])
#面积2
_,labels,stats,centroids = cv2.connectedComponentsWithStats(binary)
area2 = stats[1][4]
三、周长
周长指的是轮廓的像素点总数,也常用各个像素点的中点连线的多边形长度进行度量,若是对角线方向则为根号2个像素格,否则为1个像素格长度
常用的函数为:
length = cv2.arcLength(contours[0],True)
1、cv2.arcLength(contours[0],True)
arcLength(contour, closed)
参数解析:
contour:轮廓点集
closed:表明轮廓是否封闭与否,TRUE则表示封闭,FALSE则表示非封闭
#周长
length = cv2.arcLength(contours[0],True)
四、细长度
细长度表征图像中待识别区域的紧凑性,它的计算是由待识别区域的最小外接矩形得到,该最小外接矩形长轴和短轴的比值即为区域的细长度,表达式如下:
1、绘制外接矩形(cv2.rectangle()函数)
这个函数的原理就是取轮廓点集最上面的点、最下面的点、最左边的点和最右边的点作为外接矩形的四个点的坐标,这个矩形不一定是最小外接矩形,其边与坐标轴平行或者垂直
img = rectangle(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
img:进行绘制矩形的图像
pt1:矩形左上角角点坐标,是一个元组
pt2:矩形右下角角点坐标,是一个元组
color:绘制矩形的颜色,一般通过RGB的表示方式(R.G,B)
thickness:绘制矩形的线宽,如果是负数,则将轮廓区域进行填充
linetype:线型
rect = cv2.rectangle(rgb1,(stats[1][0],stats[1][1]),(stats[1][0]+stats[1][2],stats[1][1]+stats[1][3]),(0,0,255),2)
2、得到矩形的角点坐标和长宽cv2.boundingRect()函数
#得到外接矩形的左上角点坐标和长宽
x,y,h,w = cv2.boundingRect(contours[0])
3、求解最小外接矩形(cv2.minAreaRect()函数)
实际上求解最小外接矩形的方法就是将图像沿逆时针或者顺时针按照一定的度数进行旋转,每旋转一次,求解一次轮廓的外接矩形的面积,记录每次旋转的度数、左上角点坐标、矩形长宽,根据三角函数可以得到旋转后的角点坐标,等旋转完成一周后,取面积最小的即为最小外接矩形
img = minAreaRect(points)
points:就是轮廓的点集
返回的是:img = ((x,y),(h,w),α)
#返回的是一个元组,第一个元素是左上角点坐标组成的元组,第二个元素是矩形宽高组成的元组,第三个是旋转的角度
min_rect = cv2.minAreaRect(contours[0])
4、绘制最小外接矩形:cv2.boxPoints()函数和cv2.polylines()函数
要想在原图像中绘制出最小外接矩形,则需要知道矩形的四个角点坐标,这四个角点坐标实际上就是在旋转的时候记录后进行根据记录的角度和三角函数进行转换过来的,知道后通过绘制多边形的方法将点依次连接即可
step1 角点坐标获得cv2.boxPoints()
box = cv2.boxPoints(min_rect)#返回的是一个numpy矩阵
min_rect:是一个元组
返回的是由角点组成的numpy矩阵
step2 将角点坐标全部转换为整数
box = np.int0(box)#将其转换为整数,否则会报错
step3 依次连接起来cv2.polylines()
img = polylines(img, pts, isClosed, color, thickness=None, lineType=None, shift=None)
参数解析:
img:绘制矩形的图像
pts:装有矩形角点的点阵(一般是由boxpoints()函数得到)
isClosed:指定绘制的矩形是否为封闭的,TRUE表示封闭
color:绘制矩形的线条的颜色,用元组表示
thickness:线宽
linetype:线型
返回参数:返回的是绘制后的图像
min_rect_img = cv2.polylines(rgb2,[box],True,(0,255,0),2)
5、细长度的计算
直接利用得到的数据即可获得
#最小外接矩形
min_rect = cv2.minAreaRect(contours[0])#返回的是一个元组,第一个元素是左上角点坐标组成的元组,第二个元素是矩形宽高组成的元组,第三个是旋转的角度
#细长度
min_rect_h = min_rect[1][0]
min_rect_w = min_rect[1][1]
e = min_rect_h/min_rect_w
五、区间占空比
区间占空比指的是将轮廓区域的面积除以外接矩形的面积,这里的外接矩形一般指的是最小外接矩形
#区域占空比(轮廓区域面积除以最小外接矩形面积)
ee = area1/min_rect_area
六、重心
重心描述的是待识别区域的全局特性,反映的是区域内部像素点的分布。如果待识别区域是均匀的,密度设为1则区域的重心同时也是是区域的几何中心,它可通过计算所有像素点的平均值得到
七、图像上添加文字cv2.putText()函数
cv2.putText(img, text, org, fontFace, fontScale, color, thickness=None, lineType=None, bottomLeftOrigin=None)
img:需要添加文字的图像
text:添加的文字内容,一定是字符串
org:相当于一个文本框的左上角点坐标
fontface:文字大小
fontscale:文字比例
color:文字颜色,以元组的形式表达
thickness:线宽
linetype:线型
text2 = "width:" + str(int(min_rect[1][1]))
cv2.putText(rgb1,text1, (10, 30), 3, 0.5, (0, 255, 0), 1, cv2.LINE_AA, 0)
八、完整代码
import cv2
import numpy as np
rgb1 = cv2.imread('roi.png')
rgb2 = cv2.imread('roi.png')
rgb3 = cv2.imread('roi.png')
img = cv2.imread('roi.png',0)
ret,binary = cv2.threshold(img,100,255,cv2.THRESH_BINARY)
contours,layer_num = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
#面积1
area1 = cv2.contourArea(contours[0])
#面积2
_,labels,stats,centroids = cv2.connectedComponentsWithStats(binary)
area2 = stats[1][4]
#周长
length = cv2.arcLength(contours[0],True)
#得到外接矩形的左上角点坐标和长宽
x,y,w,h = cv2.boundingRect(contours[0])
#外接矩形
rect = cv2.rectangle(rgb1,(stats[1][0],stats[1][1]),(stats[1][0]+stats[1][2],stats[1][1]+stats[1][3]),(0,0,255),2)
rect_area = w*h
#最小外接矩形
min_rect = cv2.minAreaRect(contours[0])#返回的是一个元组,第一个元素是左上角点坐标组成的元组,第二个元素是矩形宽高组成的元组,第三个是旋转的角度
# print(min_rect)((530.0443725585938, 113.73445892333984), (40.497230529785156, 137.21890258789062), -86.68222045898438)
#获得最小外接矩形的四个角点坐标
box = cv2.boxPoints(min_rect)#返回的是一个numpy矩阵
min_rect_area = cv2.contourArea(box)
#绘制最小外接矩形,通过多边形绘制的方法进行绘制
box = np.int0(box)#将其转换为整数,否则会报错
min_rect_img = cv2.polylines(rgb2,[box],True,(0,255,0),2)
#细长度
min_rect_h = min_rect[1][0]
min_rect_w = min_rect[1][1]
e = min_rect_h/min_rect_w
#区域占空比(轮廓区域面积除以最小外接矩形面积)
ee = area1/min_rect_area
#质心
centroid = centroids[0]
text1 = 'height:'+ str(int(min_rect[1][0]))
text2 = "width:" + str(int(min_rect[1][1]))
cv2.putText(rgb1,text1, (10, 30), 3, 0.5, (0, 255, 0), 1, cv2.LINE_AA, 0)
cv2.putText(rgb1,text2, (10, 60), 3, 0.5, (0, 255, 0), 1, cv2.LINE_AA, 0)
cv2.imshow('rect',rect)
cv2.imshow('min_rect',min_rect_img)
cv2.imshow('rgb',rgb3)
cv2.waitKey(0)
print(area1)
print(area2)
print(rect_area)
print(min_rect_area)
print(e)
print(ee)
print(centroid)