基于人工智能实验平台的OpenCV对象检测与矩阵轮廓分析

1 实验目的

熟悉opencv读入图片,高斯去噪,二值化,绘制目标矩形边框。

2 实验设备

安装了python和pychrm的电脑一台。

3 实验内容

包含图片的导入、绘制矩形、显示图片。

4实验原理

opencv中轮廓特征包括:如面积,周长,质心,边界框等。
我们将图像二值化后,用findContours函数就可以很方便的找出图像的轮廓信息,循环遍历每一个信息点,cv2.boundingRect()函数再计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的,cv2.rectangle函数画出来即可。
函数原型:

findContours( image,mode,   method, Point offset=Point())

第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像。

第二个参数:mode 检索轮廓的模式,若取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略。
取值二:CV_RETR_LIST 检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓。
取值三:CV_RETR_CCOMP 检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层。两个等级关系:顶层为连通域的外围边界,次层为孔的内层边界。
取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内层轮廓还可以继续包含内嵌轮廓。
第三个参数:int型的method,定义轮廓的近似方法:
取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内。
取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours向量内,拐点与拐点之间直线段上的信息点不予保留
取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法。

findContours函数最终会返回三个值,第一个是图像,其中找到的轮廓信息都会被保存到第二个参数contours列表里,其中存储这图像中的所有轮廓;第三个参数是(轮廓的)层析结构,这是一个ndarray,其中的元素个数和轮廓个数相同,对于每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为负数。每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。

绘制轮廓
函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。

import numpy as np 
import cv2 
im = cv2.imread('../images/numb.png') 
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY) 
ret,thresh = cv2.threshold(imgray,127,255,0) 
image, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

绘制独立轮廓,如第四个轮廓。

img = cv2.drawContour(img, contours, -1, (0,255,0), 3) 

但是大多数时候,下面的方法更有用。

img = cv2.drawContours(img, contours, 3, (0,255,0), 3)

在理解层级关系前,需要对数据结构有一定的了解。
例如下图(将树结构和轮廓级联系在一起),A和B为同级,可以认为B是A的后一个轮廓,A是B的前一个轮廓;C和D为A的子树,E和F为B的子树,可以认为C和D为A的子轮廓,A为C和D的父轮廓。

在这里插入图片描述
树结构

为了更加直观,可以利用实际的图像进一步说明轮廓层级的关系,例如以下的源图,一共有4个轮廓,序号分别为0 1 2 3。
特别地,序号在程序中findcontours函数会自动标记,也是轮廓检索的序号,n个轮廓其检索序号从 0 到 n-1 。

在这里插入图片描述
轮廓层级关系

经分析,0号轮廓没有同级轮廓,有两个子级轮廓1和3,没有父级轮廓,所以其轮廓继承关系向量hierarchy为[-1 -1 1-1],-1表示无对应的关系,1表示0号轮廓的一个子轮廓的序号为1号。
同样地,1号轮廓有同级轮廓3(认为是后一个轮廓,那么无前一个轮廓),也有子级轮廓2,也有父级轮廓0,所以其轮廓继承关系向量hierarchy为[3 -1 2 0]。
同样地,2号轮廓没有同级轮廓,也没有子级轮廓,但是有父级轮廓1,所以其轮廓继承关系向量hierarchy为[-1 -1 -1 1]。
同样地,3号轮廓有同级轮廓(其前一个轮廓为1,无后一个轮廓),没有子级轮廓,但是有父级轮廓0,所以其轮廓继承关系向量hierarchy为[-1 1 -1 0]。
以上的轮廓层级关系,可以用树结构表示如下:
在这里插入图片描述

子级和父级关系

找出图像的轮廓信息后,可以用下面的方法筛选特定的轮廓(比如我们需要轮廓面积大于某个值,还有周长等)
cv2.boundingRect()函数获取轮廓的范围,即左上角原点,以及他的高和宽,这样就能得到外接矩形。然后可以用cv2.rectangle()方法画出矩形轮廓。
cv2.minAreaRect函数是找出面积最小的矩形,需要传入轮廓的信息点。
cv2.minEnclosingCircle函数计算最小包围圆的中心和半径。
cv2.minAreaRect©函数计算出面积最小的矩形。

图像的矩可以帮助我们计算图像的质心,面积等。首先,使用findContour()函数找出图像中包含的轮廓信息,然后对所有轮廓进行遍历,并计算每一个轮廓的力矩(Moment),就可以得出物体的质心位置。Moments函数可以求出轮廓的几何矩空间矩的公式为:
在这里插入图片描述
可以知道,对于01二值化的图像,m00即为轮廓的面积,中心矩的公式为:
在这里插入图片描述

其中中心Center(x0,y0):
在这里插入图片描述
在这里插入图片描述
这样就可以求得质心,最后画出质心和轮廓。列如:

import cv2import numpy as npimg = cv2.imread('star.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0] 
M = cv2.moments(cnt)
print(M)

根据这些矩的值,我们可以计算出对象的重心:
在这里插入图片描述
在这里插入图片描述

cx = int(M['m10']/M['m00']) 
cy = int(M['m01']/M['m00'])

Opencv 提供Rectangle用来绘制一个矩形框的,通常用在图片的标记上。Rectangle函数原型:

rectangle(img, pt1, pt2, color, shift)

参数:
img:源图像
pt1,pt2为左上角坐标和右下坐标
color为颜色
shift为线的大小(像素为单位)

5实验步骤

打开pycharm。我们右击相应的文件目录,选择new—>点击Python File,然后输入新建的文件名,点击确定,相应的.py文件就建好了,可以进行编写代码了。

ipoert cv2
import numpy as np

读取图片。

image = cv2.imread("..\images\\numb.png")

将源图像转为灰度图像。

gray = cv2.cvtColor(image,cv.COLOR_BGR2GRAY)

获取二值化图像(掩模图像)。

ret,binary=cv2.threshold(gray,0,255,cv.THRESH_OTSU|cv.THRESH_BINARY_INV)  

窗口显示源图像和掩模图像。

cv2.imshow("binary image",binary)
cv2.imshow(" image",image)

findContours找出图像轮廓,这里我们使用cv.RETR_EXTERNAL参数只检测外围轮廓和cv.CHAIN_APPROX_SIMPLE只保存拐点信息,就像只要四个点一样就能画出一个矩形。

i,contours,hireachy= cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

遍历每一个轮廓。contourArea函数获取每个轮廓的面积。boundingRect函数获取轮廓的外接矩形。

for i,contour in enumerate(contours):
        area = cv.contourArea(contour)      
        x,y,w,h = cv.boundingRect(contour) 

获取外接矩形宽高比,可以起到一定的筛选作。

rate = min(w,h)/max(w,h)

求轮廓的几何距离。

mm = cv.moments(contour)

求出质心。

cx = mm['m10']/mm['m00']
cy = mm['m01']/mm['m00']

根据几何距获取的中心点,画出中心圆。

cv.circle(image,(np.int(cx),np.int(cy)),2,(0,255,255),-1)

根据轮廓外接矩形返回数据,画出外接矩形。

cv.rectangle(image,(x,y),(x+w,y+h),(0,0,255),2)

显示绘制轮廓的图像。

cv2.imshow("contours", img)
cv2.waitKey()
cv2.destroyAllWindows()

可以看到效果如下。
在这里插入图片描述

当然,你也可以绘制外接圆,用minEnclosingCircle函数计算最小包围圆的中心和半径,然后画处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值