Calib3d_1_摄像机标定

image中存在扭曲,通过相机标定和remap,可以解决
针对径向因素影响(引起鱼眼效果),重新计算的位置为:
这里写图片描述
针对切向畸变(由于镜头并不是完全平行于成像平面),重新计算的位置为:
这里写图片描述

所以共有五个畸变参数:
这里写图片描述

转换使用:
这里写图片描述
w(w=Z),代表平面坐标系统
fx,fy为摄像机的焦距
cx,cy以像素表示的光学中心

Opencv支持的校准形式:
[1] Classical black-white chessboard,经典黑白棋盘
[2]Symmetrical circle pattern,旋转对称的圆型图案
[3]Asymmetrical circle pattern,不对称的圆图案

一棋盘标定

1>找到棋盘的角点

bool findChessboardCorners(InputArray image, 
     Size patternSize, OutputArray corners, 
     intflags=CALIB_CB_ADAPTIVE_THRESH
     +CALIB_CB_NORMALIZE_IMAGE )
/*image,为8-bit的灰度图或者彩色图像
 *patternSize,棋盘每一行和每一列的角点数量
 *corners,用于输出发现的角点,vector<Point2f>
 *flags(可以结合):
 *CV_CALIB_CB_ADAPTIVE_THRESH:使用自适应阈值将图像转化成二值图像
 *CV_CALIB_CB_NORMALIZE_IMAGE:归一化图像灰度系数(用直方图均衡
 *化或者自适应阈值)
 *CV_CALIB_CB_FILTER_QUADS:在轮廓提取阶段,使用附加条件排除错
 *误的假设
 *CALIB_CB_FAST_CHECK:加快检测速度
 *corners会特定排序,一行接一行,并且从左到右,如果没有检测到所有
 *点或者没有成功排序,则会返回0    
 */ 

2>呈现检测到棋盘角

void drawChessboardCorners(InputOutputArray image, 
                           Size patternSize, 
                           InputArray corners, 
                           bool patternWasFound)
//image为8-bit,三通道图像
//patternSize,每一行每一列的角
//corners,已经检测到的角
//patternWasFound,findChessboardCorners的返回值                           

3>细化角的位置

void cornerSubPix(InputArray image, InputOutputArray corners, 
                  Size winSize, Size zeroZone, 
                  TermCriteria criteria)
//image源图像
//corners,提供角点的初始坐标,返回更加精确的点
//winSize,搜索窗口的一般尺寸,如果winSize=Size(5,5),则search 
//windows为11*11
//winSize,死区的一般尺寸,用来避免自相关矩阵的奇点,(-1,1)表示没
//有死区
//criteria,控制迭代次数和精度                  

4>计算标定参数

double calibrateCamera(InputArrayOfArrays objectPoints,  
                       InputArrayOfArrays imagePoints, 
                       Size imageSize, 
                       InputOutputArray cameraMatrix, 
                       InputOutputArray distCoeffs, 
                       OutputArrayOfArrays rvecs, 
                       OutputArrayOfArrays tvecs, 
                       int flags=0, 
                       TermCriteria criteria
                       =TermCriteria(TermCriteria::COUNT
                       +TermCriteria::EPS, 30,DBL_EPSILON) )

/*objectPoints,世界坐标,用vector<vector<Vec3f>>,输入x,y*标,z坐标为0
 *imagePoints,图像坐标,vector<vector<Vec2f>>
 *imageSize,用于初始化标定摄像机的image的size
 *cameraMatrix,输出3*3的浮点型矩矩阵,
 *CV_CALIB_USE_INTRINSIC_GUESS或者*
 *CV_CALIB_FIX_ASPECT_RATIO,fx,fy,cx,cy必须提前初始化
 *distCoeffs,输出的畸变系数,(k1,k2,p1,p2[,k3[,k4,k5,k6]]),
 *可能为4,5,8个结果
 *rvecs,针对每个视角的旋转矩阵,vector<Mat>>
 *tvecs,针对每个视角的转换矩阵 
 *flags,可以组合
 */

5>计算畸变参数

void initUndistortRectifyMap(InputArray cameraMatrix, 
                             InputArray distCoeffs, 
                             InputArray R, 
                             InputArray newCameraMatrix, 
                             Size size, int m1type, 
                             OutputArray map1, 
                             OutputArray map2)
/*cameraMatrix3*3的浮点型矩矩阵
 *输出的畸变系数,(k1,k2,p1,p2[,k3[,k4,k5,k6]]),
 *可能为4,5,8个结果
 *R,在客观空间中的转换对象
 *newCameraMatrix,新的3*3的浮点型矩矩阵
 *size,为失真图像的大小
 *m1type,第一个输出的map,类型为CV_32FC1或CV_16SC2
 *map1,x映射函数
 *map2,y映射函数
 */                             

应用:

calibrate.h

//棋盘标定类
class Calibrate
{
private:
//世界坐标
std::vector<std::vector<cv::Point3f>> objectPoints;
//图像坐标
std::vector<std::vector<cv::Point2f>> imagePoints;
//输出矩阵
cv::Mat camerMatirx;
cv::Mat disCoeffs;
//计算输出矩阵时的flags
int flags;
//remap的变换矩阵
cv::Mat map1,map2;
//是否已经,计算去畸变参数
bool mustInitUndistort;

//增加标定点
void addPoints(const std::vector<cv::Point2f>&corners,
               const std::vector<cv::Point3f> &objects);

public:

Calibrate():flags(0),mustInitUndistort(true){}
//检测图像中棋盘角点,并且存储
cv::Mat addChessboardPoints(const cv::Mat &image,
                            cv::Size boardSize);
//计算标定参数
double calibrate(cv::Size imageSize);
//去畸变
cv::Mat reMap(const cv::Mat &image);
};

calibrate.cpp

#include "calibrate.h"

void Calibrate::addPoints(const std::vector<cv::Point2f>   
       &corners,const std::vector<cv::Point3f> &objects)
{
    imagePoints.push_back(corners);
    objectPoints.push_back(objects);
}

cv::Mat Calibrate::addChessboardPoints
(const cv::Mat &image,cv::Size patternsize)
{
    //存储检测到的角点
    std::vector<cv::Point2f> corners;
    //存储世界点
    std::vector<cv::Point3f> objects;

    //给世界点赋值
    for(int i=0;i<patternsize.height;i++)
    for(int j=0;j<patternsize.width;j++)
    objects.push_back(cv::Point3f(i,j,0));

    //进行角点检测
    bool patternfound=
    cv::findChessboardCorners(image,patternsize,corners,
                              CV_CALIB_CB_ADAPTIVE_THRESH
                             +CV_CALIB_CB_NORMALIZE_IMAGE
                             +CV_CALIB_CB_FAST_CHECK);
    //如果corners已经全部找到,并且已经有序
    if(patternfound)
    {
     //进行亚像素,细致化
     cv::cornerSubPix(image,corners,cv::Size(11,11),
     cv::Size(-1,-1),cv::TermCriteria
     (CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));
     //将得到点,进行添加
     addPoints(corners,objects);
    }

    cv::Mat result;
    cv::cvtColor(image,result,CV_GRAY2BGR);
    //将检测到的角点进行绘制
    cv::drawChessboardCorners(result,patternsize,
                              corners,patternfound);
    return result;
}

double Calibrate::calibrate(cv::Size imageSize)
{
    mustInitUndistort=true;
    std::vector<cv::Mat> rvecs,tvecs;
    //计算camerMatirx和disCoeffs
    return cv::calibrateCamera(objectPoints,imagePoints,
                               imageSize,camerMatirx,
                               disCoeffs,rvecs,tvecs,
                               flags);
}

cv::Mat Calibrate::reMap(const cv::Mat &image)
{
    cv::Mat result;
    if(mustInitUndistort)
    {
    //得到x,y方向的映射关系map1,map2
    cv::initUndistortRectifyMap(camerMatirx,disCoeffs,
                                cv::Mat(),cv::Mat(),
                                image.size(),CV_32FC1,
                                map1,map2);
    }
    cv::remap(image,result,map1,map2,cv::INTER_LINEAR);
    return result;
}

main.cpp

#include "calibrate.h"
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    Calibrate C;

    int num;
    cv::Mat image;
    //输入进行棋盘标定的图像数目
    cin>>num;

    for(int i=0;i<num;i++)
    {
        string filename;
        cin>>filename;
        image=cv::imread(filename,0);
        //查找相应的棋盘角点
        cv::Matresulr
        =C.addChessboardPoints(image,cv::Size(9,6));
        cv::imshow("Chess",result);
        cv::waitKey(30);
    }
    //进行标定
    C.calibrate(image.size());

    string imagename;
    cin>>imagename;
    //显示去畸变图像
    image=cv::imread(imagename,0);
    image=C.reMap(image);
    cv::imshow("Calibrate",image);
    cv::waitKey();
    return 0;
}

效果图:
[1]角点查找结果
这里写图片描述
[2]去畸变
这里写图片描述

二圆标定

1>发现圆网络的中心

bool findCirclesGrid(InputArray image, Size patternSize,                
                     OutputArray centers, 
                     int flags=CALIB_CB_SYMMETRIC_GRID, 
                     const Ptr<FeatureDetector>& 
                     blobDetector=new SimpleBlobDetector() )
/*image,8-bit灰度图或者彩色图像
 *patternSize,每行每列的circle数目
 *centers,输出的圆的中心,vector<Point2f>
 *flags(只可选择一个):
 *CALIB_CB_SYMMETRIC_GRID,使用对称的圆
 *CALIB_CB_ASYMMETRIC_GRID,使用非对称的圆
 *CALIB_CB_CLUSTERING,处理透视畸变的的能力更强,对背景杂波更加敏感
 *blobDetector,特征探测器,exp:在浅色背景上的黑圈
 */                     

应用:

cv::cvtColor(Image,Image,CV_BGR2GRAY);

cv::Size patternSize(4,11);
std::vector<cv::Point2f> centers;
//检测圆
bool patternFound=cv::findCirclesGrid(Image,patternSize,
                  centers,cv::CALIB_CB_ASYMMETRIC_GRID);
//呈现查找出来的圆
cv::drawChessboardCorners(result,patternSize,
                         cv::Mat(centers),patternFound);

效果图:
这里写图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值