(1)摄像头参数
https://blog.csdn.net/crazty/article/details/107365147
(2)双目标定方法,过程参照了一下
双目三维重建系统(双目标定+立体校正+双目测距+点云显示)Python_AI吃大瓜的博客-CSDN博客_双目三维重建
(3)直接放源码的都是好人啊,下面的大佬代码参照了一下,大家仔细看看
python、opencv 双目视觉测距代码 - 灰信网(软件开发博客聚合)
(4)另一个大佬的文章
使用OpenCV/Python进行双目测距_程序员老华的博客-CSDN博客
(5)左右摄像头联合标定,下面的代码一定要看一下!!!
【ZED】从零开始使用ZED相机(五):Opencv+Python实现相机标定(双目)_摇曳的树的博客-CSDN博客_python 双目标定
(6)wls滤波的代码的作者地址
https://blog.csdn.net/weixin_40524689/article/details/124929419
采集分别率可达3840*1080,但是是拼接好的一幅图
(1)以下代码将采集的图片分为左右两个摄像头图像,各位1920*1080
#加载opencv模块
import cv2 as cv
import copy
#获取摄像头
cap = cv.VideoCapture(0)
# https://blog.csdn.net/crazty/article/details/107365147
# cap.set(cv.CV_CAP_PROP_FRAME_WIDTH, 3840)
# cap.set(cv.CV_CAP_PROP_FRAME_HEIGHT, 1080)
width = 3840
height = 1080
# widht_split = width//2 #注意不能用/这是浮点除法, 要用//,整除法
cap.set(3, width)
cap.set(4, height)
cv.namedWindow('camera', cv.WINDOW_NORMAL)
cv.namedWindow('camera_left', cv.WINDOW_NORMAL)
cv.namedWindow('camera_right', cv.WINDOW_NORMAL)
print("start cap")
left_img = None
right_img = None
while (cap.isOpened()):
ret, frame = cap.read() #捕获图片
if ret == False or frame is None:
print("can't get img")
break
frame = cv.flip(frame,1) #镜像操作
# print(frame.shape)
#注意不能用/这是浮点除法, 要用//,整除法
left_img = copy.deepcopy(frame[:,:width//2,:])
right_img = copy.deepcopy(frame[:,width//2:,:])
cv.imshow("camera", frame)
cv.imshow("camera_left", left_img)
cv.imshow("camera_right", right_img)
key = cv.waitKey(30)
if key == ord('q'): #如果是按键r,则退出
break
cap.release()
cv.destroyAllWindows()
(1)标定板的生成,参照我前面的教程
(7)点云数据处理学习——单摄像头深度估计_chencaw的博客-CSDN博客
(2)图像采集记录程序
#加载opencv模块
import cv2 as cv
import copy
#获取摄像头
cap = cv.VideoCapture(0)
# https://blog.csdn.net/crazty/article/details/107365147
# cap.set(cv.CV_CAP_PROP_FRAME_WIDTH, 3840)
# cap.set(cv.CV_CAP_PROP_FRAME_HEIGHT, 1080)
width = 3840
height = 1080
# widht_split = width//2 #注意不能用/这是浮点除法, 要用//,整除法
cap.set(3, width)
cap.set(4, height)
cv.namedWindow('camera', cv.WINDOW_NORMAL)
cv.namedWindow('camera_left', cv.WINDOW_NORMAL)
cv.namedWindow('camera_right', cv.WINDOW_NORMAL)
print("start cap")
left_img = None
right_img = None
record_file_basepath = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/'
imgcount = 1
while (cap.isOpened()):
ret, frame = cap.read() #捕获图片
if ret == False or frame is None:
print("can't get img")
break
frame = cv.flip(frame,1) #镜像操作
# print(frame.shape)
#注意不能用/这是浮点除法, 要用//,整除法
left_img = copy.deepcopy(frame[:,:width//2,:])
right_img = copy.deepcopy(frame[:,width//2:,:])
cv.imshow("camera", frame)
cv.imshow("camera_left", left_img)
cv.imshow("camera_right", right_img)
key = cv.waitKey(10)
if key == ord('q'): #如果是按键q,则退出
break
if key == ord('r'): #如果是按键r,则分别记录左右摄像头图片
# cv.imwrite('D:/RGBD_CAMERA/1chen_code/stereo_vision/leftimg/1.jpg',left_img)
cv.imwrite(record_file_basepath+"leftimg/"+str(imgcount)+".jpg",left_img)
cv.imwrite(record_file_basepath+"rightimg/"+str(imgcount)+".jpg",right_img)
imgcount = imgcount+1
cap.release()
cv.destroyAllWindows()
(1)简单封装了一下,代码如下,转载要备注啊!
import cv2
import numpy as np
import glob
#摄像头标定
def calculate_mono_camera_param(imgfile_path,checkerboard_w_num,
checkerboard_h_num,checkerboard_real_size,xmfile_name):
#(一) 第一步:找棋盘格角点
# 设置寻找亚像素角点的参数,采用的停止准则是最大循环次数30和最大误差容限0.001
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001) # 阈值
#棋盘格模板规格
# w = 8 # 9 - 1
# h = 5 # 6 - 1
w = checkerboard_w_num
h = checkerboard_h_num
# 世界坐标系中的棋盘格点,例如(0,0,0), (1,0,0), (2,0,0) ....,(8,5,0),去掉Z坐标,记为二维矩阵
objp = np.zeros((w*h,3), np.float32)
objp[:,:2] = np.mgrid[0:w,0:h].T.reshape(-1,2)
# objp = objp*18.1 # 18.1 mm
objp = objp * checkerboard_real_size # 30 mm #实际打印方格尺寸
# 储存棋盘格角点的世界坐标和图像坐标对
objpoints = [] # 在世界坐标系中的三维点
imgpoints = [] # 在图像平面的二维点
#加载pic文件夹下所有的jpg图像
images = glob.glob(imgfile_path + '*.jpg') # 拍摄的十几张棋盘图片所在目录
i=0
cv2.namedWindow('findCorners', cv2.WINDOW_NORMAL)
for fname in images:
img = cv2.imread(fname)
# 获取画面中心点
#获取图像的长宽
h1, w1 = img.shape[0], img.shape[1]
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
u, v = img.shape[:2]
# 找到棋盘格角点
ret, corners = cv2.findChessboardCorners(gray, (w,h),None)
# 如果找到足够点对,将其存储起来
if ret == True:
print("i:", i)
i = i+1
# 在原角点的基础上寻找亚像素角点
cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
#追加进入世界三维点和平面二维点中
objpoints.append(objp)
imgpoints.append(corners)
# 将角点在图像上显示
cv2.drawChessboardCorners(img, (w,h), corners, ret)
cv2.resizeWindow('findCorners', 640, 480)
cv2.imshow('findCorners',img)
cv2.waitKey(200)
# cv2.waitKey(2000)
cv2.destroyAllWindows()
#(二) 第二步:标定
print('正在计算......')
#标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
print('ret',ret) #ret也就是retval,表示的是重投影误差
print("mtx:\n",mtx) # 内参数矩阵
print("dist畸变值:\n",dist) # 畸变系数 distortion cofficients = (k_1,k_2,p_1,p_2,k_3)
print("rvecs旋转(向量)外参:\n",rvecs) # 旋转向量 # 外参数
print("tvecs平移(向量)外参:\n",tvecs ) # 平移向量 # 外参数
#(三) 第三步:保存摄像机参数
print('保存摄像头参数,重要!!')
cv_file = cv2.FileStorage(xmfile_name,cv2.FILE_STORAGE_WRITE)
cv_file.write('intrinsic_mtx',mtx)
print(type(mtx))
cv_file.write('intrinsic_dist',dist)
print(type(dist))
cv_file.release()
if __name__ == '__main__':
checkerboard_real_size = 30
#(1)左摄像头
imgfile_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/leftimg/'
xmfile_name = 'left_camera_param.xml'
calculate_mono_camera_param(imgfile_path, 8, 5, checkerboard_real_size,xmfile_name)
#(2)右摄像头
imgfile_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/rightimg/'
xmfile_name = 'right_camera_param.xml'
calculate_mono_camera_param(imgfile_path, 8, 5, checkerboard_real_size,xmfile_name)
(2)标定结果以xml形式保存下来

这次标定的参数如下
<?xml version="1.0"?>
<opencv_storage>
<intrinsic_mtx type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1.5096201160215364e+03 0. 8.9049227410684671e+02 0.
1.5015318633100094e+03 5.5143964705119470e+02 0. 0. 1.</data></intrinsic_mtx>
<intrinsic_dist type_id="opencv-matrix">
<rows>1</rows>
<cols>5</cols>
<dt>d</dt>
<data>
1.0748359938372364e-01 -1.0045565960216591e+00
4.4327918123757016e-03 -9.0274743236329804e-03
2.9483429325418737e+00</data></intrinsic_dist>
</opencv_storage>
(1)参照了大佬的代码
【ZED】从零开始使用ZED相机(五):Opencv+Python实现相机标定(双目)_摇曳的树的博客-CSDN博客_python 双目标定
(2)代码实现如下
import cv2
import numpy as np
import glob
class Stereo_calibrate(): # 执行校正
def __init__(self,checkerboard_w_num,checkerboard_h_num,checkerboard_real_size,xmfile_name):
# 终止条件
self.criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 准备对象点,棋盘方块交界点排列:6行9列
self.row = checkerboard_w_num #w 8
self.col = checkerboard_h_num #h 5
self.real_size = checkerboard_real_size # 30 mm
self.xmfile_name = xmfile_name #保存的xml参数文件名
self.objpoints = np.zeros((self.row * self.col, 3), np.float32)
self.objpoints[:, :2] = np.mgrid[0:self.row, 0:self.col].T.reshape(-1, 2)
self.objpoints = self.objpoints * checkerboard_real_size # 30 mm #实际打印方格尺寸
def exe(self,dir_l,dir_r):
objectpoints = [] # 真实世界中的3d点
imgpoints_l = []
imgpoints_r = []
# 标定所用图像
images_l = glob.glob('%s/*'%dir_l)
images_r = glob.glob('%s/*' % dir_r)
for i in range(len(images_l)):
img_l = cv2.imread(images_l[i])
gray_l = cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY)
img_r = cv2.imread(images_r[i])
gray_r = cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY)
# 寻找到棋盘角点
ret1, corners_l = cv2.findChessboardCorners(img_l, (self.row, self.col), None)
ret2, corners_r = cv2.findChessboardCorners(img_r, (self.row, self.col), None)
# 如果找到,添加对象点,图像点(细化之后)
if ret1 == True and ret2 == True:
# 添加每幅图的对应3D-2D坐标
objectpoints.append(self.objpoints)
corners_l = cv2.cornerSubPix(gray_l, corners_l, (11, 11), (-1, -1),self.criteria)
imgpoints_l.append(corners_l)
corners_r = cv2.cornerSubPix(gray_r, corners_r, (11, 11), (-1, -1), self.criteria)
imgpoints_r.append(corners_r)
# # 绘制并显示拐角
# cv2.drawChessboardCorners(img_l, (self.row, self.col), corners_l, ret)
# cv2.drawChessboardCorners(img_r, (self.row, self.col), corners_r, ret)
# view = np.concatenate((img_l, img_r), axis=1)
# cv2.namedWindow('View')
# cv2.imshow("View", cv2.resize(view,(1920,540)))
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# 利用单目校正函数实现相机内参初始化
ret, m1, d1, _, _ = cv2.calibrateCamera(objectpoints, imgpoints_l, gray_l.shape[::-1], None, None)
ret, m2, d2, _, _= cv2.calibrateCamera(objectpoints, imgpoints_l, gray_l.shape[::-1], None, None)
# config
flags = 0
# flags |= cv2.CALIB_FIX_ASPECT_RATIO
flags |= cv2.CALIB_USE_INTRINSIC_GUESS
# flags |= cv2.CALIB_SAME_FOCAL_LENGTH
# flags |= cv2.CALIB_ZERO_TANGENT_DIST
flags |= cv2.CALIB_RATIONAL_MODEL
# flags |= cv2.CALIB_FIX_K1
# flags |= cv2.CALIB_FIX_K2
# flags |= cv2.CALIB_FIX_K3
# flags |= cv2.CALIB_FIX_K4
# flags |= cv2.CALIB_FIX_K5
# flags |= cv2.CALIB_FIX_K6
stereocalib_criteria = (cv2.TERM_CRITERIA_COUNT +
cv2.TERM_CRITERIA_EPS, 100, 1e-5)
# 输入参数:真实3d坐标点,左相机像素点、右相机像素点、左内参、左畸变、右内参、右畸变、图像尺寸、一些配置
# 输出值:未知、左内参、左畸变、右内参、右畸变(迭代优化后的)、旋转矩阵、平移向量、本质矩阵、基础矩阵
ret, m1, d1,m2, d2, R, t, E, F = cv2.stereoCalibrate(objectpoints,imgpoints_l,imgpoints_r,
m1, d1,m2, d2, gray_l.shape[::-1],
criteria=stereocalib_criteria, flags=flags)
print(ret,'\n左相机矩阵:%s\n左相机畸变:%s\n右相机矩阵:%s\n右相机畸变:%s\n旋转矩阵:%s\n平移向量:%s'
'\n本质矩阵E:%s\n基础矩阵F:%s\n'
%(m1, d1, m2, d2, R, t, E, F))
#保存摄像机参数
print('保存摄像头参数,重要!!')
cv_file = cv2.FileStorage(self.xmfile_name,cv2.FILE_STORAGE_WRITE)
cv_file.write('left_m1',m1)
cv_file.write('left_d1',d1)
cv_file.write('right_m2',m2)
cv_file.write('right_d2',d2)
cv_file.write('stereo_r',R)
cv_file.write('stereo_t',t)
cv_file.release()
if __name__ == "__main__":
# (1) 初始化参数
xmlfile_name = 'stereo_param.xml'
cal = Stereo_calibrate(8,5,30,xmlfile_name)
#(2)立体视觉标定
left_img_file_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/leftimg/'
right_img_file_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/leftimg/'
cal.exe(left_img_file_path, right_img_file_path)
(3)标定结果如下

<?xml version="1.0"?>
<opencv_storage>
<left_m1 type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1.5096198348992518e+03 0. 8.9049227714927781e+02 0.
1.5015316270463043e+03 5.5143964513223204e+02 0. 0. 1.</data></left_m1>
<left_d1 type_id="opencv-matrix">
<rows>1</rows>
<cols>14</cols>
<dt>d</dt>
<data>
1.0750374792687890e-01 -1.0035692712049433e+00
4.4327603241579574e-03 -9.0274500455266634e-03
2.9573781021023886e+00 9.5808444418142185e-06 1.1258969063255248e-03
8.5100846188187560e-03 0. 0. 0. 0. 0. 0.</data></left_d1>
<right_m2 type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1.5096198378360564e+03 0. 8.9049227891398687e+02 0.
1.5015316300540694e+03 5.5143964504318376e+02 0. 0. 1.</data></right_m2>
<right_d2 type_id="opencv-matrix">
<rows>1</rows>
<cols>14</cols>
<dt>d</dt>
<data>
1.0750374675083163e-01 -1.0035692594357535e+00
4.4327601917556643e-03 -9.0274494471253627e-03
2.9573780872480153e+00 9.5820382961066939e-06 1.1258851317497449e-03
8.5100988514177738e-03 0. 0. 0. 0. 0. 0.</data></right_d2>
<stereo_r type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1. -4.7614064551882831e-11 -1.1988571142849994e-09
4.7614064551882831e-11 1. 2.1823626572323024e-10
1.1988571142849994e-09 -2.1823626572323024e-10 1.</data></stereo_r>
<stereo_t type_id="opencv-matrix">
<rows>3</rows>
<cols>1</cols>
<dt>d</dt>
<data>
1.0755947703661318e-08 -9.0097844983336702e-08
1.1366280383436105e-06</data></stereo_t>
</opencv_storage>
(4)结论:参数有问题,有空接着研究一下!!!!!
(0)标定过程和参数导出,主要参考
Matlab双目相机标定_indigo love的博客-CSDN博客_matlab双目相机标定
(1)
matlab2016,命令窗口中输入:
stereoCameraCalibrator
(2) 标定结果
#注意,陈备注:以下数据由matlab2016的工具箱stereoCameraCalibrator标注获得 left_camera_matrix = np.array([[ 1504.835951, 0, 903.7996248], [0, 1496.764636, 561.0768711], [0, 0, 1]]) left_distortion = np.array([[0.0570108746206312, -0.477832004663628, 0.00673968704282051, -0.00388206741248358,1.12821673355428]]) right_camera_matrix = np.array([[1508.16718253864, 0, 868.820482265892], [ 0, 1497.3685484015, 574.72759642089], [ 0, 0, 1]]) right_distortion = np.array([[0.0619253328320556, -1.3099240242802, 0.00734199071917032, -0.00389020681922442,7.50657175779989]]) R = np.matrix([ [0.999999429, -0.001009115, -0.000350325], [0.001007939, 0.999993912, 0], [0.000353694, 0.00334044, 0.999994358], ]) T = np.array([-49.53961963, -0.245581652, 2.526004856]) # 平移关系向量
(1)基础方法检测,测试代码
import cv2
import numpy as np
import copy
import glob
threeD = None
#函数一,获得立体视觉的参数
def get_stereo_param(xmlfie_path,size = (1920, 1080)):
#方法(一)陈备注:opencv双目标注的方法使用有误,有空接着研究
# cv_file = cv2.FileStorage()
# cv_file.open(xmlfie_path,cv2.FileStorage_READ)
# left_camera_matrix = cv_file.getNode('left_m1').mat()
# left_distortion = cv_file.getNode('left_d1').mat()
# right_camera_matrix = cv_file.getNode('right_m2').mat()
# right_distortion = cv_file.getNode('right_d2').mat()
# R = cv_file.getNode('stereo_r').mat()
# T = cv_file.getNode('stereo_t').mat()
# print("left_camera_matrix",left_camera_matrix)
#注意,陈备注:以下数据由matlab2016的工具箱stereoCameraCalibrator标注获得
left_camera_matrix = np.array([[ 1504.835951, 0, 903.7996248],
[0, 1496.764636, 561.0768711],
[0, 0, 1]])
left_distortion = np.array([[0.0570108746206312, -0.477832004663628, 0.00673968704282051, -0.00388206741248358,1.12821673355428]])
right_camera_matrix = np.array([[1508.16718253864, 0, 868.820482265892],
[ 0, 1497.3685484015, 574.72759642089],
[ 0, 0, 1]])
right_distortion = np.array([[0.0619253328320556, -1.3099240242802, 0.00734199071917032, -0.00389020681922442,7.50657175779989]])
R = np.matrix([
[0.999999429, -0.001009115, -0.000350325],
[0.001007939, 0.999993912, 0],
[0.000353694, 0.00334044, 0.999994358],
])
T = np.array([-49.53961963, -0.245581652, 2.526004856]) # 平移关系向量
# size = (640, 480) # 图像尺寸
# 进行立体更正
R1, R2, P1, P2, Q, validPixROI1, validPixROI2 = cv2.stereoRectify(left_camera_matrix, left_distortion,
right_camera_matrix, right_distortion, size, R,
T)
# 计算更正map
left_map1, left_map2 = cv2.initUndistortRectifyMap(left_camera_matrix, left_distortion, R1, P1, size, cv2.CV_16SC2)
right_map1, right_map2 = cv2.initUndistortRectifyMap(right_camera_matrix, right_distortion, R2, P2, size, cv2.CV_16SC2)
# print("leftmap1",left_map1)
# print("right_map1",right_map1)
return left_map1, left_map2, right_map1, right_map2, Q
#立体视觉待测试视频--20221212,重要!!!!
# https://blog.csdn.net/m0_72557783/article/details/128256932
# 添加点击事件,打印当前点的距离
def callbackFunc(e, x, y, f, p):
global threeD
if e == cv2.EVENT_LBUTTONDOWN:
# print threeD[y][x]
print(threeD[y][x])
#获取立体视觉并计算函数
def stereo_vision(cap_id=0,width = 3840,height = 1080):
global threeD
xmlfie_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/stereo_param.xml'
# left_map1, left_map2, right_map1, right_map2, sterro_Q = get_stereo_param(xmlfie_path)
left_map1, left_map2, right_map1, right_map2, sterro_Q = get_stereo_param(xmlfie_path,size=(width//2,height))
#获取摄像头
cap = cv2.VideoCapture(cap_id)
cv2.namedWindow("left", cv2.WINDOW_NORMAL)
cv2.namedWindow("right", cv2.WINDOW_NORMAL)
cv2.namedWindow("depth", cv2.WINDOW_NORMAL)
cv2.moveWindow("left", 0, 0)
cv2.moveWindow("right", 600, 0)
cv2.createTrackbar("num", "depth", 0, 10, lambda x: None)
cv2.createTrackbar("blockSize", "depth", 5, 255, lambda x: None)
cv2.setMouseCallback("depth", callbackFunc, None)
# widht_split = width//2 #注意不能用/这是浮点除法, 要用//,整除法
cap.set(3, width) # CV_CAP_PROP_FRAME_WIDTH
cap.set(4, height) # CV_CAP_PROP_FRAME_HEIGHT
# cv2.namedWindow('camera', cv2.WINDOW_NORMAL)
# cv2.namedWindow('camera_left', cv2.WINDOW_NORMAL)
# cv2.namedWindow('camera_right', cv2.WINDOW_NORMAL)
print("start cap")
left_img = None
right_img = None
while (cap.isOpened()):
ret, frame = cap.read() #捕获图片
if ret == False or frame is None:
print("can't get img")
break
frame = cv2.flip(frame,1) #镜像操作
# print(frame.shape)
#注意不能用/这是浮点除法, 要用//,整除法
left_img = copy.deepcopy(frame[:,:width//2,:])
right_img = copy.deepcopy(frame[:,width//2:,:])
#噪声多,不稳定,陈添加了滤波
left_img = cv2.GaussianBlur(left_img,(9,9),0,0)
right_img = cv2.GaussianBlur(right_img,(9,9),0,0)
# cv2.imshow("camera", frame)
# cv2.imshow("camera_left", left_img)
# cv2.imshow("camera_right", right_img)
# 根据更正map对图片进行重构
img1_rectified = cv2.remap(left_img, left_map1, left_map2, cv2.INTER_LINEAR)
img2_rectified = cv2.remap(right_img, right_map1, right_map2, cv2.INTER_LINEAR)
# 将图片置为灰度图,为StereoBM作准备
imgL = cv2.cvtColor(img1_rectified, cv2.COLOR_BGR2GRAY)
imgR = cv2.cvtColor(img2_rectified, cv2.COLOR_BGR2GRAY)
cv2.imshow("chentest imgL",imgL)
cv2.imshow("chentest imgR",imgR)
# 两个trackbar用来调节不同的参数查看效果
num = cv2.getTrackbarPos("num", "depth")
blockSize = cv2.getTrackbarPos("blockSize", "depth")
if blockSize % 2 == 0:
blockSize += 1
if blockSize < 5:
blockSize = 5
# 根据Block Maching方法生成差异图(opencv里也提供了SGBM/Semi-Global Block Matching算法,有兴趣可以试试)
# stereo = cv2.StereoBM_create(numDisparities=16*num, blockSize=blockSize)
stereo = cv2.StereoSGBM_create(numDisparities=16, blockSize=11)
# numDisparities:disparity的搜索范围,即最大差异减去最小差异。该值始终大于零。在当前的实现中,这个参数必须可以被16整除
# blockSize:块的线性大小。大小应该是奇数(因为块位于当前像素的中心)。更大的块大小意味着更平滑
# stereo = cv2.StereoBM_create(numDisparities=16, blockSize=11)
# speckleWindowSize:考虑其噪声斑点的平滑差距区域的最大尺寸,并使之无效。把它设置为0以禁用斑点过滤。否则,将它设置在50-200范围内的某个地方。
# stereo = cv2.StereoSGBM_create(minDisparity=1,
# numDisparities=16,
# blockSize=11,
# uniquenessRatio = 5,
# speckleWindowSize = 100,
# speckleRange = 1,
# disp12MaxDiff = 200,
# P1 = 8*3*blockSize**2,
# P2 = 32*3*blockSize**2)
disparity = stereo.compute(imgL, imgR)
disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
# 将图片扩展至3d空间中,其z方向的值则为当前的距离
threeD = cv2.reprojectImageTo3D(disparity.astype(np.float32)/16., sterro_Q)
cv2.imshow("left", img1_rectified)
cv2.imshow("right", img2_rectified)
cv2.imshow("depth", disp)
key = cv2.waitKey(1)
if key == ord("q"):
break
elif key == ord("s"):
cv2.imwrite("snapshot/BM_left.jpg", imgL)
cv2.imwrite("snapshot/BM_right.jpg", imgR)
cv2.imwrite("snapshot/BM_depth.jpg", disp)
if key == ord('q'): #如果是按键r,则退出
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
# stereo_vision(cap_id=0,width = 1280,height = 480)
stereo_vision(cap_id=0,width = 3840,height = 1080)
(2)测试结果,画面抖动很厉害,噪点很多,很不理想
(1)安装opencv-contrib
pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
(2)测试,速度很慢
import cv2
import numpy as np
import copy
import glob
#pip install opencv-contrib-python -i https://pypi.tuna.tsinghua.edu.cn/simple
#函数一,获得立体视觉的参数
def get_stereo_param(xmlfie_path,size = (1920, 1080)):
#方法(二)设定自己的摄像机外部调整参数
# cv_file = cv2.FileStorage()
# cv_file.open(xmlfie_path,cv2.FileStorage_READ)
# left_camera_matrix = cv_file.getNode('left_m1').mat()
# left_distortion = cv_file.getNode('left_d1').mat()
# right_camera_matrix = cv_file.getNode('right_m2').mat()
# right_distortion = cv_file.getNode('right_d2').mat()
# R = cv_file.getNode('stereo_r').mat()
# T = cv_file.getNode('stereo_t').mat()
# print("left_camera_matrix",left_camera_matrix)
#注意,陈备注:以下数据由matlab2016的工具箱stereoCameraCalibrator标注获得
left_camera_matrix = np.array([[ 1504.835951, 0, 903.7996248],
[0, 1496.764636, 561.0768711],
[0, 0, 1]])
left_distortion = np.array([[0.0570108746206312, -0.477832004663628, 0.00673968704282051, -0.00388206741248358,1.12821673355428]])
right_camera_matrix = np.array([[1508.16718253864, 0, 868.820482265892],
[ 0, 1497.3685484015, 574.72759642089],
[ 0, 0, 1]])
right_distortion = np.array([[0.0619253328320556, -1.3099240242802, 0.00734199071917032, -0.00389020681922442,7.50657175779989]])
R = np.matrix([
[0.999999429, -0.001009115, -0.000350325],
[0.001007939, 0.999993912, 0],
[0.000353694, 0.00334044, 0.999994358],
])
T = np.array([-49.53961963, -0.245581652, 2.526004856]) # 平移关系向量
# size = (640, 480) # 图像尺寸
# 进行立体更正
R1, R2, P1, P2, Q, validPixROI1, validPixROI2 = cv2.stereoRectify(left_camera_matrix, left_distortion,
right_camera_matrix, right_distortion, size, R,
T)
# 计算更正map
left_map1, left_map2 = cv2.initUndistortRectifyMap(left_camera_matrix, left_distortion, R1, P1, size, cv2.CV_16SC2)
right_map1, right_map2 = cv2.initUndistortRectifyMap(right_camera_matrix, right_distortion, R2, P2, size, cv2.CV_16SC2)
# print("leftmap1",left_map1)
# print("right_map1",right_map1)
return left_map1, left_map2, right_map1, right_map2, Q
#立体视觉待测试视频--20221212,重要!!!!
# https://blog.csdn.net/m0_72557783/article/details/128256932
# 添加点击事件,打印当前点的距离
def callbackFunc(e, x, y, f, p):
if e == cv2.EVENT_LBUTTONDOWN:
# print threeD[y][x]
print("chest")
#获取立体视觉并计算函数
def stereo_vision(cap_id=0,width = 3840,height = 1080):
#重要参数,20221213
### 设置参数
#块大小必须为奇数(3-11)
blockSize = 5
img_channels = 2
num_disp = 16 * 8
param = {
'preFilterCap': 63, #映射滤波器大小,默认15
"minDisparity" : 0, #最小视差
"numDisparities" : num_disp, #视差的搜索范围,16的整数倍
"blockSize" : blockSize,
"uniquenessRatio" : 10, #唯一检测性参数,匹配区分度不够,则误匹配(5-15)
"speckleWindowSize" : 0, #视差连通区域像素点个数的大小(噪声点)(50-200)或用0禁用斑点过滤
"speckleRange" : 1, #认为不连通(1-2)
"disp12MaxDiff" : 2, #左右一致性检测中最大容许误差值
"P1" : 8 * img_channels * blockSize** 2, #值越大,视差越平滑,相邻像素视差+/-1的惩罚系数
"P2" : 32 * img_channels * blockSize** 2, #同上,相邻像素视差变化值>1的惩罚系数
# 'mode': cv2.STEREO_SGBM_MODE_SGBM_3WAY
}
# ————————————————
# wls这段代码的原文链接:https://blog.csdn.net/weixin_40524689/article/details/124929419
xmlfie_path = 'D:/RGBD_CAMERA/1chen_code/stereo_vision/stereo_param.xml'
left_map1, left_map2, right_map1, right_map2, sterro_Q = get_stereo_param(xmlfie_path,size=(width//2,height))
#获取摄像头
cap = cv2.VideoCapture(cap_id)
cv2.namedWindow("left", cv2.WINDOW_NORMAL)
cv2.namedWindow("right", cv2.WINDOW_NORMAL)
cv2.namedWindow("depth", cv2.WINDOW_NORMAL)
cv2.moveWindow("left", 0, 0)
cv2.moveWindow("right", 600, 0)
cv2.createTrackbar("num", "depth", 0, 10, lambda x: None)
cv2.createTrackbar("blockSize", "depth", 5, 255, lambda x: None)
cv2.setMouseCallback("depth", callbackFunc, None)
# widht_split = width//2 #注意不能用/这是浮点除法, 要用//,整除法
cap.set(3, width) # CV_CAP_PROP_FRAME_WIDTH
cap.set(4, height) # CV_CAP_PROP_FRAME_HEIGHT
# cv2.namedWindow('camera', cv2.WINDOW_NORMAL)
# cv2.namedWindow('camera_left', cv2.WINDOW_NORMAL)
# cv2.namedWindow('camera_right', cv2.WINDOW_NORMAL)
print("start cap")
left_img = None
right_img = None
while (cap.isOpened()):
ret, frame = cap.read() #捕获图片
if ret == False or frame is None:
print("can't get img")
break
frame = cv2.flip(frame,1) #镜像操作
# print(frame.shape)
#注意不能用/这是浮点除法, 要用//,整除法
left_img = copy.deepcopy(frame[:,:width//2,:])
right_img = copy.deepcopy(frame[:,width//2:,:])
# cv2.imshow("camera", frame)
# cv2.imshow("camera_left", left_img)
# cv2.imshow("camera_right", right_img)
# 根据更正map对图片进行重构
img1_rectified = cv2.remap(left_img, left_map1, left_map2, cv2.INTER_LINEAR)
img2_rectified = cv2.remap(right_img, right_map1, right_map2, cv2.INTER_LINEAR)
# 将图片置为灰度图,为StereoBM作准备
imgL_gray = cv2.cvtColor(img1_rectified, cv2.COLOR_BGR2GRAY)
imgR_gray = cv2.cvtColor(img2_rectified, cv2.COLOR_BGR2GRAY)
cv2.imshow("chentest imgL",imgL_gray)
cv2.imshow("chentest imgR",imgR_gray)
left_matcher = cv2.StereoSGBM_create(**param)
left_disp = left_matcher.compute(imgL_gray, imgR_gray)
# 得到深度图
# disp = cv2.normalize(dispL, dispL, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
## 接上面的参数
left_matcher = cv2.StereoSGBM_create(**param)
right_matcher = cv2.ximgproc.createRightMatcher(left_matcher)
left_disp = left_matcher.compute(imgL_gray, imgR_gray)
right_disp = right_matcher.compute(imgR_gray, imgL_gray)
wls_filter = cv2.ximgproc.createDisparityWLSFilter(left_matcher)
# sigmaColor典型范围值为0.8-2.0
wls_filter.setLambda(8000.)
wls_filter.setSigmaColor(1.3)
wls_filter.setLRCthresh(24)
wls_filter.setDepthDiscontinuityRadius(3)
filtered_disp = wls_filter.filter(left_disp, imgL_gray, disparity_map_right=right_disp)
disp = cv2.normalize(filtered_disp, filtered_disp, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
# 两个trackbar用来调节不同的参数查看效果
# num = cv2.getTrackbarPos("num", "depth")
# blockSize = cv2.getTrackbarPos("blockSize", "depth")
# if blockSize % 2 == 0:
# blockSize += 1
# if blockSize < 5:
# blockSize = 5
# # 根据Block Maching方法生成差异图(opencv里也提供了SGBM/Semi-Global Block Matching算法,有兴趣可以试试)
# # stereo = cv2.StereoBM_create(numDisparities=16*num, blockSize=blockSize)
# stereo = cv2.StereoBM_create(numDisparities=16, blockSize=11)
# disparity = stereo.compute(imgL, imgR)
# disp = cv2.normalize(disparity, disparity, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
# 将图片扩展至3d空间中,其z方向的值则为当前的距离
# threeD = cv2.reprojectImageTo3D(disparity.astype(np.float32)/16., sterro_Q)
threeD = cv2.reprojectImageTo3D(filtered_disp.astype(np.float32)/16., sterro_Q)
cv2.imshow("left", img1_rectified)
cv2.imshow("right", img2_rectified)
cv2.imshow("depth", disp)
key = cv2.waitKey(1)
if key == ord("q"):
break
elif key == ord("s"):
cv2.imwrite("snapshot/BM_left.jpg", imgL_gray)
cv2.imwrite("snapshot/BM_right.jpg", imgR_gray)
cv2.imwrite("snapshot/BM_depth.jpg", disp)
if key == ord('q'): #如果是按键r,则退出
break
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
# stereo_vision(cap_id=0,width = 1280,height = 480)
stereo_vision(cap_id=0,width = 3840,height = 1080)
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司
如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象
是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在
我有一个应用程序可以读取文件的内容并为其编制索引。我将它们存储在磁盘本身中,但现在我使用的是AmazonS3,因此以下方法不再适用。事情是这样的:defperform(docId)@document=Document.find(docId)if@document.file?#Youshould'tcreateanewversion@document.versionlessdo|doc|@document.file_content=Cloudoc::Extractor.new.extract(@document.file.file)@document.saveendendend@docu