Opencv图像处理:轮廓检测、轮廓近似、绘制外接圆外接矩形
文章目录
- 一、图像轮廓检测
- 1、比较
- 2、常见的轮廓检测方法
- 1)基于梯度的方法
- 2)基于边缘检测器的方法
- 3)基于阈值的方法
- 3、查找轮廓与绘制轮廓
- 4、参数解释
- 4、代码解释
- 1)读取原图像灰度图并用二值化显示
- 2)轮廓绘制
- 3)通过面积绘制轮廓
- 二、轮廓特征
- 1、轮廓面积
- 2、轮廓周长
- 三、轮廓近似
- 1、定义
- 2、参数说明
- 3、代码解释
- 1)图像预处理
- 2)对轮廓进行近似
- 四、轮廓外接圆,外接矩形
- 1、绘制外接圆
- 2、绘制外接矩形
一、图像轮廓检测
1、比较
边缘检测:主要是通过一些手段检测数字图像中明暗变化剧烈(即梯度变化比较大)像素点,偏向于图像中像素点的变化。
轮廓检测:指检测图像中的对象边界,指的是在图像中提取出物体边界的一种图像处理方法使用轮廓检测可以获得物体的边界,方便在图像中对他们进行定位。通常在一些有趣的应用中轮廓检测是第一处理环节。比如图像前景提取,简单的图像分割,检测以及识别等。
2、常见的轮廓检测方法
1)基于梯度的方法
利用图像中灰度值的梯度信息来检测轮廓,包括Sobel算子、Prewitt算子、Roberts算子等。
2)基于边缘检测器的方法
包括Canny边缘检测器、Laplacian边缘检测器等,这些边缘检测器可以通过检测图像中的强度变化来找到物体的边缘。
3)基于阈值的方法
将图像灰度值与设定的阈值进行比较,将高于或低于阈值的像素点标记为边界。
3、查找轮廓与绘制轮廓
cv2.findContours()
cv2.drawContours()
4、参数解释
查找轮廓的API:image, contours, hierarchy = cv2.findContours(img, mode, method)
参数:img:需要实现轮廓检测的原图。
mode: 轮廓的检索模式,主要有四种方式:
-
cv2.RETR_EXTERNAL:只检测外轮廓,所有子轮廓被忽略
-
cv2.RETR_LIST:检测的轮廓不建立等级关系,所有轮廓属于同一等级
-
cv2.RETR_CCOMP:返回所有的轮廓,只建立两个等级的轮廓。一个对象的外轮廓为第1级组织结构。而对象内部中空洞的轮廓为第2级组织结构,空洞中的任何对象的轮廓又是第1 级组织结构。
-
cv2.RETR_TREE:返回所有的轮廓,建立一个完整的组织结构的轮廓。
method:轮廓的近似方法,主要有以下两种:
-
cv2.CHAIN_APPROX_NONE:存储所有的轮廓点。
-
cv2.CHAIN_APPROX_SIMPLE:压缩模式,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
返回值:
-
image:返回处理的原图
-
contours:包含图像中所有轮廓的list对象。其中每一个独立的轮廓信息以边界点坐标(x,y)的形式储存在numpy数组中。
-
hierarchy:轮廓的层次结构。一个包含4个值的数组:[Next, Previous, First Child, Parent]
- Next:与当前轮廓处于同一层级的下一条轮廓
- Previous:与当前轮廓处于同一层级的上一条轮廓
- First Child:当前轮廓的第一条子轮廓
- Parent:当前轮廓的父轮廓
注意:做轮廓检测前需要将图片读取为二值数据,即像素值只为0和255(非黑即白)。
4、代码解释
1)读取原图像灰度图并用二值化显示
import cv2
phone = cv2.imread('phone.png')#读取原图
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY)#灰度图的处理
cv2.imshow('phone_b',phone_gray)
cv2.waitKey(0)
# phone_gray=cv2.imread('phone.png',0) #读取灰度图
ret, phone_binary = cv2.threshold(phone_gray, 120, 255, cv2.THRESH_BINARY)#阈值处理为二值
cv2.imshow('phone_binary',phone_binary)
cv2.waitKey(0)
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
print(hierarchy)
print(len(contours))
其中:
_,contours, hierarchy = cv2.findContours(phone_binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
调试一下发现总共找到了9个轮廓:
2)轮廓绘制
轮廓的绘制
cv2.drawContours(image, contours, contourIdx, color, thickness=None,
lineType=None, hierarchy=None, maxLevel=None, offset=None)
参数含义如下:
- image:要在其上绘制轮廓的输入图像。
- contours:轮廓列表,通常由cv2.findContours()函数返回。
- contourIdx:要绘制的轮廓的索引。如果为负数,则绘制所有轮廓。 -1
- color:轮廓的颜色,以BGR格式表示。例如,(0, 255, 0)表示绿色。
- thickness:轮廓线的粗细。默认值为1。
- lineType:轮廓线的类型。默认值为cv2.LINE_8。
- hierarchy:轮廓层次结构。通常由cv2.findContours()函数返回。
- maxLevel:绘制的最大轮廓层级。默认值为None,表示绘制所有层级。offset:轮廓点的偏移量。默认值为None。
image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=contours, contourIdx=6,color=(0,255,0),thickness=3)
cv2.imshow('Contours_show', image_copy)
cv2.waitKey(0)
该图片显示的是contourIdx=6的轮廓。
3)通过面积绘制轮廓
a_list=[]for i in contours:if cv2.contourArea(i)>=10000:a_list.append(i)
image_copy = phone.copy()
image_copy = cv2.drawContours(image=image_copy, contours=a_list, contourIdx=-1,color=(0,255,0),thickness=3)
cv2.imshow('Contours_show_10000', image_copy)
cv2.waitKey(0)
轮廓大于10000的只有这一个轮廓。
二、轮廓特征
1、轮廓面积
- cv2.contourArea(contour[, oriented]) → retval
- contour:顶点构成的二维向量组(如轮廓列表contours中的一个轮廓)
- oriented:定向区域标志,默认值为 False,返回面积的绝对值,Ture 时则根据轮廓方向返回带符号的数值。
area_0 = cv2.contourArea(contours[0])
print(area_0)
area_1 = cv2.contourArea(contours[1])
print(area_1)
2、轮廓周长
- arcLength(InputArray curve, bool closed)
- curve,输入的二维点集(轮廓顶点),可以是 vector 或 Mat 类型。
- closed,用于指示曲线是否封闭。
length = cv2.arcLength(contours[0],closed=True)
print(length)
三、轮廓近似
1、定义
指对轮廓进行逼近或拟合,得到近似的轮廓。在图像处理中,轮廓表示了图像中物体的边界,因此轮廓近似可以用来描述和识别物体的形状。
2、参数说明
approx = cv2.approxPolyDP(curve, epsilon, closed)
- curve:输入轮廓。
- epsilon:近似精度,即两个轮廓之间最大的欧式距离。该参数越小,得到的近似结果越接近实际轮廓;反之,得到的近似结果会更加粗略。
- closed:布尔类型的参数,表示是否封闭轮廓。如果是 True,表示输入轮廓是封闭的,近似结果也会是封闭的;否则表示输入轮廓不是封闭的,近似结果也不会是封闭的。
- 返回值:approx:近似结果,是一个ndarray数组,为1个近似后的轮廓,包含了被近似出来的轮廓上的点的坐标
3、代码解释
1)图像预处理
phone = cv2.imread('phone.png')
phone_gray = cv2.cvtColor(phone,cv2.COLOR_BGR2GRAY) #转换为灰度图
ret,phone_thresh = cv2.threshold(phone_gray,120,255,cv2.THRESH_BINARY) #二值化
image, contours, hierarchy = cv2.findContours(phone_thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)#获取轮廓
2)对轮廓进行近似
epsilon = 0.01 * cv2.arcLength(contours[0],True) #设置近似精度
approx = cv2.approxPolyDP(contours[0], epsilon, True) #对轮廓进行近似
print(approx.shape)
phone_new = phone.copy()
image_contours = cv2.drawContours(phone_new,[approx],contourIdx=-1,color=(0,255,0),thickness=3)#绘制轮廓
cv2.imshow('phone',phone)
cv2.waitKey(0)
cv2.imshow('image_contours',image_contours)
cv2.waitKey(0)
epsilon中的0.01这个值来控制精度,这个值越小绘制轮廓的点越多越精细,值越大点越少,绘制的会更粗糙。
四、轮廓外接圆,外接矩形
1、绘制外接圆
cnt = contours[6] #选择contours[6]特征
(x,y),r = cv2.minEnclosingCircle(cnt)#计算轮廓的外接圆
phone_circle = cv2.circle(phone,(int(x),int(y)),int(r),(0,255,0),2)#绘制外接圆的方法
cv2.imshow('phone_circle',phone_circle)
cv2.waitKey(0)
2、绘制外接矩形
x,y,w,h = cv2.boundingRect(cnt)#计算轮廓的最小外接矩形
phone_rectangle = cv2.rectangle(phone,(x,y),(x+w,y+h),(0,255,0),2) #在图像上绘制矩形
cv2.imshow('phone_rectangle',phone_rectangle)
cv2.waitKey(0)
注意:绘制坐标轴X轴是水平向右的;Y轴是竖直向下的。