| @@ -29,7 +29,8 @@ members = [ | |||||
| "libraries/shared-memory-server", | "libraries/shared-memory-server", | ||||
| "libraries/extensions/download", | "libraries/extensions/download", | ||||
| "libraries/extensions/telemetry/*", | "libraries/extensions/telemetry/*", | ||||
| "libraries/extensions/dora-record", | |||||
| "tool_nodes/dora-record", | |||||
| "tool_nodes/dora-rerun", | |||||
| "libraries/extensions/ros2-bridge", | "libraries/extensions/ros2-bridge", | ||||
| "libraries/extensions/ros2-bridge/msg-gen", | "libraries/extensions/ros2-bridge/msg-gen", | ||||
| "libraries/extensions/ros2-bridge/python", | "libraries/extensions/ros2-bridge/python", | ||||
| @@ -1,86 +0,0 @@ | |||||
| //! Demonstrates the most barebone usage of the Rerun SDK. | |||||
| use dora_node_api::{ | |||||
| arrow::{ | |||||
| array::{PrimitiveArray, StringArray, UInt8Array}, | |||||
| datatypes::{UInt8Type, Utf8Type}, | |||||
| ipc::Utf8, | |||||
| }, | |||||
| DoraNode, Event, | |||||
| }; | |||||
| use eyre::{Context, Result}; | |||||
| use rerun::{ | |||||
| external::{arrow2::array::Utf8Array, re_types::ArrowBuffer}, | |||||
| TensorBuffer, TensorData, TensorDimension, | |||||
| }; | |||||
| fn main() -> Result<()> { | |||||
| // `serve()` requires to have a running Tokio runtime in the current context. | |||||
| let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime"); | |||||
| let _guard = rt.enter(); | |||||
| let (_node, mut events) = | |||||
| DoraNode::init_from_env().context("Could not initialize dora node")?; | |||||
| let rec = rerun::RecordingStreamBuilder::new("dora-rerun") | |||||
| .spawn() | |||||
| .context("Could not spawn rerun visualization")?; | |||||
| let shape = vec![ | |||||
| TensorDimension { | |||||
| name: Some("width".into()), | |||||
| size: std::env::var("IMAGE_WIDTH") | |||||
| .context("Could not read image width")? | |||||
| .parse() | |||||
| .context("Could not parse value of image width env variable")?, | |||||
| }, | |||||
| TensorDimension { | |||||
| name: Some("height".into()), | |||||
| size: std::env::var("IMAGE_HEIGHT") | |||||
| .context("Could not read image height")? | |||||
| .parse() | |||||
| .context("Could not parse value of image height env variable")?, | |||||
| }, | |||||
| TensorDimension { | |||||
| name: Some("depth".into()), | |||||
| size: std::env::var("IMAGE_DEPTH") | |||||
| .context("Could not read image depth")? | |||||
| .parse() | |||||
| .context("Could not parse value of image depth env variable")?, | |||||
| }, | |||||
| ]; | |||||
| while let Some(event) = events.recv() { | |||||
| match event { | |||||
| Event::Input { | |||||
| id, | |||||
| data, | |||||
| metadata: _, | |||||
| } => { | |||||
| if id.as_str().contains("image") { | |||||
| let buffer: UInt8Array = data.to_data().into(); | |||||
| let buffer: &[u8] = buffer.values(); | |||||
| let buffer = TensorBuffer::U8(ArrowBuffer::from(buffer)); | |||||
| let tensordata = TensorData::new(shape.clone(), buffer.into()); | |||||
| let image = rerun::Image::new(tensordata); | |||||
| rec.log(id.as_str(), &image) | |||||
| .context("could not log image")?; | |||||
| } else if id.as_str().contains("text") { | |||||
| let buffer: StringArray = data.to_data().into(); | |||||
| buffer.iter().try_for_each(|string| -> Result<()> { | |||||
| if let Some(str) = string { | |||||
| rec.log(id.as_str(), &rerun::TextLog::new(str)) | |||||
| .wrap_err("Could not log text") | |||||
| } else { | |||||
| Ok(()) | |||||
| } | |||||
| })?; | |||||
| } | |||||
| } | |||||
| _ => {} | |||||
| } | |||||
| } | |||||
| Ok(()) | |||||
| } | |||||
| @@ -13,3 +13,4 @@ dora-node-api = { workspace = true, features = ["tracing"] } | |||||
| eyre = "0.6.8" | eyre = "0.6.8" | ||||
| tokio = { version = "1.36.0", features = ["rt"] } | tokio = { version = "1.36.0", features = ["rt"] } | ||||
| rerun = { version = "0.15.1", features = ["web_viewer", "image"] } | rerun = { version = "0.15.1", features = ["web_viewer", "image"] } | ||||
| ndarray = "0.15.6" | |||||
| @@ -2,6 +2,8 @@ | |||||
| dora visualization using `rerun` | dora visualization using `rerun` | ||||
| This nodes is still experimental and format for passing Images, Bounding boxes, and text are probably going to change in the future. | |||||
| ## Getting Started | ## Getting Started | ||||
| ```bash | ```bash | ||||
| @@ -0,0 +1,98 @@ | |||||
| //! Demonstrates the most barebone usage of the Rerun SDK. | |||||
| use dora_node_api::{ | |||||
| arrow::array::{Float32Array, StringArray, UInt8Array}, | |||||
| DoraNode, Event, | |||||
| }; | |||||
| use eyre::{Context, Result}; | |||||
| use rerun::{external::re_types::ArrowBuffer, TensorBuffer, TensorData, TensorDimension}; | |||||
| fn main() -> Result<()> { | |||||
| // `serve()` requires to have a running Tokio runtime in the current context. | |||||
| let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime"); | |||||
| let _guard = rt.enter(); | |||||
| let (_node, mut events) = | |||||
| DoraNode::init_from_env().context("Could not initialize dora node")?; | |||||
| let rec = rerun::RecordingStreamBuilder::new("dora-rerun") | |||||
| .spawn() | |||||
| .context("Could not spawn rerun visualization")?; | |||||
| while let Some(event) = events.recv() { | |||||
| match event { | |||||
| Event::Input { | |||||
| id, | |||||
| data, | |||||
| metadata: _, | |||||
| } => { | |||||
| if id.as_str().contains("image") { | |||||
| let shape = vec![ | |||||
| TensorDimension { | |||||
| name: Some("height".into()), | |||||
| size: std::env::var(format!("{}_HEIGHT", id.as_str().to_uppercase())) | |||||
| .context("Could not read image height")? | |||||
| .parse() | |||||
| .context("Could not parse value of image height env variable")?, | |||||
| }, | |||||
| TensorDimension { | |||||
| name: Some("width".into()), | |||||
| size: std::env::var(format!("{}_WIDTH", id.as_str().to_uppercase())) | |||||
| .context("Could not read image width")? | |||||
| .parse() | |||||
| .context("Could not parse value of image width env variable")?, | |||||
| }, | |||||
| TensorDimension { | |||||
| name: Some("depth".into()), | |||||
| size: std::env::var(format!("{}_DEPTH", id.as_str().to_uppercase())) | |||||
| .context("Could not read image depth")? | |||||
| .parse() | |||||
| .context("Could not parse value of image depth env variable")?, | |||||
| }, | |||||
| ]; | |||||
| let buffer: UInt8Array = data.to_data().into(); | |||||
| let buffer: &[u8] = buffer.values(); | |||||
| let buffer = TensorBuffer::U8(ArrowBuffer::from(buffer)); | |||||
| let tensordata = TensorData::new(shape.clone(), buffer.into()); | |||||
| let image = rerun::Image::new(tensordata); | |||||
| rec.log(id.as_str(), &image) | |||||
| .context("could not log image")?; | |||||
| } else if id.as_str().contains("textlog") { | |||||
| let buffer: StringArray = data.to_data().into(); | |||||
| buffer.iter().try_for_each(|string| -> Result<()> { | |||||
| if let Some(str) = string { | |||||
| rec.log(id.as_str(), &rerun::TextLog::new(str)) | |||||
| .wrap_err("Could not log text") | |||||
| } else { | |||||
| Ok(()) | |||||
| } | |||||
| })?; | |||||
| } else if id.as_str().contains("boxes2d") { | |||||
| let buffer: Float32Array = data.to_data().into(); | |||||
| let buffer: &[f32] = buffer.values(); | |||||
| let mut centers = vec![]; | |||||
| let mut sizes = vec![]; | |||||
| let mut classes = vec![]; | |||||
| buffer.chunks(6).for_each(|block| { | |||||
| if let [x, y, w, h, _conf, cls] = block { | |||||
| centers.push((*x, *y)); | |||||
| sizes.push((*w, *h)); | |||||
| classes.push(*cls as u16); | |||||
| } | |||||
| }); | |||||
| rec.log( | |||||
| id.as_str(), | |||||
| &rerun::Boxes2D::from_centers_and_sizes(centers, sizes) | |||||
| .with_class_ids(classes), | |||||
| ) | |||||
| .wrap_err("Could not log Boxes2D")?; | |||||
| } | |||||
| } | |||||
| _ => {} | |||||
| } | |||||
| } | |||||
| Ok(()) | |||||
| } | |||||