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.0053867radians
Gain (rpc)=0.000795302radians/pixel采用的摄像头,很普通的那种,640*480像素
做好了的实验板:
代码:
#include <iostream>
usingnamespacestd;
#include"opencv/cv.h"
#include"opencv2/highgui/highgui.hpp"
intmain( 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;
//对取到的图像做处理
unsignedint W, H;
unsignedint row, col;
unsignedlong i;
unsignedint max_row;
unsignedint max_col;
unsignedchar max_val = 0;
constdouble gain = 0.000795302;
constdouble offset = 0.0053867;
constdouble h_cm = 7.350; //我的摄像头和激光头距离7.35cm
double range;
unsignedint pixels_from_center;
W= frame->width;
H= frame->height;
unsignedchar*img_d = (unsignedchar*)frame->imageData;
//假设激光点是最亮点,最简单的实现,一般来说确实是这样,但是在背景干扰大的情况下会误判,还有很大的提高空间
for(row = 0; row < H; row++) {
for(col = 0; col < W; col++) {
i = (unsignedlong)(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;
//找到了画十字线标注
for(row = 0; row < H; row++) {
for(col = 0; col < W; col++) {
i = (unsignedlong)(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 atx="
<<max_col <<", y= " <<max_row <<", range= "<<range <<endl;
cvShowImage( "Example", frame );
charc = cvWaitKey(10);
if( c == 27 ) break;
}
cvReleaseCapture( &capture );
cvDestroyWindow( "Example" );
}
实际测试中误差还算可以,在5%以内,最主要是激光点的判断还有很大提高空间,opencv提供了不少API,网上也有一些文章距离64cm:
距离152cm: