立体声相机点云在opencv中使用viz

时间:2017-01-03 06:48:58

标签: c++ opencv image-processing camera-calibration stereo-3d

我正在尝试使用zed立体相机创建点云。 所以我写了一些简单的代码并使用viz(opencv模块之一)对其进行可视化。 但是xyz看起来似乎很好,但没有结果。 有什么问题?

{   
    double baseLine = 120.0;
    double covergence = 0.00285;
    double FX = 700;
    double FY = 700;
    double CX = 320;
    double CY = 240;
    double K1 = -0.15;
    double K2 = 0.0;
    double P1 = 0.0;
    double P2 = 0.0;

    cv::Matx33d K = cv::Matx33d(FX, 0, CX, 0, FY, CY, 0, 0, 1);
    cv::Matx41d distCoeffs = cv::Matx41d(K1, K2, P1, P2);
    cv::Matx44d Q = cv::Matx44d(    
        1.0, 0.0, 0.0, -CX,
        0.0, 1.0, 0.0, -CY,
        0.0, 0.0, 0.0, FX,
        0.0, 0.0, -1.0 / baseLine, (CX - CX) / baseLine
    );
    //// SGBM
    cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(0, 16 * 5, 9);

    // param
    int sgbmWinSize = 3;
    int numberOfDisparities = 16 * 6;
    int cn = 3;

    // filter
    cv::Ptr<cv::ximgproc::DisparityWLSFilter> wls_filter;
    wls_filter = cv::ximgproc::createDisparityWLSFilter(sgbm);
    cv::Ptr<cv::StereoMatcher> sm = cv::ximgproc::createRightMatcher(sgbm);
    // param
    double lambda = 8000.0;
    double sigma = 1.5;
    double vis_multi = 1.0;

    // init
    sgbm->setPreFilterCap(63);
    sgbm->setBlockSize(sgbmWinSize);
    sgbm->setP1(8 * cn*sgbmWinSize*sgbmWinSize);
    sgbm->setP2(32 * cn*sgbmWinSize*sgbmWinSize);
    sgbm->setMode(cv::StereoSGBM::MODE_SGBM_3WAY);

    //// viz
    cv::viz::Viz3d window("Coordinate Frame");
    window.showWidget("Coordinate Widget", cv::viz::WCoordinateSystem());

    //main loop
    while (!window.wasStopped())
    {
        cv::Mat tmpImg;
        cap.read(tmpImg);
        leftImg = tmpImg(cv::Rect(0, 0, tmpImg.cols / 2, tmpImg.rows));
        rightImg = tmpImg(cv::Rect(tmpImg.cols / 2, 0, tmpImg.cols / 2, tmpImg.rows));
        cv::Mat tmp1 = leftImg.clone();
        cv::Mat tmp2 = rightImg.clone();

        sgbm->compute(tmp1, tmp2, disparity16S);
        sm->compute(tmp2, tmp1, img16Sr);

        cv::Mat showDisparity;
        disparity16S.convertTo(showDisparity, CV_8UC1, 255 / (numberOfDisparities*16.));

        printf("disparity16S: %s %d x %d\n", type2str(disparity16S.type()).c_str(), disparity16S.rows, disparity16S.cols);
        cv::imshow("disparity", showDisparity);

        wls_filter->setLambda(lambda);
        wls_filter->setSigmaColor(sigma);
        wls_filter->filter(disparity16S, tmp1, filteredDisparity, img16Sr);

        cv::Mat showFilteredDisparity;
        filteredDisparity.convertTo(showFilteredDisparity, CV_8U, 255 / (numberOfDisparities*16.));

        printf("filteredDisparity: %s %d x %d\n", type2str(filteredDisparity.type()).c_str(), filteredDisparity.rows, filteredDisparity.cols);
        cv::imshow("Filtered Disparity", showFilteredDisparity);

        cv::Mat xyz, xyzt;
        // output : 3-channel floating-point image of the same size as disparity
        cv::reprojectImageTo3D(filteredDisparity, xyz, Q, true);
        printf("xyz: %s %d x %d\n", type2str(xyz.type()).c_str(), xyz.rows, xyz.cols);

        cv::Mat showXYZ;
        xyz.convertTo(showXYZ, CV_8UC3, 255 / (numberOfDisparities*8.));
        cv::imshow("XYZ", showXYZ);

        viz::WCloud cw(xyz, viz::Color::white());
        cw.setRenderingProperty(cv::viz::POINT_SIZE, 2);
        window.showWidget("Cloud Widget", cw);
        window.spinOnce(30, true);

    }
   //
}

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

1 个答案:

答案 0 :(得分:0)

我知道我会在很长一段时间后回答,让它对遇到此问题的人有用。

您已使用OpenCV的reprojectTo3D()函数获取3D点,并且已处理了缺失的值。使用viz显示时,诸如infinity和NaN之类的值会引起问题。因此,您只需滤除无穷大值和NaN值即可。

我使用OpenCV的forEach函数过滤这些值

xyz.forEach<Vec3f>(
[](Vec3f& val, const int *pos)
{
    if(isnan(val[0]) || isinf(val[0]))
        val = Vec3f();
});