最好的电子音响科技diy制作网站

haoDIY_音响电子电脑科技DIY小制作发明

当前位置: 主页 > 电子DIY > 工具仪表 > 仪器仪表 >

自制简易激光测距仪

时间:2015-06-30 16:50来源:未知 作者:admin 点击:
// 找到了画十字线标注 for (row = 0; row H; row++) { for (col = 0; col W; col++) { i = (unsigned long)(row*3*W + 3*col); if ((row == max_row) || (col == max_col)) *(img_d + i) = *(img_d + i + 1) = *(i
抽空做了个简单的激光测距的小东西,这个方案简单易实现,而且可以用现有的opencv库很容易作进一步性能改进。
之前在一个老外的网上看到介绍,现在找不到了。
基本原理:

自制简易激光测距仪

这个图很清晰的解释了测距的基本原理,假设激光投射到目标物体上,同时位于同一平面的摄像头画面内能够捕捉到激光照射点,(所以要求摄像头和激光头之间的距离h不能太远),激光光线和摄像头成像轴完全平行。这样,照射到目标物体的激光点和摄像头成像平面连线和摄像头轴线之间会有一个夹角theta,通过在摄像帧图像里面对这个激光点相对于轴心的像素点的判断,可以确定出theta的大小,从而就能得到距离D。D越远,画面中激光点离中心越近,D越小,激光点离中心越远。画面的激光点判断可以简单的认为最亮的点就是激光点,逐像素扫描。当然可以使用opencv的API实现更复杂更精确的激光点确定方法。
整个算法比较简单但是很实用。
D很容易由下式得出:

自制简易激光测距仪

所以只有一个未知量theta,theta由几个因素决定,一个是画面中激光点离轴心的距离pfc,这个可以通过帧画面的处理得到,
另外两个是固定量,和具体摄像头有关,每个摄像头都不一样,rpc表示每个像素的弧度(其实就是与pfc想乘的因子),还有一个是弧度偏移补偿量,用于矫正。

自制简易激光测距仪

这样我们可以得到下式:

自制简易激光测距仪

经过上面的分析,只有pfc一个变量,其他的都算已知量。那怎么得到rpc和ro呢?
可以通过实验得到:
在实际试验中先得到两组数据,分别是激光点离中心的距离和真实的距离D

矫正数据
光点离中心距离          D (cm)
  61                         137
  137                          64


代入
137 = 7.350/tan(61x+y)
64 = 7.350/tan(137x+y)

这样得到
Offset (ro) = 0.0053867 radians
Gain (rpc) = 0.000795302 radians/pixel


采用的摄像头,很普通的那种,640*480像素

自制简易激光测距仪

做好了的实验板:

自制简易激光测距仪

代码:

#include <iostream>

using namespace std;
#include "opencv/cv.h"
#p#分页标题#e##include "opencv2/highgui/highgui.hpp"

int main( int argc, char** argv ) {
   cvNamedWindow( "Example", CV_WINDOW_AUTOSIZE );
   CvCapture* capture;
   if (argc==1) {
       capture = cvCreateCameraCapture( 0 );
   } else {
       capture = cvCreateFileCapture( argv[1] );
   }
   assert( capture != NULL );

   IplImage* frame;
   while(1) {
       frame = cvQueryFrame( capture );
       if( !frame ) break;

       // 对取到的图像做处理

       unsigned int    W, H;
       unsigned int    row, col;
       unsigned long   i;
       unsigned int    max_row;
       unsigned int    max_col;
       unsigned char   max_val = 0;

       const double    gain = 0.000795302;
       const double    offset = 0.0053867;
       const double    h_cm = 7.350;              // 我的摄像头和激光头距离7.35cm
       double          range;
       unsigned int    pixels_from_center;

       W = frame->width;
       H = frame->height;
       unsigned char *img_d = (unsigned char *)frame->imageData;
       
       // 假设激光点是最亮点,最简单的实现,一般来说确实是这样,但是在背景干扰大的情况下会误判,还有很大的提高空间

       for (row = 0; row < H; row++) {
           for (col = 0; col < W; col++) {
               i = (unsigned long)(row*3*W + 3*col);

               if (*(img_d + i) >= max_val)
               {
                   max_val = *(img_d + i);
                   max_row = row;
                   max_col = col;
               }
           }
       }

       max_val = 0;#p#分页标题#e#

       // 找到了画十字线标注
       for (row = 0; row < H; row++) {
           for (col = 0; col < W; col++) {
               i = (unsigned long)(row*3*W + 3*col);
               if ((row == max_row) || (col == max_col))
                           *(img_d + i) =
                           *(img_d + i + 1) =
                           *(img_d + i + 2) = 255;
           }
       }

       pixels_from_center = max_row - H/2;

       // 算出距离并打印出来
       range = h_cm / tan(pixels_from_center * gain + offset);

       cout << "W= " << W << ", H= " << H << ", Max Value at x="
            << max_col << ", y= " << max_row << ", range= " << range << endl;


       cvShowImage( "Example", frame );
       char c = cvWaitKey(10);
       if( c == 27 ) break;
   }
   cvReleaseCapture( &capture );
   cvDestroyWindow( "Example" );
}



实际测试中误差还算可以,在5%以内,最主要是激光点的判断还有很大提高空间,opencv提供了不少API,网上也有一些文章
距离64cm:

自制简易激光测距仪

距离152cm:

自制简易激光测距仪 (责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(2)
100%
相关文章
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
推荐内容