Realsense D435i交互式测距实战:Python+OpenCV实现点击任意点深度测量

在计算机视觉和机器人领域,深度相机正变得越来越普及。Intel Realsense D435i作为一款性价比极高的深度感知设备,被广泛应用于三维重建、物体识别和距离测量等场景。传统的单点测距方法通常只能获取画面中心点的深度信息,这在很多实际应用中显得过于局限。本文将带你实现一个更灵活、更具交互性的解决方案——通过鼠标点击实时获取画面中任意位置的深度值。

1. 环境准备与基础配置

在开始编码之前,我们需要确保开发环境已正确配置。以下是所需的软硬件组件:

  • 硬件设备 :Intel Realsense D435i相机(需通过USB 3.0接口连接)
  • Python环境 :建议使用Python 3.7或更高版本
  • 关键库
    • pyrealsense2(Intel官方SDK Python封装)
    • OpenCV(用于图像处理和显示)
    • NumPy(数组处理)

安装依赖库的命令如下:

pip install pyrealsense2 opencv-python numpy

基础配置代码需要初始化相机并设置视频流参数。Realsense D435i可以同时输出RGB图像和深度图,我们需要对齐这两路数据:

import pyrealsense2 as rs
import numpy as np
import cv2

# 初始化管道和配置
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)

# 创建对齐对象(深度对齐到彩色)
align_to_color = rs.align(rs.stream.color)

2. 实现鼠标交互测距功能

2.1 鼠标回调函数设计

OpenCV提供了设置鼠标回调的接口 cv2.setMouseCallback() ,我们可以利用它来实现点击测距功能。首先定义一个全局变量来存储点击位置和深度值:

# 全局变量存储点击位置和深度
click_point = None
depth_value = 0

def mouse_callback(event, x, y, flags, param):
    global click_point, depth_value
    if event == cv2.EVENT_LBUTTONDOWN:
        click_point = (x, y)
        depth_value = depth_frame.get_distance(x, y)

2.2 主循环与实时显示

在主循环中,我们需要不断获取新的帧数据,处理鼠标事件,并实时更新显示:

try:
    while True:
        # 等待获取对齐的帧
        frames = pipeline.wait_for_frames()
        aligned_frames = align_to_color.process(frames)
        
        # 获取深度帧和彩色帧
        depth_frame = aligned_frames.get_depth_frame()
        color_frame = aligned_frames.get_color_frame()
        
        if not depth_frame or not color_frame:
            continue
            
        # 转换为NumPy数组
        depth_image = np.asanyarray(depth_frame.get_data())
        color_image = np.asanyarray(color_frame.get_data())
        
        # 显示彩色图像
        display_image = color_image.copy()
        
        # 如果有点击,显示深度信息
        if click_point:
            x, y = click_point
            cv2.circle(display_image, (x, y), 5, (0, 0, 255), -1)
            text = f"Depth: {depth_value:.2f}m at ({x}, {y})"
            cv2.putText(display_image, text, (x+10, y-10), 
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
        
        # 显示图像并设置鼠标回调
        cv2.imshow('Realsense D435i', display_image)
        cv2.setMouseCallback('Realsense D435i', mouse_callback)
        
        # 按ESC或Q退出
        key = cv2.waitKey(1)
        if key in (27, ord('q')):
            break
            
finally:
    # 停止管道
    pipeline.stop()
    cv2.destroyAllWindows()

3. 性能优化与增强功能

3.1 提高帧率的方法

原始实现可能会遇到帧率较低的问题。以下是几种优化策略:

  1. 降低分辨率 :将640x480降至480x270
  2. 关闭不需要的流 :如果不需要彩色图像,可以只开启深度流
  3. 减少后处理 :避免不必要的图像处理操作

修改配置示例:

# 更高帧率的配置
config.enable_stream(rs.stream.depth, 480, 270, rs.format.z16, 60)
config.enable_stream(rs.stream.color, 480, 270, rs.format.bgr8, 60)

3.2 添加深度图可视化

为了更直观地理解深度数据,可以添加深度图的可视化:

# 创建深度图着色器
colorizer = rs.colorizer()
colorized_depth = np.asanyarray(colorizer.colorize(depth_frame).get_data())

# 水平堆叠显示彩色图和深度图
combined = np.hstack((color_image, colorized_depth))
cv2.imshow('RGB + Depth', combined)

3.3 多点测量与轨迹记录

扩展功能:记录多个测量点并绘制测量轨迹

measure_points = []  # 存储所有测量点

def mouse_callback(event, x, y, flags, param):
    global measure_points
    if event == cv2.EVENT_LBUTTONDOWN:
        depth = depth_frame.get_distance(x, y)
        measure_points.append((x, y, depth))
        
# 在主循环中绘制所有点
for i, (x, y, d) in enumerate(measure_points):
    cv2.circle(display_image, (x, y), 3, (0, 255, 255), -1)
    if i > 0:
        prev_x, prev_y, _ = measure_points[i-1]
        cv2.line(display_image, (prev_x, prev_y), (x, y), (255, 0, 0), 1)
    text = f"{i+1}: {d:.2f}m"
    cv2.putText(display_image, text, (x+5, y-5), 
                cv2.FONT_HERSHEY_PLAIN, 0.8, (255, 255, 255), 1)

4. 实际应用场景与扩展思路

4.1 典型应用场景

这种交互式测距技术可以应用于多种场景:

  • 机器人导航 :实时测量障碍物距离
  • AR/VR应用 :增强现实中的物体交互
  • 工业检测 :测量零件尺寸或位置
  • 智能家居 :手势识别和交互

4.2 扩展功能建议

基于这个基础实现,可以考虑以下扩展方向:

  1. 区域测量 :计算矩形区域内的平均/最大/最小深度
  2. 物体尺寸测量 :结合两个点的深度信息计算实际尺寸
  3. 3D坐标转换 :将2D像素坐标转换为3D世界坐标
  4. 保存测量数据 :将测量结果导出为CSV或JSON格式

区域测量示例代码:

# 定义矩形区域
x1, y1 = 100, 100
x2, y2 = 200, 200

# 提取区域深度数据
roi_depth = depth_image[y1:y2, x1:x2]
avg_depth = np.mean(roi_depth) * depth_frame.get_units()  # 转换为米

# 在图像上绘制区域和结果
cv2.rectangle(display_image, (x1, y1), (x2, y2), (255, 0, 255), 2)
text = f"ROI Avg Depth: {avg_depth:.2f}m"
cv2.putText(display_image, text, (x1, y1-10), 
            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1)

在实际项目中,我发现这种交互式测量方式比固定点测量灵活得多。特别是在调试阶段,能够快速获取场景中任意位置的深度信息大大提高了开发效率。一个实用的技巧是结合深度图着色器,通过颜色直观判断深度范围,然后再用鼠标精确测量感兴趣的区域。

更多推荐