赞
踩
由于框架搭建的时候是先用图片进行预处理,所以首先需要用OpenCV库中的函数进行对图片的读取,并正常显示。具体代码如下:
Mat img = imread("/home/hemingshan/图片/sonny.jpg",-1);
namedWindow("example1_获取图像",cv::WINDOW_AUTOSIZE);
imshow("example1_获取图像",img);
去噪也就是滤波,主要是为了实现对图像噪声的消除,增强图像的效果。均值滤波器、高斯滤波器、中值滤波器、双边滤波器都可以进行使用。由于目标检测过程中,不会像图片那样非常平滑,会因为环境的变化参杂一些空间性的噪声,所以推荐使用双边滤波器,因为双边滤波考虑了图像的空间关系,也考虑图像的灰度关系。双边滤波同时使用了空间高斯权重和灰度相似性权重,确保了边界不会被模糊掉下去。
Mat img2;
bilateralFilter(img,img2,9,75,75);
namedWindow("example1_双边滤波",cv::WINDOW_AUTOSIZE);
imshow("example1_双边滤波",img2);
从显示的图像上可以看出,整个人物形象边缘以及轮廓都显得没有那么尖锐,有一种“美颜”的感觉(我孙哥自带美颜滤镜,根本不需要美颜)。
原来的图像格式是RGB图像格式,是通过三原色的混合来产生不同的颜色效果,三原色分别由8bit定义,在硬件实现中便于理解和处理。而HSV是通过色度hue, 亮度value,饱和度saturation来定义颜色,更接近人眼睛对颜色的定义(这是什么颜色?深浅如何?明暗如何?)两者之间的转化需求来自于硬件实现和显示效果调整两个方面的需求,前者满足具体处理过程中简便高效实现,后者按照人眼识别特点进行调整,更容易达到人眼预期的、显示效果的调整。
总的来说,RGB中都与颜色亮度相关,即我们无法将颜色信息与亮度分开。HSV或色相饱和度值用于将图像李娜高度与颜色信息分开。这样就使得我们在处理或需要图像/帧的亮度时更容易。HSV还用于颜色描述骑着不可或缺的作用的情况。
Mat mask;
inRange(imghsv,Scalar(hmin,smin,vmin),Scalar(hmax,smax,vmax),mask);//将红颜色进行过滤出来imshow("提取",mask);
目标颜色检测主要是为了将检测物体和环境进行区分开来,通过变量的上下限来获取目标物体的大致范围进行提取,之后完成后续处理。通过 inRange()
函数来完成目标颜色的分离与检测。OpenCV
中的inRange()
函数可以实现二值化功能,更关键恶是可以同时针对多通道进行操作。
//Checks if array elements lie between the elements of two other arrays
//检查数组元素是否在两外两个数组元素值之间
void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);
上面提到的数组也就是在OpenCV
中常用到的矩阵Mat
或向量。
由图像可以看出该图像除了人脸附近有红色进行提取之外,有一小部分的LOGO带有红色部分的也被进行提取后进行二值化处理。所以,在这里效果还算是可观,接下来就是为了将环境噪声进行去除进行下一步的图像处理。
Mat out2;
Mat element = getStructuringElement(MORPH_RECT,Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),Point(g_nStructElementSize,g_nStructElementSize));
erode(mask,out2,element);
imshow("腐蚀",out2);
首先getStructuringElement()
函数可用于构造一个特定大小和形状的结构元素,或指定形状和尺寸的结构元素,用于图像形态学处理。其函数具体说明为,
Mat getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));
腐蚀后有一大部分的红色区域都被剔除掉了,而且最大的噪声(LOGO)也被剔除了。所以有很大的效果,为之后的轮廓提取奠定了一定的基础。
高斯模糊又叫高斯平滑,是广泛使用的处理效果,通常用来减少图像噪声以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同平滑比例大小下的图像效果。从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又称作“高斯分布”,所以这项技术就叫做高斯模糊。图像与圆形方框模糊作卷积将生成更加精确的焦外成像效果。由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。
//高斯模糊
Mat gaussian;
GaussianBlur(out2,gaussian,Size(g_nGaussianBlurValue*2+1,g_nGaussianBlurValue*2+1),0,0);//模糊化
imshow("高斯模糊",gaussian);
代码中最主要的函数是GaussianBlur()
函数,其函数说明为,
void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );
其中Size ksize
是高斯模糊中用到的平滑比例大小,不同平滑比例大小下的图像所呈现的平滑处理都不同。
虽然该图不太明显,但是和上一张腐蚀后的图像比较可以发现,图像有所模糊化了。效果不高的原因是该图片没有非常明显的红色区域,因为在HSV图像基础上进行提取的颜色是红色,导致体去除的红色并不是太多。放到环境中取,特定识别一块红色物体还是有很明显的效果。
//轮廓提取 vector<vector<Point> > contours; vector<Vec4i> hierarchy; Mat imgcontours; Point2f center; float radius; findContours(gaussian, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); double maxarea = 0; int maxareaidx = 0; for (int index = contours.size() - 1; index >= 0; index --)// find the maxarea return contour index { double tmparea = fabs(contourArea(contours[index])); if (tmparea > maxarea) { maxarea = tmparea; maxareaidx = index; } } minEnclosingCircle(contours[maxareaidx], center, radius);//using index ssearching the min circle circle(img, static_cast<Point>(center), (int)radius, Scalar(255,0,0), 3);//using contour index to drawing circle imshow("轮廓", img); waitKey(0);
代码中最重要的函数是findContours()
函数,在OpenCV
中通过使用该函数,简单几个步骤就可以检测出物体的轮廓,很方便。其函数原型为,
void findContours( InputOutputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());
第一个参数:image
,单通道图像矩阵,也就是可以是灰度图、二值图,但一般来说更常用的是二值图。
第二个参数:contours
,定义为vector<vector<Point>> contours
,是一个向量,并且是一个双重向量,向量内每一个元素保存了一组由连续的Point
点构成的点的集合的向量,每一组Point
点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。
第三个参数:hierarchy
,定义为vector<Vec4i>hierarchy
,其定义了一个向量内每一个元素包含了4个int型变量的向量。向量hierarchy
内的元素和轮廓向量contours
内的元素是一一对应的,向量的容量相同。hierarchy
向量内每一个元素的4个int型变量——hierarchy[i][0]~hierarchy[i][3]
,分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的最后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0]~hierarchy[i][3]
的相应位置被设置为默认值-1。
第四个参数:int型的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_CHIAN_APPROX_TC89_L1,CV_CHIAN_APPROX_TC89_KCOS使用teh-Chinl chain近似算法
第六个参数:Point偏移量,所有的轮廓信息相对于院士图像对应点的偏移量,相当于在每一个检测出的轮廓点上加该偏移量。
然后往下的程序就是寻找最大的轮廓,简单易懂,所以不加以赘述。运行结果如下图所示
红唇被标记出来了!!
之后就需要将该程序移植到Turtlebot3机器人的自带摄像头上面,主要用了其RGB摄像头,深度摄像头也可以用,但是没有RGB摄像头的效果好。
具体思路是:首先获取摄像头图像,通过cv_bridge转换成OpenCV可以处理的Mat格式的数据,之后通过上述的识别算法,识别出Turtlebot3_1机器人,并且返回其中心点和半径,在这里我将距离以半径形式体现出来,也就是半径越大,距离越近。
在控制部分由于第一次开发,所以就简单来,就是Turtlebot3_1机器人在Turtlebot3_2机器人的摄像头中的识别位置靠左边,那么我就通过对cmd_vel进行数据发布,使Turtlebot3_2向左转,以此类推,如果距离远了,那么识别出来的半径就会小,也就需要Turtlebot3_2向前移动靠近。
如果要运行,需要先在预先设计好的环境中运行两个Turtlebot3
模型,这个已经在launch文件夹中已经编辑完毕,只需要运行launch文件即可。
$ roslaunch opencv_examples turtlebot3_follow.launch
然后运行目标识别结点其结合了对第二个机器人的控制,具体运行
$ rosrun opencv_examples find_contours
之后,通过控制第一个机器人移动即可,验证第二个机器人是否会跟随移动
$ rosrun turtlebot_teleop turtlebot3_1_teleop
项目地址:GitHub’https://github.com/MingshanHe/Turtlebot3-Robot-based-target-recognition-and-tracking’
微信公众号:小河和他的机器人
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。