c++ - 如何获得物体的距离以及如何正确使用相机校准矩阵?

标签 c++ opencv computer-vision

我使用opencv成功校准了相机。我正在使用的相机镜头。
https://www.baslerweb.com/en/products/vision-components/lenses/basler-lens-c125-0418-5m-f1-8-f4mm/

内部和外部摄像机参数如下。

cv::Mat cameraMatrix(3, 3, cv::DataType<double>::type);
    cameraMatrix.at<double>(0) = 1782.80;//fx //432.2 in mm
    cameraMatrix.at<double>(1) = 0;
    cameraMatrix.at<double>(2) = 3.0587694283633488e+002;//cx
    cameraMatrix.at<double>(3) = 0;
    cameraMatrix.at<double>(4) = 1782.80;//fy
    cameraMatrix.at<double>(5) = 3.0535864258476721e+002;//cy
    cameraMatrix.at<double>(6) = 0;
    cameraMatrix.at<double>(7) = 0;
    cameraMatrix.at<double>(8) = 1;


    cv::Mat disCoeffs(1, 5, cv::DataType<double>::type);
    disCoeffs.at<double>(0) = -8.1752937039996709e-001;//k1
    disCoeffs.at<double>(1) = -2.5660653367749450e+001;//k2
    disCoeffs.at<double>(2) = -1.5556922931812768e-002;//p1
    disCoeffs.at<double>(3) = -4.4021541217208054e-002;//p2
    disCoeffs.at<double>(4) = 1.5042036073609015e+002;//k3

我知道此公式用于计算物体的距离。但是我很困惑如何正确使用它。

enter image description here

我的相机分辨率为640x480。

焦距= 1782.80(px)不知道如何正确转换为mm

我知道焦距是传感器到图像平面的距离。那么这个值实际代表什么呢?像素只是一个单位,代表屏幕上的点。

我正在使用的对象是圆圈。
半径=22。(宽和高44 * 44)
圆心:300,300(x,y)

传感器高度不知道怎么得到?

我在哪里使用原理点?

我如何获得相机到物体的距离?如何获得圆的真实世界坐标?

我知道要问的太多了。我尝试一个月。找不到任何适当的解决方案。

我使用功能solvePnP来获取相机的平移和旋转矩阵。但是我有问题如何计算目标点?

最佳答案

您的cxcy似乎是错误的,因为它们应该是分辨率的一半:640/2480/2fxfy以您从校准过程中获得的像素为单位。要将其转换为mm,请使用以下公式:

pixels width = (image width in pixels) * (focal length in mm) / (CCD width in mm)

pixels height = (image height in pixels) * (focal length in mm) / (CCD height in mm)

校准相机时,请使用这些公式来确保您具有正确的值。对我来说cxcy是错误的,因为它们代表图像的中心(除非您的图像是正方形的,否则它们不应该相等)。对于fxfy,我无法分辨,因为我不知道您相机的CCD。如果CCD为正方形,则它们可以相等。

请勿手动更改这些参数,而应让您的校准软件对其进行计算。

现在有了这些参数,如何计算距离?

在某种意义上说,您提供的公式没有用处,因为如果可以测量实际高度,通常可以测量距离(至少在您的情况下)..为什么要使用相机!

因此,要计算现实世界中的距离,您还需要另外两件事:外部参数(您的cameraMatrix矩阵是固有参数)和现实世界坐标中至少四个点(点越多越好)。
一旦有了这些东西,就可以使用solvePnP函数查找对象的姿势。姿势表示相对于相机框架的平移和旋转。
http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#solvepnp

这是一段代码可以帮助实现这一点:
//Four points in real world with `x,y and z` coordinates
vector<Point3f> vec3d;
vec3d.push_back(Point3f(0, 0, 0));
vec3d.push_back(Point3f(0, 211, 0));
vec3d.push_back(Point3f(295, 211, 0));
vec3d.push_back(Point3f(295, 0, 0));
z=0,因为您的真实点在平面上。
//The same four points but in your image plan, therefore there is no z and they're in pixel unit
vector<Point2f> vec2d;
vec2d.push_back(Point2f(532, 412)); //(y,x)
vec2d.push_back(Point2f(583, 594));
vec2d.push_back(Point2f(927, 535));
vec2d.push_back(Point2f(817, 364));

//The pose of the object: rvec is your rotation vector, tvec is your translation vector
cv::Mat rvec, tvec;
solvePnP(vec3d, vec2d, cameraMatrix, distCoeffs, rvec, tvec);

最后,您可以将tvec的实际距离计算为欧几里得距离:d=std::sqrt(tx*tx+ty*ty+tz*tz)

您的问题:

传感器高度不知道怎么得到?

在Internet或手册中查找您的相机规格,即可找到。

我在哪里使用原理点?

它们是您的固有参数。您不会单独使用它们。

我如何获得相机到物体的距离?如何获得圆的真实世界坐标?

我在上面解释了。您需要四个点,一个圆只有一个,不足以计算姿势。

但是我有问题如何计算目标点?

resolvePnP中的objectPoints是您的实际坐标。例如,一个棋盘有一些角,在这些角上,我们知道相对于您在棋盘上选择的世界框架的每个mm的确切位置。它可以在左上角或类似的位置,并且z = 0,因为棋盘就像您的圈子一样被打印在纸上!

编辑:

您可以在手册第13页here中找到更多规格。据说7.4 x 7.4µm:
f (mm)=f(pixel) x pixel_size(mm) => f (mm) = 1782.80x7.2e-6 = 12.83616 (mm) 

不是4mm!那么您需要再次进行校准,这是错误的!

3D点:
vector vec3d;vec3d是存储3D坐标点的位置。我为您提供了第一个起点的示例:
vec3d.push_back(Point3f(0, 0, 0)); //y,x,z

EDIT3

如果你采取这样的模式

enter image description here

然后选择例如左上角或右上角的圆,它的坐标为(0,0,0),即原点。之后,它旁边的圆是您的第二个点,它将具有(x,0,0) x是两个圆之间的距离(以毫米为单位)。对图案中的四个点都执行相同操作。您可以选择所需的任何图案,只要可以在图像中检测到它并以像素为单位检索它们的坐标即可。
如果您仍然不理解,建议您参加projective geometrycamera models ..的类(class),以便您了解每个参数的含义。

关于c++ - 如何获得物体的距离以及如何正确使用相机校准矩阵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45364856/

相关文章:

python - 当使用 OpenCV 完成图像加载和调整大小时,Resnet50 会产生不同的预测

c++ - 如果大于则无锁增量

c++ - 在纹理 OpenGL 中使用 GL_LINEAR 时的外部伪影

c++ - 当迭代器是类成员时,为什么在C++中for循环变慢

image - 如何在 OpenCV 中重新映射特定区域

opencv - 签名的 HOG 描述符

python - 将文本图像切成字符的最佳方法

c# - 是否可以使用 Blob 分析删除图像的小块?

python - 使用 OpenCv-python 的失真效果

c++ - 两阶段查找-需要说明