计算机视觉——相机标定

实验环境

系统:Ubuntu16.04
语言:python3.7

实验原理

我们拍摄的物体都处于三维世界坐标系中,而相机拍摄时镜头看到的是三维相机坐标系,成像时三维相机坐标系向二维图像坐标系转换。不同的镜头成像时的转换矩阵不同,同时可能引入失真,标定的作用是近似地估算出转换矩阵和失真系数。为了估算,需要知道若干点的三维世界坐标系中的坐标和二维图像坐标系中的坐标,也就是拍摄棋盘的意义。通过相机标定,获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。

也即是我们所希望找出的,是相机的内参数;也即包含它们的内参矩阵

内参矩阵

设P=(X,Y,Z)为场景中的一点,在针孔相机模型中,其要经过以下几个变换,最终变为二维图像上的像点p=(μ,ν):

将P从世界坐标系通过刚体变换(旋转和平移)变换到相机坐标系,这个变换过程使用的是相机间的相对位置,也就是相机的外参数。
从相机坐标系,通过透视投影变换到相机的成像平面上的像点p=(x,y)。
将像点p从成像坐标系,通过缩放和平移变换到像素坐标系上点p=(μ,ν)。
相机将场景中的三维点变换为图像中的二维点,也就是各个坐标系变换的组合,可将上面的变换过程整理为矩阵相乘的形式:
在这里插入图片描述
将矩阵K称为相机的内参数
在这里插入图片描述
其中,α,β表示图像上单位距离上像素的个数,则fx=αf,fy=βf将相机的焦距f变换为在x,y方向上像素度量表示。
另外,为了不失一般性,可以在相机的内参矩阵上添加一个畸变参数γ,该参数用来表示像素坐标系两个坐标轴的畸变大小。则内参矩阵K变为
在这里插入图片描述

张正友相机标定法

张正友相机标定法是张正友教授1998年提出的单平面棋盘格的相机标定方法。传统标定法的标定板是需要三维的,需要非常精确,这很难制作,而张正友教授提出的方法介于传统标定法和自标定法之间,但克服了传统标定法需要的高精度标定物的缺点,而仅需使用一个打印出来的棋盘格就可以。同时也相对于自标定而言,提高了精度,便于操作。因此张氏标定法被广泛应用于计算机视觉方面。

  • 计算外参
  • 计算内参
  • 最大似然估计
  • 径向畸变估计

该方法将位于棋盘格上的点的Z坐标都设为0,即
在这里插入图片描述
再利用homographic(共线方程)进行单应性变换,得到棋盘平面Π和图像平面π的单应矩阵H。再根据上式可得出将棋盘格所在的平面映射到相机的成像平面的方程 p=Hp其中p为棋盘格所成像的像点坐标,P棋盘格角点在世界坐标系的坐标。
将上面两个等式进行整合,则可以得到单应矩阵H和相机矩阵(包含内参和外参)的相等:
在这里插入图片描述

标定流程

  1. 打印棋盘格
  2. 针对棋盘格拍摄照片
  3. 在图片中检测特征点(Harris角点)
  4. 根据角点位置信息及图像中的坐标,求解Homographic矩阵
  5. 利用解析解估算方法计算出5个内部参数,以及6个外部参数
  6. 根据极大似然估计策略,设计优化目标并实现参数的refinement

实验过程

先从不同的角度和位姿拍摄标定板,部分数据如下所示
在这里插入图片描述

代码展示

import cv2
import numpy as np
import glob

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
w = 9  
h = 6

objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点

images = glob.glob('picture/*.jpg')
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
    if ret == True:
        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)#角点精确检测
        objpoints.append(objp)
        imgpoints.append(corners)
        cv2.drawChessboardCorners(img, (w,h), corners, ret)
        cv2.imshow('findCorners',img)
        cv2.waitKey(1000)
cv2.destroyAllWindows()

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

print (("ret:"),ret)
print (("mtx:\n"),mtx)        # 内参数矩阵
print (("dist:\n"),dist)      # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print (("rvecs:\n"),rvecs)    # 旋转向量  # 外参数
print (("tvecs:\n"),tvecs)    # 平移向量  # 外参数
# 去畸变
img2 = cv2.imread('picture/5.jpg')
h,w = img2.shape[:2]


dst = cv2.undistort(img2, mtx, dist, None, newcameramtx)

x,y,w,h = roi
dst = dst[y:y+h, x:x+w]
cv2.imwrite('calibresult.jpg',dst)


total_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)
    total_error += error
print (("total error: "), total_error/len(objpoints))

角点检测结果

在这里插入图片描述

实验结果

特别注意:相机的内参会根据不同的手机变化,即便是同一类型的手机也会因为生产工艺使得参数有所变化。
在这里插入图片描述
内参矩阵
在这里插入图片描述
畸变系数dist
在这里插入图片描述

旋转向量
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值