一.摄像头标定
1. 打印一张棋盘图,网上自己随便找,或者自己用CAD画一个。
2.使用左右两个摄像头,分别同时拍摄不同角度的棋盘图,并保存到目标文件夹下。可参考我的博客:OpenCV011
3.使用matlab工具箱标定:TOOLBOX_calib,标定方法百度一下,就有很多介绍
3.编写一个摄像头参数文件,并命名为:camera_configs.py,我的摄像头参数如下:
# -- coding: utf-8 --
#如若程序有中文注释,将上行代码加到代码的第一行或第二行
#blog:
#https://www.cnblogs.com/zhiyishou/p/5767592.html
#Camera Matrix,distortion
#http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_calib3d/py_calibration/py_calibration.html
# fx 0 cx
#Camera Matrix= 0 fy cy
# 0 0 1
#distortion coefficients=(k1,k2,p1,p2,k3)
#filename: camera_configs.py
import cv2
import numpy as np
left_camera_matrix = np.array([[743.75550, 0., 309.19470],
[0., 742.26143, 247.91394],
[0., 0., 1.]])
left_distortion = np.array([[0.13950, -0.45453, 0.00300, -0.00260, 0.00000]])
right_camera_matrix = np.array([[752.48868, 0., 369.93495],
[0., 748.39473, 234.17570],
[0., 0., 1.]])
right_distortion = np.array([[0.15105, -0.50820, 0.00157, 0.01659, 0.00000]])
om = np.array([-0.00573, 0.00361, 0.00487]) # 旋转关系向量
R = cv2.Rodrigues(om)[0] # 使用Rodrigues变换将om变换为R
T = np.array([-95.74804, 2.60574, 4.01073]) # 平移关系向量
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)
二.双目测距实现
废话不说,直接上验证过的代码。调整两个滑块,改变算法阈值。
StereoBM在我之前的博文中有讲解
# -- coding: utf-8 --
#如若程序有中文注释,将上行代码加到代码的第一行或第二行
#blog:
#https://www.cnblogs.com/zhiyishou/p/5767592.html
import numpy as np
import cv2
import camera_configs
cv2.namedWindow("left")
cv2.namedWindow("right")
cv2.namedWindow("depth")
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)
camera1 = cv2.VideoCapture(1)
camera2 = cv2.VideoCapture(0)
# 添加点击事件,打印当前点的距离
def callbackFunc(e, x, y, f, p):
if e == cv2.EVENT_LBUTTONDOWN:
print threeD[y][x]
cv2.setMouseCallback("depth", callbackFunc, None)
while True:
ret1, frame1 = camera1.read()
ret2, frame2 = camera2.read()
if not ret1 or not ret2:
break
# 根据更正map对图片进行重构
img1_rectified = cv2.remap(frame1, camera_configs.left_map1, camera_configs.left_map2, cv2.INTER_LINEAR)
img2_rectified = cv2.remap(frame2, camera_configs.right_map1, camera_configs.right_map2, cv2.INTER_LINEAR)
# 将图片置为灰度图,为StereoBM作准备
imgL = cv2.cvtColor(img1_rectified, cv2.COLOR_BGR2GRAY)
imgR = cv2.cvtColor(img2_rectified, cv2.COLOR_BGR2GRAY)
# 两个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(0,16*num, blockSize)
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., camera_configs.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)
camera1.release()
camera2.release()
cv2.destroyAllWindows()