现实生活中的物体都处于三维世界坐标系中,当我们的照相机进行拍摄时,镜头看到的是三维世界坐标系,然而成像时却是二维图像坐标系。由于这种差异,导致镜头成像时的转换矩阵不同,同时还可能引起失真。例如:桶状畸变
枕形畸变:
每个镜头的畸变程度各不相同,通过相机标定可以校正这种镜头畸变,通过标定近似地估算出转换矩阵和失真系数。为了估算,需要知道若干点的三维世界坐标系中的坐标和二维图像坐标系中的坐标,也就是拍摄棋盘的意义。通过相机标定,获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
具体的公式推导,参考博客:相机标定 https://blog.csdn.net/honyniu/article/details/51004397
张正友标定介绍 https://blog.csdn.net/heroacool/article/details/50286677
1、打印一张棋盘格A4纸张(黑白间距已知),并贴在一个平面上
2、针对棋盘格拍摄若干张图片(一般10~20张)
3、在图片中检测特征点(Harris角点)
4、根据角点位置信息及图像中的坐标,求解Homographic矩阵
5、利用解析解估算方法计算出5个内部参数,以及6个外部参数
6、根据极大似然估计策略,设计优化目标并实现参数的refinement
读取文件夹中的所有测试的图片,将所有的图片都变灰度,并以相同的尺寸进行resize,因图片太大会影响运行效率,所以进行了统一的压缩,最后将图片保存在指定的文件夹中,以便后面的相机标定的使用。注意:文件夹的绝对路径,要用符号‘/’,否则会找不到图片,出现像这样的错误:
并且在代码中是没有自动生成文件夹的,所以要事先在指定位置建立好文件夹,以便保存灰度后的新图片。
# -*- coding: cp936 -*-
import cv2
#循环灰度图片并保存
def grayImg():
for x in range(1,15):
#读取图片
img = cv2.imread("F:/test/{}.jpg".format(str(x)))
GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
GrayImage=cv2.resize(GrayImage,(1000,1333))
#保存灰度后的新图片
cv2.imwrite("F:/计算机视觉/实验六/Camera/pic/{}.jpg".format(str(x)),GrayImage)
grayImg()
注意:根据你们棋盘的尺寸,在以下画框的代码块中修改参数。例如我用的是7*5的黑白格,而实际写入的参数却是6*4的,即不考虑边缘,只考虑内角点
具体代码如下:
#!usr/bin/env/ python
# _*_ coding:utf-8 _*_
import cv2 as cv
import numpy as np
import os
from step.homography import get_homography
from step.intrinsics import get_intrinsics_param
from step.extrinsics import get_extrinsics_param
from step.distortion import get_distortion
from step.refine_all import refinall_all_param
def calibrate():
#求单应矩阵
H = get_homography(pic_points, real_points_x_y)
#求内参
intrinsics_param = get_intrinsics_param(H)
#求对应每幅图外参
extrinsics_param = get_extrinsics_param(H, intrinsics_param)
#畸变矫正
k = get_distortion(intrinsics_param, extrinsics_param, pic_points, real_points_x_y)
#微调所有参数
[new_intrinsics_param, new_k, new_extrinsics_param] = refinall_all_param(intrinsics_param,
k, extrinsics_param, real_points, pic_points)
print("intrinsics_parm:\t", new_intrinsics_param)
print("distortionk:\t", new_k)
print("extrinsics_parm:\t", new_extrinsics_param)
if __name__ == "__main__":
file_dir = r'..\pic'
# 标定所用图像
pic_name = os.listdir(file_dir)
# 由于棋盘为二维平面,设定世界坐标系在棋盘上,一个单位代表一个棋盘宽度,产生世界坐标系三维坐标
cross_corners = [6, 4] #棋盘方块交界点排列
real_coor = np.zeros((cross_corners[0] * cross_corners[1], 3), np.float32)
real_coor[:, :2] = np.mgrid[0:6, 0:4].T.reshape(-1, 2)
real_points = []
real_points_x_y = []
pic_points = []
for pic in pic_name:
pic_path = os.path.join(file_dir, pic)
pic_data = cv.imread(pic_path)
# 寻找到棋盘角点
succ, pic_coor = cv.findChessboardCorners(pic_data, (cross_corners[0], cross_corners[1]), None)
if succ:
# 添加每幅图的对应3D-2D坐标
pic_coor = pic_coor.reshape(-1, 2)
pic_points.append(pic_coor)
real_points.append(real_coor)
real_points_x_y.append(real_coor[:, :2])
calibrate()
手机型号说明:iphone7plus