use openigtlink_rust::error::Result;
use openigtlink_rust::io::{ClientBuilder, SyncIgtlClient};
use openigtlink_rust::protocol::message::IgtlMessage;
use openigtlink_rust::protocol::types::{
CoordinateSystem, ImageMessage, ImageScalarType,
};
use std::env;
use std::thread;
use std::time::Duration;
fn main() {
if let Err(e) = run() {
eprintln!("[ERROR] {}", e);
std::process::exit(1);
}
}
fn run() -> Result<()> {
let scenario = parse_scenario();
let mut client = ClientBuilder::new()
.tcp("127.0.0.1:18944")
.sync()
.build()?;
println!("[INFO] Connected to OpenIGTLink server\n");
match scenario.as_str() {
"ct" => stream_ct_scan(&mut client)?,
"mri" => stream_mri_scan(&mut client)?,
"ultrasound" => stream_ultrasound(&mut client)?,
_ => unreachable!(),
}
println!("\n[INFO] Streaming completed successfully");
Ok(())
}
fn parse_scenario() -> String {
let args: Vec<String> = env::args().collect();
if args.len() > 1 {
let scenario = args[1].to_lowercase();
if ["ct", "mri", "ultrasound"].contains(&scenario.as_str()) {
return scenario;
}
}
println!("Usage: cargo run --example image_streaming [ct|mri|ultrasound]");
println!("Defaulting to CT scan...\n");
"ct".to_string()
}
fn stream_ct_scan(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== CT Scan Streaming ===");
println!("Resolution: 512x512x100");
println!("Scalar Type: Uint16 (Hounsfield units)");
println!("Spacing: 0.7mm x 0.7mm x 1.0mm\n");
let total_slices = 100;
for slice_num in 0..total_slices {
let image_data = generate_ct_slice(slice_num);
let image = ImageMessage::new(
ImageScalarType::Uint16,
[512, 512, 1],
image_data,
)?
.with_coordinate(CoordinateSystem::LPS);
let msg = IgtlMessage::new(image, "CTScanner")?;
client.send(&msg)?;
print!("\r[CT] Sending slice {}/{}", slice_num + 1, total_slices);
std::io::Write::flush(&mut std::io::stdout()).ok();
thread::sleep(Duration::from_millis(50));
}
println!(); Ok(())
}
fn stream_mri_scan(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== MRI Scan Streaming ===");
println!("Resolution: 256x256x60");
println!("Scalar Type: Float32 (normalized intensity)");
println!("Spacing: 1.0mm x 1.0mm x 2.0mm\n");
let total_slices = 60;
for slice_num in 0..total_slices {
let image_data = generate_mri_slice(slice_num);
let image = ImageMessage::new(
ImageScalarType::Float32,
[256, 256, 1],
image_data,
)?
.with_coordinate(CoordinateSystem::RAS);
let msg = IgtlMessage::new(image, "MRIScanner")?;
client.send(&msg)?;
print!("\r[MRI] Sending slice {}/{}", slice_num + 1, total_slices);
std::io::Write::flush(&mut std::io::stdout()).ok();
thread::sleep(Duration::from_millis(100));
}
println!(); Ok(())
}
fn stream_ultrasound(client: &mut SyncIgtlClient) -> Result<()> {
println!("=== Ultrasound Streaming ===");
println!("Resolution: 640x480");
println!("Scalar Type: Uint8");
println!("Frame Rate: 30 fps");
println!("Duration: 5 seconds\n");
let fps: usize = 30;
let duration_sec: usize = 5;
let total_frames = fps * duration_sec;
let frame_interval = Duration::from_millis(1000 / fps as u64);
for frame_num in 0..total_frames {
let start_time = std::time::Instant::now();
let image_data = generate_ultrasound_frame(frame_num);
let image = ImageMessage::new(
ImageScalarType::Uint8,
[640, 480, 1],
image_data,
)?
.with_coordinate(CoordinateSystem::RAS);
let msg = IgtlMessage::new(image, "UltrasoundProbe")?;
client.send(&msg)?;
print!("\r[US] Streaming frame {}/{} @ {}fps",
frame_num + 1, total_frames, fps);
std::io::Write::flush(&mut std::io::stdout()).ok();
let elapsed = start_time.elapsed();
if elapsed < frame_interval {
thread::sleep(frame_interval - elapsed);
}
}
println!(); Ok(())
}
fn generate_ct_slice(slice_num: usize) -> Vec<u8> {
let width = 512;
let height = 512;
let mut data = Vec::with_capacity(width * height * 2);
for y in 0..height {
for x in 0..width {
let center_x = width as f32 / 2.0;
let center_y = height as f32 / 2.0;
let dx = (x as f32 - center_x) / center_x;
let dy = (y as f32 - center_y) / center_y;
let distance = (dx * dx + dy * dy).sqrt();
let mut value = ((1.0 - distance) * 1500.0 + 500.0) as i16;
value = value.max(-1024).min(3071);
value += (slice_num as i16 * 10) % 200;
let unsigned_value = (value + 1024) as u16;
data.push((unsigned_value & 0xFF) as u8);
data.push((unsigned_value >> 8) as u8);
}
}
data
}
fn generate_mri_slice(slice_num: usize) -> Vec<u8> {
let width = 256;
let height = 256;
let mut data = Vec::with_capacity(width * height * 4);
for y in 0..height {
for x in 0..width {
let center_x = width as f32 / 2.0;
let center_y = height as f32 / 2.0;
let dx = (x as f32 - center_x) / center_x;
let dy = (y as f32 - center_y) / center_y;
let distance = (dx * dx + dy * dy).sqrt();
let mut intensity = (1.0 - distance).max(0.0);
intensity *= 0.7 + 0.3 * ((slice_num as f32 * 0.1).sin() + 1.0) / 2.0;
let bytes = intensity.to_le_bytes();
data.extend_from_slice(&bytes);
}
}
data
}
fn generate_ultrasound_frame(frame_num: usize) -> Vec<u8> {
let width = 640;
let height = 480;
let mut data = Vec::with_capacity(width * height);
for y in 0..height {
for x in 0..width {
let phase = frame_num as f32 * 0.1;
let nx = x as f32 * 0.05 + phase;
let ny = y as f32 * 0.05;
let value = ((nx.sin() * ny.cos() + 1.0) * 127.5) as u8;
let attenuation = 1.0 - (y as f32 / height as f32) * 0.3;
let final_value = (value as f32 * attenuation) as u8;
data.push(final_value);
}
}
data
}