opencv+WLS进行双目视觉测量进

第一个就是opencvcontribuild的编译,需要使用cmake进行,直接编译source,网上有教程,注意如果最后想编译成一个opencv.lib需要勾选buildonetgarget

#include "measure.h"


static int state = 0;//通过0 1 2 来控制目前的状态,0采集鼠标单机的第一个点,2 采集鼠标单机的第二个点
static std::vector<cv::Point> pointList(2);//记录鼠标点击两点出的距离
static std::vector<cv::Vec3f> Point3D(2);

Mymeasure::Mymeasure() {
    calibrationFilePath = "calibration_results.xml";
    imgSize = cv::Size(640, 480);
    isPaused = false;
    block_size = 13;
    NumDisparities = 4;
    img_channels = 1;
    UniquenessRatio = 15;
    SpeckleWindowSize = 0;
}

void Mymeasure::getDist(int event, int x, int y, int flag, void* userdata) {
    if (event == cv::EVENT_LBUTTONDOWN) {
        if (state == 0) {
            pointList[state] = cv::Point(x, y);
            std::cout << state + 1 << "th point saved:" << pointList[state].x << " ; " << pointList[state].y << std::endl;
            state++;
        }
        else if (state == 1) {
            pointList[state] = cv::Point(x, y);
            std::cout << state + 1 << "th point saved:" << pointList[state].x << " ; " << pointList[state].y << std::endl;
            state++;
        }
        else {
            std::cout << "Reset!" << std::endl;
            state = 0;
        }
    }
}

void mouseWrapperOnline(int event, int x, int y, int flags, void* param)
{
    Mymeasure* ptr = (Mymeasure*)(param);
    ptr->getDist(event, x, y, flags, 0);
}

void Mymeasure::measureDistOnline() {
    // 打开 XML 相机标定文件
    cv::FileStorage fs(calibrationFilePath, cv::FileStorage::READ);  

    // 读取左相机的内参数矩阵和畸变系数
    fs["M1"] >> leftCameraMatrix;
    fs["D1"] >> leftDistCoeffs;

    // 读取右相机的内参数矩阵和畸变系数
    fs["M2"] >> rightCameraMatrix;
    fs["D2"] >> rightDistCoeffs;

    // 读取相机之间的旋转矩阵和平移向量
    fs["R"] >> R;
    fs["T"] >> T;

    fs.release();  // 关闭文件

    //创建StereoBM对象并设置参数
    static cv::Ptr<cv::StereoSGBM> matcher = cv::StereoSGBM::create();
    matcher->setMinDisparity(0);
    matcher->setDisp12MaxDiff(1);
    matcher->setPreFilterCap(1);
    matcher->setSpeckleRange(1);
    matcher->setMode(cv::StereoSGBM::MODE_SGBM);
    matcher->setBlockSize(block_size);
    matcher->setP1(16 * img_channels * block_size * block_size);
    matcher->setP1(32 * img_channels * block_size * block_size);
    matcher->setNumDisparities(NumDisparities * 16);//一般64是比较理想的效果
    matcher->setUniquenessRatio(UniquenessRatio);
    matcher->setSpeckleWindowSize(SpeckleWindowSize);

    stereoRectify(leftCameraMatrix, leftDistCoeffs, rightCameraMatrix, rightDistCoeffs, imgSize, R, T, R1, R2, P1, P2, Q, cv::CALIB_ZERO_DISPARITY,
        0, imgSize, &validROI1, &validROI2);

    cv::initUndistortRectifyMap(leftCameraMatrix, leftDistCoeffs, R1, P1,
        imgSize, CV_16SC2, map1Left, map2Left);

    cv::initUndistortRectifyMap(rightCameraMatrix, rightDistCoeffs, R2, P2,
        imgSize, CV_16SC2, map1Right, map2Right);

    cv::namedWindow("Online measure");
    cv::namedWindow("Disparity");
    cv::namedWindow("WLSDisparity");


    cv::setMouseCallback("Online measure", mouseWrapperOnline);
    /*cv::createTrackbar("BlockSize", "Disparity", &block_size, 21, barWrapperBS);
    cv::createTrackbar("NumDisparities", "Disparity", &NumDisparities, 16, barWrapperNDC);
    cv::createTrackbar("UniquenessRatio", "Disparity", &UniquenessRatio, 30, barWrapperUR);
    cv::createTrackbar("SpeckleWindowSize", "Disparity", &SpeckleWindowSize, 100, barWrapperSWSC);*/
    cv::Mat imgLeftGray, imgRightGray;
    cv::Mat copyL, copyR;
    //"G:/CodeFiles/Visual Studio/OpenCV/CV_Demo/CV_Demo/outputleft.avi"
    cv::VideoCapture cap1(1), cap2(2);
    while (1) {
        if (isPaused == false) {
            cap1.read(imgLeft);
            cap2.read(imgRight);
        }
        else {
            if (state == 0) {
                imgLeft.copyTo(copyL);
                imgRight.copyTo(copyR);
            }
            else if (state == 2) {
                copyL.copyTo(imgLeft);
                copyR.copyTo(imgRight);
            }
        }

        /*matcher->setBlockSize(block_size);
        matcher->setP1(8 * img_channels * block_size * block_size);
        matcher->setP1(32 * img_channels * block_size * block_size);
        matcher->setNumDisparities(NumDisparities * 16);
        matcher->setUniquenessRatio(UniquenessRatio);
        matcher->setSpeckleWindowSize(SpeckleWindowSize);*/
        //将原始图像转化为灰度图进行全局匹配
        cv::cvtColor(imgLeft, imgLeftGray, cv::COLOR_BGR2GRAY);
        cv::cvtColor(imgRight, imgRightGray, cv::COLOR_BGR2GRAY);

        cv::Mat imgLeft2;
        cv::remap(imgLeft, imgLeft2, map1Left, map2Left, cv::INTER_LINEAR);

        //对图像进行映射
        cv::remap(imgLeftGray, imgLeftRec, map1Left, map2Left, cv::INTER_LINEAR);
        cv::remap(imgRightGray, imgRightRec, map1Right, map2Right, cv::INTER_LINEAR);

        cv::Ptr<cv::StereoMatcher> right_matcher = cv::ximgproc::createRightMatcher(matcher);
        cv::Mat right_disp;
        cv::Mat filtered_disp;

        matcher->compute(imgLeftRec, imgRightRec, disparityMap);
        right_matcher->compute(imgRightRec, imgLeftRec, right_disp);


        //matcher->compute(imgLeftRec, imgRightRec, disparityMap);
        //disparityMap.convertTo(disparityMap, CV_32F, 1.0 / 16);                //除以16得到真实视差值

        //cv::Mat disp8 = cv::Mat(disparityMap.rows, disparityMap.cols, CV_8UC1);
        //normalize(disparityMap, disp8, 0, 255, cv::NORM_MINMAX, CV_8UC1);
        //cv::reprojectImageTo3D(disparityMap, myPointCloud, Q, true);
        //myPointCloud *= 16;
         //把这段代码放在这里就不会相互影响了
        cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_filter = cv::ximgproc::createDisparityWLSFilter(matcher);
        wls_filter->filter(disparityMap, imgLeft2, filtered_disp, right_disp);

        int vis_mult = 1.0;
        cv::Mat WLSdisp8 = cv::Mat(filtered_disp.rows, filtered_disp.cols, CV_8UC1);
        cv::ximgproc::getDisparityVis(filtered_disp, WLSdisp8, vis_mult);

        
        //cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_filter = cv::ximgproc::createDisparityWLSFilter(matcher);
        wls_filter->setLambda(lambda);
        wls_filter->setSigmaColor(sigma);

        //cv::Mat filtered_disparity;
        //wls_filter->filter(disparityMap, imgLeftRec, filtered_disparity, imgRightRec);
        //cv::Mat dispWLS = cv::Mat(filtered_disparity.rows, filtered_disparity.cols, CV_8UC1);
        //normalize(filtered_disparity, dispWLS, 0, 255, cv::NORM_MINMAX, CV_8UC1);
        cv::reprojectImageTo3D(filtered_disp, myPointCloud, Q, true);
        myPointCloud *= 16;

        if (state == 2) {
            Point3D[0] = myPointCloud.at<cv::Vec3f>(pointList[0]);
            Point3D[1] = myPointCloud.at<cv::Vec3f>(pointList[1]);
 
            cv::rectangle(imgLeft, pointList[0], pointList[1], cv::Scalar(255, 0, 0));
            float distance = sqrt((Point3D[0][0] - Point3D[1][0]) * (Point3D[0][0] - Point3D[1][0]) +
                (Point3D[0][1] - Point3D[1][1]) * (Point3D[0][1] - Point3D[1][1]) +
                (Point3D[0][2] - Point3D[1][2]) * (Point3D[0][2] - Point3D[1][2]));
            int fontFace = cv::FONT_HERSHEY_SIMPLEX;
            cv::putText(imgLeft, std::to_string(distance), pointList[0], fontFace, 0.8, cv::Scalar(0, 0, 1));
        }
        cv::imshow("Online measure", imgLeft);
        //cv::imshow("Disparity", disp8);
        cv::imshow("WLSDisparity", WLSdisp8);
        cv::waitKey(1);
    }
}

void Mymeasure::testWLS() {
    //创建StereoBM对象并设置参数
    static cv::Ptr<cv::StereoSGBM> matcher = cv::StereoSGBM::create();
    matcher->setMinDisparity(0);
    matcher->setDisp12MaxDiff(1);
    matcher->setPreFilterCap(1);
    matcher->setSpeckleRange(1);
    matcher->setMode(cv::StereoSGBM::MODE_SGBM);
    matcher->setBlockSize(block_size);
    matcher->setP1(16 * img_channels * block_size * block_size);
    matcher->setP1(32 * img_channels * block_size * block_size);
    matcher->setNumDisparities(NumDisparities * 16);//一般64是比较理想的效果
    matcher->setUniquenessRatio(UniquenessRatio);
    matcher->setSpeckleWindowSize(SpeckleWindowSize);

    cv::Mat imgLeftGray, imgRightGray;
    imgLeft = cv::imread("ambush_5_left.jpg");
    imgRight = cv::imread("ambush_5_right.jpg");

    cv::cvtColor(imgLeft, imgLeftGray, cv::COLOR_BGR2GRAY);
    cv::cvtColor(imgRight, imgRightGray, cv::COLOR_BGR2GRAY);
    
    cv::Ptr<cv::StereoMatcher> right_matcher = cv::ximgproc::createRightMatcher(matcher);
    cv::Mat right_disp;
    cv::Mat filtered_disp;
    matcher->compute(imgLeftGray, imgRightGray, disparityMap);
    right_matcher->compute(imgRightGray, imgLeftGray, right_disp);

    //把这段代码放在这里就不会相互影响了
    cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_filter = cv::ximgproc::createDisparityWLSFilter(matcher);
    wls_filter->filter(disparityMap, imgLeft, filtered_disp, right_disp);

    int vis_mult = 1.0;
    cv::Mat disp8 = cv::Mat(disparityMap.rows, disparityMap.cols, CV_8UC1);
    cv::ximgproc::getDisparityVis(disparityMap, disp8, vis_mult);
    //normalize(disparityMap, disp8, 0, 255, cv::NORM_MINMAX, CV_8UC1);

    cv::Mat WLSdisp8 = cv::Mat(filtered_disp.rows, filtered_disp.cols, CV_8UC1);
    cv::ximgproc::getDisparityVis(filtered_disp, WLSdisp8, vis_mult);

    cv::imshow("WLSDisparity", WLSdisp8);
    cv::imshow("Disparity", disp8);
    cv::waitKey(0);
}

int main() {
    Mymeasure my;
    my.measureDistOnline();
    //my.testWLS();
    system("pause");
    return 0;
}

#pragma once
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/ximgproc.hpp>

class Mymeasure {
public:
    Mymeasure();
    void getDist(int event, int x, int y, int flag, void* userdata);
    void measureDistOnline();
    void testWLS();
private:
    bool isPaused;
	cv::Size imgSize;    //图像尺寸,默认一般为640,480
    cv::Mat leftCameraMatrix, leftDistCoeffs, rightCameraMatrix, rightDistCoeffs;
    std::vector<cv::Mat> leftRvecs, leftTvecs, rightRvecs, rightTvecs;
    cv::Mat R, T, E, F;
    std::string calibrationFilePath;
    cv::Mat imgLeft, imgRight, imgBackup;    //进行三维重建的左右相机图片
    cv::Mat R1, R2, P1, P2, Q;            //矫正映射矩阵
    cv::Rect validROI1, validROI2;
    cv::Mat map1Left, map2Left, map1Right, map2Right;
    cv::Mat imgLeftRec, imgRightRec;    //矫正后的左右图像
    cv::Mat disparityMap;
    cv::Mat myPointCloud;        //openCV的点云格式
    int block_size;
    int NumDisparities;
    int img_channels;
    int UniquenessRatio;
    int SpeckleWindowSize;
    double lambda = 8000.0;  // 控制平滑度的参数
    double sigma = 1.5;     // 控制像素权重的参数
    int num_iterations = 3; // 迭代次数

};

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 双目相机是利用两个摄像头分别拍摄同一场景,从而获取不同视角下的图像信息,以实现深度信息的获取。三维重建是指通过图像处理技术将拍摄得到的二维图像转化为三维模型的过程。 在实现双目相机三维重建的过程中,可以使用OpenCV和PCL这两个开源库。OpenCV是一款计算机视觉库,提供了许多图像处理和计算机视觉相关的函数和工具,比如图像读取和处理、特征提取和匹配等。PCL是一款点云处理库,能够处理三维点云数据,提供了点云滤波、分割、配准和特征提取等功能。 具体步骤如下: 1. 获取双目相机的图像,进行标定。标定可以校准摄像头对应的内参矩阵和外参矩阵,以保证匹配时的准确度。 2. 通过绝对/相对模板匹配获取左右匹配的特征点。之后可以使用立体匹配算法(例如SGBM算法)计算出匹配点的视差(即左右视图在深度方向上的偏差),根据视差反向计算出点的深度。 3. 将获取的深度点云数据使用PCL进行处理,如点云滤波、重采样、分割等。之后可以使用PCL提供的立体配准算法对左右图像进行配准,基于此获取的点云数据中的关键点,进行特征点匹配,从而实现三维重建。 总之,双目相机三维重建opencv-pcl结合使用能够高效地完成三维重建任务,这是一个较为复杂的过程,需要仔细设计,注意参数设置和优化算法。 ### 回答2: 双目相机三维重建是利用双目相机获取的两幅图像,通过计算机视觉算法对相机观察到的场景进行三维重建的技术。OpenCV是一种开源的计算机视觉库,提供了许多图像处理和计算机视觉算法,PCL(PointCloud Library)则是一种开源的点云处理库,提供了各种点云相关的处理算法。 通过结合OpenCV和PCL,我们可以实现双目相机的三维重建。首先,需要利用OpenCV双目相机获取的两幅图像进行立体匹配,得到两幅图像中对应像素点的视差。然后,通过视差计算相机与场景物体之间的距离信息,并将其转化为点云数据。最后,利用PCL对点云数据进行处理,实现三维重建。 具体的步骤包括: 1.读取左右相机的图像并进行预处理,包括图像去畸变和校正,以及调整图像的大小和尺度等。 2.使用OpenCV的立体匹配算法对左右相机图像进行匹配,得到像素点的视差图像。 3.通过三角化算法将视差信息转化为深度信息,并将深度信息转换为点云数据。 4.利用PCL对点云数据进行后续处理,包括点云滤波、点云重建和点云配准等。 5.最终得到的结果是场景的三维模型,可以对其进行渲染和可视化等操作。 总之,双目相机的三维重建是一项复杂的技术,在实践过程中需要综合运用计算机视觉、图像处理和点云处理等多个领域的知识和算法,但是对于建模、制造等领域来说,这是一项非常重要的技术。 ### 回答3: 双目相机三维重建是一种利用双目相机获取的视差数据来进行三维物体建模的技术。这种技术可以被应用到多个领域,如机器人导航、自动驾驶、医疗影像等。OpenCV是一个强大的计算机视觉库,支持多种计算机视觉算法和工具,能够方便地进行图像处理、特征提取和目标跟踪。而PCL是点云库,提供了处理点云数据的算法、工具和可视化功能。 实现双目相机三维重建,需要使用OpenCV和PCL。首先,利用双目相机捕获的两幅图像计算出视差图。然后,使用OpenCV提供的函数或者自定义算法,将视差图转换为深度图。接着,利用PCL提供的点云算法,将深度图转换为点云数据。最后,利用PCL的可视化工具,对点云数据进行可视化展示或二次处理。 在使用OpenCV和PCL进行双目相机三维重建时,需要注意几个关键点。首先,在捕获图像前需要进行相机标定,获取相机内参和外参等参数。这是很重要的,因为只有相机准确校准后,才能保证三维建模的精度和稳定性。其次,在计算视差图和深度图时,需要选择适合的计算方法和参数。这些参数可能会受到图像分辨率、灰度分布和光照等因素的影响。最后,在进行点云处理和可视化时,需要选择合适的算法和工具,以免因数据量过大或算法不精确而影响计算效率和准确性。 总之,双目相机三维重建结合OpenCV和PCL,是一种强大的三维重建技术。它可以应用到多个领域,包括机器人导航、自动驾驶、医疗影像等。在实现过程中,需要根据具体实际情况进行合理选择和优化,以保证算法的精度、效率和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值