【opencv】相机标定矫正相关函数记录

1. cv2.calibrateCamera

作用:

通过要标定相机拍摄的不同方位的棋盘图,获取相机的内参矩阵,畸变系数,以及每幅图的相应旋转,平移矩阵

函数定义:

def calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs=None, tvecs=None, flags=None, criteria=None)

参数说明:

>objectPoints:棋盘格角点在棋盘格坐标系的三维坐标
>imagePoints:棋盘格对应的角点
>imageSize:拍摄的图像分辨率(w,h)

返回值:

>retval:标志位(是否成功找到对应参数)
> cameraMatrix:内参矩阵
> distCoeffs:畸变参数
> rvecs
> tvecs

ps:

内参矩阵:

A = [ f x 0 c x 0 f y c y 0 0 1 ] A = \begin{bmatrix} f_x&0&c_x\\ 0&f_y&c_y\\ 0&0&1\\ \end{bmatrix} A=fx000fy0cxcy1

畸变系数:

( k 1 , k 2 , p 1 , p 2 [ , k 3 [ , k 4 , k 5 , k 6 [ , s 1 , s 2 , s 3 , s 4 [ , τ x , τ y ] ] ] ] ) (k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]]) (k1,k2,p1,p2[,k3[,k4,k5,k6[,s1,s2,s3,s4[,τx,τy]]]]),其按照需求可以有4,5,8,12,14个元素


2. cv2.getOptimalNewCameraMatrix

作用:

当使用cv2.calibrateCamera获得相机内参矩阵后,若直接进行去畸变操作,产生的图片会带有部分黑色的无效值,可通过调用本函数来优化相机内参矩阵,去除黑边。

在这里插入图片描述
函数定义:

def getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, alpha, newImgSize=None, centerPrincipalPoint=None)

参数说明:

>cameraMatrix:优化前的内参矩阵
>distCoeffs:畸变系数
>imageSize:原先图像尺寸
>alpha:值位于[0,1]之间的缩放因子,如果alpha=0,去畸变后的图像中的所有像素都是有效的(不会产生黑色无效像素),
		但原有图片中的部分像素也会被丢弃。如果alpha=1,则未去畸变图片中的所有像素均被保留至去畸变后的图像中,
		但也会产生相应黑色无效像素
>newImgSize:矫正后的图像尺寸
>centerPrincipalPoint:可选标志,表示在新的相机内参矩阵中,主点(the principal point光轴与相面的交点)是否应该位于图像中心。默认情况下,主点被设置为最佳拟合原图片子集的位置,以使其更好修正图片

返回值:

新的内参矩阵,validPixROI(outlines all-good-pixels region in the undistorted image.)
其中新的内参矩阵代表不对图像进行ROI截取对应的相机内参。(截取后,图像分辨率发生变化,相机内参再次变化)


3. cv2.initUndistortRectifyMap

作用:

获得从畸变图像到去畸变图像的像素映射函数

函数定义

def initUndistortRectifyMap(cameraMatrix, distCoeffs, R, newCameraMatrix, size, m1type, map1=None, map2=None)

4. cv2.remap

作用:

借助映射函数将畸变图像映射回去畸变图像


5.cv2.undistort

该函数实际上是cv2.initUndistortRectifyMap(其中R=单位矩阵)和cv2.remap(使用双线性插值)的结合体。

作用:

将畸变图像通过相机内参矩阵和畸变系数矩阵转换为无畸变图像

函数定义:

def undistort(src, cameraMatrix, distCoeffs, dst=None, newCameraMatrix=None): 

参数说明:

>src:输入的原始畸变图像
>cameraMatrix:通过cv2.calibrateCamera获得的相机内参A
>distCoeffs:畸变系数
>dst: 畸变矫正后的图像,其格式与尺寸和输入图像一致(默认设置为None>newCameraMatrix:默认情况下等于cameraMatrix,但当你相对输出图像进行缩放平移时,可输入该图像

返回值:

代表矫正后无畸变的图像矩阵,其格式与尺寸和输入图像一致。若在函数调用时应用newCameraMatrix,则还要对返
回图像进行相应的截取等操作以得到最终的图像。


6.综合代码

# encoding: utf-8
# by HoveXb
# 2021-06-12
####
import cv2
import numpy as np
import glob
import argparse


def calib(opt):
    # 导入配置信息
    width, height, square_size = opt.width, opt.height, opt.square_size
    imgs_source = opt.imgs_source
    images_format = opt.image_format
    imgs_source = imgs_source + f'*.{images_format}'
    drawChessboardCorners = opt.drawChessboardCorners

    # 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
    criteria = (cv2.TERM_CRITERIA_MAX_ITER | cv2.TERM_CRITERIA_EPS, 30, 0.001)

    # 获取标定板角点的位置
    objp = np.zeros((width * height, 3), np.float32)
    # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y
    objp[:, :2] = (np.mgrid[0:height, 0:width] * square_size).T.reshape(-1, 2)

    obj_points = []  # 存储3D点
    img_points = []  # 存储2D点

    images = glob.glob(imgs_source)

    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, (height, width), None)

        if ret:

            obj_points.append(objp)

            corners2 = cv2.cornerSubPix(gray, corners, (5, 5), (-1, -1), criteria)  # 在原角点的基础上寻找亚像素角点
            if [corners2]:
                img_points.append(corners2)
            else:
                img_points.append(corners)
            # 是否画出角点并保存
            if drawChessboardCorners:
                cv2.drawChessboardCorners(img, (height, width), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
                i += 1
                cv2.imwrite('conimg' + str(i) + f'.{images_format}', img)
                cv2.waitKey(150)
        else:
            print("can't find cornet!")

    print("there are total ", len(img_points), "images.\n")
    cv2.destroyAllWindows()

    # 标定
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, size, None, None)

    print("mtx:\n", mtx)  # 内参数矩阵
    print("dist:\n", dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)

    # 保存数据
    mtx_save = np.array(mtx)
    dist_save = np.array(dist)
    np.save("mtx_LK15.npy", mtx_save)
    np.save("dist_LK15.npy", dist_save)

    # undistort_img = opt.undistort
    # if undistort_img:
    img = cv2.imread(images[0])
    h0, w0 = img.shape[:2]

    # If the scaling parameter alpha=0, it returns undistorted image with minimum unwanted pixels.
    # So it may even remove some pixels at image corners.
    # If alpha=1, all pixels are retained with some extra black images.
    # This function also returns an image ROI which can be used to crop the result.
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w0, h0), 1, (w0, h0))  # 图片中的像素都是有效信息

    print("------------------使用undistort函数(newcameramtx)-------------------")
    dst = cv2.undistort(img, mtx, dist, None, newcameramtx)

    x, y, w, h = roi
    dst1 = dst[y:y + h, x:x + w]
    cv2.imwrite('calibresult1' + f'.{images_format}', dst1)
    print("Using cv.undistort_img(),dst的大小为:", dst1.shape)

    print("------------------使用remapping-------------------")
    mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w0, h0), 5)
    print('111111:',mapx.shape)
    dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
    # crop the image
    dst2 = dst[y:y + h, x:x + w]
    print("Using remapping", dst2.shape)
    cv2.imwrite('calibresult2' + f'.{images_format}', dst2)


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--imgs-source', type=str, default='./123/', help='imgs source')
    parser.add_argument('--image-format', type=str, default='jpg', help='imgs source')
    parser.add_argument('--width', type=int, default=8, help='how many inner squares there are in the chessboard')
    parser.add_argument('--height', type=int, default=6, help='how many inner squares there are in the chessboard')
    parser.add_argument('--square-size', type=int, default=1, help='square size of chess board(mm)')
    parser.add_argument('--drawChessboardCorners', action='store_true', help='drawChessboardCorners or not')
    parser.add_argument('--undistort', action='store_true', help='undistort')
    opt = parser.parse_args()
    calib(opt)

源码分析见:
https://blog.csdn.net/chengde6896383/article/details/88583653
https://zhuanlan.zhihu.com/p/66863619

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值