0
点赞
收藏
分享

微信扫一扫

Opencv实验合集——实验八:相机校准

1.定义

首先,我们来理解一下怎么从相机的角度去看一张图片,就好比如你用眼睛作为相机来进行摄影,但是比摄影机强的是,你是怎么摄影图片之后再将它矫正出现在你眼前,将歪歪扭扭的图片变成一张在你眼前是一张直的图片

为了轻松理解问题,假设您在房间中部署了一个摄像头。

给定这个房间中的一个 3D 点 P,我们希望在相机拍摄的图像中找到这个 3D 点的像素坐标 (u, v),即你眼前对应的二位平面的坐标

现在我们一步步进行推理变换

 1.世界坐标系

2.相机坐标系

在射影几何中,使用齐次坐标来表示点,它在坐标上添加了一个额外的维度。
世界坐标在等式中使用齐次坐标,这允许在有限数内表示无限量,例如表示无穷远处的点 

3.图像坐标系

现在则需要将相机坐标系中的3D坐标投影成投影面的2D坐标

 

特殊情况:如果相机不是正方形的,则x方向和y方向的焦距不相等,

因此我们可能有两种不同的焦距 fx 和 fy 相机的光学中心 (Cx,Cy) 可能与图像坐标系的中心不重合

总结

将世界坐标系中的 3D 点投影到相机像素坐标分两步完成。

  1. 使用外部矩阵将 3D 点从世界坐标转换为相机坐标,该矩阵由两个坐标系之间的旋转和平移组成。
  2. 相机坐标系中的新 3D 点使用内在矩阵投影到图像平面上,该矩阵由内部相机参数(如焦距、光学中心等)组成。

 

2.相关的函数方法

3.代码演示

import numpy as np
import cv2 as cv
import glob

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3d 点 
imgpoints = [] # 在图像平面中的 2d 点

images = glob.glob('*.jpg')

for fname in images:
    img = cv.imread(fname)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # 找到棋盘上所有的角点
    ret, corners = cv.findChessboardCorners(gray, (7,6), None)

    # 如果找到了,便添加对象点和图像点(在细化后)
    if ret == True:
        objpoints.append(objp)

        corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners)

        # 绘制角点
        cv.drawChessboardCorners(img, (7,6), corners2, ret)
        cv.imshow('img', img)
        cv.waitKey(500)

cv.destroyAllWindows()

 

矫正

 

import numpy as np
import cv2 as cv
import glob

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点, 如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3d 点 
imgpoints = [] # 在图像平面中的 2d 点

images = glob.glob('*.jpg')

for fname in images:
    img = cv.imread(fname)
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # 找到棋盘上所有的角点
    ret, corners = cv.findChessboardCorners(gray, (7,6), None)

    # 如果找到了,便添加对象点和图像点(在细化后)
    if ret == True:
        objpoints.append(objp)

        corners2 = cv.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners)

        # 绘制角点
        cv.drawChessboardCorners(img, (7,6), corners2, ret)
        ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
        img2 = cv.imread(fname)
        h, w = img.shape[:2]
        newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
        # 矫正
        dst = cv.undistort(img2, mtx, dist, None, newcameramtx)

        # 裁切图像
        x, y, w, h = roi
        dst = dst[y:y + h, x:x + w]
        cv.imwrite('calibresult.png', dst)

cv.destroyAllWindows()

4.总结 

总结一下上面的叙述,首先是理解整个相机校准的原理,然后是通过代码进行进一步叙述,首先还是检测角点,如果是棋盘检测可以用上面的代码,也有很多其他检测角点的方法在上面简单提了一下,然后是通过角点位置,包括3d点(世界坐标系中的三维点)和2d点位置(图像检测出的角点坐标),接着利用calibrateCamera计算相机参数(旋转,平移等),最后通过计算出的相机参数来矫正图片,使得图片尽量在平面上是以平面的形式展示。注意:检测角点和计算相机参数都需要通过额外的方法来修正。

下面简单演示一下用Harris检测角点的效果

import numpy as np
import cv2 as cv

# 终止标准
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 准备对象点,如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# 用于存储所有图像对象点与图像点的矩阵
objpoints = [] # 在真实世界中的 3D 点
imgpoints = [] # 在图像平面中的 2D 点

# 图像路径
image_path = r'C:\Users\xiaoou\Desktop\picture\chess.jpg'

# 读取图像
img = cv.imread(image_path)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# 使用 cornerHarris 找到角点
dst = cv.cornerHarris(gray, 2, 3, 0.04)
print(dst.shape)
# 通过阈值筛选角点
img[dst > 0.01 * dst.max()] = [0, 0, 255]

# 寻找非零像素的坐标
y, x = np.nonzero(dst > 0.01 * dst.max())

# 将坐标转换为图像点格式
corners = np.vstack([x, y]).T.reshape(-1, 1, 2).astype(np.float32)

# 如果找到了,便添加对象点和图像点(在细化后)

if corners.shape[0] >= 42:
    # print(objp.shape)
    # print(corners.shape)
    objpoints.append(objp)
    imgpoints.append(corners[:42])

    # 绘制角点
    cv.drawChessboardCorners(img, (7, 6), corners, True)
    cv.imshow('img', img)
    cv.waitKey(0)

本次实验主要演示了三维重建中的相机校准,这对于要学自动驾驶或者三维重建的小伙伴都是要学的一门基础,主要函数方法怎么实现这里也不再一一介绍了。

如有错误或遗漏,希望小伙伴批评指正!!!! 

希望这篇博客对你有帮助!!!!

实验七:Opencv实验合集——实验七:二维码和条形码匹配-CSDN博客

举报

相关推荐

0 条评论