计算机视觉--相机标定

文章目录

      • 1、相机标定
        • 1.1 原理
        • 1.2 基本流程
      • 2、实验过程
        • 2.1 标定面数据集
        • 2.2 实验结果展示
        • 2.3 小结
        • 2.4 源代码
      • 3、实验遇到的问题

1、相机标定

1.1 原理

相机标定简单来说是从世界坐标系转换为相机坐标系,再由相机坐标系转换为图像坐标系的过程。
世界坐标系: 用户定义的三维世界的坐标系,为了描述目标物在真实世界里的位置而引入。
相机坐标系: 在相机上建立的坐标系,为了从相机的角度描述物体位置而定义,作为沟通世界坐标系和图像/像素坐标系的中间一环。
图像坐标系: 为了描述成像过程中物体从相机坐标系到图像坐标系的投影透射关系而引入,方便进一步得到像素坐标系下的坐标。
世界坐标系–>相机坐标系:
这一步是三维点到三维点的转换,包括R,t(相机外参)等参数。
计算机视觉--相机标定_第1张图片
相机坐标系–>图像坐标系:
这一步是三维点到二维点的转换,包括K(相机内参)等参数。
计算机视觉--相机标定_第2张图片
计算机视觉--相机标定_第3张图片
可推导出下面的变换公式:
计算机视觉--相机标定_第4张图片
计算机视觉--相机标定_第5张图片
像主点的偏移:
计算机视觉--相机标定_第6张图片
可推导出下面的变换公式:
计算机视觉--相机标定_第7张图片
内参矩阵K:
f:焦距
x0、y0:像主点坐标
计算机视觉--相机标定_第8张图片
上述内参矩阵K其实并不能完整表达投影原理,在相机拍摄过程中,由于透镜质量或者光线在远离透镜中心的地方比靠近中心的地方更加弯曲等因素影响,图像可能会发生畸变现象,因此需要一个畸变参数s来表示畸变现象对图像产生的影响。即完整的内参矩阵K如下图所示:
计算机视觉--相机标定_第9张图片
畸变现象分为两类:
1)桶状畸变
畸变前:
计算机视觉--相机标定_第10张图片
畸变后:
计算机视觉--相机标定_第11张图片
2)枕形畸变
畸变前:
计算机视觉--相机标定_第12张图片
畸变后:
计算机视觉--相机标定_第13张图片
外参矩阵[R丨t]:
外参矩阵[R丨t]中R表示旋转、t表示平移。
计算机视觉--相机标定_第14张图片
结合内参外参公式得到总的公式如下:
计算机视觉--相机标定_第15张图片

1.2 基本流程

相机标定的基本流程如下:
1、针对一个黑白棋盘格(黑白间距已知)拍摄若干张图片(一般10-20张)
2、在图片中检测特征点(Harris角点)
3、根据角点位置信息及图像中的坐标,求解Homographic矩阵
4、利用解析解估算方法计算出5个内部参数,以及6个外部参数
5、根据极大似然估计策略,设计优化目标并实现参数的refinement

2、实验过程

2.1 标定面数据集

标定面高度、宽度设置如下:
在这里插入图片描述
标定面数据集:
计算机视觉--相机标定_第16张图片

2.2 实验结果展示

角点检测结果展示:
计算机视觉--相机标定_第17张图片
矫正结果前后展示:
矫正前:
计算机视觉--相机标定_第18张图片
矫正后:
计算机视觉--相机标定_第19张图片
参数结果展示:
计算机视觉--相机标定_第20张图片
计算机视觉--相机标定_第21张图片
计算机视觉--相机标定_第22张图片

2.3 小结

  • 拍摄使用的手机型号为:OPPO R11 Plus,拍摄的棋盘格是7*7的棋盘格。
  • 手机图像传输至电脑保存时有些模糊,且运行时会出现无法运行的现象,故所运行的图片是经过比例压缩的,若是不经比例压缩,可能无法得出运行结果或者结果会有较大偏差;也不排除是手机像素的原因,导致照片本身不够清晰,所以代码无法运行。
  • 因为拍摄角度不同,所以每一张图片的外参也不相同,有多少张图片就有多少个外参,如上图所示,平移、旋转两个外参都有15个不同的值(数据集有15张图片)。

2.4 源代码

# coding=utf-8
import numpy as np
import cv2
import glob
# 终止标准
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
#w = 6
#h = 6
objp = np.zeros((6*6,3), np.float32)
objp[:,:2] = np.mgrid[0:6,0:6].T.reshape(-1,2)

# 用于存储所有图像中的对象点和图像点的数组。
objpoints = [] # 在现实世界空间的3d点
imgpoints = [] # 图像平面中的2d点。
images = glob.glob('C:/B/*.jpg')
for fname in images:
    #对每张图片,识别出角点,记录世界物体坐标和图像坐标
    print('processing img:{fname}')
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#转灰度
    print('grayed')
    #寻找角点,存入corners,ret是找到角点的flag
    ret, corners = cv2.findChessboardCorners(gray, (6, 6),None)

    # 如果找到,添加对象点,图像点(精炼后)
    if ret == True:
        print('chessboard detected')
        objpoints.append(objp)
        #执行亚像素级角点检测
        corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
        imgpoints.append(corners2)

        # 绘制并显示角点
        img = cv2.drawChessboardCorners(img, (6,6), corners2,ret)
        cv2.namedWindow('img',0)
        cv2.resizeWindow('img', 500, 500)
        cv2.imshow('img',img)
        cv2.waitKey(500)
        cv2.destroyAllWindows()
        
img2 = cv2.imread("C:/B/13.jpg")
print("type objpoints:{objpoints[0].shape}")
print("type imgpoints:{imgpoints[0].shape}")

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

newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
#纠正畸变
dst = cv2.undistort(img2, 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)
print ("newcameramtx旋转(向量)外参:\n",rvecs)
print ("dist平移(向量)外参:\n",tvecs)
#计算误差
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))

3、实验遇到的问题

1)问题:拍摄的照片运行代码时只能运行一部分照片
计算机视觉--相机标定_第23张图片
解决办法:可能因为是手机拍摄的原因,传输到电脑时比例失调,保存到电脑的时候有些模糊,把图片一一修改了大小之后就没有这样的问题了。
2)问题:角点数目计算错误
计算机视觉--相机标定_第24张图片
解决办法:角点检测时,角点数目错误会导致程序出现上图错误,更改为正确的角点数目即可。

你可能感兴趣的:(python,计算机视觉)