实验五 图像分割、表示与特征提取
一.实验目的
掌握图像分割,表示及特征提取的方法
二. 实验要求
·理解什么是轮廓
·学习找轮廓,绘制轮廓等,了解函数:cv2.?ndContours(),cv2.drawContours() ·查找轮廓的不同特征,例如面积,周长,重心,边界框等,以及学习轮廓的相关函数 2.1 什么是轮廓
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。 ? 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测。
? 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。
? 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。
让我们看看如何在一个二值图像中查找轮廓:函数 cv2.?ndContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python 列表,其中存储这图像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。 2.2 如何绘制轮廓
函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。在一幅图像上绘制轮廓: import cv2
img = cv2.imread('leaf.jpg',0)
ret, thresh = cv2.threshold(img,120,255,0)
contours,hierarchy=cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img,contours,-1,(0,0,200),3)
cv2.imshow(\cv2.waitKey(0) 显示结果:
2.3轮廓特征 2.3.1矩
图像的矩可以帮助我们计算图像的质心,面积等。函数 cv2.moments() 会将计算得到的矩以一个字典的形式返回。如下: import cv2
import numpy as np
img = cv2.imread('leaf.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
轮廓的面积可以使用函数 cv2.contourArea() 计算得到,也可以使用矩(0 阶矩),M['m00']。
area = cv2.contourArea(cnt)
轮廓的周长可以使用函数 cv2.arcLength() 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。 perimeter = cv2.arcLength(cnt,True) 2.4边界矩形
有两类边界矩形。直边界矩形 一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查 找得到。(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高。
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)//注意取消返回值 显示结果:
旋转的边界矩形 这个边界矩形是面积最小的,因为它考虑了对象的旋转。用到的函数为 cv2.minAreaRect()。返回的是一个 Box2D 结构,其中包含矩形左上角角点的坐标(x,y),矩形的宽和高(w,h),以及旋转角度。但是要绘制这个矩形需要矩形的 4 个角点,可以通过函数 cv2.boxPoints() 获得。
rect = cv2.minAreaRect(cnt) box = cv2.cv.BoxPoints(rect) box = np.int0(box)
cv2.drawContours(im,[box],0,(0,0,255),2)#注意去掉返回值
PS:尝试自行完成旋转的边界矩形的实验 2.5最小外接圆
函数 cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆。它是所有能够包括对象的圆中面积最小的一个。
(x,y),radius = cv2.minEnclosingCircle(cnt) center = (int(x),int(y)) radius = int(radius)
cv2.circle(img,center,radius,(0,255,0),2)#编写时去掉返回值 PS:请自行完成
2.6轮廓的性质 2.6.1 长宽比
x,y,w,h = cv2.boundingRect(cnt) aspect_ratio = float(w)/h
2.6.2 轮廓面积与边界矩形面积的比
area = cv2.contourArea(cnt) x,y,w,h = cv2.boundingRect(cnt) rect_area = w*h
extent = float(area)/rect_area
2.6.3 轮廓面积与凸包面积的比。
area = cv2.contourArea(cnt) hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull) solidity = float(area)/hull_area
2.6.4 与轮廓面积相等的圆形的直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
2.6.5 对象的方向
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
2.6.6 掩模和像素点
mask = np.zeros(imgray.shape,np.uint8) # 这里一定要使用参数-1, 绘制填充的的轮廓 cv2.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
2.6.7最大值和最小值及它们的位置 我们可以使用掩模图像得到这些参数;
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
2.6.8 平均颜色及平均灰度
我们也可以使用相同的掩模求一个对象的平均颜色或平均灰度; mean_val = cv2.mean(im,mask = mask)
2.6.9 极点
一个对象最上面,最下面,最左边,最右边的点。
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0]) rightmost = tuple(cnt[cnt[:,:,0].argmax()][0]) topmost = tuple(cnt[cnt[:,:,1].argmin()][0]) bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])
自行完成2.6.1到2.6.9的轮廓性质操作,根据这些特性判断树叶类型,去对树叶进行分类。
三. 实验步骤
1.了解轮廓的概念,学习找轮廓绘制轮廓等,了解函数:cv2.findContours(),cv2.drawContours()。函数 cv2.?ndContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个 Python列表,其中存储这像中的所有轮廓。每一个轮廓都是一个 Numpy 数组,包含对象边界点(x,y)的坐标。
2.学习掌握轮廓的特征,了解矩的意义,以及对轮廓进行的一些数学运算,比如面积,周长等,并且能够掌握画出目标的矩形边界和最小外接圆。 3.在学习轮廓性质,学会将这些性质运用在实际操作上。
PS:可以对下面提供的所有图片都进行以上的测试,记录最后的结果。
四.综合作业。
1.自实现对植物叶片的自动分类。请根据实验课程知识,实现一个植物叶片自动分类系统。 功能:
(1)通过视频获取一篇植物叶片,程序自动报告植物种类。 (2)用户界面友好;
(3)综合使用多个叶片特征; (4)构建自动分类算法。
注:薛老师实验室正在构建植物叶片自动识别软件,若优秀的作品一旦被采用,会给物质奖励。
(例如,叶片自动分割效果好,能识别叶片种类多,数据库齐全,IOS或Android开发的均有加分)
附实验叶片: