use std::error::Error;
use std::time::Duration;
use depthai::camera::{CameraNode, CameraOutputConfig};
use depthai::common::{CameraBoardSocket, ImageFrameType, ResizeMode};
use depthai::pipeline::Pipeline;
use depthai::{DepthUnit, Device, DevicePlatform, ImageAlignNode, RgbdNode, StereoDepthNode, StereoPresetMode};
use depthai::pointcloud::rgba32_from_rgba;
use depthai::{RerunHostNode, RerunHostNodeConfig, RerunViewer, RerunWebConfig};
use rerun as rr;
fn main() -> Result<(), Box<dyn Error>> {
let device = Device::new()?;
let platform = device.platform()?;
let is_rvc4 = matches!(platform, DevicePlatform::Rvc4);
let disable_pointclound = std::env::var("DEPTHAI_DISABLE_POINTCLOUD")
.ok()
.map(|v| matches!(v.as_str(), "1" | "true" | "TRUE" | "yes" | "YES"))
.unwrap_or(false);
let (frame_w, frame_h) = if is_rvc4 { (640, 400) } else { (640, 400) };
let fps = if is_rvc4 { 15.0 } else { 30.0 };
let _ = device.set_ir_laser_dot_projector_intensity(0.3);
let pipeline = Pipeline::new().with_device(&device).build()?;
let _web = pipeline.create_with::<RerunHostNode, _>(RerunHostNodeConfig {
app_id: "depthai_rgbd_server".to_string(),
viewer: RerunViewer::Web(RerunWebConfig {
open_browser: false,
..Default::default()
}),
..Default::default()
})?;
let rec = rr::RecordingStreamBuilder::new("depthai_rgbd").connect_grpc()?;
let cam_color = pipeline.create_with::<CameraNode, _>(CameraBoardSocket::CamA)?;
let cam_left = pipeline.create_with::<CameraNode, _>(CameraBoardSocket::CamB)?;
let cam_right = pipeline.create_with::<CameraNode, _>(CameraBoardSocket::CamC)?;
let out_color = cam_color.request_output(CameraOutputConfig {
size: (frame_w, frame_h),
frame_type: Some(ImageFrameType::RGB888i),
resize_mode: ResizeMode::Crop,
fps: Some(fps),
enable_undistortion: None,
})?;
let out_left = cam_left.request_output(CameraOutputConfig {
size: (frame_w, frame_h),
frame_type: Some(ImageFrameType::GRAY8),
resize_mode: ResizeMode::Crop,
fps: Some(fps),
enable_undistortion: None,
})?;
let out_right = cam_right.request_output(CameraOutputConfig {
size: (frame_w, frame_h),
frame_type: Some(ImageFrameType::GRAY8),
resize_mode: ResizeMode::Crop,
fps: Some(fps),
enable_undistortion: None,
})?;
let stereo = pipeline.create::<StereoDepthNode>()?;
stereo.set_default_profile_preset(if is_rvc4 {
StereoPresetMode::Default
} else {
StereoPresetMode::Robotics
});
stereo.set_left_right_check(!is_rvc4);
stereo.set_output_size(frame_w as i32, frame_h as i32);
stereo.set_output_keep_aspect_ratio(true);
out_left.link_to(stereo.as_node(), Some("left"))?;
out_right.link_to(stereo.as_node(), Some("right"))?;
let depth_out = stereo.as_node().output("depth")?;
let depth_to_rgbd = if is_rvc4 {
let align = pipeline.create::<ImageAlignNode>()?;
align.set_run_on_host(true);
align.set_output_size(frame_w as i32, frame_h as i32);
align.set_out_keep_aspect_ratio(true);
depth_out.link_to(align.as_node(), Some("input"))?;
out_color.link_to(align.as_node(), Some("inputAlignTo"))?;
align.as_node().output("outputAligned")?
} else {
out_color.link_to(stereo.as_node(), Some("inputAlignTo"))?;
depth_out
};
let rgbd = pipeline.create::<RgbdNode>()?;
rgbd.set_depth_unit(DepthUnit::Meter);
rgbd.build_ex(
false,
if is_rvc4 { StereoPresetMode::Default } else { StereoPresetMode::Robotics },
(frame_w as i32, frame_h as i32),
Some(fps),
)?;
out_color.link_to(rgbd.as_node(), Some("inColorSync"))?;
depth_to_rgbd.link_to(rgbd.as_node(), Some("inDepthSync"))?;
let debug_sizes = std::env::var("DEPTHAI_DEBUG_SIZES")
.ok()
.map(|v| matches!(v.as_str(), "1" | "true" | "TRUE" | "yes" | "YES"))
.unwrap_or(false);
let q_dbg_color = if debug_sizes {
Some(out_color.create_queue(2, false)?)
} else {
None
};
let q_dbg_depth = if debug_sizes {
Some(depth_to_rgbd.create_queue(2, false)?)
} else {
None
};
let q_pcl = if !disable_pointclound {
Some(rgbd.as_node().output("pcl")?.create_queue(2, false)?)
} else {
eprintln!("Pointcloud logging disabled (set DEPTHAI_DISABLE_POINTCLOUD=1 to enable)");
None
};
let q_rgbd = rgbd.as_node().output("rgbd")?.create_queue(2, false)?;
pipeline.start()?;
if let (Some(qc), Some(qd)) = (q_dbg_color.as_ref(), q_dbg_depth.as_ref()) {
for i in 0..2 {
let c = qc.blocking_next(Some(Duration::from_millis(500)))?;
let d = qd.blocking_next(Some(Duration::from_millis(500)))?;
eprintln!("debug_sizes[{i}]: color={:?} depth={:?}", c.as_ref().map(|f| f.describe()), d.as_ref().map(|f| f.describe()));
}
}
let mut frame_nr: i64 = 0;
loop {
rec.set_time_sequence("frame", frame_nr);
frame_nr += 1;
if let Some(rgbd_msg) = q_rgbd.blocking_next_rgbd(Some(Duration::from_millis(200)))? {
let rgb = rgbd_msg.rgb_frame()?;
let w = rgb.width();
let h = rgb.height();
let bytes = rgb.bytes();
rec.log("rgb", &rr::Image::from_rgb24(bytes, [w, h]))?;
}
if let Some(q_pcl) = q_pcl.as_ref() {
if let Some(pcl) = q_pcl.try_next_pointcloud()? {
let pts = pcl.points();
let step = 4usize;
let mut positions = Vec::with_capacity(pts.len() / step + 1);
let mut colors = Vec::with_capacity(pts.len() / step + 1);
for p in pts.iter().step_by(step) {
if !p.x.is_finite() || !p.y.is_finite() || !p.z.is_finite() {
continue;
}
if p.z == 0.0 {
continue;
}
positions.push(rr::Position3D::from([p.x, p.y, p.z]));
colors.push(rr::Color::from(rr::Rgba32(rgba32_from_rgba(p.r, p.g, p.b, p.a))));
}
rec.log("pcl", &rr::Points3D::new(positions).with_colors(colors))?;
}
}
}
}