这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » OpenVINO生态社区 » 【原创】OpenCV-Python系列之相机校准实践(六十二)

共4条 1/1 1 跳转至

【原创】OpenCV-Python系列之相机校准实践(六十二)

高工
2020-08-14 21:30:47     打赏

OpenCV-Python系列之相机校准实践

上个教程已经谈到,为了校准摄像头,我们至少需要10种测试模式。现在我们使用示例图片:

                                              image.png

用同一相机从不同的位置,不同的角度,拍摄标定板的多张照片(10-20张最佳),将照片放到文件夹中:

image.png

设想一张棋盘的图像,需要用于校准摄像头最重要的输入数据是3D真实世界点的集合以及图像中这些点的相应2D坐标。2D图像点我们得能够轻易从图像中找出来。(这些图像点是棋盘中两个黑色方块相互接触的位置)

那现实世界空间的3D点怎么来呢?这些图像是从一个静止的摄像头上取下来的,并且棋盘被放置成了不同的位置和方向。所以我们得知道(X,Y,Z)值。但是为了简单,我们可以说棋盘在XY平面保持静止(所以 Z总是等于0),并且摄像头也相应的移动了。这样的考虑方式帮助我们可以只算出XY值。现在对于XY值,我们可以简单的传入点,比如(0,0), (1,0), (2,0), ... 用于表示点的位置。在这种情况下,我们得到的结果将是棋盘方格的放缩后的大小。但如果我们知道方格尺寸(比方说 30 mm),我们可以传入这样的值(0,0), (30,0), (60,0), ... . 于是我们得到的结果就是mm为单位的。(当前情况下,我们不知道方格的尺寸,因为我们没有取那些图像,所以我们按照方格尺寸放缩的模式传参)

3D 点被称为是object points 对象点,而2D 图像上的点被称为 image points 图象点。

实现步骤:

1、为了找到棋盘格模板,可使用OpenCV中的函数cv2.findChessboardCorners()。需要告诉程序标明模板是何规格,在这里我们使用的是13x11的棋盘格,含有12x10的内部角点。这个函数如果检测到模板,会返回对应的角点,并返回true。当然不一定所有的图像都能找到需要的模板,所以我们可以使用多幅图像进行定标。

2、找到角点后,我们可以使用cv2.cornerSubPix()可以得到更为准确的角点像素坐标。我们也可以使用cv2.drawChessboardCorners()将角点绘制到图像上显示。

3、通过前面的步骤,得到了用于标定的三维点和与其对应的图像上的二维点对。我们使用cv2.calibrateCamera()进行标定,这个函数会返回标定结果、相机的内参数矩阵、畸变系数、旋转矩阵和平移向量。

4、通过反投影误差,我们可以来评估结果的好坏。越接近0,说明结果越理想。通过之前计算的内参数矩阵、畸变系数、旋转矩阵和平移向量,使用cv2.projectPoints()计算三维点到二维图像的投影,然后计算反投影得到的点与图像上检测到的点的误差,最后计算一个对于所有标定图像的平均误差,这个值就是反投影误差。

5、使用cv2.undistort()方法去除畸变

相关函数的参数解释在这里不再详细说明。

来看代码:

 
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((6 * 4, 3), np.float32)
objp[:, :2] = np.mgrid[0:6, 0:4].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y
 
obj_points = []  # 存储3D点
img_points = []  # 存储2D点
 
images = glob.glob("D:/Python/ComputerView/test1/*.jpg")
for fname in images:
    img = cv2.imread(fname)
    cv2.imshow('img',img)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
    size = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, (6, 4), None)
    print(ret)
 
    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, (8, 6), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
        cv2.imshow('img', img)
        cv2.waitKey(10)
 
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)
dst = cv2.undistort(img,mtx,dist,None,newcameramtx)
x,y,w,h = roi
dst1 = dst[y:y+h,x:x+w]
cv2.imwrite('D:/Python/ComputerView/test1/calibresult3.jpg', dst1)
print ("dst的大小为:", dst1.shape)

结果:

角点检测结果:

image.png

内参数矩阵:

image.png

畸变系数dist

image.png

旋转向量:

image.png

平移向量:

image.png

畸变后内参矩阵:

image.png

最终畸变矫正后的图片:

image.png

 

 

 

 

 

 

 

 

 

 

 


对计算机视觉感兴趣?这个社区推荐给你~

>>点击了解OpenVINO生态开发社区



工程师
2020-08-14 23:30:01     打赏
2楼

学到了


工程师
2020-08-19 16:55:44     打赏
3楼

学习一下


工程师
2020-09-03 08:34:14     打赏
4楼

666


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]