目录
摘 要
关键词
一、系统方案
1.1 系统基本方案
1.2 程序算法的具体流程
二、视觉程序识别框架
2.1多线程
2.2 opencv配置文件
2.3 主函数
三、装甲板识别算法
3.1 装甲板识别
3.2 识别函数介绍
四、目标位置解算
4.1 摄像头标定
4.2 根据小孔成像原理得到需要的转角
(在这里打公式实在是太麻烦了,我直接在我的文档里截图算了。。。)
4.3 角度测量验证
五、程序源码(代码及完整论文可私)
摘 要:
一、系统方案
①降低相机曝光:在装甲识别中,曝光度是决定能否成功识别到装甲板的关键因素,当我们拍摄能自主发光的物体时,可以降低曝光时间可以减少环境光的影响。这时通过阈值处理得到二值图就可以进一步处理。
下面是我对比的一下摄像头正常曝光和低曝光的巨大差别:
为了让便于分离灯条与其他光线,一般将曝光设置得很低,如下图为相机获取到的实际画面:
②预处理:通过相机,我们能够源源不断地获取到当前的画面,也就是一帧帧的图像。该算法处理的对象,就是这每一张图像。因为我们要从图像中找到装甲板上的灯条,因此需要先对图像进行预处理,即排除掉画面中的其他多余的光线。
下面是我程序中使用的处理方法:
下图为经过预处理之后的效果(二值化图像),可见除了灯条外的地方几乎都被排除掉了:
③找到符合灯条条件的轮廓:通过预处理得到的图片是二值图,即我们把可能是灯条的位置处理变成白色,其他地方都是黑的。此时可以通过Opencv的函数对轮廓用矩形框起来,然后通过几何关系判断其是否符合灯条的条件(角度,长宽比等条件)
下图为框选出来的符合灯条条件的灯条:
④匹配装甲板:如果上一步得到的灯条个数大于1,就进行装甲板的匹配,主要是通过两个灯条的几何信息进行匹配(高度差,宽度差,角度差,形成的装甲板的角度,长宽比等信息),最终得到若干个装甲板。
下图为用黄色矩形框选出来的装甲板:
⑤选择最后的装甲板:如果上一步得到的装甲板个数大于0,则进行装甲板的选择。
⑥PNP结算装甲板信息:我们找到了装甲板的位置,还需要告诉舵机应当如何移动才能让枪管指向装甲板的中心。这里的如何移动,其实就是角度的偏移,左右偏多少度(yaw角),上下偏多少度(pitch角),相机距离装甲板的距离是多少,得到这些信息之后,发送给下位机,舵机就知道怎么动了。
最后展示一下最终算法效果图:
二、视觉程序识别框架
由于我们相机每秒钟可以获取到很多张图片,实际处理中最好是几毫秒处理一张图,否则就会因为延时而无法跟上装甲板的移动。 而程序中采用多线程就是一个实现加速的好方法,因为相机获取图片和我们处理图片是两个相对独立的过程,因此可以利用多线程进行加速。
使用 opencv 的时候写程序通常的流程就是读入图片/视频/摄像头,对每张图片进行处理,处理后进行输出(显示图片/显示识别结果等等)。这种模式基本上是一条线走下来的,前一个步骤没有完成就无法进行下一步的操作。
而使用多线程后就可以把每个步骤拆分开,用单独的线程来完成对应的操作。
由于使用了多线程就可以进行流水线作业,这样在图像处理线程处理本张图片的时候图像读取线程可以读入下一张图片。
多结构结构框图如下:
我是在linux平台上使用qtcreate搭建的opencv程序,在程序中的.pro文件就是该项目的配置文件。
然后是头文件和源文件,这些是添加相应文件后 qtcreator 自动生成的,也可以手动添加或者手动注释。
主函数的主要功能是:作为一个入口,创建 ImgProdCons 类,执行初始化成员函数,创建多线程。
主函数如下:
其中produceThread()函数负责获取图像保存到缓存队列中,consumeThread()函数负责对图图片的处理和指令的发送,而 senseThread()函数用于接收数据。
三、装甲板识别算法
装甲板识别步骤:
1、找出图片中所有的灯条
2、根据长宽比、面积大小和凸度来筛选灯条
3、对找出的灯条进行匹配找到合适的配对
4、配对灯条作为候选装甲板
在识别主程序中首先定义要用到的一些变量,定义时间变量t1记录当前时间用于之后的算法耗费时间的度量,之后获取待识别图片,图片可以通过produce线程获得也可以通过视频获得,之后将图片载入到armorDetector中进行识别,识别到后的返回值在
ArmorDetector.h中有定义:
enum ArmorFlag
{
ARMOR_NO = 0,
ARMOR_LOST = 1,
ARMOR_GLOBAL = 2,
ARMOR_LOCAL = 3
};
若识别到则获取关于装甲板矩形四个顶点的图像坐标来解算装甲板相对摄像头的空间坐标,之后将数据发给下位机就可以了(发送给下位机的是拍下这张图片时以摄像头或装甲板为原点的相对坐标值转化成的角度值,依靠这个可以随动跟踪)。
识别函数int ArmorDetector::detect()函数是算法的核心,类中的其他函数都是为它服务的。
该算法的第一步是存储灯条对应上面的第一步和第二步。
对于图像中红色物体来说,其rgb分量中r的值最大,g和b在理想情况下应该是0,同理蓝色物体的b分量应该最大。
如果识别红色物体可以直接用r通道-b通道。由于在低曝光下只有灯条是有颜色的,两通道相减后,其他区域的部分会因为r和b的值差不多而被减去,而蓝色灯条部分由于r通道比b通道的值小,相减后就归0了,也就是剩下的灰度图只留下了红色灯条。
①颜色识别处理程序如下:
// 功能:把一个3通道图像转换成3个单通道图像
split(_roiImg,channels);//分离色彩通道
if(_enemy_color==RED)
_grayImg=channels.at(2)-channels.at(0);//Get red-blue image;
Else
_grayImg=channels.at(0)-channels.at(2);//Get blue-red image;
②膨胀处理:得到灰度图后需要阈值化处理得到二值图,之后可以进行膨胀处理让图像中的轮廓更明显。
Mat binBrightImg;
//阈值化
threshold(_grayImg, binBrightImg,_param.brightness_threshold
, 255, cv::THRESH_BINARY);
Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
//膨胀
dilate(binBrightImg, binBrightImg, element);
③找轮廓:这步是整个算法中最耗时的部分,如果预处理做的好,可以极大地减少找轮廓中花费的时间。
④找到轮廓后开始遍历轮廓提取灯条:
⑤对灯条进行匹配筛选:
⑥对找到的装甲板进行筛选:判断是不是装甲板我用的是模板匹配的方法,模板匹配特别适合待识别图片不会变化的场景,选择合适的模板可以得到很高的准确率。
⑦对装甲板筛选后可能会有多个装甲板,这时候需要选定一个进行跟踪。
四、目标位置解算
因为我们需要从图像中得到关于物理世界的信息,所以需要标定摄像头来得到摄像头内参。
标定板:
直接而在MATLAB的Command Window里面输入cameraCalibrator即可调用标定应用。
Matlab中标定如下:
点击show Undistorted即可看到无畸变的图像:
最后选择导出参数,即可把参数进行保存。
如何知道我们测出的角度是正确的呢?可以通过一把三角尺来进行测量。
将三角尺的30度尖对准摄像头,不断调整位置,使尖对准cx的像素值位置,之后不断调整摄像头,使三角尺的两条边在图像中平行于y轴,此时就可以选取三角尺边上的像素点来测量角度了,如下图:
拍摄出的图像如图:
这个时候选择左边那条边测得的角度就是30度,选择右边的那条边测得的角度就是0度。
五、程序源码(代码及完整论文可主页联系)
这里也可下载
机器视觉预处理、滤波算法+自动瞄准算法+自定义协议与下位机进行通信-智能家居文档类资源-CSDN文库