概述
文章目录
- 环境
- 前言
- 一、实验原理
- 1.相机标定
- 2.张正友标定法
- 3.步骤
- 二、实验过程
- 1.实验步骤
- 2.结果展示
- 3.分析
- 三、问题和总结
环境
win10,64位,python2.7,编译器:PyCharm
手机型号:oppo R11
前言
我们拍摄的物体都处于三维世界坐标系中,而相机拍摄时镜头看到的是三维相机坐标系,成像时三维相机坐标系向二维图像坐标系转换。不同的镜头成像时的转换矩阵不同,同时可能引入失真,标定的作用是近似地估算出转换矩阵和失真系数。 为了估算,需要知道若干点的三维世界坐标系中的坐标和二维图像坐标系中的坐标,也就是拍摄棋盘的意义。
一、实验原理
1.相机标定
相机标定指建立相机图像像素位置与场景点位置之间的关系,根据相机成像模型,由特征点在图像中坐标与世界坐标的对应关系,求解相机模型的参数。相机需要标定的模型参数包括内部参数和外部参数。
针孔相机成像原理其实就是利用投影将真实的三维世界坐标转换到二维的相机坐标上去,其模型示意图如下图所示:
从图中我们可以看出,在世界坐标中的一条直线上的点在相机上只呈现出了一个点,其中发生了非常大的变化,同时也损失和很多重要的信息,这正是我们3D重建、目标检测与识别领域的重点和难点。实际中,镜头并非理想的透视成像,带有不同程度的畸变。理论上镜头的畸变包括径向畸变和切向畸变,切向畸变影响较小,通常只考虑径向畸变。
• 为什么需要相机标定?
(1)一个是由于每个镜头的在生产和组装过程中的畸变程度各不相同,通过相机标定可以校正这种镜头畸变,生成矫正后的图像——矫正透镜畸变;
(2)另一个是根据标定后的到的相机参数建立相机成像几何模型,由获得的图像重构出三维场景。具体来说:当我们用摄像机拍照时,从照片里得到一些空间信息(比如距离,尺寸等),是要利用二维图像得到三维信息。我们拍照的时候把空间物体信息通过摄像机变成了二维图像,这个过程本来是不可逆的。但如果我们可以找到一个摄像机的数学模型,就可以 :从二维图像+模型逆推得到原来三维信息。标定就是在找这个模型。
• 相机标定可以做什么?
(1)相机在出厂之前都需要进行相机标定,用软件的方法校正生成的图像,避免拍摄出的图像产生桶形和枕形畸变;
(2)根据相机成像的几何模型,将世界坐标系中的3D物体映射到2D成像平面上;
(3)求解多个相机对之间的映射关系。
• 相机标定后可以得到什么?
(1)相机的内参矩阵A(dx,dy,r,u,v,f),外参矩阵[R|T]、畸变系数[k1,k2,k3,,p1,p2,]。
(2)内参矩阵各元素意义:一个像素的物理尺寸dx和dy,焦距f,图像物理坐标的扭曲因子r,图像原点相对于光心成像点的的纵横偏移量u和v(像素为单位)。
(3)外参矩阵: 世界坐标系转换到相机坐标系的旋转R和平移T矩阵。
(4)畸变系数: 包括相机的径向畸变系数k1,k2,k3,~, 和相机的切向畸变系数p1,p2,~。
2.张正友标定法
”张正友标定法” 是指张正友教授1998年提出的单平面棋盘格的摄像机标定方法。文中提出的方法介于传统标定法和自标定法之间,但克服了传统标定法需要的高精度标定物的缺点。相对于自标定而言,提高了精度,便于操作。因此张正友标定法被广泛应用于计算机视觉方面。
在张氏标定法中,用于标定的棋盘格是三维场景中的一个平面Π,其在成像平面的像是另一个平面π,知道了两个平面的对应点的坐标,就可以求解得到两个平面的单应矩阵H。其中,标定的棋盘格是特制的,其角点的坐标是已知的;图像中的角点,可以通过角点提取算法得到(如Harris角点),这样就可以得到棋盘平面Π和图像平面π的单应矩阵H。
3.步骤
1、计算单应性矩阵H
单应性:在计算机视觉中被定义为一个平面到另一个平面的投影映射。首先确定,图像平面与标定物棋盘格平面的单应性。
设三维世界坐标的点为 ,二维相机平面像素坐标为,所以标定用的棋盘格平面到图像平面的单应性关系为: (其中,K为相机的内参矩阵,R为外部参数矩阵(旋转矩阵),T为平移向量。令,设棋盘格位于Z=0的平面,定义旋转矩阵R的第i列为 ri, 则有:
于是空间到图像的映射可改为:H=λK[r1 r2 t]
其中H 是描述Homographic矩阵,可通过最小二乘,从角点世界坐标到图像坐标的关系求解。
2、计算内参数矩阵
根据步骤1中的式子,令 H 为 H = [h1 h2 h3],则 [h1 h2 h3]=λK[r1 r2 t],再根据正交和归一化的约束可以得到等式:
即每个单应性矩阵能提供两个方程,而内参数矩阵包含5个参数,要求解,至少需要3个单应性矩阵。为了得到三个不同的单应性矩阵,我们使用至少三幅棋盘格平面的图片进行标定。通过改变相机与标定板之间的相对位置来得到三个不同的图片。为了方便计算,我们定义:
B 中的未知量可表示为6D 向量 b,
设H中的第i列为 hi,,根据b的定义,可以推导出公式,,最后推导出
通过上式,我们可知当观测平面 n ≥ 3 时,即至少3幅棋盘格图像,可以得到b的唯一解,求得相机内参数矩阵K。
3、计算外参数矩阵
外部参数可通过Homography求解,由 H = [h1 h2 h3] = λA[r1 r2 t],可推出
4、最大似然估计
上述的推导结果是基于理想情况下而言,但由于可能存在一些其他干扰,所以使用最大似然估计进行优化。假设拍摄了n张棋盘格图像,每张图像有m个角点。最终获得的最大似然估计公式为
二、实验过程
1.实验步骤
(1)取材:打印一张棋盘格,把它贴在一个平面上,作为标定物,通过调整标定物或摄像机 的方向,为标定物拍摄一些不同方向的照片。
(2)从照片中提取棋盘格角点。
(3)估算理想无畸变的情况下,五个内参和六个外参。
(4)应用最小二乘法估算实际存在径向畸变下的畸变系数。
(5)极大似然法,优化估计,提升估计精度。
数据集:
代码:
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import glob
# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)
# 获取标定板角点的位置
objp = np.zeros((7 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:7].T.reshape(-1, 2) # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y
obj_points = [] # 存储3D点
img_points = [] # 存储2D点
images = glob.glob("D:/qipange/*.jpg")
i=0;
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
size = gray.shape[::-1]
ret, corners = cv2.findChessboardCorners(gray, (7, 7), None)
#print(corners)
if ret:
obj_points.append(objp)
corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria) # 在原角点的基础上寻找亚像素角点
#print(corners2)
if [corners2]:
img_points.append(corners2)
else:
img_points.append(corners)
cv2.drawChessboardCorners(img, (7, 7), corners, ret) # 记住,OpenCV的绘制函数一般无返回值
i+=1;
cv2.imwrite('conimg'+str(i)+'.jpg', img)
cv2.waitKey(1500)
print(len(img_points))
cv2.destroyAllWindows()
# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, 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 ) # 平移向量 # 外参数
print("-----------------------------------------------------")
img = cv2.imread(images[2])
h, w = img.shape[:2]
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))#显示更大范围的图片(正常重映射之后会删掉一部分图像)
print (newcameramtx)
print("------------------使用undistort函数-------------------")
dst = cv2.undistort(img,mtx,dist,None,newcameramtx)
x,y,w,h = roi
dst1 = dst[y:y+h,x:x+w]
cv2.imwrite('D:/qipange/1.jpg', dst1)
print ("方法一:dst的大小为:", dst1.shape)
'''
传入所有图片各自角点的三维、二维坐标,相机标定。
每张图片都有自己的旋转和平移矩阵,但是相机内参和畸变系数只有一组。
mtx,相机内参;dist,畸变系数;revcs,旋转矩阵;tvecs,平移矩阵。
'''
img = cv2.imread("D:/qipange/1.jpg")
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# 注意这里跟循环开头读取图片一样,如果图片太大要同比例缩放,不然后面优化相机内参肯定是错的。
# img = cv2.resize(img,None,fx=0.5, fy=0.5, interpolation = cv2.INTER_CUBIC)
h, w = img.shape[:2]
'''
优化相机内参(camera matrix),这一步可选。
参数1表示保留所有像素点,同时可能引入黑色像素,
设为0表示尽可能裁剪不想要的像素,这是个scale,0-1都可以取。
'''
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.imwrite('calibresult.png', dst)
# 打印我们要求的两个矩阵参数
print ("newcameramtx:n", newcameramtx)
print ("dist:n", dist)
# 计算误差
tot_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)
tot_error += error
print ("total error: ", tot_error / len(objpoints))
2.结果展示
3.分析
• 我们可以标定出相机的畸变参数,内参矩阵,外参矩阵对相机进行参数调整,从而完成畸变校正。
畸变参数:计算机在径向和切向的畸变程度
内参矩阵:一个像素的物理尺寸dx和dy,焦距 f,图像物理坐标的扭曲因子r,图像原点相对于光心成像点的的纵横偏移量u和 v。
外参矩阵:世界坐标转换成相机坐标系的旋转和平移矩阵。
• 把打印的棋盘纸张贴在平板上,拍出来的照片和显示图像及物理点和世界点存在的误差才会理想,找一个光线较暗不会造成拍摄反光的地方对图片进行拍摄,可以有效减小误差。
• 从实验结果可以看出,mtx为内参矩阵,dist为畸变系数,外参数为rvecs(旋转向量)和tvecs(平移向量)。归一化焦距fx=575.46539307,fy=568.10003662,像主点(光心)的坐标Cx=324.2929208,Cy=259.90821087。所有图像投影坐标和亚像素角点坐标之间的总体的平均误差大概为0.16,误差较小,说明手机拍照性能较优。
• 原始图片和校准之后的图片对比:
如上图,在校准前左图在角度和尺度上都有一定的畸变,而校准后的图片得到了明显的改善,效果较好。
三、问题和总结
1.
这是由于我角点个数超出范围,棋盘格角点数为7 * 7,而我写成8 * 8,所以数组超出导致报错。
2.
这边出错是由于原来的objp = np.zeros((7 * 7, 1), np.float32),表示维度信息,世界坐标系中的3D点坐标,所以要把1改成3才不会出错,改完后是objp = np.zeros((7 * 7, 3) 。
最后
以上就是纯真缘分为你收集整理的计算机视觉——张正友棋盘格标定法环境前言一、实验原理二、实验过程三、问题和总结的全部内容,希望文章能够帮你解决计算机视觉——张正友棋盘格标定法环境前言一、实验原理二、实验过程三、问题和总结所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复