OpenCV单目视觉定位(测量)系统

OpenCV单目视觉定位(测量)系统转自:http://blog.csdn.net/chenmohousuiyue/article/details/56300915OpenCV单目视觉定位(测量)系统TheSystemofVisionLocationwithSignalCameraAbstract:Thispassagemainlydescribeshowtolo

大家好,又见面了,我是你们的朋友全栈君。

转自:http://blog.csdn.net/chenmohousuiyue/article/details/56300915

OpenCV单目视觉定位(测量)系统

The System of Vision Location with Signal Camera



Abstract:This passage mainly describes how to locate with signalcamera,which bases on OpenCV library.

Key words: OpenCV; Locate;Signalcamera

摘  要本文主要描述的是利用开源计算机视觉库OpenCV实现单目视觉定位系统。

关键词: OpenCV;单位视觉定位

1     总体设计方案

单目视觉定位系统是通过单个分辨率为640*480,20万的USB手动调焦摄像头获取图片并传到计算机利用OpenCV进行预处理、识别、定位、测量等图像处理算法,进而得出目标物体相对摄像头的二维坐标距离。

2     预处理

对摄像头获取的图片进行均值滤波处理,目的是抑制电气元件或者环境因素引起的噪声。滤波也叫平滑处理,滤波的目的是抑制噪声,平滑滤波属于低频增强空间滤波技术,因为图像的能量大部分集中在幅度谱的低中频,噪声一般存在于高频段。

在本系统中主要采用均值滤波算法,也叫邻域平均算法。领域平均算法的基本思想是对含噪声图像的每一个像素点f(x,y)取领域S,用领域S中所包含的像素灰度平均值来代替该点的灰度值。

领域平均法的优点是处理方法简计算速度快,缺点是在降低噪声的同时是图像产生一定程度的模糊,领域半径越大,去噪效果越好,但图像越模糊。

因此,本系统采用3 X 3模板h,其转置矩阵为:1/9 [1,1,1 ; 1,1,1 ; 1,1,1],设f(x,y)为原图像的每一个像素值,g(x,y)为输出图像对应的每一个像素值,则均值滤波核心算法为原图像的每一个像素(除图像边缘像素)和3 X 3模板h进行卷积运算得出输出图像。

 图一 灰度图                 OpenCV单目视觉定位(测量)系统


图二 均值滤波              OpenCV单目视觉定位(测量)系统             


3     识别

对于目标物体的识别,本系统是采用Canny边缘检测找出所有可能的边缘信息,然后对边缘信息进行提取和分析,进而识别出目标物体。与该目标物体的识别还有一种方法是采用阈值算法分割出特定灰度值范围内的物体,但该算法受光照影响较大,而边缘检测受光照影响较少,因此Canny采用边缘检测算法。

3.1目标物体

对目标物体的设计,我采用了外面六边形,里面五边形,六边形与五边形之间黑色填充,其余白色填充,六边形与五边形中心基本上一致。如下图所示

OpenCV单目视觉定位(测量)系统

 图三打印的目标物体

 

 3.2 Canny边缘检测

边缘检测的算法只要是基于图像增强的一阶和二阶导数。Canny边缘检测算子是JohnF.Canny于1986年开发出来的一个多级边缘检测算法。Canny的目标是找到一个最优的边缘检测算法。其具有的优点是:

l  低错误性:标识出尽可能多的实际边缘,同时尽可能地减少噪声产生的误报。

l  高定位性:标识出的边缘要与图像中的实际边缘尽可能接近

l  最小效应:图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘

其步骤是,首先使用高斯平滑滤波器卷积降噪,计算梯度幅值和方向,然后进行非极大值抑制,排除非边缘像素,仅仅保留了一些细线条,最后滞后阈值。

对上面经过均值滤波的灰度图进行Canny边缘检测。

OpenCV单目视觉定位(测量)系统

 图四 边缘检测图

 

3.3 轮廓分析

对上面的Canny边缘检测得出的信息运用OpenCV提供的findContours函数边缘信息转化为轮廓信息,最后再对轮廓进行分析处理,找出目标物体。

 OpenCV单目视觉定位(测量)系统

图五 轮廓图

轮廓分析算法:遍历所有轮廓,排除凹轮廓和轮廓面积小于100像素的轮廓,找出轮廓为逼近六边形和逼近五边形的所有轮廓,找出这些逼近六边形和逼近五边形轮廓的最小外接矩形,并各提取最小外接矩形的中心(即逼近六边形和逼近五边形轮廓中心),若逼近六边形轮廓的最小外接矩形和逼近五边形轮廓的最小外接矩形中心基本在同一点(考虑畸变原因,中心点不一定一致),则为目标物体。

3       定位

本系统是采用640*480分辨率,20万像素的手动调焦的USB摄像头进行实验的,该摄像头广角较低,畸变不厉害。

定位功能得出的坐标是相对于自定义的图像坐标原点,在该系统中,定义的原点就是图像中心(320,240)单位为像素。因此,在摄像头水平放置的情况下,自定义图像原点即为二维空间上的摄像头正下方。

定位的基本思想是利用已知目标物体的长度和求出的目标物体的像素长度,得出像素的尺寸,再利用像素尺寸和目标物体在自定义原点的X,Y方向的像素距离,进而求出目标物体相对水平放置的摄像头的X,Y方向实际距离。

实验结果,本实验是摄像头距目标物体正上方大约50cm上进行测量的,摄像头为水平放置。经过多次测量,测出距离与实际距离误差基本上维持在1cm到2cm之间。如下图所示:(红色点为自定义的图象原点,左上方的Target_X,Target_Y分别为系统测出的目标距原点(摄像头正下方)的X和Y方向的测出距离。图像上的白色坐标系为实际理论距离。

 OpenCV单目视觉定位(测量)系统

图六 实验结果图

 

OpenCV单目视觉定位(测量)系统

                                                                               图、实验情况

1     结束语

该测量系统只在短范围内测量,实验还存在误差。因为该摄像头本身畸变不大,没有进行标定,矫正等一系列处理,实验数据还能接受,但对于广角大、畸变大的摄像头,本系统根本无法适用。还有的是,本系统还没有进行相机姿态估计,因此,对于摄像头与水平面有一定角度时,误差会大大增加。

在接下来的时间里,作者会尽量完善该系统,争取能用于无人机以及机器人的单目视觉定位系统。

本文难免有错漏,欢迎大家指出,本人联系方式:821992904@qq.com


核心代码:

[cpp] 
view plain
 copy

  1. //定位函数  
  2. void Location(){  
  3.   
  4.     //均值滤波  
  5.     blur(gray, gray_blur, Size(3, 3));  
  6.   
  7.     //边缘检测提取边缘信息  
  8.     Canny(gray_blur, dstThreshold, 150, 450);  
  9.     imshow(“canny边缘检测”, dstThreshold);  
  10.       
  11.     //对边缘图像提取轮廓信息  
  12.     vector<vector<Point> >contours;  
  13.     findContours(dstThreshold, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);  
  14.       
  15.     //画出轮廓  
  16.     drawContours(contours_image, contours, -1, Scalar(0, 0, 255));  
  17.     imshow(“contours”, contours_image);  
  18.   
  19.     //画出定义的原点  
  20.     circle(src, Point2f(oriX, oriY), 2, Scalar(0, 0, 255), 3);  
  21.   
  22.     //定义分别逼近六边形和五边形的轮廓  
  23.     vector< vector<Point> > Contour1_Ok, Contour2_Ok;  
  24.   
  25.     //轮廓分析  
  26.     vector<Point> approx;  
  27.     for (int i = 0; i < contours.size(); i++){  
  28.         approxPolyDP(Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.04, true);  
  29.   
  30.         //去除 小轮廓,只提取凸轮廓  
  31.         if (std::fabs(cv::contourArea(contours[i])) < 600 || !cv::isContourConvex(approx))  
  32.             continue;  
  33.   
  34.         //保存逼近六边形的轮廓 到 Contour1_Ok  
  35.          if (approx.size() == 6){  
  36.             Contour1_Ok.push_back(contours[i]);  
  37.         }  
  38.         //保存逼近五边形的轮廓 到 Contour2_Ok  
  39.          else if (approx.size() == 5){  
  40.              Contour2_Ok.push_back(contours[i]);  
  41.         }  
  42.   
  43.     }  
  44.   
  45.     //对所有符合要求的六边形,五边形轮廓进行分析  
  46.     //识别出自定义的物体的关键是:  
  47.     //1.六边形和五边形轮廓的最小外接矩形的中心基本在同一点  
  48.     //2.六边形轮廓的最小外接矩形的任一边长大于五边形轮廓的最小外接矩形的任一边长  
  49.     for (int i = 0; i < Contour1_Ok.size(); i++){  
  50.         for (int j = 0; j < Contour2_Ok.size(); j++){  
  51.             RotatedRect minRect1 = minAreaRect(Mat(Contour1_Ok[i]));  //六边形轮廓的最小外接矩形  
  52.             RotatedRect minRect2 = minAreaRect(Mat(Contour2_Ok[j]));  //五边形轮廓的最小外界矩形  
  53.             //找出符合要求的轮廓的最小外接矩形  
  54.             if ( fabs(minRect1.center.x – minRect2.center.x) < 30 && fabs(minRect1.center.y – minRect2.center.y)<30 && minRect1.size.width > minRect2.size.width){  
  55.                 Point2f vtx[4];  
  56.                 minRect1.points(vtx);  
  57.                   
  58.                 //画出找到的物体的最小外接矩形  
  59.                 for (int j = 0; j < 4; j++)  
  60.                     line(src, vtx[j], vtx[(j + 1) % 4], Scalar(0, 0, 255), 2, LINE_AA);  
  61.   
  62.                 //画出目标物中心到图像原点的直线  
  63.                 line(src, minRect1.center, Point2f(oriX, oriY), Scalar(0, 255, 0), 1, LINE_AA);  
  64.   
  65.                 //目标物距图像原点的X,Y方向的像素距离  
  66.                 targetImage_X = minRect1.center.x – oriX;  
  67.                 targetImage_Y = oriY – minRect1.center.y;  
  68.   
  69.                 line(src, minRect1.center, Point2f(minRect1.center.x, oriY), Scalar(255, 0, 0), 1, LINE_AA);  
  70.                 line(src, Point2f(oriX, oriY), Point2f(minRect1.center.x, oriY), Scalar(255, 0, 0), 1, LINE_AA);  
  71.   
  72.                 Point2f pointX((oriX + minRect1.center.x) / 2, oriY);  
  73.                 Point2f pointY(minRect1.center.x, (oriY + minRect1.center.y) / 2);    
  74.           
  75.                 //找出最大边  
  76.                 float a = minRect1.size.height, b = minRect1.size.width;  
  77.                 if (a < b) a = b;  
  78.                   
  79.                 mm_per_pixel = targetLength / a;               //计算像素尺寸 = 目标物的实际长度(cm)/ 目标物在图像上的像素长度(pixels)  
  80.                 targetActualX = mm_per_pixel *targetImage_X;   //计算实际距离X(cm)  
  81.                 targetActualY = mm_per_pixel *targetImage_Y;   //计算实际距离Y(cm)  
  82.   
  83.                 //打印信息在图片上  
  84.                 String text1 = “X:”+format(“%f”, targetImage_X);  
  85.                 String text2 = “Y:”+format(“%f”, targetImage_Y);  
  86.                 putText(src, text1, pointX, FONT_HERSHEY_SIMPLEX, 0.4, Scalar(0, 0, 255), 1, 8);  
  87.                 putText(src, text2, pointY, FONT_HERSHEY_SIMPLEX, 0.4, Scalar(0, 0, 255), 1, 8);  
  88.   
  89.                 String text3 = “Target_X:”+format(“%f”, targetActualX);  
  90.                 String text4 = “Target_Y:”+format(“%f”, targetActualY);  
  91.                 putText(src, text3, Point(10,30), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 1, 8);  
  92.                 putText(src, text4, Point(10,60), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 1, 8);  
  93.   
  94.                   
  95.             }  
  96.             break;  
  97.         }         
  98.         break;  
  99.     }  
  100.   
  101.     imshow(“SRC”, src);  
  102.   
  103. }  

完整代码

http://download.csdn.net/download/chenmohousuiyue/9947409


点击打开链接


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/149803.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • sql server之pivot函数「建议收藏」

    PIVOT用于将列值旋转为列名(即行转列)今天整理以前的笔记时,发现以前在PPD实习的时候遇到一个场景,感觉很实用所以想记录一下,说不定以后能用到,话不多说,直接上案例:–表table1问题编号时间节点listing_sizeTotalAmount1.120140-1k623.9001.12014…

  • 微信开放平台扫码登录[通俗易懂]

    微信开放平台扫码登录[通俗易懂]微信开放平台扫码登录的功能只有已经认证过的微信公众号才可以使用,很多学习微信的同学可能没办法使用这个功能,但是别担心,以下网址中有很多账号可以使用:【想要获取更多公众账号可以关注微信公众号:小D课堂】https://mp.weixin.qq.com/s?__biz=MzUyMDg1MDE2MA%3D%3D&amp;idx=2&amp;mid=2247483689&amp;sn=5…

  • 实战:sqlserver 2008 扩展事件-XML转换为标准的table格式[通俗易懂]

    实战:sqlserver 2008 扩展事件-XML转换为标准的table格式

  • Vue快速入门

    Vue快速入门迫于无奈还得学下前端的东西,虽然本人学的是后端,但是很早也就听过了Vue很火,所以这里花一天时间学一些基础的Vue知识,至少保证能看懂吧!

  • mac的内核_Mac编程

    mac的内核_Mac编程MAC内核编程指南-综述等

  • 详解scheduleAtFixedRate与scheduleWithFixedDelay原理

    详解scheduleAtFixedRate与scheduleWithFixedDelay原理前言前几天,肥佬分享了一篇关于定时器的文章你真的会使用定时器吗?,从使用角度为我们详细地说明了定时器的用法,包括fixedDelay、fixedRate,为什么会有这样的区别呢?下面我们从源码角度分析下二者的区别与底层原理。jdk定时器这里不再哆嗦延迟队列、线程池的知识了,请移步下面的链接延迟队列原理,http://cmsblogs.com/?p=2448线程池原理,http://…

    2022年10月24日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号