python opencv 三维重建_一起学opencv-python四十一(相机校准和三维重建:图像校正)...

b25bc644d0c5ee4e5e88c26425c99f1a656749be.png

opencv实现标定校准工作

参考https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html

和https://blog.csdn.net/hongbin_xu/article/details/78988450aa0c4886f1b7ef20424bc89278c7feba82bebd8e.png

标定图片需要使用标定板在不同位置、不同角度、不同姿态下拍摄。在前面的博客中进行推导时,我们分析得知至少要有3张图片,才能有唯一解。通常以10~20张为佳。

通常都会购买专门的标定板,如果精度要求不高,也可以自己打印。 网上也有别人已经拍好的照片,下面是下载链接:https://pan.baidu.com/s/1mhG3mHU

程序中就直接使用这些现成的图片来测试了,省事。一共有14张图片。853a2b3f148b65a4ba0e6c274ebc0dd43f9d591e.png

20b81d8ee430f905e3956771b394899e543d28da.png

python的格式返回一个ret和corner。f25824aef97f39f00f35b3636f619a29bccbe9ec.png

这个我们已经见识过了。fbe16fcb52a6f251feb23052324fe4e1babcba01.png

27794d4e77fff0aba0d9dfb1eab435fccab60e05.png

如果patterWasFound是真,就会有连线。069305575ecfc44e448bfae6980063fadb8c708e.png

如果是false358dda11071794c0d4b899c5e963b84a05cb879f.png

就没有连线。这个是又找了一张的测试图,内焦点也还不错。这里我觉得选内角点的时候最好全部选择,上面的(6,4)就是这么选择的,这因为zhe'g棋盘是我们选择的,我们当然是知道横竖有多少个角点了。f4c35970ec0cda805b44d42423dc2412e6642b6d.png

如果选择的不对是会报错的。少了会报错,ret直接就是False。0390b1d42661cdebd9f4a9ac4e885941e50d4d34.png

多给了虽然能画出来图,不过ret也还是false,这个结果还是有问题的。052d62f7d3b794971029759c314ab98b87290307.png

函数:4d3ad41efa99e48803cbbb0ca8ccc2e9ba89865f.png

82c84d0ae69ff695712d701526cbea95d55be39d.png

objectponit我们只需要给世界坐标系的X,Y的坐标,因为Z=0。imagePoints就是像素坐标系中角点的坐标。flags里面是标定的一些算法,LM方法其实是一种非最小二乘法。a0be65e9761640374de56c2e5858c6458cf5a01c.png

上一讲提出的问题我在这里其实还是有一定的疑问,就是k1,k2的初值是如何确定的?7143ae88fe6e36f727c8e989457d6f33bb999a44.png

其实我们可以不用知道未畸变的棋盘是什么样的,只用4个在一条直线上的点就可以了。因为棋盘在一条直线上的点的间距应该是一样的,就根据这一点列方程。7bfe265d05b002262a8b02368ce1d75fc67a686a.png

假设有上面4个点,Ai对应的点是(xi,yi),离主点的距离是ri,这些我们都可以知道。那么我们就可以列方程了,每三个点可以一个方程:78e32d098eb44140b33ca4d1376180ec50852ea5.png

关于y也可以列方程,不过那个和x的系数一样,因为都是ri^2的差或者说和x列的方程是齐次的。这样就可以解出k1,k2。不过可能每张图我们可能不止四个点,而且不止一张图,这个时候我们就用最小二乘法求k1,k2了。这里我们解决了如何求k1,k2初值的问题,后面还是要进行极大似然估计,但是这个初值对于LM算法还是比较重要的。我们如果要标定还需要考虑抑恶个问题,就是棋盘坐标在世界坐标系的坐标,Z坐标是0我们知道了。其它坐标我们如何确定呢?我们就随便定咯,这里我们知道的是棋盘的方格是10*10的。d30cf241ab8134bdfc761097a8daec8c27890274.png

那么:b478f26d0398b13009c1217b5a58be589a28c09b.png

mgrid是meshgrid的缩写。是生成坐标网格,输入的参数是坐标范围,得到的网格的点坐标。44aaf42f122cb3d9cd5ad982dce6e191202f0c41.png

这个ret据说就是极大似然函数的那个最小值。fcc405104f8632276383b16cf89639a5a748eace.png

mtx是内参矩阵,我们看到c=0。31ed3474dcecc75f6da842f74fd4c8cf09f96af8.png

这个旋转用的的旋转向量的形式,因为用了14张图,所以有14组外参数。7171ae744cfd800d4ff4da4936b61bf2abe5b175.png

26b91ef3eea816be9ecdf5052423e390c8f71f07.png

这个是把世界坐标系投影到像素坐标系,因为其实是求解一个非线性最小二乘,误差函数不可能是0的,所以肯定会有一些偏差的。b7a098ad4b5cd3050fa50dbbfeeb8efe5917f0e0.png

这个计算出来之后,可以计算一下平均平方误差,cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2),这个误差也可以叫做重投影误差,这个是评价相机标定结果的一个指标。5365e72504911580d479643dafec6f175d579d85.png

结果是0.033,这个结果看起来还是不错的。上面是完成标定工作了,并且还对标定结果作出了评价。据官方文档说,这个ret也可以是一个指标。13c24e74ed8db997ffdcc8d6d32bdf4a1b84b925.png

RMS就是e8c763e32ad4bc9a9dca24b5517a266b37602110.png

不过还是有点不太一样,但是差的很少,一个是0.16,一个是0.18。c5056f772a95de1a3ce8033ef15f075eff5e424b.png

下面介绍一个模块,叫做glob。参考https://blog.csdn.net/u010472607/article/details/76857493/b98ff528f03ae2a14e862464d9a28db31b1a6404.png

需要注意的是这个不会迭代查找,它不会去子文件夹中继续查找。24a1f00624d39eb5dca439ec7bef0de45478e5b3.png

这种通配符的用法就是*代表任意个(很多个)任意字符而?代表一个字符。52101119f3bf3ee87c88e3546301daca8d7023a2.png

我没有觉得iglob有什么存在的必要。关于查找文件,我们在学习python的时候就已经将结果如何去查找某一个类型的文件,后来我们又学了正则表达式,就可以不仅仅是查找某种类型的文件了,那个时候我们学的是可以递归查找的。2b4e69984cb547b944d39f7d516ca53255ecd3a5.png

opencv校正图像

undistortion就是去畸变的意思,distortion是畸变的意思。

上面我们已经完成了标定工作,但是没有对图片进行校正,下面我们要做的事校正工作。opencv有两个函数可以校正图像。我们下面都会看到,在那之前,我们可以用cv2.getOptimalNew优化一下相机内参数矩阵,我觉得这一步做的就是把畸变的形式和相机内矩阵的形式结合一下,得出一个新的相机内参矩阵。还参考了:https://www.cnblogs.com/riddick/p/6711263.html412c35e1d5567b15f9bf0d04ad37c2734b7955eb.png

86622bfb2ac7bf77c015c7e9ab9cc49093619a64.png

d07f7089272a1104c6b2230f4899989e89c97f26.png

83852b10293331d86e1473e3eeab9732219bd361.png

330f04bac7522b2f3da830857fd7286c8d33ab48.png

b12dfad53419f67ebf3d91106913a7a2e063c893.png

也就是调整alhpa的值主要还是为了调整显示范围,也就是ROI。148b1a6b1003fdba19f473d25309e04a92d17fda.png

cameraMatrix是上面张氏标定得出的相机内参矩阵,distCoeffs是畸变向量,ImageSize是原始输入图像的大小,alpha就是调整输出图像区域的一个值,如果为0,就只会保留校正后的像素,如果为1,就会保留所有像素,就会出现那些黑色区域。validPixROi是校正后比较好的区域的一个矩形参数。centerPrincipalPoint,这个参数说的是是否要把主点移动到图像平面中心。8ab150dec7fc95b134789f34b6f3e84e1a6793ac.png

undistort是校正的函数。5de9c136c6ee038f514317cec66105b37d525386.png

其实我们上面的失真向量里面的值都比较小。ea5db5c49434d79f2339fe68cb949a54059535c7.png

校正的时候为什么需要用到相机内参矩阵呢?因为计算r的时候是计算和主点的距离,所以需要用到内参数的u0和v0参数。我们来试一试。b471b652ed44558b8cd09f166579f059636c27cf.png

其实这两个矩阵差别不大,主要还是我们的畸变向量的值都比较小,这个主点也不是正好在中间。645b064d2f91ddd0d5e05a6f4480e4806eca157e.png

这个应该能看懂什么意思。88ff0cf69993ed169b3d53f3143e3f656e02e86f.png

由于我们的畸变向量的参数都很小。基本上看不出来什么区别。4ab71c14c339be9a6d05f3abb8f3a4325617cb84.png

如果不用这个getOptimalNewCameraMatrix呢?fa9308b2af07e4fd5aeeec85eb7ea4a171594009.png

还是因为我这个图片基本上畸变很小,看不出来。

试试第二种方式吧。27ab8b6ba1230bc80a2f46bf79cfe7f5473edfa6.png

c2f12f64b6793afba27f1c44a3dffba379801909.png

cdb6e39501b87be48ebbed43429d7e02eb4bad0b.png

238ac7cc6b3fa128afdb304dffd52941abce5ef8.png

用getOptimalNewCameraMatrix:6f6a368804494b3c252081b89dd1494ef25b9289.png

不用:24cd91836d0b197e6372222fcdf3e9cfe55f4083.png

可以看出区别,如果不用,右边就多出来一列黑色的地带。d5044632cb70e6d8d053f98aecb577f2e992e50c.png

mapx,mapy里面存的是原来的480*640个像素校正之后的位置。

这个5不能随便改动。37580db725212563ff34355405288a25c25750f8.png

这里有一个鱼眼校正的:https://blog.csdn.net/hpuhjl/article/details/8089993102db465212d3c374a43c60fa2625cc1caeaab796.png

张正友标定和校正就到这里了。

其实github速度也不慢的:8daab031b8eb6125d8d6022552f3b3ae75d4ab7e.png

github地址:https://github.com/lcl1026504480/opencv-python-turorial

码云地址:https://gitee.com/lcl1026504480/opencv-python-turorial5893dd93a9a9115f829386fa37a558325c23a8ed.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值