双目立体视觉标定
双目立体视觉标定
1. 两个摄像头录像
摄像头是通过电脑浏览器页面打开的,为了方便,我直接在电脑上开启了两个摄像头,并且使用左右分屏直接开始录像,效果如下:

(模糊了一下隐私信息,可以大致看出是左右两个摄像头,棋盘格图像分别在两个摄像头正中间)
2. 视频切割
使用python,分割为独立的左右摄像头视频
import cv2
def extract_video_roi(src_video_path, dst_video_path, roi_start, roi_end):
cap = cv2.VideoCapture(src_video_path)
if not cap.isOpened():
print(f"无法打开视频文件:{src_video_path}")
return
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(dst_video_path, fourcc, fps, (roi_end[0] - roi_start[0], roi_end[1] - roi_start[1]))
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
roi_frame = frame[roi_start[1]:roi_end[1], roi_start[0]:roi_end[0]]
out.write(roi_frame)
cap.release()
out.release()
# 示例用法
src_video_path = "test.mp4"
dst_video_path = "test3.mp4"
roi_start = (978, 178)
roi_end = (1684, 969)
extract_video_roi(src_video_path, dst_video_path, roi_start, roi_end)
src_video_path是原摄像头mp4地址
dst_video_path是切割后的视频存放地址
roi_start和roi_end是左上角和右下角像素位置
修改完以上三个数值,就可以进行切割,我将左右摄像头画面存为test2.mp4和test3.mp4
test2.mp4:

test3.mp4

3. 逐帧提取
每秒一帧,将视频转为图片
import cv2
import os
def extract_frames(video_path, result_folder):
# 创建结果文件夹
os.makedirs(result_folder, exist_ok=True)
# 打开视频文件
cap = cv2.VideoCapture(video_path)
frame_count = 0
saved_count = 0
# fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
frame_interval = int(cap.get(cv2.CAP_PROP_FPS)) # 设置帧采样间隔为1秒
while cap.isOpened():
# 读取视频帧
ret, frame = cap.read()
if not ret:
break
frame_count += 1
# 每秒保存一帧
if frame_count % frame_interval == 0:
saved_count += 1
# 保存帧到结果文件夹
# frame_path = os.path.join(result_folder, f"{saved_count}.jpg")
frame_path = os.path.join(result_folder, '%s.jpg' % saved_count)
print(frame_path)
cv2.imwrite(frame_path, frame)
# 释放视频文件
cap.release()
# 文件夹路径不能有中文!!!!!!
video_path, result_folder = 'test3.mp4', 'right'
extract_frames(video_path, result_folder)
video_path, result_folder分别是视频路径和图片存放文件夹。
根据刚刚的左右摄像头录像(test2.mp4,test3.mp4),我将图片存在left文件夹和right文件夹。
图片提取完毕效果如下(left文件夹):

right文件夹效果也差不多,就不展示了。
4. 转灰度图
如果直接用现在的图片到matlab中标定,会显示一个错误:串联的数组维度不一致

原因,是因为matlab双目标定工具箱有bug,不支持彩色图输入,只能输入灰度图。
于是将文件夹中的图片进行批量灰度化处理:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time :2023/10/1 22:41
# @Author :Ji Huiting
import cv2
import os
def to_gray(input_path, output_path):
images = os.listdir(input_path)
if not os.path.exists(output_path):
os.makedirs(output_path)
for image in images:
print(image)
input_image = os.path.join(input_path, image)
output_image = os.path.join(output_path, image)
image = cv2.imread(input_image, cv2.IMREAD_GRAYSCALE)
cv2.imwrite(output_image, image)
if __name__ == '__main__':
input_path = "right" # 要处理的图片所在的文件夹
output_path = "right2" # 处理完的图片放在这里
to_gray(input_path, output_path)
input_path是图片文件夹
output_path是图片转灰度图后要存放的文件夹
现在我将left和right文件夹分别转灰度图,存放到left2和right2文件夹中。
5. matlab双目标定
【matlab启动】->【导航栏APP】->【Stero Camera Cailbrator为双目标定工具箱】

左右摄像头地址选择为刚刚转完灰度图的left2和right2文件夹
第三个参数是棋盘格每个格子的边长,每个人参数不一,自定义。(注意,单位是毫米,不是厘米)
确定后得到结果:

可以看到参数:
左右摄像头每个是180张,148张可用,32张不可用。
点击确定后,出现窗口:

在棋盘格上绿色的圈圈就是棋盘格的黑白相交的角点,可以看到是很准确的,没有出现错误。
如果出现了,需要手动剔除。

工具栏中:
Radial Distortion Compute选择【3 Coefficients】和【Tangential Distortion】,然后点击Calibrate进行校准。(时间比较长不用担心,去玩会再回来)
最后,工具栏中点击导出参数【Export Camera Parameters】就行了。可以顺便点击【save session】保存变量。
导出参数后,可以看到:
右边变量取出现了【stereoParams】变量:

这就是需要的相机参数。为了避免手工获取数据时出错,下面转载一个参数导出代码,将【stereoParams】变量转为excel:
rowName = cell(1,10);
rowName{1,1} = '平移矩阵';
rowName{1,2} = '旋转矩阵';
rowName{1,3} = '相机1内参矩阵';
rowName{1,4} = '相机1径向畸变';
rowName{1,5} = '相机1切向畸变';
rowName{1,6} = '相机2内参矩阵';
rowName{1,7} = '相机2径向畸变';
rowName{1,8} = '相机2切向畸变';
rowName{1,9} = '相机1畸变向量';
rowName{1,10} = '相机2畸变向量';
xlswrite('out.xlsx',rowName(1,1),1,'A1');
xlswrite('out.xlsx',rowName(1,2),1,'A2');
xlswrite('out.xlsx',rowName(1,3),1,'A5');
xlswrite('out.xlsx',rowName(1,4),1,'A8');
xlswrite('out.xlsx',rowName(1,5),1,'A9');
xlswrite('out.xlsx',rowName(1,6),1,'A10');
xlswrite('out.xlsx',rowName(1,7),1,'A13');
xlswrite('out.xlsx',rowName(1,8),1,'A14');
xlswrite('out.xlsx',rowName(1,9),1,'A15');
xlswrite('out.xlsx',rowName(1,10),1,'A16');
xlswrite('out.xlsx',stereoParams.TranslationOfCamera2,1,'B1'); % 平移矩阵
xlswrite('out.xlsx',stereoParams.RotationOfCamera2.',1,'B2'); % 旋转矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters1.IntrinsicMatrix.',1,'B5'); % 相机1内参矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters1.RadialDistortion,1,'B8'); % 相机1径向畸变(1,2,5)
xlswrite('out.xlsx',stereoParams.CameraParameters1.TangentialDistortion,1,'B9'); % 相机1切向畸变(3,4)
xlswrite('out.xlsx',stereoParams.CameraParameters2.IntrinsicMatrix.',1,'B10'); % 相机2内参矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters2.RadialDistortion,1,'B13'); % 相机2径向畸变(1,2,5)
xlswrite('out.xlsx',stereoParams.CameraParameters2.TangentialDistortion,1,'B14'); % 相机2切向畸变(3,4)
xlswrite('out.xlsx',[stereoParams.CameraParameters1.RadialDistortion(1:2), stereoParams.CameraParameters1.TangentialDistortion,...
stereoParams.CameraParameters1.RadialDistortion(3)],1,'B15'); % 相机1畸变向量
xlswrite('out.xlsx',[stereoParams.CameraParameters2.RadialDistortion(1:2), stereoParams.CameraParameters2.TangentialDistortion,...
stereoParams.CameraParameters2.RadialDistortion(3)],1,'B16'); % 相机2畸变向量
效果图:

亲测有效,在选择的目录下生成了out.xlsx文件,所见即所得。
可以顺便把【stereoParams】右键另存为文件,备份一下。
最后
标定已经完成,可以整理一下所有的数据。
└── matlab过程数据/
├── calibrationSession.mat
├── stereoParams.mat
├── 一些截图………………
└── 图片/
└── left/
├── 1.jpg
├── ……………………
└── left2/
├── 1.jpg
├── ……………………
└── right/
├── 1.jpg
├── ……………………
└── right2/
├── 1.jpg
├── ……………………
├── 结果.xlsx
└── 视频/
├── test.mp4
├── 右.mp4
├── 左.mp4

浙公网安备 33010602011771号