feat(camera): 添加相机标定与运动估计功能

- 新增 camera_calibration.py 文件,实现相机标定功能
- 新增 motion_estimation.py 文件,实现运动估计功能- 编写实验报告,总结相机标定与运动估计的原理和实验结果
This commit is contained in:
fly6516 2025-05-23 11:43:17 +08:00
commit 39d6065521
6 changed files with 154 additions and 0 deletions

56
camera_calibration.py Normal file
View File

@ -0,0 +1,56 @@
import cv2
import numpy as np
import glob
# 棋盘格尺寸:内角点数量(宽度,高度)
chessboard_size = (9, 6)
# 创建棋盘格世界坐标系下的三维点阵
# 生成形如(0,0,0), (1,0,0)...(8,5,0)的三维坐标
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
# 存储对象点和图像点的列表
objpoints = [] # 世界坐标系中的3D点
imgpoints = [] # 图像坐标系中的2D点
# 加载所有棋盘格图像路径
images = glob.glob('images/*.jpg')
for fname in images:
img = cv2.imread(fname)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 寻找棋盘格角点
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
if ret:
objpoints.append(objp)
imgpoints.append(corners)
# 绘制并显示检测到的角点
cv2.drawChessboardCorners(img, chessboard_size, corners, ret)
cv2.imshow('Corners', img)
cv2.waitKey(0) # 修改此处:改为等待用户按键关闭窗口
# 销毁所有OpenCV创建的窗口
cv2.destroyAllWindows()
if len(objpoints) > 0:
# 执行相机标定,获取相机矩阵、畸变系数等参数
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
# 输出相机矩阵和畸变系数
print("相机矩阵:\n", mtx)
print("畸变系数:\n", dist)
# 计算重投影误差
mean_error = 0
for i in range(len(objpoints)):
imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
mean_error += error
print("平均重投影误差: ", mean_error / len(objpoints))
else:
print("未找到有效的棋盘格图像。")

BIN
images/calib_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
images/left.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
images/right.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

55
motion_estimation.py Normal file
View File

@ -0,0 +1,55 @@
import cv2
import numpy as np
# 读取左右视角图像(灰度模式)
img1 = cv2.imread('images/left.jpg', 0)
img2 = cv2.imread('images/right.jpg', 0)
# 初始化SIFT特征检测器
sift = cv2.SIFT_create() # 创建SIFT对象
# 检测关键点并计算描述符
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# FLANN匹配器参数配置
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) # KD树算法参数
search_params = dict(checks=50) # 搜索参数:检查次数
# 创建FLANN匹配器实例
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2) # k近邻匹配
pts1 = []
pts2 = []
good_matches = [] # 初始化优质匹配列表
# 使用Lowe's比率测试筛选优质匹配
for i, (m, n) in enumerate(matches):
if m.distance < 0.7 * n.distance: # 修改此处:调整距离比阈值
good_matches.append(m)
pts2.append(kp2[m.trainIdx].pt) # 记录右图匹配点坐标
pts1.append(kp1[m.queryIdx].pt) # 记录左图匹配点坐标
if len(good_matches) > 8:
pts1 = np.int32(pts1)
pts2 = np.int32(pts2)
# 计算基础矩阵使用RANSAC算法
F, mask = cv2.findFundamentalMat(pts1, pts2, cv2.FM_RANSAC)
print("基础矩阵:\n", F)
# 通过基础矩阵恢复旋转和平移变换
_, R, t, _ = cv2.recoverPose(F, pts1, pts2)
print("旋转矩阵:\n", R)
print("平移向量:\n", t)
# 可视化优质匹配结果
img_match = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None,
flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('特征匹配', img_match)
cv2.waitKey(0)
cv2.destroyAllWindows()
else:
print("匹配点不足,无法计算基础矩阵。")

View File

@ -0,0 +1,43 @@
# 计算机视觉实验报告:相机标定与运动估计
## 一、 实验目的
1. 了解相机标定和运动估计的基本原理;
2. 了解相机标定和运动估计的应用;
3. 掌握相机标定和运动估计实现方法。
## 二、 基本思想
### 相机标定
相机标定旨在计算相机的内部参数焦距、主点坐标等和外部参数位置和方向以及校正镜头畸变。使用棋盘格图案作为标定物通过已知的3D-2D对应关系来求解相机矩阵和畸变系数。
### 运动估计
运动估计是通过分析连续图像帧之间的特征匹配,确定两个视图之间的相对旋转和平移变换。这通常涉及基础矩阵或本质矩阵的计算,从而恢复场景的三维结构和相机运动。
## 三、 源码
### 相机标定代码
```python
# 见camera_calibration.py文件
```
### 运动估计代码
```python
# 见motion_estimation.py文件
```
## 四、 算法分析
### 时间复杂度
- **相机标定**主要耗时在角点检测O(N)和线性优化迭代求解参数整体近似为O(N·T)其中N为像素数T为迭代次数。
- **运动估计**SIFT特征提取为O(M), 特征匹配为O(M²)RANSAC筛选为O(K)。总体时间复杂度约为O(M²+K)。
### 空间复杂度
- **相机标定**存储对象点和图像点的数组为O(P)P为角点数目。
- **运动估计**保存关键点和描述符的空间为O(Q), Q为特征数量。
## 五、 实验运行结果图
### 相机标定角点检测示例
![标定角点](results/calibration_corners.png)
### 运动估计特征匹配图
![特征匹配](results/feature_matching.jpg)
## 六、 实验总结
这里可以添加你的实验心得和遇到的问题及解决方案。