目录
本文是毕设项目的一部分,现总结为后续复习之用,如果对你有些帮助可以探讨。
下文目标追踪链接:【毕业设计】运用PID算法实现目标颜色追踪_其实很简单H的博客-CSDN博客
基于深度学习的颜色识别链接:【毕业设计】基于深度学习与图像处理的目标颜色识别示例_其实很简单H的博客-CSDN博客
一、概述
本文的研究目标是在深入了解颜色识别与追踪相关技术的基础上,设计出了基于OpenCV图像处理的颜色识别方案,基于OpenCV图像处理的颜色识别方案采用高斯滤波、转换HSV空间、形态学处理、掩膜、多边形轮廓拟合等算法完成,颜色识别后的追踪方案为采用PID算法控制二维云台舵机追踪即可(该部分下一篇总结)。整套系统是基于树莓派4B 8G为核心的硬件平台完成。
二、基于OpenCV图像处理的颜色识别方案
2.1 流程图
图2-1 程序流程图
程序流程图如图2-1所示,首先由摄像头获取视频并分割为帧进行处理,然后调用OpenCV库对图像进行预处理,图像预处理之后通过函数寻找目标轮廓即识别指定颜色,当识别到指定颜色后LED灯会亮起并进行目标追踪,当未识别到指定颜色时LED灯不亮并结束流程。
2.2 图像处理
图像处理是对给定图像进行的前期操作,目的是提高图像质量,以便后期对特定图像中目标特征的提取。它涉及图像的采集、增强、分割、分类、检索和压缩等技术。本文中采用的图像处理是高斯滤波、转换HSV空间、掩膜处理、开运算、位运算。
1.调取图像
首先,初始化摄像头
usb_cap = cv2.VideoCapture(0)
然后从视频输入流中读取帧图像的代码
ret,frame = usb_cap.read()
- ret 布尔型 (True 或者False),表示有没有读取到图片
- frame 表示截取到的一帧的图片的数据,是个三维数组
2.高斯滤波
高斯滤波是一种图像处理技术,它可以通过对图像进行平滑处理,来减少噪声和其他一些不需要的像素信息,从而提高图像质量和清晰度。高斯滤波的原理基于一种称为高斯核函数的数学模型,该模型将图像中每个像素的值计算为周围像素的加权平均值。在实际应用中,高斯滤波可以应用于许多不同类型的图像处理任务,包括降噪、平滑处理、边缘检测和特征提取等。它可以通过调整高斯核函数的大小、方向和参数等来实现不同的效果和结果。
frame=cv2.GaussianBlur(frame,(5,5),0)
cv2.GaussianBlur(frame, (5, 5), 0)函数对图像进行高斯滤波。高斯滤波前后的图像如图2-2所示,可以发现经过高斯滤波后图像会更模糊点。
| |
a.源图像 | b.高斯滤波后的图像 |
图2-2 源图像与高斯滤波后的图像
3.转换HSV空间
HSV空间是一种基于颜色特征分量的颜色空间,它包括三个分量:色调(Hue)、饱和度(Saturation)和明度(Value),通常也称为HSV模型。
由于RGB颜色空间不适合人眼的视觉特性,因此通常会将颜色从RGB空间域转换到HSV颜色空间进行处理。可以使用OpenCV中cv2.cvtColor()函数来改变图像的颜色空间,该函数为:
hsv= cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
frame为要进行处理的图片;cv2.COLOR_BGR2RGB要进行的色彩转换方式。
4.掩膜处理
掩膜处理是一种基于图像处理中的滤波技术,用于增强或减弱图像中的特定区域。掩膜处理利用一个掩膜矩阵,也称为卷积核或滤波器,对图像进行像素级的操作。
首先,掩膜处理需要设置一个阈值,以下是黄色的HSV阈值区间
ball_yellow_lower=np.array([26,43,46])
ball_yellow_upper=np.array([34,255,255])
掩膜处理用到的函数如下:
mask=cv2.inRange(hsv,ball_yellow_lower,ball_yellow_upper)
- hsv指的是原图
- ball_yellow_lower指的是图像中低于这个ball_yellow_lower的值,图像值变为0
- ball_yellow_upper指的是图像中高于这个ball_yellow_upper的值,图像值变为0
而在ball_yellow_lower~ball_yellow_upper之间的值变成255
5.开运算
开运算=先腐蚀运算,再膨胀运算
它通过对图像进行膨胀(dilation)和腐蚀(erosion)等操作,来达到去噪、目标提取、边缘检测等效果。
腐蚀运算用到cv2.erode()函数
mask=cv2.erode(mask,None,iterations=2)
膨胀运算用到cv2.dilate()函数
mask=cv2.dilate(mask,None,iterations=2)
经过开运算后的结果如图2-3所示,左边为开运算处理前的图像,右边为开运算处理后的图像,可以发现一些离散且区域很小的白色区域被滤去。
| |
a.形态学处理前的图像 | b.形态学处理后的图像 |
图2-3 形态学处理效果图
6.位运算
需要用到的位运算逻辑与
函数位cv2.bitwise_and(src1, src2, dst=None, mask=None)
- dst表示与输入值具有同样大小的array输出值。
- src1表示第一个array或scalar类型的输入值。
- src2表示第二个array或scalar类型的输入值。
- mask表示可选操作掩码,8位单通道array。
代码:
res=cv2.bitwise_and(frame,frame,mask=mask)
2.3 轮廓提取
1.发现轮廓
轮廓可以理解为一系列相邻的点组成的曲线。在了解到轮廓的概念后,首先需要把彩色图像及灰色图像处理成二值图像,前面的图像处理后返回的mask即为二值图像,所以需要用到的代码是:
cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]
其中有三个参数,
- mask.copy()表示经过处理后的二值图像;
- cv2.RETR_EXTERNAL是一种轮廓检索方式,表示只寻找最高层级的轮廓;
- cv2.CHAIN_APPROX_SIMPLE表示轮廓的估计方法。
第二个参数cv2.RETR_EXTERNAL是一种轮廓检索方式,还有cv2.RETR_LIST、cv2.RETR_EXTERNAL、cv2.RETR_CCOMP检索方法,刚兴趣可以深入了解。
第三个参数cv2.CHAIN_APPROX_SIMPLE是一种轮廓估计方式,物体轮廓是具有相同灰度值的形状的边界。它是以形状边界上的点的坐标(x,y)储存的,但是cnts里边是储存了边界上所有点的坐标吗?还是只储存了个别点的坐标?这是由第三个参数轮廓的估计方法指定的。例如一个矩形轮廓,那么只需要存储其四个点的坐标即可以表示该轮廓,不需要存储轮廓所有的坐标点,可以减少内存。
返回值cnts表示一个包含了图像中所有轮廓的list对象。其中每一个独立的轮廓信息以边界点坐标(x,y)的形式储存在numpy数组中。
2.得到周长
运用cv2.arcLength()函数得到周长
epsilon = 0.0005*cv2.arcLength(cnts[0],True)
- cnts[0]表示第一个轮廓的坐标点集
- True表示轮廓闭合
返回值epsilon表示得到轮廓的周长,精度为0.0005*周长(数字越小越精确)
3.轮廓拟合
轮廓拟合方式有许多,有矩形包围拟合、最小包围矩形拟合、最小包围圆形拟合、最优拟合椭圆、最优拟合直线、逼近多边形等。本文经过对比采用逼近多边形的拟合方式,逼近多边形拟合运用函数 cv2.apprxPolyDP()。
函数 cv2.apprxPolyDP() 采用 Douglas-Peucker算法(DP算法),Douglas-Peucker算法是一种常用于轮廓线简化的算法,其主要思想是将一条复杂的轮廓线简化成一条近似的但相对简单的轮廓线。该算法的优点是速度快,且可以应用于任意类型的曲线。以下是Douglas-Peucker算法的主要步骤:
(1)输入一条曲线,由一系列点构成;
(2)找到曲线上距离起点和终点最远的点,将其作为起点和终点,将曲线分割为两部分;
(3)对分割出来的每一部分递归执行步骤2,直到所有分割出来的部分都满足抽稀条件;
(4)抽稀条件由预先设定的阈值决定——如果曲线上的某个点到近似曲线的距离小于阈值,这个点将会被忽略。同时,如果任意两个抽稀后的点之间距离不足阈值,则这些点被合并为一个点。
以下是Douglas-Peucker算法的公式:
假设轮廓线上的点集为P,近似直线L的两个端点为P_1和P_n,任意点P_i到近似直线L的距离为d_i,则Douglas-Peucker算法可以表示为:
(1)计算距离最远的点:
d_max = max(d_i), 2 ≤ i ≤ n-1 (2-1)
式中:d_max-距离最远的点
d_i-任意点到近似直线的距离
(2)判断最远距离是否超过阈值tolerance。
(3)若d_max > tolerance,则最远距离对应的点为P_m,以P_m为节点将曲线划分为两段P1-Pm和Pm-Pn。分别对P1-Pm、Pm-Pn两段进行递归调用。
(4)最终,Douglas-Peucker算法将得到一条尽可能接近原始曲线的简化曲线。
在OpenCV中Douglas-Peucker算法(DP算法)用cv2.approxPolyDP()函数体现
approx= cv2.approxPolyDP(cnts[0],epsilon,True)
- cnts[0]表示第一个轮廓的二维点向量的集合;
- epsilon表示指定的近似精度,原始曲线与近似曲线之间的最大距离;
- True 表示闭合多边形,False 表示多边形不闭合。
经过实验,采用Douglas-Peucker算法(DP算法)可对不同形状物体进行拟合,且拟合效果显著。拟合效果如图2-4所示。
| |
图2-4 非标准形状物体颜色识别
4.轮廓绘制
采用cv2.drawContours()函数可以进行轮廓绘制
frame = cv2.drawContours(frame,[approx],0,(0,0,255),2)
- 第一个参数frame表示需要绘制的图像;
- 第二个参数[approx]表示估计的轮廓,用list表示
- 第三个参数表示画第几个轮廓,如果该参数为负值,则画全部轮廓,本代码画第一个轮廓即可;
- 第四个参数表示所画的轮廓的颜色,是一个三元组,RGB格式表示,这里表示蓝色;
- 第五个参数表示轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,这里为2;
后续会对识别到的最大轮廓的坐标点求平均值就得到了目标的中心坐标,建立坐标系对该目标中心坐标进行追踪即可。
2.4 源代码
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# import the necessary packages
import cv2
import numpy as np
#初始化摄像头并设置阙值
usb_cap = cv2.VideoCapture(0)
# 设置球体追踪的HSV值,上下限值
ball_yellow_lower=np.array([26,43,46])
ball_yellow_upper=np.array([34,255,255])
# 设置显示的分辨率,设置为320×240 px
usb_cap.set(3, 320)
usb_cap.set(4, 240)
# loop over the frames from the video stream
while True:
ret,frame = usb_cap.read()
#高斯模糊处理
frame=cv2.GaussianBlur(frame,(5,5),0)
hsv= cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
#ROI及形态学找到小球进行处理
mask=cv2.inRange(hsv,ball_yellow_lower,ball_yellow_upper) # 掩膜处理
mask=cv2.erode(mask,None,iterations=2)
mask=cv2.dilate(mask,None,iterations=2)
mask=cv2.GaussianBlur(mask,(3,3),0)
res=cv2.bitwise_and(frame,frame,mask=mask)
cnts=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2] #发现小球
# 发现轮廓后才进行处理
if len(cnts) > 0:
epsilon = 0.0005*cv2.arcLength(cnts[0],True)
approx= cv2.approxPolyDP(cnts[0],epsilon,True)
frame = cv2.drawContours(frame,[approx],0,(0,0,255),2)
vertex_array = approx.reshape(-1, 2) # 将坐标数组转换为二维数组
pid_x = int(np.mean(vertex_array[:, 0])) # 求x坐标的平均值并转换为整型
pid_y = int(np.mean(vertex_array[:, 1])) # 求y坐标的平均值并转换为整型
cv2.imshow("mask", mask)
cv2.imshow("MAKEROBO Robot", frame) # 显示图像
if cv2.waitKey(1)==119:
break
# do a bit of cleanup
print("\n [INFO] Exiting Program and cleanup stuff \n")
cv2.destroyAllWindows()
usb_cap.stop()
三、总结
基于图像处理的颜色识别方案对于环境要求较高,经过测试,如果环境光线较亮或较暗识别效果就不太好,后面增加了可调的HSV阈值按钮,可以解决这个问题。针对以上识别方案暴露出的问题,继续尝试运用了Tensorflow深度学习框架训练了一个颜色小球数据集,最后识别效果非常不错,有效解决了颜色识别精度不够高及目标遮挡的问题。在颜色识别后,建立坐标系,运用PID算法根据目标轮廓中心坐标进行视野追踪,经过测试效果不错。
本人非科班,这算是完成的第二个项目,总结交流之用,如有错误敬请指出!