FAST-LIVO2相机内参标定

NMV 相机标定工具

海康威视工业相机(MVS SDK)驱动及内参标定完整流程。

环境要求

  • Linux aarch64(推荐 ARM 架构)
  • Python 3.x
  • OpenCV (pip install opencv-python)
  • 海康 MVS SDK(arm64 版)

目录

  1. [MVS SDK 安装](#MVS SDK 安装)
  2. 相机驱动
  3. 拍摄采集
  4. 标定板生成
  5. 多角度拍摄
  6. 内参标定
  7. 标定结果

1. MVS SDK 安装

下载 ARM 版本 SDK:

https://www.hikrobotics.com/cn/machinevision/service/download/?module=0

使用 .deb 包安装。

安装完成后,SDK 路径为 /opt/MVS/

2. 相机驱动

CAM.py 是海康相机的 Python 驱动封装,接口与 cv2.VideoCapture 一致。

核心功能

方法 说明
read() 等价于 cv2.VideoCapture.read(),返回 (ret, frame),frame 为 BGR 格式 numpy 数组
start() 开始采集
release() 释放相机资源
set(prop, value) 设置参数(曝光、增益、帧率等)
set_exposure(us) 设置曝光时间(微秒),自动关闭自动曝光
set_gain(gain) 设置增益(dB),自动关闭自动增益
set_auto_exposure(enable) 开启/关闭自动曝光
get_exposure() 获取当前曝光时间
get_gain() 获取当前增益

cv2.VideoCapture 属性映射

OpenCV 属性 相机参数 说明
CAP_PROP_FRAME_WIDTH (3) Width 图像宽度
CAP_PROP_FRAME_HEIGHT (4) Height 图像高度
CAP_PROP_EXPOSURE (9) ExposureTime 曝光时间(微秒)
CAP_PROP_GAIN (11) Gain 增益(dB)
CAP_PROP_FPS (15) FrameRate 帧率

使用示例

python 复制代码
from CAM import HikCamera
import cv2

capture = HikCamera(index=0)

# 手动设置曝光(微秒)
capture.set_exposure(50000)  # 50ms 曝光
# capture.set_gain(10.0)     # 10dB 增益

print(f"Exposure: {capture.get_exposure()} us")
print(f"Gain: {capture.get_gain()} dB")

while True:
    ret, frame = capture.read()
    if ret and frame is not None:
        cv2.imshow("HikCamera", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

capture.release()
cv2.destroyAllWindows()

3. 拍摄采集

test.py 用于实时预览并保存标定图像。按 s 保存当前帧,按 q 退出。

python 复制代码
from CAM import HikCamera
import cv2
from datetime import datetime

capture = HikCamera(index=0)

# 设置曝光和增益
capture.set_exposure(30000)  # 30ms 曝光
capture.set_gain(20.0)       # 20dB 增益

while True:
    ret, frame = capture.read()
    if ret:
        cv2.imshow("Camera", frame)

    key = cv2.waitKey(1) & 0xFF
    if key == ord('s'):
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"photo_{timestamp}.jpg"
        cv2.imwrite(filename, frame)
        print(f"已保存: {filename}")
    elif key == ord('q'):
        break

capture.release()
cv2.destroyAllWindows()

4. 标定板生成

生成指定尺寸的棋盘格标定板,保存为 chessboard.png

参数说明

参数 默认值 说明
pattern_size (9, 6) 内角点数量(列, 行)
square_size 30 mm 每个格子的物理尺寸
image_size (330, 270) 输出图像尺寸(宽, 高)

代码

python 复制代码
import cv2
import numpy as np

pattern_size = (9, 6)      # 内角点数量(列, 行)
square_size = 30           # 每个格子的物理尺寸(毫米)
image_size = (330, 270)    # 图像尺寸(宽, 高)

board_w = (pattern_size[0] + 1) * square_size
board_h = (pattern_size[1] + 1) * square_size

offset_x = (image_size[0] - board_w) // 2
offset_y = (image_size[1] - board_h) // 2

board = np.full((image_size[1], image_size[0]), 255, dtype=np.uint8)

for row in range(pattern_size[1] + 1):
    for col in range(pattern_size[0] + 1):
        if (row + col) % 2 == 0:
            x1 = offset_x + col * square_size
            y1 = offset_y + row * square_size
            x2 = offset_x + (col + 1) * square_size
            y2 = offset_y + (row + 1) * square_size
            cv2.rectangle(board, (x1, y1), (x2, y2), 0, -1)

cv2.imwrite("chessboard.png", board)
print(f"标定板尺寸: {board_w}x{board_h}px, 居中于 {image_size[0]}x{image_size[1]}px 图像中")
print(f"物理尺寸: {pattern_size[0]+1}x{pattern_size[1]+1} 格子, 每格 {square_size}mm")

5. 多角度拍摄

使用第 3 步的拍摄代码,对打印出的棋盘格标定板拍摄 20~30 张不同角度和距离的照片,建议:

  • 包含棋盘格位于画面各区域的照片
  • 包含不同倾斜角度(俯仰、偏航、翻滚)的照片
  • 覆盖画面中心和边缘
  • 棋盘格占画面 30%~70% 为宜

建议保存路径:/home/a1/FAST-LIVO-/NMV/Desktop/

6. 内参标定

运行标定代码,从 Desktop/ 目录读取图像,计算相机内参和畸变系数。

python 复制代码
import cv2
import numpy as np
import glob

# 标定板参数(必须与 creat.py 保持一致)
pattern_size = (9, 6)        # 内角点(列, 行)
square_size = 30             # 每格物理尺寸(毫米)

# 准备世界坐标系中的点
objp = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)
objp *= square_size

objpoints = []  # 3d 点
imgpoints = []  # 2d 点

criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

images = glob.glob(r'/home/a1/FAST-LIVO-/NMV/Desktop/*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    ret, corners = cv2.findChessboardCorners(gray, pattern_size, None)

    if ret:
        objpoints.append(objp.copy())
        corners2 = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
        imgpoints.append(corners2)

if len(objpoints) == 0:
    print("错误: 未找到有效的标定图像")
else:
    ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
        objpoints, imgpoints,
        (gray.shape[1], gray.shape[0]),
        None, None
    )

    mean_error = 0
    for i in range(len(objpoints)):
        imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
        mean_error += cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints[i])
    mean_error /= len(objpoints)

    print(f"内参矩阵 mtx:\n{mtx}")
    print(f"畸变系数 dist:\n{dist}")
    print(f"重投影误差: {mean_error:.4f} 像素")
    print(f"共 {len(objpoints)} 张图像标定成功")

    np.savez('calib_result.npz', mtx=mtx, dist=dist, rvecs=rvecs, tvecs=tvecs)
    print("标定结果已保存到 calib_result.npz")

7. 标定结果

典型标定输出示例:

复制代码
内参矩阵 mtx:
[[1.30604136e+03 0.00000000e+00 6.47029232e+02]
 [0.00000000e+00 1.30584980e+03 4.84674313e+02]
 [0.00000000e+00 0.00000000e+00 1.00000000e+00]]
畸变系数 dist:
[[-2.84377903e-01  2.83396706e+00 -1.15991120e-04  2.67718470e-03
  -1.09059273e+01]]
重投影误差: 0.0597 像素
共 29 张图像标定成功
标定结果已保存到 calib_result.npz

参数解读

  • 内参矩阵 mtx :相机固有参数,(fx, fy) 为焦距,(cx, cy) 为主点坐标
  • 畸变系数 dist :径向畸变 k1, k2, k3 和切向畸变 p1, p2
  • 重投影误差 :越小越好,一般 < 1 像素 可接受

文件结构

复制代码
NMV/
├── CAM.py              # 海康相机驱动
├── test.py             # 采集拍摄脚本
├── creat.py            # 棋盘格生成脚本
├── calibrate.py        # 标定脚本
├── calib_result.npz    # 标定结果(输出)
└── Desktop/            # 标定图像存放目录
    └── *.jpg

感谢王同学的倾情制作

相关推荐
进阶的猪2 小时前
Linux 学习笔记
linux·笔记·学习
ljh5746491192 小时前
linux du 命令
linux·运维
sz66cm2 小时前
Linux基础 -- systemd 用户服务残留条目清除
linux·服务器
❀͜͡傀儡师2 小时前
macOS/Linux Gemini CLI安装指南
linux·运维·macos
liulilittle2 小时前
LINUX RING BUFFER TUN/TAP 2
linux·运维·服务器·开发语言·网络·c++
Chase_______2 小时前
【2026最新保姆级】VMware 安装与虚拟机创建指南 (Window版)
linux
疯狂吧小飞牛2 小时前
修改crashkernel为0
linux·服务器
我在人间贩卖青春4 小时前
SysTick 定时器
单片机·嵌入式硬件·滴答定时器·systick
llilian_164 小时前
IRIG-B码产生器立足用户痛点,提供精准授时解决方案
大数据·数据库·功能测试·单片机·嵌入式硬件·测试工具