use anyhow::{ensure, Result};
use realsense_rust::{
config::Config,
context::Context,
frame::{DepthFrame, PixelKind},
kind::{Rs2Format, Rs2StreamKind},
pipeline::InactivePipeline,
processing_blocks::{
colorizer::Colorizer, decimation::Decimation, hole_filling::HoleFillingFilter, options::*,
spatial_filter::SpatialFilter, temporal_filter::TemporalFilter, threshold::ThresholdFilter,
},
};
use rerun::{self as rr, external::image};
use std::{collections::HashSet, convert::TryFrom, time::Duration};
fn main() -> Result<()> {
let rec = rr::RecordingStreamBuilder::new("realsense_processing_options").spawn()?;
let context = Context::new()?;
let devices = context.query_devices(HashSet::new());
ensure!(!devices.is_empty(), "No devices found");
println!("Found {} device(s), using the first one", devices.len());
println!("This example demonstrates configurable processing block options.");
let pipeline = InactivePipeline::try_from(&context)?;
let mut config = Config::new();
config.enable_stream(Rs2StreamKind::Depth, Some(0), 640, 480, Rs2Format::Z16, 30)?;
let mut active_pipeline = pipeline.start(Some(config))?;
println!("\nConfiguring processing blocks with custom options...");
let mut decimation = Decimation::new(5)?;
let decimation_opts = DecimationOptions {
filter_magnitude: Some(4.0), };
decimation.apply_options(&decimation_opts)?;
println!("✓ Decimation: 4x magnitude reduction");
let mut spatial_filter = SpatialFilter::new(5)?;
let spatial_opts = SpatialFilterOptions {
smooth_alpha: Some(0.8), smooth_delta: Some(10.0), magnitude: Some(3.0), holes_fill: Some(2.0), };
spatial_filter.apply_options(&spatial_opts)?;
println!("✓ Spatial Filter: Aggressive noise reduction");
let mut temporal_filter = TemporalFilter::new(5)?;
let temporal_opts = TemporalFilterOptions {
smooth_alpha: Some(0.4), smooth_delta: Some(20.0), persistence_control: Some(3.0), };
temporal_filter.apply_options(&temporal_opts)?;
println!("✓ Temporal Filter: Moderate temporal smoothing");
let mut hole_filling = HoleFillingFilter::new(5)?;
let hole_filling_opts = HoleFillingOptions {
holes_fill: Some(2.0), };
hole_filling.apply_options(&hole_filling_opts)?;
println!("✓ Hole Filling: Nearest neighbor interpolation");
let mut threshold_filter = ThresholdFilter::new(5)?;
let threshold_opts = ThresholdOptions {
min_distance: Some(0.3), max_distance: Some(3.0), };
threshold_filter.apply_options(&threshold_opts)?;
println!("✓ Threshold Filter: 0.3m - 3.0m range");
let mut colorizer = Colorizer::new(5)?;
let colorizer_opts = ColorizerOptions {
color_scheme: Some(2.0), histogram_equalization: Some(1.0), min_distance: Some(0.0), max_distance: Some(4.0), };
colorizer.apply_options(&colorizer_opts)?;
println!("✓ Colorizer: Jet color scheme with histogram equalization");
println!("\nStarting processing pipeline...");
println!("Processing: Raw -> Decimation -> Spatial -> Temporal -> Hole Fill -> Threshold -> Colorize");
println!("Press Ctrl+C to quit.");
let mut frame_count = 0;
loop {
let frames = active_pipeline.wait(Some(Duration::from_millis(1000)))?;
let depth_frames: Vec<DepthFrame> = frames.frames_of_type();
if let Some(depth_frame) = depth_frames.into_iter().next() {
frame_count += 1;
let depth_data: Vec<u16> = depth_frame
.iter()
.map(|pixel| match pixel {
PixelKind::Z16 { depth } => *depth,
_ => 0,
})
.collect();
let depth_image: image::ImageBuffer<image::Luma<u16>, Vec<u16>> =
image::ImageBuffer::from_raw(
depth_frame.width() as u32,
depth_frame.height() as u32,
depth_data,
)
.unwrap();
rec.log(
"pipeline/00_original",
&rr::DepthImage::try_from(depth_image)?,
)?;
decimation.queue(depth_frame)?;
let frame = decimation.wait(Duration::from_millis(100))?;
let depth_data: Vec<u16> = frame
.iter()
.map(|pixel| match pixel {
PixelKind::Z16 { depth } => *depth,
_ => 0,
})
.collect();
let depth_image: image::ImageBuffer<image::Luma<u16>, Vec<u16>> =
image::ImageBuffer::from_raw(
frame.width() as u32,
frame.height() as u32,
depth_data,
)
.unwrap();
rec.log(
"pipeline/01_decimated",
&rr::DepthImage::try_from(depth_image)?,
)?;
spatial_filter.queue(frame)?;
let frame = spatial_filter.wait(Duration::from_millis(100))?;
temporal_filter.queue(frame)?;
let frame = temporal_filter.wait(Duration::from_millis(100))?;
hole_filling.queue(frame)?;
let frame = hole_filling.wait(Duration::from_millis(100))?;
threshold_filter.queue(frame)?;
let frame = threshold_filter.wait(Duration::from_millis(100))?;
let depth_data: Vec<u16> = frame
.iter()
.map(|pixel| match pixel {
PixelKind::Z16 { depth } => *depth,
_ => 0,
})
.collect();
let depth_image: image::ImageBuffer<image::Luma<u16>, Vec<u16>> =
image::ImageBuffer::from_raw(
frame.width() as u32,
frame.height() as u32,
depth_data,
)
.unwrap();
rec.log(
"pipeline/02_filtered",
&rr::DepthImage::try_from(depth_image)?,
)?;
colorizer.queue(frame)?;
let colorized_frame = colorizer.wait(Duration::from_millis(100))?;
let mut rgb_data = Vec::new();
for pixel in colorized_frame.iter() {
match pixel {
PixelKind::Bgr8 { b, g, r } => {
rgb_data.extend_from_slice(&[*r, *g, *b]);
}
PixelKind::Rgb8 { r, g, b } => {
rgb_data.extend_from_slice(&[*r, *g, *b]);
}
_ => {
rgb_data.extend_from_slice(&[0, 0, 0]);
}
}
}
rec.log(
"pipeline/03_final_colorized",
&rr::Image::from_rgb24(
rgb_data,
[
colorized_frame.width() as u32,
colorized_frame.height() as u32,
],
),
)?;
if frame_count % 60 == 0 {
println!(
"Processed {} frames - Final resolution: {}x{}",
frame_count,
colorized_frame.width(),
colorized_frame.height()
);
}
}
}
}