单目测距实战

前言

单目测距是通过使用单个摄像头捕获的图像信息俩估计物体的距离。这是一种在计算机领域广泛研究的问题,并且困难之处在于从2d图像中恢复3d信息。

单目测距常用的或者是实用方法是相似三角形法。
相似三角形法:假设有一个距离为w的目标的或者物体。然后,我们用相机对物体进行拍照并且测距物体的像素宽度p,相机焦距为f。根据相似三角形得到目标放在距离我们相机为d的位置
d = f * w/p
在这里插入图片描述

图像去畸变

图像去畸变是使用相机校准参数来修改图像,进而消除由于镜头的光学因素和相机的构造因素导致的图像畸变。
畸变主要有两种类型:径向畸变和切向畸变。径向畸变是由于透镜的形状导致光线弯曲的比例变化,使得图像看起来像在水面下观察物体。切向畸变则是由于透镜和成像平面之间的不平行导致的。

桶形畸变发生时,图像的边缘向外弯曲,像被拉伸到一个“桶”形状上,像是鱼眼镜头拍摄的效果。在图像的中心,物体看起来比实际更大g,而在边缘则显得更小。这是因为镜头折射光线的方式,使得直线在图像上呈现成曲线。

枕形畸变则正好与桶形畸变相反,直线会向图像的中心弯曲,就好像被压缩在一款“枕头”上。在图像的中心,物体看起来比实际要小,而在边缘则看起来更大。
在这里插入图片描述
一般情况下,从摄像头或图像文件中读取的原始图像都包含一定的畸变,取决于具体的摄像头和镜头参数。因此,直接读取的图像是原始的,畸变的。
在进行单目测距或者其他涉及准确的空间量测的计算机视觉任务中,预处理步骤通常会包括一个图像去畸变(undistortion)的步骤。原因是摄像头的镜片畸变会扭曲图像,在图像上测得的距离可能会因此产生偏差。对图像进行去畸变可以提高测量结果的准确性。
因此,进行单目测距通常会需要一个去畸变的步骤。你需要摄像头的校准参数才能正确地去除畸变。在OpenCV中,这通常通过cv::undistort()函数来进行,需要提供摄像头的内参矩阵和畸变系数。

CameraMatrix(相机矩阵):这是一个3x3的矩阵,也被称为内参矩阵。它包含了相机的主要内部特性,其中包括焦距(focal lengths)、图像中心(principal point),并作为投影函数的一部分将三维的世界坐标转换为二维的图像坐标。

DistCoeffs(畸变系数):这是一个一维的矩阵,用于描述和校正相机镜头的径向和切向畸变。径向畸变包括前面提到的桶形畸变和枕形畸变,而切向畸变通常是由于镜头和图像传感器之间的不完全平行导致的。

单目测距代码

1、基于实际物体的高度或者宽度的单目测距

单目测距使用的方法大多数是通过参照物,即已知实际物体的高度或者宽度来进行测距。但是这种方法的缺点必须要已经实际物体的高度或者宽度。

	double calculateDistance(double &objectHeight, double &imageHeight, double &focalLength)
	{
		// 距离 = 相机的焦距(像素)* 物体的实际高度(米)/ 物体在图像上的成像高度(像素) //* 相机传感器的单位像素高度(米)
		double distance = (focalLength * objectHeight) / (imageHeight);
		return distance;
	}

2、基于相机安装高度的单目测距

通过已知相机的高度作为先验条件,计算物体的距离

cv::Point3f MonocularRanging(int x0, int y0)
{
	/*
      x1为检测框左上角x坐标,x2为检测框右下角x坐标,y2为检测框右下角y坐标;
      取检测框底边中点作为单目测距点输入。
                y
                |
                |
      x <-------
    */
    //RGB相机相关参数
    float Theta = 97.5 / 2; //水平视场角一半
	float Beta  = 79.4 / 2; //垂直视场角一半
	float Alpha = 10; //10; //相机安装仰角
    float Mh    = 46.52;    //相机安装高度
    // Opencv
    cv::Mat CameraMatrix = (cv::Mat_<float>(3,3) <<  2.9489061908999292e+02,       0., 3.1866700927076226e+02,
                                                     0., 2.9491166478751404e+02, 2.4225251338364708e+02,
                                                      0.,        0.,        1.);
    cv::Mat DistCoeffs = (cv::Mat_<float>(1,5) << 1.2105428797704496e-02, -1.9610247948251138e-02, 4.2034414972305298e-04, 4.9760569760944572e-04, 0.);
    float Tt = Theta * PI / 180.;
    float Bt = (Beta + pitch)  * PI / 180.;
    float x, y, kx, ky;
    kx = x0;   // 如果考虑到图像去畸变的情况,可以对x0和y0进行去畸变处理。
    ky = y0;
    double a, b;
	double py = abs(ky - CameraMatrix.at<float>(1, 2));
    double px = CameraMatrix.at<float>(0, 2) - kx;
    a = atan(tan(Bt) * py / CameraMatrix.at<float>(1, 2)) * 180 / PI;
    //b = (90 - a - Alpha) * PI / 180;//相机为俯角时
    b = (a - Alpha) * PI / 180;//相机为仰角时
	y = Mh / tan(b);
    y = abs(y);
    x = tan(Tt) * px * hypot(Mh,y) / CameraMatrix.at<float>(0, 2);
    cv::Point3f point;
    point.x = x * 1e-3;
    point.y = y * 1e-3;
    point.z = 0;
    return point;

备注

  • 角度和弧度是两种经常在数学和物理中使用的角度测量单位。
弧度 = 角度 * π / 180 
  • 在数学中,正弦(sine)、余弦(cosine)、切线(tangent)等三角函数的定义和计算通常是基于弧度制的。这意味着这些三角函数的输入应该是以弧度为单位的角度值。

参考链接:
1、https://zhuanlan.zhihu.com/p/642601409

  • 11
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值