一、相机标定

标定的资料很多,就是确定其相机的内参矩阵fx,fy,x0,y0,k1,k2,k3,p1,p2;目前来看可分为online 和offline两种方式,前者在cv领域较多,后者在摄影测量中较多。摄影测量中标定分为平面场标定和三维场标定。
平面场的标定多采用张正友的方法,而三维场标定即是2D-3D的变换。

二、极线矫正

极线矫正的目的是使得立体相对具有相同的y坐标,可分为两种:
1、标定相机的极线矫正
2、未标定相机的极线矫正,也称为Hartly方法

三、生成视差图

opencv 自带函数是BM和SGBM、GC,其中GC算法效果最好,但是时间太慢。而且这三种算法都只能用于分辨率不大图像,当分辨率太大,就效果欠佳。2010年《Library for Efficient Large-scale Stereo Matching》问世,解决了大尺度视差图的计算,其原理是先匹配,得到稳定的点称为support points,然后根据sp来建立三角网,得到先验区域然后利用MAP得到候选点。
本程序介绍:
1、自动完成标定,极线矫正,视差图,标定图放在文件夹1,要矫正的图像在外边,由于网上的标定板子,所以从标定板子中选了两幅图来计算视差,因为是平面图,所有效果不好。也尝试用手机拍摄标定板,再拍摄其它东西来标定,发现苹果手机畸变贼大,所以就放弃。
2、本程序流程

标定
去畸变undistort
待矫正像对匹配
估计E矩阵
分解得到R和t
stereoRectify得到各个图像相对新的矫正坐标系的变换矩阵
重新映射
elas生成视差图

部分代码main.cpp

#include"camera_calibrate.h"
#include<vector>
#include<omp.h>
#include "elas/elas.h"
#include "elas/image.h"
void LK_points_pairs(const Mat im1,const Mat im2,vector<Point2f> &p1,vector<Point2f> &p2)
{goodFeaturesToTrack(im1, p1, 100, 0.01, 30);
//    vector<cv::KeyPoint> kps
//    cv::Ptr<cv::FastFeatureDetector> detector = cv::FastFeatureDetector::create();
//    detector->detect(im1, kps );
//    for ( auto kp:kps )
//    {//        p1.push_back( kp.pt );
//    }vector <uchar> status;vector <float> err;calcOpticalFlowPyrLK(im1, im2, p1, p2 ,status, err);auto prev_it = p1.begin();auto curr_it = p2.begin();//如果不用迭代器的删除,循环非常耗时for(size_t k = 0; k < status.size(); k++){if(status[k]){prev_it++;curr_it++;}else{prev_it = p1.erase(prev_it);curr_it = p2.erase(curr_it);}}Mat con_im;cv::hconcat(im1,im2,con_im);for(int i=0;i<p1.size();++i){cv::line(con_im,cv::Point(p1[i].x,p1[i].y),cv::Point(p2[i].x+im1.cols,p2[i].y),cv::Scalar(0,0,255),1);}
//    for(int i=0;i<p1.size();++i)
//    {//        cv::circle(im1,p1[i],3,Scalar(0,255,0),2);
//        cv::circle(im2,p2[i],3,Scalar(0,255,0),2);
//    }//    imwrite("im1.jpg",im1);imwrite("result.jpg",con_im);
}
void SURF_points_pairs(const Mat im1,const Mat im2,vector<Point2f> &p1,vector<Point2f> &p2)
{Ptr<cv::xfeatures2d::SURF> surf=cv::xfeatures2d::SURF::create();vector<KeyPoint> kp1,kp2;Mat des1,des2;surf->detectAndCompute(im1,Mat(),kp1,des1);surf->detectAndCompute(im2,Mat(),kp2,des2);FlannBasedMatcher matcher;vector<DMatch> mps;vector<vector<DMatch>> knn_matches;
//    matcher.match(des1,des2,mps, Mat());matcher.knnMatch(des1,des2,knn_matches,2);//lowe NNDR算法float distanceRatio=0.6;for(int i=0;i<knn_matches.size();++i){if(knn_matches[i][0].distance<knn_matches[i][1].distance*distanceRatio){mps.push_back(knn_matches[i][0]);}}for(int i=0;i<30;++i){p1.push_back(kp1[mps[i].queryIdx].pt);p2.push_back(kp2[mps[i].trainIdx].pt);}if(mps.size()<8){throw runtime_error("估计F矩阵匹配点不够");}Mat F;vector<uchar> status;F=cv::findFundamentalMat(p1,p2,status,CV_FM_RANSAC);//剔除点auto prev_it = p1.begin();auto curr_it = p2.begin();for(size_t k = 0; k < status.size(); k++){if(status[k]){prev_it++;curr_it++;}else{prev_it = p1.erase(prev_it);curr_it = p2.erase(curr_it);}}Mat con_im;cv::hconcat(im1,im2,con_im);for(int i=0;i<p1.size();++i){cv::line(con_im,cv::Point(p1[i].x,p1[i].y),cv::Point(p2[i].x+im1.cols,p2[i].y),cv::Scalar(0,0,255),1);}imwrite("result.jpg",con_im);
//     for(int i=0;i<p1.size();++i)
//     {//         cv::circle(im1,p1[i],3,Scalar(0,255,0),2);
//         cv::circle(im2,p2[i],3,Scalar(0,255,0),2);
//     }//     imwrite("im1.jpg",im1);
//     imwrite("im2.jpg",im2);
}
void getR_T(vector<Point2f> p1,vector<Point2f> p2,Mat cam,Mat &R,Mat &t)//这里的t是把左像当作世界坐标系的源
{//    Mat R1,R2;Mat E=findEssentialMat(p1,p2,cam);recoverPose(E,p1,p2,cam,R,t);
//    decomposeEssentialMat(E,R1,R2,t);
//    R=R1.clone();
//    t=-t.clone();//R*t才是两相机坐标系之间的平移。
}
void rectified_image(const Mat im1,const Mat im2,Mat cam,Mat dis,Mat R,Mat t,Mat &rectified_L,Mat &rectified_R)
{Mat R1,R2,P1,P2,Q;stereoRectify(cam,dis,cam,dis,im1.size(),R,-R*t,R1,R2,P1,P2,Q);//t是相机坐标系之间的平移Mat mapx1,mapy1,mapx2,mapy2;initUndistortRectifyMap(P1(Rect(0,0,3,3)),dis,R1,P1(Rect(0,0,3,3)),im1.size(),CV_32FC1,mapx1,mapy1);initUndistortRectifyMap(P2(Rect(0,0,3,3)),dis,R2,P2(Rect(0,0,3,3)),im2.size(),CV_32FC1,mapx2,mapy2);remap(im1, rectified_L, mapx1, mapy1, CV_INTER_LINEAR);remap(im2, rectified_R, mapx2,mapy2,CV_INTER_LINEAR);imwrite("rectified_left_img.pgm",rectified_L);imwrite("rectified_right_img.pgm",rectified_R);
}
Mat generateDisparityMap(Mat& left, Mat& right) {Mat lb, rb;if (left.empty() || right.empty())return left;// convert images to grayscaleif (left.dims==3 || right.dims==3){cvtColor(left, lb, CV_BGR2GRAY);cvtColor(right, rb, CV_BGR2GRAY);}else{lb=left.clone();rb=right.clone();}const Size imsize = lb.size();const int32_t dims[3] = {imsize.width,imsize.height,imsize.width};Mat leftdpf = Mat::zeros(imsize, CV_32F);Mat rightdpf = Mat::zeros(imsize, CV_32F);Elas::parameters param;param.postprocess_only_left = true;Elas elas(param);elas.process(lb.data,rb.data,leftdpf.ptr<float>(0),rightdpf.ptr<
float>(0),dims);// normalize disparity values between 0 and 255int max_disp = -1;for (int i = 0; i < imsize.width; i++) {for (int j = 0; j < imsize.height; j++) {if (leftdpf.at<uchar>(j,i) > max_disp) max_disp = leftdpf.at<uchar>(j,i);}}for (int i = 0; i < imsize.width; i++) {for (int j = 0; j < imsize.height; j++) {leftdpf.at<uchar>(j,i) =
(int)max(255.0*(float)leftdpf.at<uchar>(j,i)/max_disp,0.0);}}Mat show = Mat(left.rows, left.cols, CV_8UC1, Scalar(0));leftdpf.convertTo(show, CV_8U, 5.);return show;
}
int main()
{Mat Cam;Mat dis;vector<cv::String> filename;glob("1/*.jpg",filename);camera_params(filename,9,6,Cam,dis);Mat im1=imread("1.jpg",0);Mat im2=imread("2.jpg",0);Mat im1U,im2U;undistort(im1,im1U,Cam,dis);//去畸变undistort(im2,im2U,Cam,dis);vector<Point2f> p1;vector<Point2f> p2;
//    LK_points_pairs(im1U,im2U,p1,p2);//这个环节,如果错误的匹配多,那么E就出错了SURF_points_pairs(im1U,im2U,p1,p2);Mat R,t;getR_T(p1,p2,Cam,R,t);Mat rectified_left_img,rectified_right_img;rectified_image(im1U,im2U,Cam,dis,R,t,rectified_left_img,rectified_right_img);
//    SURF_points_pairs(rectified_left_img,rectified_right_img,p1,p2);//用elas 计算视差图Mat img_disp = generateDisparityMap(rectified_left_img, rectified_right_img);imwrite("im_disp.pgm",img_disp);return 0;
}

参考学习网站:http://www.cvlibs.net/projects.php

相机标定+极线矫正+elas生成视差图相关推荐

  1. 计算机视觉|针孔成像,相机内外参及相机标定,矫正的重要性

    计算机视觉|相机内外参及相机标定,矫正的重要性 这篇博客将介绍针孔成像,透镜(弥补了针孔成像曝光不足成像速度慢的缺点,但引进了畸变,主要是径向畸变和切向畸变,径向畸变主要是离中心越远越弯曲,切向畸变当 ...

  2. 基于Python实现相机标定正畸并生成鸟瞰图

    资源下载地址:https://download.csdn.net/download/sheziqiong/85836848 资源下载地址:https://download.csdn.net/downl ...

  3. matlab获取视差图,Matlab生成视差图

    [实例简介] 双目视觉,根据块匹配方法的视差图生成.依据Matlab生成视差图. Dbasic= zeros(size(leftI),'single') disparity range 15; Sel ...

  4. win10+pycharm 调用相机进行拍摄图片并自动进行相机标定、矫正

    利用pycharm工具+python语言,设计一个单目摄像头的调用函数,可以进行实时的抓拍的功能.具体封装的函数,实现的代码如下: def read_show():cap = cv2.VideoCap ...

  5. 相机标定与矫正(总结)

    Overview 欢迎访问 持续更新: https://cgabc.xyz/posts/d12004a8/ What Is Camera Calibration? Camera Calibration ...

  6. 【立体视觉】双目图像立体匹配,生成视差图

    ###图像匹配的方法很多,一般分为两大类: (1)基于灰度匹配的方法.也称作相关匹配算法,用空间二维滑动模板进行图像匹配,不同算法的区别主要体现在模板及相关准则的选择方面. 参考:[图像配准]基于灰度 ...

  7. 张正友相机标定Opencv实现以及标定流程标定结果评价图像矫正流程解析(附标定程序和棋盘图)

    from:https://blog.csdn.net/dcrmg/article/details/52939318 使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么 ...

  8. 标题 相机标定(Camera calibration)原理和步骤

    标题 相机标定(Camera calibration)原理和步骤 为什么要相机标定? 在图像测量过程和机器视觉应用中,为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系,必须建立相机 ...

  9. 相机成像模型、相机内参、外参、以及相机标定

    看了一圈各个平台讲解相机模型.相机标定的文章,很多只是简单罗列几个公式,其中的细节都没说明,本着学习的出发点写下这篇文章,希望能给初学者解惑.本文主要讲解相机模型,一步步推导从世界坐标系到图像坐标系的 ...

  10. OpenCV-Python相机标定

    OpenCV-Python相机标定--张正友标定法为例(待更新) 写在前面 数学/物理原理(不更新) 编程实现 参考与致谢 写在前面 为什么机器视觉要用相机标定:直接目的是求出相机的内.外参数,以及畸 ...

最新文章

  1. 正方形分成16份,将1到16填入其中。让行和列都是从大到小。问一共有多少种方法?...
  2. 【转】以操作系统的角度述说线程与进程
  3. 完整的维纳滤波器Matlab源程序
  4. CodeSmith使用笔记
  5. java 默认网关,java 获得默认网关 和 子网掩码 本机
  6. git 管理 Linux 文件系统
  7. iPhone X 的新解锁技术:用 Python 编写 Face ID!
  8. 以太坊源码分析:共识(1)矿工
  9. 使用U盘引导安装linux
  10. ASP.NET AJAX中防止用户多次提交页面
  11. 怎样快速学习shell语言
  12. 苹果手机屏幕尺寸_苹果有意推出 折叠屏手机,屏幕尺寸或为 7.2 寸!
  13. Photoshop定义画笔选区为空的原因
  14. 企业自动运行系统——定价策略
  15. App架构设计经验谈
  16. Inception-V3论文翻译——中文版
  17. java响应式交友网站计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  18. JMeter基础系列:接口响应时间
  19. 如何放大图片不模糊?教你一招
  20. 学习笔记TF058:人脸识别

热门文章

  1. 商品档案,文具五金服装鞋帽酒店烟酒饰品,日用百货超市,批发零售进销存收银财务一体管理软件
  2. 小米android安装包下载安装,小米应用商店安装包下载
  3. Android日历控件方法,Android日历控件的实现方法
  4. 夏普电视账号服务器异常,夏普电视故障通病维修案例,你中了几个?
  5. windows 10 Docker Desktop TeamTalk 安装笔记
  6. stl格式导入matlab,机器人模型导入MATLAB(三):导入MATLAB URDF/stl 格式
  7. xmlspy xsd生成java_XmlSpy / XSD 以及 验证
  8. 传统推荐系统算法(一):协同过滤(Collaborative Filtering,CF)
  9. HTML:使用JavaScript(js)脚本在网页上显示实时时间
  10. 阿里云国际版云服务器Linux和Windows操作系统的链路测试工具-Unirech