一、产品介绍
Intel RealSense D435i 是英特尔公司推出的一款消费级深度相机。主要包含一个 RGB 相机、两个红外相机以及一个红外发射器,此外还有一个 IMU 单元(这也就是 D435i 和 D435 的区别,i 就表示 imu)。简单来说它的深度成像原理是主动立体红外成像,不是传统意义上理解的双目 RGB 相机成像,这点需要注意一下。
有了深度图 (3D 点云) 和对应的 RGB 影像,因此也就很容易获得 RGB-D 点云了。因此从输出的角度而言,D435i 可以看做是一个 RGB-D 传感器相机。后续可以搭配 ORB-SLAM 中 RGB-D 的模式进行使用。当然,也可以只用单目 RGB 影像,以单目 SLAM 模式运行,或者单目结合 IMU,以 Mono-Initial 模式运行。唯一不能运行的是双目 RGB 模式 (因为两个红外相机是单通道的)。当然我们可以获取双目的红外影像,以此作为输入,进行双目 SLAM,结果也是类似的。因此可以看出,D435i 是一个比较'全能'的传感器,从单目、单目+IMU、双目、双目+IMU、RGB-D 都可以使用。
对于它的一些技术上的参数,这里也简单列举一下:
- 深度技术:主动立体 IR
- 图像传感器技术:3μm×3μm 像素大小,全局快门
- 深度视场 (H×V):86°×57°(±3°)
- 深度分辨率&帧率:1280×720,90FPS(最高)
- RGB 传感器技术:卷帘快门
- RGB 传感器分辨率&帧率:1920×1080,30FPS(最高)
- RGB 传感器 FOV(H×V):69°×42°(±1°)
- 最小深度距离 (Min-Z):0.105m
- 最大范围:约 10m
- 尺寸 (长宽高):90mm × 25mm × 25mm
从上面的参数中,也可以看出来它的一些特点。比如深度图和 RGB 影像的大小是不同的,换句话说 RGB 影像中只有和深度图重叠的那部分才有深度信息,否则是没有的。同时帧率也不相同,如果需要使用 RGB-D 信息,那么时间同步也可能是个需要处理的问题。第二点是 RGB 传感器采用的是卷帘快门,因此在一些高速运动的场景下,可能会出现果冻效应。最后由于采用主动红外测距技术,而红外传感器本身发射的信号强度有限,最大 10m 左右,因此并不能适用于室外很大的场景。
二、SDK 下载
2.1 下载
进入网址:RealSense SDK 2.0
直接拉到网站最下端,在 Asset 下可以看到很多 exe 可执行软件,由于我的电脑是 win11,所以选择第三个。
注:win11 和 win10 的 SDK 通用的,均可使用。
装 SDK 会附带安装可视化界面 Viewer、Examples 和 Depth Quality Tool。
2.2 安装与测试
首先,连接 D435i 到电脑上,然后在终端中输入 realsense-viewer 启动数据可视化界面。
点击左侧的 Stereo Module 可以开启深度图显示,RGB Module 可以显示 RGB 影像,Motion Module 会显示 IMU 相关数据。
如果可以正常显示画面,那么就说明 RealSense 的基本配置就成功了,可以向电脑传输数据了。
同样地,Stereo Module 和 RGB Camera 可以分别设置参数(很重要,后面要用到)。这里简单说一下,Stereo Module 的作用是用来设置深度信息的,而 RGB Camera 就是用来设置 RGB 颜色信息的!当然,主要用到的还是分辨率和 FPS。
三、结合 python 配置相机
3.1 虚拟环境配置
- 首先在 windows 下安装 anaconda 和 Vscode,然后配置 open3d 新环境。
- 创建一个新的环境,以下分别是 python 版本是 3.8 和 3.6 的安装教程。
- 在 conda 终端下使用命令:
conda create -n Rd543i python=3.6
conda activate Rd543i
conda create -n Rd543i python=3.8
conda activate Rd543i
- 配置 opencv 环境,安装 opencv。
pip install -i https://mirrors.aliyun.com/pypi/simple/ opencv-python==4.3.0.38 pip install opencv-contrib-python==4.4.0.46
pip install opencv-python pip install opencv-contrib-python
- 接着安装 open3d 和 pyrealsense2,open3d 需要等很长时间。
pip install pywinpty==1.1.4 pip install open3d==0.15.1 pip install pyrealsense2==2.48.0.3891
pip install open3d pip install pyrealsense2
3.2 可视化
可视化脚本:
import pyrealsense2 as rs
import numpy as np
import cv2
if __name__ == "__main__":
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 640, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 640, 480, rs.format.bgr8, 30)
pipeline.start(config)
try:
while True:
frames = pipeline.wait_for_frames()
depth_frame = frames.get_depth_frame()
color_frame = frames.get_color_frame()
if not depth_frame or not color_frame:
continue
depth_image = np.asanyarray(depth_frame.get_data())
color_image = np.asanyarray(color_frame.get_data())
depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=0.03), cv2.COLORMAP_JET)
images = np.hstack((color_image, depth_colormap))
cv2.namedWindow('RealSense', cv2.WINDOW_AUTOSIZE)
cv2.imshow('RealSense', images)
key = cv2.waitKey(1)
if key & 0xFF == () key == :
cv2.destroyAllWindows()
:
pipeline.stop()
四、结合 python+Vscode 实现数据采集
4.1 实现 RGB 数据采集
脚本:
import os
import cv2
import numpy as np
import pyrealsense2 as rs
import time
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.color, 1920, 1080, rs.format.bgr8, 15)
profile = pipeline.start(config)
cv2.namedWindow('RGB Image', cv2.WINDOW_AUTOSIZE)
save_dir = 'E:/my_images/'
os.makedirs(save_dir, exist_ok=True)
counter = 0
try:
while True:
frames = pipeline.wait_for_frames()
color_frame = frames.get_color_frame()
if not color_frame:
continue
color_image = np.asanyarray(color_frame.get_data())
cv2.imshow('RGB Image', color_image)
key = cv2.waitKey(1)
if key == ord('t'):
rgb_file = os.path.join(save_dir, f'rgb_{counter:04d}.png')
cv2.imwrite(rgb_file, color_image)
print(f'Saved: {rgb_file}')
counter += 1
if key in [27, ord('q')]:
cv2.destroyAllWindows()
break
finally:
pipeline.stop()
五、一些其他扩展玩法
5.1 YOLOv8 结合相机
具体脚本如下:
import cv2
import pyrealsense2 as rs
import time
import numpy as np
import math
from ultralytics import YOLO
model = YOLO("runs/detect/train/weights/best.pt")
pipeline = rs.pipeline()
config = rs.config()
config.enable_stream(rs.stream.depth, 848, 480, rs.format.z16, 30)
config.enable_stream(rs.stream.color, 848, 480, rs.format.bgr8, 30)
pipeline.start(config)
align_to = rs.stream.color
align = rs.align(align_to)
def get_aligned_images():
frames = pipeline.wait_for_frames()
aligned_frames = align.process(frames)
aligned_depth_frame = aligned_frames.get_depth_frame()
color_frame = aligned_frames.get_color_frame()
intr = color_frame.profile.as_video_stream_profile().intrinsics
depth_intrin = aligned_depth_frame.profile.as_video_stream_profile().intrinsics
'''camera_parameters = {'fx': intr.fx, 'fy': intr.fy, 'ppx': intr.ppx, 'ppy': intr.ppy, 'height': intr.height, 'width': intr.width, 'depth_scale': profile.get_device().first_depth_sensor().get_depth_scale() }'''
depth_image = np.asanyarray(aligned_depth_frame.get_data())
depth_image_8bit = cv2.convertScaleAbs(depth_image, alpha=)
depth_image_3d = np.dstack((depth_image_8bit, depth_image_8bit, depth_image_8bit))
color_image = np.asanyarray(color_frame.get_data())
intr, depth_intrin, color_image, depth_image, aligned_depth_frame
():
x = depth_pixel[]
y = depth_pixel[]
dis = aligned_depth_frame.get_distance(x, y)
camera_coordinate = rs.rs2_deproject_pixel_to_point(depth_intrin, depth_pixel, dis)
dis, camera_coordinate
fps =
frame_count =
start_time = time.time()
:
:
intr, depth_intrin, color_image, depth_image, aligned_depth_frame = get_aligned_images()
depth_image.() color_image.():
time1 = time.time()
depth_colormap = cv2.applyColorMap(cv2.convertScaleAbs(depth_image, alpha=), cv2.COLORMAP_JET)
images = np.hstack((color_image, depth_colormap))
results = model.predict(color_image, conf=)
annotated_frame = results[].plot()
detected_boxes = results[].boxes.xyxy
i, box (detected_boxes):
x1, y1, x2, y2 = (, box)
xrange = (, math.ceil(((x1 - x2)/)))
yrange = (, math.ceil(((y1 - y2)/)))
point_cloud_data = []
x_position (x1, x2, xrange):
y_position (y1, y2, yrange):
depth_pixel = [x_position, y_position]
dis, camera_coordinate = get_3d_camera_coordinate(depth_pixel, aligned_depth_frame, depth_intrin)
point_cloud_data.append()
(, ) file:
file.write()
file.write(.join(point_cloud_data))
ux = ((x1 + x2)/)
uy = ((y1 + y2)/)
dis, camera_coordinate = get_3d_camera_coordinate([ux, uy], aligned_depth_frame, depth_intrin)
formatted_camera_coordinate =
cv2.circle(annotated_frame, (ux, uy), , (, , ), )
cv2.putText(annotated_frame, formatted_camera_coordinate, (ux + , uy + ), , , [, , ], thickness=, lineType=cv2.LINE_AA)
frame_count +=
time2 = time.time()
fps = (/(time2 - time1))
cv2.putText(annotated_frame, , (, ), cv2.FONT_HERSHEY_SIMPLEX, , (, , ), , cv2.LINE_AA)
cv2.imshow(, annotated_frame)
cv2.waitKey() & == ():
:
pipeline.stop()
5.2 关键点识别结合相机
脚本思路:
- 获取相机对齐图像帧与相机参数
frames = pipeline.wait_for_frames()
aligned_frames = align.process(frames)
aligned_depth_frame = aligned_frames.get_depth_frame()
aligned_color_frame = aligned_frames.get_color_frame()
depth_intrin = aligned_depth_frame.profile.as_video_stream_profile().intrinsics
color_intrin = aligned_color_frame.profile.as_video_stream_profile().intrinsics
img_color = np.asanyarray(aligned_color_frame.get_data())
img_depth = np.asanyarray(aligned_depth_frame.get_data())
- 检测
result = list(model(image, conf=0.3, stream=True))[0]
boxes = result.boxes
boxes = boxes.cpu().numpy()
- 遍历所有的 Keypoints
keypoints = result.keypoints
keypoints = keypoints.cpu().numpy()
- 获得所有关键点二维坐标
point1 = (int(x0), int(y0))
point2 = (int(x1), int(y1))
- 计算所有点的深度值
point1_dis = depth_frame.get_distance(x0, y0)
point2_dis = depth_frame.get_distance(x1, y1)
- 计算所有点的三维坐标
point1_dis = depth_frame.get_distance(x0, y0)
point2_dis = depth_frame.get_distance(x1, y1)