Mastering Opencv ch4:SFM详解(一)

本文深入探讨了使用OpenCV进行结构从运动(SFM)的细节,包括从两幅图像估计摄像机姿态、场景重构、重构细化和三维点云的可视化。首先介绍了相机标定的内参数初始化,然后讲解了图像获取和预处理。接着,重点讨论了特征提取,特别是基础矩阵和本质矩阵的计算,以及特征匹配的不同方法,如一般特征匹配、GPU加速匹配和光流法匹配。最后,提到了使用光流法的优势和在连续图像上的快速处理能力。
摘要由CSDN通过智能技术生成

从运动中恢复结构以便能更好的通过摄像机移动来提取图像几何结构。在书中为了使用单目相机,一个离散且稀疏的视频帧集合,而不是连续的视频流。这在后面两两循环组合配对提供了方便性。

主要内容:
1:从两幅图像估计摄像机的运动姿态。
2:重构场景
3:从视图中重构
4:重构细化
5:可视化三维点云

I:假定使用一个标定过的摄像机——一个先前标定过的摄像机。前面的博客也提到如何进行相机标定。因此,我们假定摄像机内参数存在,并且具体化到K矩阵中,K矩阵为摄像机标定过程的一个结果输出。
在程序中初始化相机标定内参数:

//load calibration matrix
    cv::FileStorage fs;
    if(fs.open(imgs_path_+ "\\out_camera_data.yml",cv::FileStorage::READ)) //打开校正参数文件
    {
        fs["camera_matrix"]>>cam_matrix;
        fs["distortion_coefficients"]>>distortion_coeff;
    } else {
        //若没有标定文件,就组合一个标定内参数
        cv::Size imgs_size = imgs_[0].size();
        double max_w_h = MAX(imgs_size.height,imgs_size.width);
        cam_matrix = (cv::Mat_<double>(3,3) <<  max_w_h ,   0   ,       imgs_size.width/2.0,
                                                0,          max_w_h,    imgs_size.height/2.0,
                                                0,          0,          1);
        distortion_coeff = cv::Mat_<double>::zeros(1,4);
    }

    K = cam_matrix;
    cv::invert(K, Kinv); //对内参数进行取反

    distortion_coeff.convertTo(distcoeff_32f,CV_32FC1);
    K.convertTo(K_32f,CV_32FC1);

若有标定文件,就从文件中导入,若没有标定文件,就组合一个相机内参K,根据图像大小就可以组合,畸变参数设为0,对相机内参取反得Kinv,转换成32FC1精度。

II:获取图像
书中在获取图像时,采用给定目录,逐个读取目录中的图像,保存在一个std::vector& imgs中。我们也可以挨个读取,或者截取视频帧。
我觉得这是一个常规代码片,放在下面供以后随便调用。

//给定目录的路径,读取目录下图像文件,保存图片名,设置图像缩放比率
void open_imgs_dir(char* dir_name, std::vector<cv::Mat>& images, std::vector<std::string>& images_names, double downscale_factor) {
    if (dir_name == NULL) {
        return;
    }

    string dir_name_ = string(dir_name);
    vector<string> files_;

#ifndef WIN32  
//open a directory the POSIX way
//linux或者macos下面读取图片,需要包含#include <dirent.h>

    DIR *dp;
    struct dirent *ep;     
    dp = opendir (dir_name);

    if (dp != NULL)
    {
        while (ep = readdir (dp)) {
            if (ep->d_name[0] != '.')
                files_.push_back(ep->d_name);
        }

        (void) closedir (dp);
    }
    else {
        cerr << ("Couldn't open the directory");
        return;
    }

#else
//open a directory the WIN32 way
    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATA fdata;

    if(dir_name_[dir_name_.size()-1] == '\\' || dir_name_[dir_name_.size()-1] == '/') {
        dir_name_ = dir_name_.substr(0,dir_name_.size()-1);
    }

    hFind = FindFirstFile(string(dir_name_).append("\\*").c_str(), &fdata); 
    if (hFind != INVALID_HANDLE_VALUE)
    {
        do
        {
            if (strcmp(fdata.cFileName, ".") != 0 &&
                strcmp(fdata.cFileName, "..") != 0)
            {
                if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                {
                    continue; // a diretory
                }
                else
                {
                    files_.push_back(fdata.cFileName);
                }
            }
        }
        while (FindNextFile(hFind, &fdata) != 0);
    } else {
        cerr << "can't open directory\n";
        return;
    }

    if (GetLastError() != ERROR_NO_MORE_FILES)
    {
        FindClose(hFind);
        cerr << "some other error with opening directory: " << GetLastError() << endl;
        return;
    }

    FindClose(hFind);
    hFind = INVALID_HANDLE_VALUE;
#endif

    for (unsigned int i=0; i<files_.size(); i++) {
        if (files_[i][0] == '.' || !(hasEndingLower(files_[i],"jpg")||hasEndingLower(files_[i],"png"))) {
            continue;
        }
        cv::Mat m_ = cv::imread(string(dir_name_).append("/
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值