RealSense D435i 图像采集与数据读取

一、相机会读取哪些数据?

1. 彩色图像(RGB / Color)

保存格式:.png 或 .jpg

就像普通相机拍的照片,记录葡萄、叶片、枝梗的颜色和纹理。可用于目标分割、葡萄区域识别,以及给点云添加颜色。

2. 原始深度图(Depth)

保存格式:16 位 png、.npy

图像的每个像素记录对应位置的深度值。它是生成三维点云的关键输入。深度为 0 的像素通常表示没有有效深度测量。

3. 三维点云(Point Cloud)

保存格式:.ply、.pcd

每个点包含三维坐标 \((x,y,z)\),还可以附带 RGB 颜色。点云不是相机直接输出的原始图像,而是利用深度、相机内参等数据计算得到的。

4. 相机标定参数与采集信息

保存格式:.json 或 .csv

包括焦距、主点坐标、畸变参数、深度比例尺、深度与彩色相机之间的外参、时间戳和帧编号。

5.左右红外图像

6.内置六轴 IMU(加速度计和陀螺仪)数据


二、这些数据之间是什么关系?

三、数据的保存

方法一:纯 SDK(Python)

1.安装 pyrealsense2

bash 复制代码
pip install pyrealsense2

2.基础读取 + 保存(彩色、深度、点云、相机内参、外参、深度比例尺与时间戳)

单帧采集

新建data.py

操作方式:

  • 运行程序后,窗口会同时显示彩色图像和深度预览。

  • 按 S:保存当前这一组数据。

  • 按 Q:退出程序

python 复制代码
import os
import json
from datetime import datetime

import cv2
import numpy as np
import pyrealsense2 as rs


# ==========================================
# 1. 基本设置
# ==========================================
SAVE_ROOT = "realsense_data"
os.makedirs(SAVE_ROOT, exist_ok=True)

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
)

# 启动相机
profile = pipeline.start(config)
device = profile.get_device()

# 获取深度比例尺:原始深度单位转换为米
depth_scale = device.first_depth_sensor().get_depth_scale()

# 将深度图对齐到彩色图像坐标系
align = rs.align(rs.stream.color)

# 点云计算对象
pc = rs.pointcloud()


# ==========================================
# 2. 辅助函数:读取相机标定参数
# ==========================================
def get_device_info(device, key):
    try:
        return device.get_info(key)
    except Exception:
        return None


def get_intrinsics(frame):
    intr = frame.profile.as_video_stream_profile().intrinsics

    return {
        "width": int(intr.width),
        "height": int(intr.height),
        "fx": float(intr.fx),
        "fy": float(intr.fy),
        "cx": float(intr.ppx),
        "cy": float(intr.ppy),
        "distortion_model": str(intr.model),
        "distortion_coefficients": [
            float(v) for v in intr.coeffs
        ]
    }


def get_extrinsics(depth_frame, color_frame):
    ext = depth_frame.profile.get_extrinsics_to(
        color_frame.profile
    )

    return {
        "rotation": [float(v) for v in ext.rotation],
        "translation_m": [
            float(v) for v in ext.translation
        ]
    }


# ==========================================
# 3. 保存当前一组数据
# ==========================================
def save_sample(
    depth_frame,
    color_frame,
    aligned_depth_frame,
    depth_raw,
    color_bgr,
    aligned_depth_raw
):
    # 每次采集创建独立文件夹
    sample_name = datetime.now().strftime(
        "sample_%Y%m%d_%H%M%S_%f"
    )
    sample_dir = os.path.join(SAVE_ROOT, sample_name)
    os.makedirs(sample_dir, exist_ok=True)

    # 原始深度单位转换为米
    depth_m = (
        depth_raw.astype(np.float32) * depth_scale
    )
    aligned_depth_m = (
        aligned_depth_raw.astype(np.float32) * depth_scale
    )

    # 1) 保存彩色图像
    cv2.imwrite(
        os.path.join(sample_dir, "color.png"),
        color_bgr
    )

    # 2) 保存原始深度图
    # PNG 保留 uint16 数值,不要先转成 8 位图
    cv2.imwrite(
        os.path.join(sample_dir, "depth_raw_z16.png"),
        depth_raw
    )
    np.save(
        os.path.join(sample_dir, "depth_raw_z16.npy"),
        depth_raw
    )

    # 3) 保存以米为单位的深度数组
    np.save(
        os.path.join(sample_dir, "depth_m.npy"),
        depth_m
    )

    # 4) 保存对齐到彩色图像的深度数据
    cv2.imwrite(
        os.path.join(
            sample_dir, "depth_aligned_to_color_z16.png"
        ),
        aligned_depth_raw
    )
    np.save(
        os.path.join(
            sample_dir, "depth_aligned_to_color_m.npy"
        ),
        aligned_depth_m
    )

    # 5) 保存深度可视化图,仅供观察,不用于精度计算
    valid = depth_raw > 0
    depth_vis_gray = np.zeros(
        depth_raw.shape, dtype=np.uint8
    )

    # 0.2~2.0 m 仅用于设置显示范围
    depth_vis_gray[valid] = np.clip(
        (depth_m[valid] - 0.2) / (2.0 - 0.2) * 255,
        0, 255
    ).astype(np.uint8)

    depth_vis = cv2.applyColorMap(
        depth_vis_gray, cv2.COLORMAP_JET
    )
    depth_vis[~valid] = (0, 0, 0)

    cv2.imwrite(
        os.path.join(sample_dir, "depth_preview.png"),
        depth_vis
    )

    # 6) 根据原始深度生成带颜色的三维点云
    pc.map_to(color_frame)
    points = pc.calculate(depth_frame)

    points.export_to_ply(
        os.path.join(sample_dir, "pointcloud_rgb.ply"),
        color_frame
    )

    # 7) 保存标定参数和采集信息
    metadata = {
        "camera_name": get_device_info(
            device, rs.camera_info.name
        ),
        "serial_number": get_device_info(
            device, rs.camera_info.serial_number
        ),
        "firmware_version": get_device_info(
            device, rs.camera_info.firmware_version
        ),
        "depth_scale_m_per_unit": float(depth_scale),
        "depth_raw_note": (
            "depth_m = depth_raw_z16 * "
            "depth_scale_m_per_unit; raw=0 means invalid"
        ),
        "depth_timestamp_ms": float(
            depth_frame.get_timestamp()
        ),
        "color_timestamp_ms": float(
            color_frame.get_timestamp()
        ),
        "depth_frame_number": int(
            depth_frame.get_frame_number()
        ),
        "color_frame_number": int(
            color_frame.get_frame_number()
        ),
        "depth_intrinsics": get_intrinsics(depth_frame),
        "color_intrinsics": get_intrinsics(color_frame),
        "depth_to_color_extrinsics": get_extrinsics(
            depth_frame, color_frame
        ),
        "depth_aligned_to_color": True,
        "coordinate_unit": "meter"
    }

    with open(
        os.path.join(sample_dir, "metadata.json"),
        "w",
        encoding="utf-8"
    ) as f:
        json.dump(
            metadata, f, ensure_ascii=False, indent=2
        )

    print("已保存一组数据:", sample_dir)


# ==========================================
# 4. 实时采集与键盘控制
# ==========================================
try:
    # 预热相机,等待自动曝光等状态稳定
    for _ in range(30):
        pipeline.wait_for_frames()

    print("相机已启动。")
    print("按 S 保存一组数据;按 Q 退出。")

    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

        # 对齐深度到彩色图像
        aligned_frames = align.process(frames)
        aligned_depth_frame = (
            aligned_frames.get_depth_frame()
        )

        if not aligned_depth_frame:
            continue

        # 读取相机输出
        depth_raw = np.asanyarray(
            depth_frame.get_data()
        )
        color_bgr = np.asanyarray(
            color_frame.get_data()
        )
        aligned_depth_raw = np.asanyarray(
            aligned_depth_frame.get_data()
        )

        # 生成仅供预览的深度图
        depth_m = (
            depth_raw.astype(np.float32) * depth_scale
        )
        valid = depth_raw > 0
        depth_vis_gray = np.zeros(
            depth_raw.shape, dtype=np.uint8
        )
        depth_vis_gray[valid] = np.clip(
            (depth_m[valid] - 0.2) / 1.8 * 255,
            0, 255
        ).astype(np.uint8)

        depth_vis = cv2.applyColorMap(
            depth_vis_gray, cv2.COLORMAP_JET
        )
        depth_vis[~valid] = (0, 0, 0)

        # 左侧彩色图,右侧深度预览
        preview = np.hstack((color_bgr, depth_vis))
        cv2.imshow("RGB | Depth", preview)

        key = cv2.waitKey(1) & 0xFF

        if key == ord("s"):
            save_sample(
                depth_frame,
                color_frame,
                aligned_depth_frame,
                depth_raw,
                color_bgr,
                aligned_depth_raw
            )

        elif key == ord("q"):
            break

finally:
    pipeline.stop()
    cv2.destroyAllWindows()
    print("相机已关闭。")

连续采集

使用 RealSense 的 .bag 录制功能。.bag 是相机数据记录文件,可以保存配置的传感器数据流及其时间信息,之后再回放、处理和导出点云。官方 SDK 支持这种录制与回放流程。

python 复制代码
import pyrealsense2 as rs

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
)

# 开始采集前指定录制文件
config.enable_record_to_file("grape_capture.bag")

pipeline.start(config)

print("正在录制 RGB 和深度数据。")
print("按 Ctrl+C 停止录制。")

try:
    while True:
        pipeline.wait_for_frames()

except KeyboardInterrupt:
    print("正在停止录制...")

finally:
    pipeline.stop()
    print("录制结束,请检查 grape_capture.bag")

代码会持续录制彩色图像和深度数据,直到按 Ctrl+C 停止

相关推荐
小豆庄1 天前
Mac 上给视频人脸打码:本地工具的依赖、追踪与推理管线
算法·视觉检测·视频·敏捷流程·纹理贴图
朗锐智科_机器视觉1 天前
纺织布匹表面疵点视觉检测实战:从验布机到成品检验的完整方案设计
视觉检测·机器视觉·工业相机·硬件选型·朗锐智科·纺织检测
工业视觉老A1 天前
攻克牙膏朝向人工分拣痛点,AI 视觉检测保障包装工序稳定
人工智能·计算机视觉·视觉检测
济南凡维1 天前
智能相机 VS 工业相机:机器视觉选型一次讲透
网络·数码相机·视觉检测
Raymond16882 天前
AI配音工具长文本合成架构技术解析:全局音色锚定与声学状态跟踪
人工智能·架构·实时互动·视觉检测·音视频·语音识别
工业视觉老A4 天前
攻克西林瓶液位人工灯检短板,AI 视觉检测保障灌装剂量稳定
人工智能·计算机视觉·视觉检测
VisionDataLab6 天前
机器视觉技改可扩展性设计:模块化视觉架构,实现分阶段工位扩容
自动化·视觉检测
波力海苔夹心脆6756 天前
VisionMaster 常用工具入门:图像采集、定位、测量、识别一篇打通
经验分享·机器人·视觉检测·工业相机·visionmaster·海康
VisionDataLab7 天前
机器视觉项目落地周期优化:一体化预标定方案,削减现场调试停机时长
自动化·视觉检测