摄像头畸变矫正

简单介绍

所谓畸变其实就是由摄像头引起的图片失真 , 一般在广角摄像头表现明显, 原本平整的桌面通过镜头看像个球面, 直观的解释直线被拍成了曲线, 这让我想起来了一个表情包.

去畸变的办法

首先我们需要一个标准棋盘(印有特定的标定图案), 如图:

把它摊平放在桌子上, 然后用需要去畸变的相机 对它进行拍摄, 拍几张(10~20张差不多)不同角度的棋盘图片, 保存好. 然后我们有两种方法进行畸变矫正.

1. 借助matlab的Camera Calibration Toolbox工具

我们打开matlab,

应用程序这里.

找到 Camera Calibration, 然后点击打开.

然后点击Add Images添加图片,

这里会弹出此弹框, 意思是选择我们棋盘格子的大小, 根据实际情况选择就行.

添加后会显示角点, 如果有不清楚的或者识别错误,红色边框, 可以删掉换一张图片就行.

导入多张图片后, 直接点击Calibrate 开始标定

完成后大致如上图, 会显示各个参数

  • 重投影误差(Reprojection Error):理想情况下应 < 0.5 像素.
  • 相机内参:
    1. 焦距(Focal Length)

    2. 主点(Principal Point)

    3. 畸变系数(Radial, Tangential)

      新版有这两项

  • 可视化:
  1. Show Undistorted Images 查看校正效果。
  2. Plot Reprojection Errors 分析误差分布。
    我2016版本并没有这个框

确认无误后可以点击 Export Camera Parameters 导出数据, 则会导出到workspace当中生成mat 文件

当然也可以点击第二个生成matlab代码进行后续操作

2. 使用OpenCV进行标定

OpenCV是计算机视觉库, 可以用来进行图像处理, 里面有很多函数, 我们可以借助它来进行畸变矫正.

首先我们将拍摄的照片全部保存到一个文件夹中然后, 然后我们需要手动指定实际拍摄图片中有多少个棋盘角点 .

比如说这张图片, 是 9 X 5 的棋盘

对于所有的图片, 我们都需要进行同样的操作, 然后保存到列表中.类似于

python 复制代码
# 每张图片的棋盘格参数, 9 X 6 格大小
    objp_dict = {
        1: (9, 5),
        2: (9, 6),
        3: (9, 6),
        4: (9, 6),
        5: (9, 6),
        6: (9, 6),
        7: (9, 6),
        8: (9, 6),
        9: (9, 6),
        10: (9, 6),
        11: (9, 6),
        12: (9, 6),
        13: (9, 6),
        14: (9, 6),
        15: (9, 6),
        16: (9, 6),
        17: (9, 6),
        18: (9, 6),
        19: (9, 6),
        20: (9, 6),
    }

根据指定的大小获取三维(np.zeros((nx*ny, 3), np.float32)) 理论坐标

python 复制代码
    objp_list = []		 # 存储对象点
    corners_list = []	 # 存储角点

        # 遍历objp_dict的每个参数
    for k in objp_dict:
        nx, ny = objp_dict[k]	# 取出长宽

        # (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
        objp = np.zeros((nx*ny, 3), np.float32)	              # 生成三维坐标,即每个点理论坐标应该是多少
        objp[:, : 2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)  # 生成x和y的坐标,z坐标都是0

读取图片通过 cv2.cvtColor(灰度化) 和 cv2.findChessboardCorners(棋盘角点) 寻找真实的情况

python 复制代码
# 对于识别的点应该的坐标序号初始化好后, 开始来读取图片中每个点的真实位置
        fname = 'camera_cal/calibration%s.jpg' % str(k)
        img = cv2.imread(fname)	# 读取一张图片

        # 转成灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 检测角点
        ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)

将返回值保存到列表中

python 复制代码
        if ret == True:	 # 成功检测到了
            # Save object points and corresponding corners
            objp_list.append(objp)	#
            corners_list.append(corners)

将列表带入 cv2.calibrateCamera 中即可得到参数 内参矩阵(mtx)和畸变系数(dist)

python 复制代码
    img = cv2.imread('test_images/straight_lines1.jpg')		# 这里得保证所有图像的大小一致
    img_size = (img.shape[1], img.shape[0])		# 获取测试图片的尺寸

    #  获取相关参数
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objp_list, corners_list, img_size,None,None)

最后使用 cv2.undistort 将图片进行去畸变即可

python 复制代码
# 去畸变
    img = mpimg.imread('camera_cal/calibration5.jpg')	 #  读取图像
    dst = cv2.undistort(img, mtx, dist, None, mtx)

下面来康康完整代码:

python 复制代码
import numpy as np
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import pickle

def calibrate_camera():
    # Mapping each calibration image to number of checkerboard corners
    # Everything is (9,6) for now
    # 每张图片的棋盘格参数, 9 X 6 格大小
    objp_dict = {
        1: (9, 5),
        2: (9, 6),
        3: (9, 6),
        4: (9, 6),
        5: (9, 6),
        6: (9, 6),
        7: (9, 6),
        8: (9, 6),
        9: (9, 6),
        10: (9, 6),
        11: (9, 6),
        12: (9, 6),
        13: (9, 6),
        14: (9, 6),
        15: (9, 6),
        16: (9, 6),
        17: (9, 6),
        18: (9, 6),
        19: (9, 6),
        20: (9, 6),
    }

    # List of object points and corners for calibration
    objp_list = []		 # 存储对象点
    corners_list = []	 # 存储角点

    # Go through all images and find corners
    # 遍历objp_dict的每个参数
    for k in objp_dict:
        nx, ny = objp_dict[k]	# 取出长宽

        # Prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
        objp = np.zeros((nx*ny, 3), np.float32)	              # 生成三维坐标,即每个点理论坐标应该是多少
        objp[:, : 2] = np.mgrid[0:nx, 0:ny].T.reshape(-1, 2)  # 生成x和y的坐标,z坐标都是0

        # 对于识别的点应该的坐标序号初始化好后, 开始来读取图片中每个点的真实位置
        # Make a list of calibration images
        fname = 'camera_cal/calibration%s.jpg' % str(k)
        img = cv2.imread(fname)	# 读取一张图片

        # Convert to grayscale	转成灰度图
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # Find the chessboard corners
        # 检测角点
        ret, corners = cv2.findChessboardCorners(gray, (nx, ny), None)

        # If found, save & draw corners
        if ret == True:	 # 成功检测到了
            # Save object points and corresponding corners
            objp_list.append(objp)	#
            corners_list.append(corners)

            # Draw and display the corners
            #cv2.drawChessboardCorners(img, (nx, ny), corners, ret)
            #plt.imshow(img)
            #plt.show()
            #print('Found corners for %s' % fname)
        else:	# 否则没有检测到
            print('Warning: ret = %s for %s' % (ret, fname))

    # Calibrate camera and undistort a test image
    img = cv2.imread('test_images/straight_lines1.jpg')		# 这里得保证所有图像的大小一致
    img_size = (img.shape[1], img.shape[0])		# 获取测试图片的尺寸

    #  获取相关参数
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objp_list, corners_list, img_size,None,None)

    return mtx, dist


if __name__ == '__main__':
    mtx, dist = calibrate_camera()
    save_dict = {'mtx': mtx, 'dist': dist}		# 得到数据
    #  将mtx和dist通过pickle保存至calibrate_camera.p中
    #  pickle库将此序列转化成二进制字节流存入.p文件中, wb:w--写入, b--以二进制形式
    with open('calibrate_camera.p', 'wb') as f:
        pickle.dump(save_dict, f)

    # Undistort example calibration image
    # 去畸变
    img = mpimg.imread('camera_cal/calibration5.jpg')	 #  读取图像
    dst = cv2.undistort(img, mtx, dist, None, mtx)
    plt.imshow(dst)	# 显示矫正结果
    plt.savefig('example_images/undistort_calibration.png')		# 然后保存图片

参考资料:

代码来自github的开源项目
Lane Detection with OpenCV

十年前的牢项目了, 还是很有参考意义的
上海交通大学AuTop战队开源算法讲解(三)标定与透视变换
摄像头校准之白平衡&畸变&坏点

相关推荐
Zevalin爱灰灰37 分钟前
编程技巧(基于STM32)第一章 定时器实现非阻塞式程序——按键控制LED灯闪烁模式
stm32·单片机·嵌入式硬件
鸡鸭扣1 小时前
Docker:3、在VSCode上安装并运行python程序或JavaScript程序
运维·vscode·python·docker·容器·js
paterWang2 小时前
基于 Python 和 OpenCV 的酒店客房入侵检测系统设计与实现
开发语言·python·opencv
东方佑2 小时前
使用Python和OpenCV实现图像像素压缩与解压
开发语言·python·opencv
神秘_博士2 小时前
自制AirTag,支持安卓/鸿蒙/PC/Home Assistant,无需拥有iPhone
arm开发·python·物联网·flutter·docker·gitee
Moutai码农4 小时前
机器学习-生命周期
人工智能·python·机器学习·数据挖掘
苏慕TRYACE4 小时前
RT-Thread+STM32L475VET6实现红外遥控实验
stm32·单片机·嵌入式硬件·rt-thread
小白教程4 小时前
python学习笔记,python处理 Excel、Word、PPT 以及邮件自动化办公
python·python学习·python安装
武陵悭臾5 小时前
网络爬虫学习:借助DeepSeek完善爬虫软件,实现模拟鼠标右键点击,将链接另存为本地文件
python·selenium·网络爬虫·pyautogui·deepseek·鼠标右键模拟·保存链接为htm
代码猪猪傻瓜coding5 小时前
关于 形状信息提取的说明
人工智能·python·深度学习