照相机标定

news2025/1/23 4:43:08

一.相机标定的原理

1.1 相机如何成像:

相机成像系统中,共包含四个坐标系:世界坐标系、相机坐标系、图像坐标系、像素坐标系。

1.1.1 世界坐标系:
世界坐标系(world coordinate),也称为测量坐标系,是一个三维直角坐标系,以其为基准可以描述相机和待测物体的空间位置。世界坐标系的位置可以根据实际情况自由确定。

1.1.2 相机坐标系:
相机坐标系(camera coordinate),也是一个三维直角坐标系,原点位于镜头光心处,x、y轴分别与相面的两边平行,z轴为镜头光轴,与像平面垂直
1.1.3 像素坐标系、图像坐标系:

像素坐标系(pixel coordinate)
如上图,像素坐标系是一个二维直角坐标系,反映了相机CCD/CMOS芯片中像素的排列情况。原点位于图像的左上角,轴、轴分别于像面的两边平行。像素坐标系中坐标轴的单位是像素(整数)。

像素坐标系不利于坐标变换,因此需要建立图像坐标系,其坐标轴的单位通常为毫米(mm),原点是相机光轴与相面的交点(称为主点),即图像的中心点,轴、轴分别与轴、轴平行。故两个坐标系实际是平移关系,即可以通过平移就可得到。

1.2 相机标定的目的:
求出相机的内、外参数,以及畸变参数。

标定相机后通常是想做两件事:一个是由于每个镜头的畸变程度各不相同,通过相机标定可以校正这种镜头畸变矫正畸变,生成矫正后的图像;另一个是根据获得的图像重构三维场景。

1.2 相机标定的总体原理:
摄像机标定(Camera calibraTIon)简单来说就是从世界坐标系换到图像坐标系的过程,也就是求最终的投影矩阵的过程。

二.相机标定步骤

1)、准备一个张正友标定法的棋盘格,棋盘格大小已知,用相机对其进行不同角度的拍摄,得到一组图像;

2)、对图像中的特征点如标定板角点进行检测,得到标定板角点的像素坐标值,根据已知的棋盘格大小和世界坐标系原点,计算得到标定板角点的物理坐标值;

3)、求解内参矩阵与外参矩阵。

根据物理坐标值和像素坐标值的关系,求出 H 矩阵,进而构造 V 矩阵,求解 B 矩阵,利用B矩阵求解相机内参矩阵 A ,最后求解每张图片对应的相机外参矩阵 :

4)、求解畸变参数。

构造 D 矩阵,计算径向畸变参数;

5)、利用L-M(Levenberg-Marquardt)算法对上述参数进行优化

三、实现
3.1 数据准备

对标定板在不同角度拍照,得到10张图片。得到如下类似的图片。

3.2 代码(Python+OpenCV)

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((4 * 4, 3), np.float32)
objp[:, :2] = np.mgrid[0:4, 0:4].T.reshape(-1, 2)  # 将世界坐标系建在标定板上,所有点的Z坐标全部为0,所以只需要赋值x和y

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

images = glob.glob(r"D:\software\pycharm\PycharmProjects\computer-version\biaoding\images\*.jpg")
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, (4, 4), None)
    # print(corners)

    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, (4, 4), corners, ret)  # 记住,OpenCV的绘制函数一般无返回值
        i += 1
        cv2.imwrite('conimg' + str(i) + '.jpg', img)
        cv2.waitKey(1500)

print(len(img_points))
cv2.destroyAllWindows()

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

print("内参数矩阵:\n", mtx)  # 内参数矩阵
print("畸变系数:\n", dist)  # 畸变系数   distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("旋转向量:\n", rvecs)  # 旋转向量  # 外参数
print("平移向量:\n", tvecs)  # 平移向量  # 外参数

print("-----------------------------------------------------")

img = cv2.imread(images[2])
h, w = img.shape[:2]
# 获取新的相机矩阵和ROI
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
# 进行畸变校正
dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
# 裁剪校正后的图片,去掉黑边
x, y, w, h = roi
dst = dst[y:y + h, x:x + w]
# 保存校正后的图片
cv2.imwrite('undistorted.jpg', dst)
print("校正后的图片已保存到文件 'undistorted.jpg'")

结果如下:

D:\software\anaconda3\envs\homework\python.exe D:\software\pycharm\PycharmProjects\computer-version\biaoding\biaoding.py 
10
内参数矩阵:
 [[2.96560599e+04 0.00000000e+00 1.14649373e+03]
 [0.00000000e+00 2.27193976e+04 2.23086118e+03]
 [0.00000000e+00 0.00000000e+00 1.00000000e+00]]
畸变系数:
 [[-2.89172774e+00 -7.08266723e+02 -8.71069820e-02  9.23282091e-03
   2.69077473e+04]]
旋转向量:
 (array([[ 0.00393121],
       [-0.55572922],
       [ 0.00146949]]), array([[-0.24713914],
       [-0.62161368],
       [ 1.12164248]]), array([[0.03655035],
       [0.72426273],
       [0.58207192]]), array([[ 0.03267646],
       [-0.81493845],
       [ 0.33111165]]), array([[ 0.10136185],
       [-0.8188412 ],
       [ 0.0126507 ]]), array([[ 0.07815116],
       [-0.45667052],
       [ 0.04574239]]), array([[-0.06538785],
       [-0.45146705],
       [ 0.29559633]]), array([[0.19950015],
       [0.59439631],
       [1.05909245]]), array([[-0.61847323],
       [-0.65382223],
       [ 1.44780297]]), array([[-0.56075885],
       [-0.65910126],
       [ 1.21835979]]))
平移向量:
 (array([[-1.88349377],
       [-2.34826569],
       [79.07381781]]), array([[-3.71964945e-03],
       [-2.09696872e+00],
       [ 9.57830776e+01]]), array([[  2.82236969],
       [-10.16609008],
       [105.50710577]]), array([[  2.4498244 ],
       [ -9.91592803],
       [113.69245822]]), array([[  1.94032193],
       [ -9.41660327],
       [118.34213194]]), array([[  3.29323168],
       [-10.37799624],
       [150.0005035 ]]), array([[  1.90004234],
       [ -9.89181093],
       [136.81120801]]), array([[  3.81109485],
       [ -9.80118203],
       [131.55206487]]), array([[  0.12140321],
       [ -3.0523607 ],
       [114.3591686 ]]), array([[ 0.17173674],
       [-2.75540486],
       [80.26443015]]))
-----------------------------------------------------
校正后的图片已保存到文件 'undistorted.jpg'

Process finished with exit code 0

畸变矫正前的图像:

畸变矫正后的图像:

分析:

运行程序,成功的实现了自己手机参数的标定,计算出了照相机的内部参数和外部参数。通过此次实验让我进一步了解了张正友标定法的奇妙之处。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/568416.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试技巧:原来薪资可以这样谈~

从房地产到程序员是蓄谋已久,也是时机成熟 2020年毕业之后,我便开始从事房地产销售工作,卖了两年房子才来黑马学习。 其实毕业那年就想来黑马学习的,虽然大学专业学的工商管理,但是我对计算机专业更感兴趣。毕业时&a…

2个半月学习成功上岗软件测试,我一个文科女也能吃IT饭了

想不到我一个文科生也能吃上IT饭,真的是太香了!!! 程序员的待遇怎么这么好!(请大家原谅我没有见过市面的感叹,对于我这种刚上岗的新手而言,能够在厦门这个全国工资房价比最低的地方…

手机照片如何压缩?高效软件分享

现如今,手机已经成为了人们生活中不可或缺的一部分。我们用手机来拍摄照片,记录生活中的点滴,与朋友分享美好时刻。但是,随着手机像素越来越高,照片的体积也越来越大,使得手机储存空间不够用,而…

ApiKit 干货纯享|20分钟搞定接口管理、开发、测试全流程!

一. ApiKit 简介 ApiKit 是 API 管理 Mock 自动化测试 异常监控 团队协作 ApiKit 主要用于接口管理、开发、测试全流程集成工具,使用受众为整个研发技术团队,主要使用者为前端开发、后端开发和测试人员。从个人开发者到跨国企业用户,Api…

aop实现自定义注解

注解简单知识 关键字 自定义注解的关键字是interface 参数类型 自定义注解的参数类型:八大基础类型、String、枚举、注解,还可以是以上类型对应的数组 如果只有一个成员变量,名字叫value 注解赋值 如果定义了成员变量,必须…

ROS/ROS2工程中的路径管理

1 Launch文件访问yaml ROS2中,launch文件可以用python编写,且后缀名为.launch.py,由于python比传统的xml更加灵活,因此,可以在launch文件中找到某个package的yaml。yaml通常存在package下面的config目录下&#xff0c…

30 KVM管理系统资源-CPU热插

文章目录 30 KVM管理系统资源-CPU热插30.1 概述30.2 约束限制30.3 操作步骤30.3.1 配置虚拟机XML30.3.2 热插并上线CPU 30 KVM管理系统资源-CPU热插 30.1 概述 在线增加(热插)虚拟机CPU是指在虚拟机处于运行状态下,为虚拟机热插CPU而不影响…

企业级信息系统开发——初探Spring - 采用Java配置类管理Bean

文章目录 一、打开项目二、创建子包三、创建杀龙任务类四、创建勇敢骑士类五、创建Spring配置类六、创建测试类七、运行测试类八、总结Spring管理Bean的四种方式 一、打开项目 Maven项目 - SpringDemo 二、创建子包 在net.shuai.spring包里创建day04子包 三、创建杀龙任务…

open3d-gui 所有不同种类的部件

整体效果如上. 下面一步一步添加部件来实现. 目录 1. 菜单栏 2. 文件选择部件 3. 垂直可折叠部件 3.1 label部件 3.2 复选框checkbox 3.3 色板 3.4 下拉框combobox 3.5 拨动开关toggleSwitch 3.6 部件代理WidgetProxy 3.7 WidgetStack 3.8 列表 3.9 树形视图 3.…

AI时代的数据革命,分布式融合存储为何堪当大任?

有人说,以ChatGPT为代表的人工智能应用的兴起标志着AI时代奇点来临。 诚然如斯。这一波AIGC浪潮来袭,让人们真正意识到AI给生产力带来的巨大飞跃。从今年起,AI大模型成为行业用户重点关注的对象,甚至金融、媒体、广告营销等用户纷…

LangChain 实践之工具使用

参考:LangChain中文入门教程 LangChain官网 通过 Google 搜索并返回答案 import os os.environ["OPENAI_API_KEY"] "xxx" os.environ[SERPAPI_API_KEY] "xxx"from langchain.agents import load_tools from langchain.agents im…

华为OD机试真题 Java 实现【优秀学员统计】【2023Q1 100分】

一、题目描述 公司某部门软件教导团正在组织新员工每日打卡学习活动,他们开展这项学习活动已经一个月了,所以想统计下这个月优秀的打卡员工。每个员工会对应一个id,每天的打卡记录记录当天打卡员工的id集合,一共30天。 请你实现…

进入阿里外包一个月,我离职了

有一种打工人的羡慕,叫做“大厂”。 真是年少不知大厂香,错把青春插稻秧。 但是,在深圳有一群比大厂员工更庞大的群体,他们顶着大厂的“名”,做着大厂的工作,还可以享受大厂的伙食,却没有大厂…

设计模式详解之工厂模式

作者:刘文慧 本文将着眼于工厂模式,从简单工厂模式、工厂方法模式和抽象工厂模式出发,展开学习和深入探讨。 ​ 一、概述 我们在进行软件开发时要想实现可维护、可扩展,就需要尽量复用代码,并且降低代码的耦合度&…

SwiftUI 实现一个 iOS 上 Files App 兼容的文件资源管理器

功能需求 在 SwiftUI 中自己白手起家写一个 iOS(或iPadOS)上迷你的文件资源管理器是有些难度滴,不过从 iOS 11 (2017年) 官方引入自家的 Files App 之后,我们就可以借助它的魔力轻松完成这一个功能了。 …

防抖和节流 含义及区别图文详解秒懂

防抖和节流都是为解决短时间内频繁触发某个功能函数而导致的性能问题。比如,触发频率过高而导致响应速度跟不上,以致出现延迟,假死或卡顿的现象。 防抖 图解:一件事情,计划5s以后触发,结果中途意外触发了…

一款可以自动写代码的编辑器,解放你的双手

Cursor 是集成了 GPT-4 的 IDE 工具,目前免费并且无需 API Key,支持 Win、Mac、Linux 平台,可以按要求生成代码,或者让 AI 帮助优化代码,分析代码。Cursor目前已经集成了openai的GPT-4,它或将彻底改变我们写…

gdb调试 与 coredump

gdb调试 与 coredump调试 1. 启动gdb2.gdb中的相关命令3. coredump调试(附属于gdb调试中一种,当程序出现错误时,会使用coredump调试)1)coredump是什么?2)前期设置3)什么情况下会导致…

JavaEE进阶5/25

1.五大类注解详解(重点 1.Controller 控制器,用于业务逻辑层,来控制用户的行为。它用来检查用户参数的有效性。 当用户的参数有效的话会继续分发到服务层。controller可以理解为程序的安保系统 2.Service 服务层。归属服务层,调用…

MySQL---SQL优化上(explain分析执行计划、查看SQL的执行效率、定位低效率SQL)

1. 查看SQL的执行效率 MySQL 客户端连接成功后,通过 show [session|global] status 命令可以查看服务器状态信息。通 过查看状态信息可以查看对当前数据库的主要操作类型。 --下面的命令显示了当前 session 中所有统计参数的值 show session status like Com____…