OpenCV-图像去畸变方法
OpenCV 图像去畸变方法详解
在计算机视觉应用中,相机镜头通常会引入各种类型的畸变,主要包括径向畸变和切向畸变。OpenCV 提供了多种方法来校正这些畸变,本文将详细介绍基于相机内参和畸变系数的图像去畸变方法。
1. 畸变模型
在进行去畸变之前,需要了解相机的畸变模型。OpenCV 使用以下参数来描述畸变:
- 径向畸变系数:k1, k2, k3, k4, k5, k6
- 切向畸变系数:p1, p2
畸变系数通常表示为一个向量:[k1, k2, p1, p2, k3, k4, k5, k6]
2. 关键函数详解
2.1 cv2.getOptimalNewCameraMatrix()
此函数用于计算去畸变后的最优相机内参矩阵和感兴趣区域(ROI)。
函数签名
newCameraMatrix, validPixROI = cv2.getOptimalNewCameraMatrix(
cameraMatrix,
distCoeffs,
imageSize,
alpha,
newImgSize=None,
centerPrincipalPoint=None
)
参数说明
| 参数 | 类型 | 描述 |
|---|---|---|
| cameraMatrix | numpy.ndarray | 3x3 的原始相机内参矩阵 |
| distCoeffs | numpy.ndarray | 畸变系数向量 (1x4, 1x5, 1x8, 1x12, or 1x14) |
| imageSize | tuple | 图像尺寸 (width, height) |
| alpha | float | 自由缩放参数,范围 [0, 1] |
| newImgSize | tuple | 去畸变图像的尺寸 (width, height),默认与原图相同 |
| centerPrincipalPoint | bool | 是否将主点居中,默认为 False |
返回值
- newCameraMatrix: 3x3 的新相机内参矩阵
- validPixROI: 有效像素区域 (x, y, width, height)
alpha 参数说明
- alpha = 0: 裁剪掉所有无效区域,图像中不会出现黑边
- alpha = 1: 保留所有原始像素,可能会有黑边
- 0 < alpha < 1: 介于两者之间的折中方案
2.2 cv2.initUndistortRectifyMap()
此函数用于计算去畸变和矫正映射,生成用于 remap 函数的映射矩阵。
函数签名
map1, map2 = cv2.initUndistortRectifyMap(
cameraMatrix,
distCoeffs,
R,
newCameraMatrix,
size,
m1type
)
参数说明
| 参数 | 类型 | 描述 |
|---|---|---|
| cameraMatrix | numpy.ndarray | 3x3 的原始相机内参矩阵 |
| distCoeffs | numpy.ndarray | 畸变系数向量 |
| R | numpy.ndarray | 3x3 的矫正旋转矩阵(通常为 None 或单位矩阵) |
| newCameraMatrix | numpy.ndarray | 3x3 的新相机内参矩阵(通常由 getOptimalNewCameraMatrix 生成) |
| size | tuple | 校正图像的尺寸 (width, height) |
| m1type | int | 映射数据类型(cv2.CV_32FC1 或 cv2.CV_16SC2) |
返回值
- map1: x 坐标的映射矩阵
- map2: y 坐标的映射矩阵(当 m1type 为 CV_16SC2 时,map2 为 None)
m1type 参数说明
- cv2.CV_32FC1: 生成两个 32 位浮点型映射矩阵(map1 和 map2)
- cv2.CV_16SC2: 生成一个双通道的 16 位有符号整数映射矩阵(只有 map1)
2.3 cv2.remap()
此函数根据映射矩阵对图像进行重采样,实现去畸变效果。
函数签名
dst = cv2.remap(
src,
map1,
map2,
interpolation,
borderMode=None,
borderValue=None
)
参数说明
| 参数 | 类型 | 描述 |
|---|---|---|
| src | numpy.ndarray | 输入图像 |
| map1 | numpy.ndarray | x 坐标的映射矩阵 |
| map2 | numpy.ndarray | y 坐标的映射矩阵 |
| interpolation | int | 插值方法 |
| borderMode | int | 边界像素外推方法,默认为 cv2.BORDER_REFLECT_101 |
| borderValue | tuple | 用于 cv2.BORDER_CONSTANT 的边界值 |
插值方法
- cv2.INTER_NEAREST: 最近邻插值
- cv2.INTER_LINEAR: 双线性插值(推荐)
- cv2.INTER_CUBIC: 三次样条插值
- cv2.INTER_LANCZOS4: Lanczos 插值
边界模式
- cv2.BORDER_CONSTANT: 填充固定值
- cv2.BORDER_REPLICATE: 复制边界像素
- cv2.BORDER_REFLECT: 镜像反射边界
- cv2.BORDER_REFLECT_101: 镜像反射边界(不包括边界像素)
3. 完整实现示例
import cv2
import numpy as np
def undistort_image(input_image, camera_matrix, dist_coeffs):
"""
基于相机内参和畸变系数进行图像去畸变
返回:去畸变图像 + ROI区域 + 新内参
参数说明:
input_image:原始畸变图像(BGR格式)
camera_matrix:相机内参矩阵 (3x3)
[[fx, 0, cx],
[0, fy, cy],
[0, 0, 1]]
dist_coeffs:畸变系数向量 (k1, k2, p1, p2[, k3[, k4, k5, k6]])
"""
h, w = input_image.shape[:2]
image_size = (w, h)
# 1. 计算新内参和ROI (平衡图像区域和有效内容)
# alpha=1: 保留所有原始像素(可能有黑边)
# alpha=0: 裁剪掉所有无效区域
alpha = 0
new_cam_matrix, roi = cv2.getOptimalNewCameraMatrix(
cameraMatrix=camera_matrix,
distCoeffs=dist_coeffs,
imageSize=image_size,
alpha=alpha,
newImgSize=image_size
)
# 2. 计算去畸变映射 (x映射和y映射)
mapx, mapy = cv2.initUndistortRectifyMap(
cameraMatrix=camera_matrix,
distCoeffs=dist_coeffs,
R=None, # 无旋转
newCameraMatrix=new_cam_matrix,
size=image_size,
m1type=cv2.CV_32FC1 # 32位浮点型映射
)
# 3. 应用映射执行去畸变
undistorted = cv2.remap(
src=input_image,
map1=mapx,
map2=mapy,
interpolation=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT
)
# 提取ROI坐标 (可选的裁剪区域)
x, y, w_roi, h_roi = roi
if w_roi != 0 and h_roi != 0:
# 裁剪掉黑边
undistorted = undistorted[y:y+h_roi, x:x+w_roi]
return undistorted, new_cam_matrix, roi
# ======= 使用示例 =======
if __name__ == "__main__":
# 示例参数(需替换为实际标定结果)
camera_matrix = np.array([
[800, 0, 320],
[0, 800, 240],
[0, 0, 1]
])
# k1, k2, p1, p2, k3 格式
dist_coeffs = np.array([-0.35, 0.15, 0.001, -0.003, 0.0])
# 读取原始畸变图像
distorted_img = cv2.imread("distorted_image.jpg")
# 执行去畸变
result, new_matrix, roi = undistort_image(
input_image=distorted_img,
camera_matrix=camera_matrix,
dist_coeffs=dist_coeffs
)
# 打印关键信息
print("原始内参:\n", camera_matrix)
print("新内参:\n", new_matrix)
print("ROI区域 (x, y, w, h):", roi)
# 保存结果
cv2.imwrite("undistorted_result.jpg", result)
# 显示对比 (左:原图 | 右:去畸变结果)
cv2.imshow("Comparison", np.hstack((distorted_img, result)))
cv2.waitKey(0)
cv2.destroyAllWindows()
4. 性能优化建议
4.1 映射重用优化
对于视频流处理,推荐预计算映射矩阵并在每帧中重用:
# 初始化阶段
mapx, mapy = cv2.initUndistortRectifyMap(
cameraMatrix,
distCoeffs,
None,
newCameraMatrix,
imageSize,
cv2.CV_32FC1
)
# 视频处理循环
while True:
frame = capture.read()
undistorted_frame = cv2.remap(
frame,
mapx,
mapy,
interpolation=cv2.INTER_LINEAR
)
# 处理去畸变后的帧
4.2 简化方法
对于简单场景,可以使用 cv2.undistort() 函数一步完成去畸变:
undistorted = cv2.undistort(
src=distorted_image,
cameraMatrix=camera_matrix,
distCoeffs=dist_coeffs,
newCameraMatrix=new_camera_matrix
)
但这种方法灵活性较低,无法获得映射矩阵用于后续处理。
5. 注意事项
- 参数获取:实际应用中,相机内参和畸变系数需要通过相机标定获得
- 畸变系数:OpenCV 支持 4-8 个畸变参数
- 精度选择:使用 CV_32FC1 类型可以获得更高精度的映射结果,但代价是存储和计算资源消耗
- 裁剪优化:通过
alpha参数可以在保留黑色背景的情况下裁剪掉无效内容 - 视频优化:对于视频处理,推荐预计算映射并在每帧中重复使用

浙公网安备 33010602011771号