单目相机校正和Mat、Bitmap、Image<Bgr,byte>相互转换

最近需要做单目相机校正的项目,自己归纳总结记录一下,以便后期查看和回顾,同时希望帮到需要的人,有需要的可以点赞、收藏、关注、转发一下。

相机校正就摆脱不了标定,现在标定方法主要还是用张正友的相机标定方法,那就先了解几个问题:相机为什么需要标定,标定需要的输入和输出分别是哪些?

相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。

相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。

相机标定的输出:摄像机的内参、外参系数。

这三个基础的问题就决定了使用Opencv实现张正友法标定相机的标定流程、标定结果评价以及使用标定结果矫正原始图像的完整流程:

1. 准备标定图片

2. 对每一张标定图片,提取角点信息

3. 对每一张标定图片,进一步提取亚像素角点信息

4. 在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)

5. 相机标定

6. 对标定结果进行评价

7. 查看标定效果——利用标定结果对棋盘图进行矫正

(不过现在2,3,4,5的标定工作都可以用MATLAB软件自动标定,只需要把标定结果转化为可以程序引用和读取的文本文件就可以,6,7就需要把标定结果带入程序中进行验证即可)

上面的标定方法和内容 网上资料很多就不在文章中赘述。这里主要说下标定结果的验证,也就是把MATLAB生成的文本文件如何带入程序中进行验证和试验:

利用求得的相机的内参和外参数据,可以对图像进行畸变的矫正,这里有两种方法可以达到矫正的目的,分别说明一下。

方法一:使用initUndistortRectifyMap和remap两个函数配合实现

initUndistortRectifyMap用来计算畸变映射,remap把求得的映射应用到图像上。

initUndistortRectifyMap的函数原型:

//! initializes maps for cv::remap() to correct lens distortion and optionally rectify the image  
CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,  
                           InputArray R, InputArray newCameraMatrix,  
                           Size size, int m1type, OutputArray map1, OutputArray map2 ); 

第一个参数cameraMatrix为之前求得的相机的内参矩阵;对应标定参数里面的IntrinsicMatrix

第二个参数distCoeffs为之前求得的相机畸变矩阵;对应标定参数里面的RadialDistortion

第三个参数R,可选的输入,是第一和第二相机坐标之间的旋转矩阵;

第四个参数newCameraMatrix,输入的校正后的3X3摄像机矩阵;可以与一个参数相同

第五个参数size,摄像机采集的无失真的图像尺寸;

第六个参数m1type,定义map1的数据类型,可以是CV_32FC1或者CV_16SC2;

第七个参数map1和第八个参数map2,输出的X/Y坐标重映射参数;

remap函数原型:

//! warps the image using the precomputed maps. The maps are stored in either floating-point or integer fixed-point format  
CV_EXPORTS_W void remap( InputArray src, OutputArray dst,  
                         InputArray map1, InputArray map2,  
                         int interpolation, int borderMode=BORDER_CONSTANT,  
                         const Scalar& borderValue=Scalar()); 

第一个参数src,输入参数,代表畸变的原始图像;

第二个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小;

第三个参数map1和第四个参数map2,X坐标和Y坐标的映射;

第五个参数interpolation,定义图像的插值方式;自己使用的线性插值

第六个参数borderMode,定义边界填充方式;

方法二:使用undistort函数实现

undistort函数原型:

//! corrects lens distortion for the given camera matrix and distortion coefficients
CV_EXPORTS_W void undistort( InputArray src, OutputArray dst,
                             InputArray cameraMatrix,
                             InputArray distCoeffs,
                             InputArray newCameraMatrix=noArray() );

第一个参数src,输入参数,代表畸变的原始图像;

第二个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小;

第三个参数cameraMatrix为之前求得的相机的内参矩阵;

第四个参数distCoeffs为之前求得的相机畸变矩阵;

第五个参数newCameraMatrix,默认跟cameraMatrix保持一致;

方法一相比方法二执行效率更高一些,推荐使用。到此校正部分说完了

下面就说说使用过程中遇到个几个图片类型转换:Mat、Bitmap、Image<Bgr,byte>转换

1.Bitmap转Image<Bgr,byte>

public Mat GetMatFromSDImage(System.Drawing.Image image)
        {
            int stride = 0;
            Bitmap bmp = new Bitmap(image);

            System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
            System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);   
            Image<Bgr, byte> cvImage = new Image<Bgr, byte>(bmp.Width, bmp.Height,bmpData. stride, (IntPtr)bmpData.Scan0);
            bmp.UnlockBits(bmpData);
            return cvImage.Mat;
        }

但是这是Emgu4.2上的方法,但是Emgu4.4上面已经更新了新的更简单的方法:将构造函数Image<TColor, TDepth> Constructor (Bitmap)删除,增加了Bitmap扩展方法BitmapExtension.ToImage<TColor, TDepth> Method,用于从Bitmap获取图像,使用起来更加简洁易懂,示例如下:

Bitmap source;
Image<Bgr, byte> image = source.ToImage<Bgr, Byte>();
Mat matImage = image.Mat;

1.Image<Bgr,byte>转Mat

Image<Bgr, byte> cvImage = new Image<Bgr, byte>(bmp.Width, bmp.Height,bmpData. stride, 
cvImage.Mat;

是不是方便的惊艳到你了,欢迎补充和交流

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 4
收藏 5
关注 18
成为作者 赚取收益
全部留言
0/200
  • lihui710884923 2021-01-14 18:33
    给力
    回复
  • 星球居民-sCcAfEGY 2021-01-14 17:14
    👍👍👍
    回复
  • 十三猫 2021-01-14 17:06
    惊艳到了,赞👍
    回复