相机投影及相机畸变

转载自:三维空间刚体运动 - 古月居

现实中的物体如何与照片中的像素关联起来,需要涉及到相机成像的物理过程和坐标系转换。

相机成像

针孔相机模型

针孔相机模型是目前大部分相机的成像模型,其成像原理为小孔成像。

按照光线再同一介质中按直线传播的原理,在小孔另一面会形成一个按比例缩小的倒立实相。

如果不借助其他介质,成像过程将遵循:小孔越小,成像越好,光线越暗的规则。

如果想要解决照片既清晰、光线又足够亮的问题,一般会采用透镜来聚集光线,在保证有较大进光面的同时,让光线也能汇聚到较小范围。

关于透镜,有两个概念:聚焦失焦

聚焦:从物体不同部分射出的光线,通过镜头之后,聚焦在底片的一个点上,使影像具有清晰的轮廓与真实的质感,这个过程称为聚焦。

失焦:即接收的点的信息未聚焦到一起会导致成像模糊。

注意:物体“聚焦”有特定距离(景深),在景深内可清晰成像,景深外成像模糊。

加入透镜之后,成像规律会有一点变化,此时当物体离透镜不同距离时,会形成不同的像。当物体处于凸透镜的 2 倍焦距之外,会形成倒立的、缩小的实像。一倍焦距到二倍焦距之间,则会形成倒立的、放大的实像。成像物体则在一倍焦距内,成正立的、放大的虚像

一般地,相机成像时,物体在透镜的二倍焦距之外。而对于投影仪,则会把成像物体放在一倍焦距到二倍焦距之间。对于放大镜,成像物体则在一倍焦距内。

最后,将成像处实像,用感光元件接收后,就形成了拍摄的照片。在比较早的年代,感光元件使用胶片,胶片的原理是通过光产生化学反应来记录。而到了数码时代,感光元件则使用了CCD或者CMOS,其原理是将光转化为模拟电信号来记录。

电子感光元件也叫图像传感器(sensor),分为两种:一种是广泛使用的 CCD(电荷耦合)元件,另一种是 CMOS(互补金属氧化物半导体)器件。其产生的模拟信号,首先经过模拟信号放大器进行信号放大,进而经过数模转换电路(DAC)变为数字图像,数字图像再经过 ISP(Image Signal Processor)图像处理器进行数字图像处理,最后数字图像经过压缩编码算法,存储到 SD 卡中成为一个照片文件。

  1. CCD

CCD 全称 Charge Coupled Device,它使用一种高感光度的半导体材料制成,由许多感光单位组成,通常以百万像素为单位。当 CCD 表面受到光线照射时,每个感光单位会将电荷反映在组件上,即把光转换为电荷,所有的感光单位所产生的信号加在一起,就构成了一幅完整的画面。

  1. CMOS

CMOS 全称 Complementary Metal-Oxide Semiconductor,它主要是利用硅和锗这两种元素所做成的半导体,使其在 CMOS 上共存着 N 极和 P 极的半导体,这两个互补效应所产生的电流即可被处理芯片记录为影像。

两者最主要的区别在于:CCD 传感器的图像质量优于 CMOS 传感器,而 CMOS 传感器在成像速度、功耗、价格等方面优于 CCD 传感器。

成像坐标系

要把相机拍摄的照片与实际物体关联起来,就要建立三维世界到二维图像平面的映射关系,这个过程主要通过几个坐标系之间的转换来实现

相机成像的坐标系主要有四个,分别是世界坐标系,相机坐标系,图像坐标系与像素坐标系。世界坐标系下物体的光线(世界坐标系),通过透镜(相机坐标系),投射到感光原件上(图像坐标系),最后计算机在像素坐标系(离散化过程)上做处理。

世界坐标系:用于表示空间物体的绝对坐标,使用(Xw,Yw,Zw)表示,世界坐标系可通过旋转和平移得到相机坐标系。

相机坐标系:以相机的光心为坐标系原点,Xc.Yc轴平行于图像坐标系的x,y轴,相机的光轴为Zc轴,坐标系满足右手法则,相机的光心可理解为相机透镜的几何中心。

图像物理坐标系:坐标原点在CCD图像平面的中心x,y轴分别平行于图像像素坐标系的(u,v)轴,坐标用(x,y)表示。

图像像素坐标系:表示三维空间物体在图像平面上的投影,像素是离散化的,其坐标原点在CCD图像平面的左上角,u轴平行于CCD平面水平向右,v轴垂直于u轴向下,坐标使用(u,v)来表示。图像宽度W,高度H。

内参矩阵

内参矩阵的作用为将相机坐标系的下三维的坐标点转换为图像上的二维像素坐标,具体推导请参考:https://blog.csdn.net/qq_43742590/article/details/104109103?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170944317516800215032187%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=170944317516800215032187&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~baidu_landing_v2~default-5-104109103-null-null.142^v99^pc_search_result_base3&utm_term=%E5%86%85%E5%8F%82%E7%9F%A9%E9%98%B5&spm=1018.2226.3001.4187

图像畸变

如果相机成像过程没有畸变,则一个正方形投影成像后,还是一个正方形,但实际情况往往不是这样。大家拍照中可能也会发现,在拍一个人时,可能会把一个脸不大的人,脸拍出来却比较大,这时候不一定是你拍照技术的问题,有可能是因为相机畸变。相机成像过程的图像畸变主要是镜片加工与安装的缺陷造成的。

相机畸变主要由于相机镜头的光学性质造成的。相机镜头中的光线经过折射、反射等多个光学过程,导致不同位置的物体在图像中呈现出不同的形变。这种形变被称为畸变。畸变可以分为两种:径向畸变和切向畸变。

径向畸变

向畸变来自透镜形状不规则以及建模的方式,导致镜头不同部分焦距不同。光线在远离透镜中心的地方偏折更大(向外偏移远离中心为枕型畸变,左图)或更小(向中心靠拢为桶形畸变,右图)。

下图显示矩形网格因径向畸变而产生的位移。越远离光轴中心的地方,矩形网格上的点偏移越大。

对于径向畸变,常用如下公式进行修正

xcorrected =x(1+k1r2+k2r4+k3r6)

ycorrected =y(1+k1r2+k2r4+k3r6)。

其中: r2=x2+y2

k1,k2,k3称为径向畸变校正系数。

切向畸变

切向畸变来自于整个摄像机的组装过程。由于透镜制造上的缺陷使得透镜本身与图像平面不平行而产生的,如下图所示。

切向图像畸变使用如下公式进行修正

xcorrected =x+[2p1xy+p2(r2+2x2)]

ycorrected=y+[p1(r2+2y2)+2p2xy]

其中:r2=x2+y2

其中 p1,p2为切向畸变系数。

经过畸变消除后即可完成图像校正

相机内参标定简介

到目前为止,相机成像有两大转换过程,相机投影及畸变消除,主要由内参矩阵以及畸变参数,这两种参数来决定。而求出这两类参数的过程,就是相机标定,目前相机常用的方法是借助棋盘格标定板,在相机前面拿着标定板上下左右前后移动,然后借助标定算法来求出以上参数,常用的标定算法有张正友标定法。

相机内参标定工具

OpenCV

OpenCV是一款广泛使用的计算机视觉库,其中包含相机内参标定的相关函数。在OpenCV中,使用calibrateCamera函数进行相机内参标定,该函数使用棋盘格等标定板,通过对标定板拍摄的多幅图像进行处理,得出相机的内参参数。OpenCV还提供了相关的可视化工具,如drawChessboardCorners函数,用于显示标定板的角点,以及projectPoints函数,用于将3D点投影到2D图像平面上。

  1. 循环读取图片

  2. 使用findChessboardCorners函数检测角点(需提前输入角点数)

  3. 使用find4QuadCornerSubpix函数对角点进行亚像素精确化

  4. 可用drawChessboardCorners将角点显示

  5. 根据角点数和尺寸创建一个理想的棋盘格(用point向量存储所有理论上的角点坐标)

  6. 通过calibrateCamera函数由理想坐标和实际图像坐标进行标定,可得到标定结果

  7. 由projectPoints函数计算反向投影误差

MATLAB

MATLAB也提供了相机内参标定的工具箱,包括Camera Calibration Toolbox和Image Processing Toolbox等。Camera Calibration Toolbox使用标定板对相机进行标定,并提供了可视化工具,如ShowExtrinsics函数,用于显示相机的外参参数。Image Processing Toolbox提供了更加高级的算法,如多目相机标定,以支持更加复杂的应用场景。

简单过程如下:

  1. 应用程序中找到Camera Calibration

  2. 添加标定板拍摄图片(按Ctrl可一次添加多张)

  3. 输入棋盘格每格的尺寸大小

  4. 显示已检测出的棋盘格,点击Calibration,开始标定。

  5. 得到标定结果(平均误差小于0.5即可认为结果可靠)

  6. 可查看标定结果和程序

ROS

ROS(Robot Operating System)是一种常用的机器人操作系统,其中包含相机内参标定的相关包,如camera_calibration。该包通过对标定板拍摄的多幅图像进行处理,计算出相机的内参参数,并自动保存标定结果。此外,ROS还提供了一系列可视化工具,如image_view,用于显示相机的图像和标定结果。

参考链接

https://blog.csdn.net/TimeRiverForever/article/details/117283430

https://blog.51cto.com/u_15242250/2870251

  • 27
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 下面是一个计算重投影坐标的 Python 代码示例: ```python import cv2 import numpy as np # 定义相机内参 fx = 500 fy = 500 cx = 300 cy = 300 # 定义三维点的坐标 point_3d = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]]) # 定义三维点的姿态(旋转矩阵和平移向量) rvec = np.array([[0, 0, 0]]) tvec = np.array([[0, 0, 0]]) # 计算重投影坐标 point_2d, _ = cv2.projectPoints(point_3d, rvec, tvec, cameraMatrix=np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]]), distCoeffs=np.zeros((4, 1))) # 输出重投影坐标 print(point_2d) ``` 注意:上述代码中的参数均为示例,实际应用中需要根据实际情况修改。 ### 回答2: 以下是一个用Python编写的计算重投影坐标的示例代码: ```python import numpy as np # 相机内参 fx = 800 # x轴方向的焦距 fy = 800 # y轴方向的焦距 cx = 320 # 图像中心点的x坐标 cy = 240 # 图像中心点的y坐标 def calc_reprojection(pt_3d): # 转换为齐次坐标 pt_3d_homo = np.array([pt_3d[0], pt_3d[1], pt_3d[2], 1]) # 投影矩阵 projection_mat = np.array([[fx, 0, cx, 0], [0, fy, cy, 0], [0, 0, 1, 0]]) # 计算重投影坐标 pt_2d_homo = np.dot(projection_mat, pt_3d_homo) # 归一化坐标 pt_2d_norm = pt_2d_homo[:2] / pt_2d_homo[2] return pt_2d_norm # 3D点坐标 pt_3d = np.array([1, 2, 3]) # 计算重投影坐标 pt_2d_norm = calc_reprojection(pt_3d) print("重投影坐标为:", pt_2d_norm) ``` 在这个示例代码中,我们通过定义相机内参(焦距和图像中心坐标)和给定的三维点坐标,计算其在图像上的重投影坐标。其中`calc_reprojection`函数实现了计算重投影坐标的过程,最后通过调用这个函数输出结果。 ### 回答3: 相机内参(Intrinsic parameters)是指相机固有的参数,包括焦距、光心等,这些参数能够帮助我们了解相机的成像原理。利用相机内参进行重投影是将三维空间中的点投影到二维图像中,计算其在图像上的坐标。 在Python中,可以使用OpenCV库来进行相机内参的计算和重投影坐标的计算。下面是一个简单的代码示例: ```python import cv2 import numpy as np # 定义相机内参 focal_length = 800 # 焦距 principal_point = (320, 240) # 光心 # 定义三维空间点的坐标 point_3d = np.array([0, 0, 1]) # 定义相机的旋转矩阵和平移向量 rotation_vector = np.array([0, 0, 0]) # 旋转向量 translation_vector = np.array([0, 0, 0]) # 平移向量 # 计算相机投影矩阵 camera_matrix = np.array([[focal_length, 0, principal_point[0]], [0, focal_length, principal_point[1]], [0, 0, 1]]) # 使用Rodrigues函数将旋转向量转换为旋转矩阵 rotation_matrix, _ = cv2.Rodrigues(rotation_vector) # 计算三维点在相机坐标系下的坐标 point_3d_camera = np.dot(rotation_matrix, point_3d) + translation_vector # 使用相机内参和三维点在相机坐标系下的坐标,计算投影点在图像上的坐标 reprojection = np.dot(camera_matrix, point_3d_camera) reprojection = reprojection / reprojection[2] # 归一化 # 输出投影点在图像上的坐标 reprojection_point = (reprojection[0], reprojection[1]) print("Reprojection point: ", reprojection_point) ``` 在上述示例代码中,我们首先定义了相机内参,包括焦距和光心,以及一个三维空间点的坐标。然后通过Rodrigues函数将旋转向量转换为旋转矩阵,再计算三维点在相机坐标系下的坐标。最后使用相机投影矩阵,将三维点投影到图像上,并将其归一化得到投影点坐标。最终通过打印可以得到重投影点的坐标信息。 请注意,上述示例中的旋转向量和平移向量都设为了零,实际应用中需要根据实际情况进行调整。此外,上述代码只计算了一个点的重投影坐标,实际应用中需要计算多个点的重投影坐标时,可以将上述代码放入循环中进行计算。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值