十五天掌握OpenCV——摄像机标定和3D重构!—摄像机标定

魏老师学生——Cecil:学习OpenCV-机器视觉之旅


Aim:
学习摄像机畸变以及摄像机的内部参数和外部参数;
对畸变图像进行修复。

基础

  1. 低价单孔摄像机(照相机)会给图像带来畸变。
  2. 畸变:径向畸变、切向畸变。
  3. 表现:图像中的直线也会变弯。
  4. 方程组验证畸变:1
  5. 切向畸变:由于透镜与成像平面存在不平行造成。 影响:造成图像中某些点看上去位置比我们认为的位置要近。通过方程组校正:2
  6. 对畸变图像校正需要找到五个造成畸变的系数:Distortioncofficients=(k1,k2,p1,p2,k3)
    摄像机内部参数(独有):焦距(fx,fy),光学中心(cx,cy)。被称为摄像机矩阵。取决于摄像机自身,只需计算一次,以后就可以一直使用。
    摄像机矩阵:摄像机矩阵
    摄像机外部参数:与旋转和变换向量相对应,可以将3D点的坐标转换到坐标系统中。
  7. 3D应用中:先校正畸变,必须提供一些包含明显图案模式的样本图片找出参数。先在图案上找到特殊点,根据特殊点图中位置和真实位置,使用数学方法求解畸变系数。需要至少10个图案模式得到更好结果。

代码

  1. 摄像机标定时需要输入一组3D真实世界中的点以及与它们对应的2D图像中的点。
  2. 3D点位:图像来源于静态摄像机和图像不同的摆放位置和朝向,需要知道(x,y,z)的值。简化后z=0.为了求x、y,需要传入点位,结果就是需要的图像部分的大小。
  3. 3D点称为对象点,2D点称为图像点。

设置

  1. cv2.findChessboardCorners() ——解释:找出棋盘图案。传入图案类型。返回角点Retval,得到图像则返回True。角点按序排列:从左到右,从上到下。
    找出所有图像中应有图案:编写代码,启动摄像机并在每一帧中检查是否有应有图案。获取图案后找出角点并保存为一个列表。读取下一帧图像前设置一定间隔,保证足够时间调整图案方向。迭代过程直到获取足够多好的图案。
  2. cv2.findCirclesGrid() ——解释:使用环形格子找图案,只需要很少的一组图片。
  3. cv2.cornerSubPix() ——解释:增加校正畸变的准确度。
  4. cv2.drawChessboardCorners() ——解释:绘制图案。

标定

  1. cv2.calibrateCamera() ——解释:返回摄像机矩阵,畸变系数,旋转和变换向量。

畸变校正

cv2.getOptimalNewCameraMatrix() ——解释:使用自由缩放系数对摄像机矩阵进行优化。缩放系数alpha=0,返回的非畸变图像带有最少量多余像素,有可能在图像角点去除一些像素。alpha=1,返回所有像素(包括一些黑图像),返回一个ROI图像用来对结果进行裁剪。

  1. cv2.undistort() ——解释:联合ROI对结果裁剪。
  2. cv2.remap() ——解释:先找到从畸变图像到非畸变图像的映射方程,再使用重映射方程。

反向投影误差

利用反向投影误差估计找到的参数的准确性,返回结果越接近0越好。
前提:已知内部参数、畸变参数和旋转变换矩阵,利用cv2…projectPoints() 将对象点转换到图像点,再通过计算变换得到图像与角点检测算法的绝对差,最后计算所有标定图像的误差平均值。

代码演示

#coding=utf-8
import cv2
import numpy as np
import glob

criteria=(cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER,30,0.001)

objp=np.zeros((6*7,3),np.float32)
objp[:,:2]=np.mgrid[0:7,0:6].T.reshape(-1,2)

objpoints=[]
imgpoints=[]

images=glob.glob('*.jpg')

for fname in images:
    img=cv2.imread(fname)
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

    ret,corners=cv2.findChessboardCorners(gray,(7,6),None)

    if ret==True:
        objpoints.append(objp)

        corners2=cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners2)

        img=cv2.drawChessboardCorners(img,(7,6),corners2,ret)
        cv2.imshow('img',img)
        cv2.waitKey(500)
cv2.destroyAllWindows()

ret,mtx,dist,rvecs,tvecs=cv2.calibrateCamera(objpoints,imgpoints,gray.shape[::-1],None,None)

img=cv2.imread('./image2/mario.jpg')
h,w=img.shape[:2]
newcameramtx,roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))

dst=cv2.undistort(img,mtx,dist,None,newcameramtx)
x,y,w,h=roi
dst=dst[y:y+h,x:x+w]
cv2.imshow('calibresult',dst)

mapx,mapy=cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
dst=cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
cv2.imshow('cali',dst)

mean_error=0
for i in range(len(objpoints)):
    imgpoints2,_=cv2.projectPoints(objpoints[i],rvecs[i],tvecs[i],mtx,dist)
    error=cv2.norm(imgpoints[i],imgpoints2,cv2.NORM_L2/len(imgpoints2))
    error += error
print("total error:",mean_error/len(objpoints))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值