3.37. Stereo Depth Video
此示例是升级的 Depth Preview 。它具有更高的分辨率(720p),可以显示每一帧(mono left-right, rectified left-right, disparity and depth)。您可以在代码中选择 6 种模式:
withDepth: 如果你关闭它,它将变成 Mono Preview ,所以它只会显示2个单目相机。
outputDepth: 如果你打开它会显示深度
lrcheck: 用于更好的处理阴影。欲了解更多信息, 请点击此处
extended: 适用于短距离物体。欲了解更多信息, 请点击此处
subpixel: 适合远距离。欲了解更多信息, 请点击此处
类似样本:
3.37.1. 设置
请运行以下命令以安装所需的依赖项
Warning
说明:此处安装的是第二代depthai库
python3 -m pip install depthai numpy==1.19.5 opencv-python==4.5.1.48
有关更多信息,请参阅 Python API 安装指南
3.37.2. 源代码
可以在 GitHub 上找到。国内用户也可以在 gitee 上找到。
代码流程图
#!/usr/bin/env python3
import cv2
import numpy as np
import depthai as dai
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"-res",
"--resolution",
type=str,
default="720",
help="Sets the resolution on mono cameras. Options: 800 | 720 | 400",
)
parser.add_argument(
"-md",
"--mesh_dir",
type=str,
default=None,
help="Output directory for mesh files. If not specified mesh files won't be saved",
)
parser.add_argument(
"-lm",
"--load_mesh",
default=False,
action="store_true",
help="Read camera intrinsics, generate mesh files and load them into the stereo node.",
)
parser.add_argument(
"-rect",
"--out_rectified",
default=False,
action="store_true",
help="Generate and display rectified streams",
)
parser.add_argument(
"-lr",
"--lrcheck",
default=False,
action="store_true",
help="Better handling for occlusions",
)
parser.add_argument(
"-e",
"--extended",
default=False,
action="store_true",
help="Closer-in minimum depth, disparity range is doubled",
)
parser.add_argument(
"-s",
"--subpixel",
default=False,
action="store_true",
help="Better accuracy for longer distance, fractional disparity 32-levels",
)
parser.add_argument(
"-m",
"--median",
type=str,
default="7x7",
help="Choose the size of median filtering. Options: OFF | 3x3 | 5x5 | 7x7 (default)",
)
parser.add_argument(
"-d",
"--depth",
default=False,
action="store_true",
help="Display depth frames",
)
args = parser.parse_args()
resolutionMap = {"800": (1280, 800), "720": (1280, 720), "400": (640, 400)}
if args.resolution not in resolutionMap:
exit("Unsupported resolution!")
resolution = resolutionMap[args.resolution]
meshDirectory = args.mesh_dir # Output dir for mesh files
generateMesh = args.load_mesh # Load mesh files
outRectified = args.out_rectified # Output and display rectified streams
lrcheck = args.lrcheck # Better handling for occlusions
extended = args.extended # Closer-in minimum depth, disparity range is doubled
subpixel = args.subpixel # Better accuracy for longer distance, fractional disparity 32-levels
depth = args.depth # Display depth frames
medianMap = {
"OFF": dai.StereoDepthProperties.MedianFilter.MEDIAN_OFF,
"3x3": dai.StereoDepthProperties.MedianFilter.KERNEL_3x3,
"5x5": dai.StereoDepthProperties.MedianFilter.KERNEL_5x5,
"7x7": dai.StereoDepthProperties.MedianFilter.KERNEL_7x7,
}
if args.median not in medianMap:
exit("Unsupported median size!")
median = medianMap[args.median]
print("StereoDepth config options:")
print(" Resolution: ", resolution)
print(" Left-Right check: ", lrcheck)
print(" Extended disparity:", extended)
print(" Subpixel: ", subpixel)
print(" Median filtering: ", median)
print(" Generating mesh files: ", generateMesh)
print(" Outputting mesh files to: ", meshDirectory)
def getMesh(calibData):
M1 = np.array(calibData.getCameraIntrinsics(dai.CameraBoardSocket.LEFT, resolution[0], resolution[1]))
d1 = np.array(calibData.getDistortionCoefficients(dai.CameraBoardSocket.LEFT))
R1 = np.array(calibData.getStereoLeftRectificationRotation())
M2 = np.array(calibData.getCameraIntrinsics(dai.CameraBoardSocket.RIGHT, resolution[0], resolution[1]))
d2 = np.array(calibData.getDistortionCoefficients(dai.CameraBoardSocket.RIGHT))
R2 = np.array(calibData.getStereoRightRectificationRotation())
mapXL, mapYL = cv2.initUndistortRectifyMap(M1, d1, R1, M2, resolution, cv2.CV_32FC1)
mapXR, mapYR = cv2.initUndistortRectifyMap(M2, d2, R2, M2, resolution, cv2.CV_32FC1)
meshCellSize = 16
meshLeft = []
meshRight = []
for y in range(mapXL.shape[0] + 1):
if y % meshCellSize == 0:
rowLeft = []
rowRight = []
for x in range(mapXL.shape[1] + 1):
if x % meshCellSize == 0:
if y == mapXL.shape[0] and x == mapXL.shape[1]:
rowLeft.append(mapYL[y - 1, x - 1])
rowLeft.append(mapXL[y - 1, x - 1])
rowRight.append(mapYR[y - 1, x - 1])
rowRight.append(mapXR[y - 1, x - 1])
elif y == mapXL.shape[0]:
rowLeft.append(mapYL[y - 1, x])
rowLeft.append(mapXL[y - 1, x])
rowRight.append(mapYR[y - 1, x])
rowRight.append(mapXR[y - 1, x])
elif x == mapXL.shape[1]:
rowLeft.append(mapYL[y, x - 1])
rowLeft.append(mapXL[y, x - 1])
rowRight.append(mapYR[y, x - 1])
rowRight.append(mapXR[y, x - 1])
else:
rowLeft.append(mapYL[y, x])
rowLeft.append(mapXL[y, x])
rowRight.append(mapYR[y, x])
rowRight.append(mapXR[y, x])
if (mapXL.shape[1] % meshCellSize) % 2 != 0:
rowLeft.append(0)
rowLeft.append(0)
rowRight.append(0)
rowRight.append(0)
meshLeft.append(rowLeft)
meshRight.append(rowRight)
meshLeft = np.array(meshLeft)
meshRight = np.array(meshRight)
return meshLeft, meshRight
def saveMeshFiles(meshLeft, meshRight, outputPath):
print("Saving mesh to:", outputPath)
meshLeft.tofile(outputPath + "/left_mesh.calib")
meshRight.tofile(outputPath + "/right_mesh.calib")
def getDisparityFrame(frame):
maxDisp = stereo.initialConfig.getMaxDisparity()
disp = (frame * (255.0 / maxDisp)).astype(np.uint8)
disp = cv2.applyColorMap(disp, cv2.COLORMAP_JET)
return disp
print("Creating Stereo Depth pipeline")
pipeline = dai.Pipeline()
camLeft = pipeline.create(dai.node.MonoCamera)
camRight = pipeline.create(dai.node.MonoCamera)
stereo = pipeline.create(dai.node.StereoDepth)
xoutLeft = pipeline.create(dai.node.XLinkOut)
xoutRight = pipeline.create(dai.node.XLinkOut)
xoutDisparity = pipeline.create(dai.node.XLinkOut)
xoutDepth = pipeline.create(dai.node.XLinkOut)
xoutRectifLeft = pipeline.create(dai.node.XLinkOut)
xoutRectifRight = pipeline.create(dai.node.XLinkOut)
camLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
camRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
res = (
dai.MonoCameraProperties.SensorResolution.THE_800_P
if resolution[1] == 800
else dai.MonoCameraProperties.SensorResolution.THE_720_P
if resolution[1] == 720
else dai.MonoCameraProperties.SensorResolution.THE_400_P
)
for monoCam in (camLeft, camRight): # Common config
monoCam.setResolution(res)
# monoCam.setFps(20.0)
stereo.setDefaultProfilePreset(dai.node.StereoDepth.PresetMode.HIGH_DENSITY)
stereo.initialConfig.setMedianFilter(median) # KERNEL_7x7 default
stereo.setRectifyEdgeFillColor(0) # Black, to better see the cutout
stereo.setLeftRightCheck(lrcheck)
# FIXME: RuntimeError: StereoDepth(2) - StereoDepth | ExtendedDisparity is not implemented yet.
stereo.setExtendedDisparity(extended)
stereo.setSubpixel(subpixel)
xoutLeft.setStreamName("left")
xoutRight.setStreamName("right")
xoutDisparity.setStreamName("disparity")
xoutDepth.setStreamName("depth")
xoutRectifLeft.setStreamName("rectifiedLeft")
xoutRectifRight.setStreamName("rectifiedRight")
camLeft.out.link(stereo.left)
camRight.out.link(stereo.right)
stereo.syncedLeft.link(xoutLeft.input)
stereo.syncedRight.link(xoutRight.input)
stereo.disparity.link(xoutDisparity.input)
if depth:
stereo.depth.link(xoutDepth.input)
if outRectified:
stereo.rectifiedLeft.link(xoutRectifLeft.input)
stereo.rectifiedRight.link(xoutRectifRight.input)
streams = ["left", "right"]
if outRectified:
streams.extend(["rectifiedLeft", "rectifiedRight"])
streams.append("disparity")
if depth:
streams.append("depth")
calibData = dai.Device().readCalibration()
leftMesh, rightMesh = getMesh(calibData)
if generateMesh:
meshLeft = list(leftMesh.tobytes())
meshRight = list(rightMesh.tobytes())
stereo.loadMeshData(meshLeft, meshRight)
if meshDirectory is not None:
saveMeshFiles(leftMesh, rightMesh, meshDirectory)
print("Creating DepthAI device")
with dai.Device(pipeline) as device:
# Create a receive queue for each stream
qList = [device.getOutputQueue(stream, 8, blocking=False) for stream in streams]
while True:
for q in qList:
name = q.getName()
frame = q.get().getCvFrame()
if name == "depth":
frame = frame.astype(np.uint16)
elif name == "disparity":
frame = getDisparityFrame(frame)
cv2.imshow(name, frame)
if cv2.waitKey(1) == ord("q"):
break
有疑问?
我们很乐意为您提供代码或其他问题的帮助。
我们的联系方式
还可以通过我们发布的视频和文章了解OAK