最近研究了一下单目测距,关于单目测距的原理有各位大神的讲解,这里只写一些自已使用上的记录,使用环境为windows10+opencv3.1+vs2015。
买了一个摄像头(笔记本的定焦摄像头也可以),不知道具体参数,想用它实现测距功能。
原理上就是根据三角性的相似性,假设摄像头焦距为f,摄像头距物体距离为dmm,物体在图像中的尺寸为p个像素(假设物体水平放置,为水平上的长度),物体实际长度为xmm, 根据三角形相似性,有
(式1)
显然,这里的焦距是以图像像素为单位的。
这里我们可以以棋盘纸为标准,用于计算相关参数,我所画的棋盘纸是在A4纸上打印的单元格为为20m*20mm,7行*10列个格,即boardSize为9*6。
显然,现在焦距f是未知的,为了计算f,我们可以在距摄像头距离d的位置横放一张带有棋盘的A4纸。
首先,我们估计一下摄像头的焦距,调整A4纸的位置,使的横放的A4纸的一边刚好填满图像的横坐标,测量此时A4纸距摄像头的距离d1 = 300mm,因为A4纸的尺寸是固定的为210mm*297mm,若图像尺寸为640*480,则也就是将297mm的宽度填满图像中的640像素,这样就有
(式2)
于是可以计算出焦距f。这里的值只是个大概估计值,可以用来后来用棋盘纸校准的时候相对照估量。
下面使用棋盘纸进行单目校准,关于棋盘纸的单目校准原理也有很多大神讲解,下面贴出来的仅为部分代码。里面缺少类成员函数声明以及相关头文件。
- 1、使用opencv获取图像,并保存。
//打开摄像头
bool CCamera::OpenCamera(int index, VideoCapture &cap)
{
if (cap.isOpened())
{
std::cout << "警告!摄像头"<<index<<"已经被打开!" << std::endl;
}
if (cap.open(index))
{
cout << "摄像头" << index << "打开成功!" << endl;
}
else
{
cout << "Error!摄像头" << index << "打开失败." << endl;
return false;
}
return true;
}
//获取图像
void CCamera::GetCameraImage(VideoCapture cap, Mat &img)
{
if (!cap.isOpened())
{
cout << "摄像头未打开!" << endl;
return;
}
cap >> img;
}
//保存图像
int CCamera::SaveCameraImage(VideoCapture cap, int nGroup)
{
Mat img;
string imgName;
int index = 1;
cout << "--------操作指南--------" << endl;
cout << "按'q'或'Q'退出图像采集\