单目相机测距

#include <Eigen/Dense>
#include <iostream>
#include <vector>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>


Eigen::Matrix4f m_camera2robot;
Eigen::Matrix3f cameraIntrinsic;
cv::Mat distCoeffs;




void buildPlaneFromPoints(const Eigen::Vector3f& point1, const Eigen::Vector3f& point2, const Eigen::Vector3f& point3, Eigen::Vector4f& plane) {
    // Compute two vectors lying on the plane
    Eigen::Vector3f vector1 = point2 - point1;
    Eigen::Vector3f vector2 = point3 - point1;

    // Compute the normal vector of the plane (cross product of vector1 and vector2)
    Eigen::Vector3f normal_vector = vector1.cross(vector2);

    // Check if the normal vector is zero (which happens when the points are collinear or not unique)
    if (normal_vector.isZero()) {
        std::cout << "Error: The provided points do not form a valid plane (they might be collinear or identical)." << std::endl;
        plane.setZero();
        return;
    }

    // Normalize the normal vector
    normal_vector.normalize();

    // Compute the D coefficient of the plane equation using one of the points
    float D = -normal_vector.dot(point1);

    // Set the coefficients of the plane equation (Ax + By + Cz + D = 0)
    // Here we make sure that the plane is assigned correctly without causing alignment issues
    plane.head<3>() = normal_vector;
    plane[3] = D;
}

void tranformatePlane(const Eigen::Vector4f& planeInA, const Eigen::Matrix4f& T_A2B, Eigen::Vector4f& planeInB) {
    // Extract normal vector from plane
    Eigen::Vector3f normal_vector = (planeInA.head<3>()).normalized();

    // Find the index of the maximum absolute component in the normal vector
    int max_index = 0;
    for (int i = 1; i < 3; ++i) {
        if (std::abs(normal_vector(i)) > std::abs(normal_vector(max_index))) {
            max_index = i;
        }
    }
    Eigen::Vector3f pointA;
    Eigen::Vector3f pointB;
    Eigen::Vector3f pointC;
    pointA.setZero();
    pointB.setZero();
    pointC.setZero();
    pointA(max_index) = 1.0f;
    pointB((max_index + 1) % 3) = 1.0f;
    pointC((max_index + 2) % 3) = 1.0f;

    float scale_factor = -planeInA(3) / normal_vector(max_index);
    pointA = pointA * scale_factor;
    pointB(max_index) = -(pointB.dot(normal_vector) + planeInA(3)) / normal_vector(max_index);
    pointC(max_index) = -(pointC.dot(normal_vector) + planeInA(3)) / normal_vector(max_index);

    Eigen::Vector3f pointA2 = T_A2B.block<3, 3>(0, 0) * pointA + T_A2B.block<3, 1>(0, 3);
    Eigen::Vector3f pointB2 = T_A2B.block<3, 3>(0, 0) * pointB + T_A2B.block<3, 1>(0, 3);
    Eigen::Vector3f pointC2 = T_A2B.block<3, 3>(0, 0) * pointC + T_A2B.block<3, 1>(0, 3);

    buildPlaneFromPoints(pointA2, pointB2, pointC2, planeInB);
}
bool getLinePlaneCrossPt(const Eigen::Vector3f& p1, const Eigen::Vector3f& p2, const Eigen::Vector4f& plane, Eigen::Vector3f& crossPoint) {
    // 求分子P1D
    auto P1D = plane[0] * p1[0] + plane[1] * p1[1] + plane[2] * p1[2] + plane[3]; // ax1+by1+cz1+d//or采用向量点乘方式

    const Eigen::Vector3f P1P2 = p2 - p1;

    // 求分母P1D2
    auto P1D2 = plane[0] * P1P2[0] + plane[1] * P1P2[1] + plane[2] * P1P2[2];
    if (std::abs(P1D2) < FLT_EPSILON)
        return false; // 平行

    auto m = P1D / P1D2;
    crossPoint = p1 - m * P1P2; // 注意:此处是 负号- 同时求m时无绝对值符号

    return true;
}
template <typename PointT>
void transformPointCloud(const std::vector<PointT>& cloudin, std::vector<PointT>& cloudout, const Eigen::Matrix4f& T)
{
    // 为输出点云分配空间
    int num = cloudin.size();
    cloudout.resize(num);

    Eigen::Matrix3f rotate = T.topLeftCorner<3, 3>();
    Eigen::Vector3f translate = T.col(3).head<3>();
    // 进行点云变换
    for (int i = 0; i < num; ++i)
    {

        Eigen::Vector3f transformedPoint = translate + rotate * cloudin[i].template head<3>(); // 矩阵乘法
        cloudout[i] = cloudin[i];                                                              // 赋值其他信息
        cloudout[i].template head<3>() = transformedPoint;
    }
    return;
}

void getPointSetByPlane(const std::vector<cv::Point2f>& imagePoints, const Eigen::Matrix3f& cameraIntrinsic, const Eigen::Vector4f& plane, std::vector<Eigen::Vector3f>& crossPoints) {
    int num = imagePoints.size();
    crossPoints.resize(num);
    float fx = cameraIntrinsic(0, 0);
    float fy = cameraIntrinsic(1, 1);
    float cx = cameraIntrinsic(0, 2);
    float cy = cameraIntrinsic(1, 2);
    for (int i = 0; i < num; i++) {
        cv::Point2f pt2d = imagePoints[i];
        Eigen::Vector3f pt3d;
        pt3d(0) = (pt2d.x - cx) / fx;
        pt3d(1) = (pt2d.y - cy) / fy;
        pt3d(2) = 1;
        Eigen::Vector3f line_origin{ 0, 0, 0 };
        Eigen::Vector3f ptCross;

        if (getLinePlaneCrossPt(line_origin, pt3d, plane, ptCross)) {
            crossPoints[i] = ptCross;
        }
    }
}
void getUndistoredPixels(const std::vector<cv::Point2f>& input, std::vector<cv::Point2f>& output, cv::Mat& cameraMatrix, cv::Mat& distCoeffs) {
     cv::fisheye::undistortPoints(input, output, cameraMatrix, distCoeffs, cv::Mat(), cameraMatrix); // 矫正角点
}

void restorePixels(const std::vector<cv::Point2f>& input, std::vector<cv::Point2f>& output, cv::Mat& cameraMatrix) {// 假设 fx, fy, cx, cy 是相机内参矩阵中的值
    float fx = cameraMatrix.at<float>(0, 0);  // 焦距 fx
    float fy = cameraMatrix.at<float>(1, 1);  // 焦距 fy
    float cx = cameraMatrix.at<float>(0, 2);  // 主点 cx
    float cy = cameraMatrix.at<float>(1, 2);  // 主点 cy
    std::vector<cv::Point2f> output_pixel;
    for (const auto& pt : input) {
        cv::Point2f pixel_point;
        pixel_point.x = pt.x * fx + cx;
        pixel_point.y = pt.y * fy + cy;
        output_pixel.push_back(pixel_point);
    }
    output = output_pixel;
    // 输出像素坐标结果
    for (const auto& pt : output) {
        std::cout << "Pixel Point: " << pt << std::endl;
    }
}


int main() {
    m_camera2robot << 3.39371385e-03, -3.47959429e-01, 9.37503338e-01, 4.27294761e-01,
        -9.99993742e-01, -1.97809911e-03, 2.88561685e-03, 4.05987427e-02,
        8.50516604e-04, -9.37507451e-01, -3.47963899e-01, 2.34021828e-01,
        0., 0., 0., 1.;

    cameraIntrinsic << 1.83869247e+02, 0., 1.58713028e+02, 0., 1.83787170e+02,
        1.33699142e+02, 0., 0., 1.;

    distCoeffs = (cv::Mat_<double>(4, 1) << -1.09969601e-01, 2.19760053e-02, -2.66296137e-02,
        1.13827791e-02);
    std::cout << m_camera2robot << std::endl;
    Eigen::Vector4f m_planeInRGB; 
    m_planeInRGB(3) = -1000; // 先默认机器平行地面
    Eigen::Vector4f planen0{ 0, 0, 1, 0 };
    tranformatePlane(planen0, m_camera2robot.inverse(), m_planeInRGB);
    std::cout << m_planeInRGB << std::endl;
    std::vector<cv::Point2f> imagePoints;
    cv::Point2f Point = { 160,70 };
    imagePoints.push_back(Point);
    cv::Mat cameraMatrix(3, 3, CV_32F, cameraIntrinsic.data());
    std::cout << cameraMatrix << std::endl;
    getUndistoredPixels(imagePoints, imagePoints, cameraMatrix,distCoeffs);
    restorePixels(imagePoints, imagePoints, cameraMatrix);
    std::vector<Eigen::Vector3f> Pts3d;
    getPointSetByPlane(imagePoints, cameraIntrinsic, m_planeInRGB, Pts3d);
    transformPointCloud(Pts3d, Pts3d, m_camera2robot);

    std::cout <<"Pts3d:"<< Pts3d[0] << std::endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值