From 6872c04aa99d43064f88a3f70780d2e111f1c3b3 Mon Sep 17 00:00:00 2001 From: Timo Schneider Date: Mon, 5 May 2025 16:23:53 +0200 Subject: [PATCH] added pipeline --- src/main.rs | 138 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 48 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3ffabae..0c252fd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,84 +1,126 @@ use std::collections::VecDeque; use std::iter::zip; +use std::sync::{mpsc, Arc}; +use std::sync::mpsc::Receiver; +use std::thread; use std::time::{Duration, Instant}; use hdbscan::{Hdbscan, HdbscanHyperParams}; use image::{DynamicImage, ImageReader, Rgb, RgbImage}; use rand::{Rng}; -use show_image::{create_window, ImageInfo, ImageView, PixelFormat}; use rayon::prelude::*; +use show_image::{create_window, ImageInfo, ImageView, PixelFormat}; -fn extract_highlights_and_distort(image: &Vec, width: u32, threshold: u8, downsample: f64) -> Vec> { - let max_rng = (u32::MAX as f64 * downsample) as u32; - let width_2 = width as f64 / 2.0; - let poi = image - .par_iter() - .enumerate() - .filter(move |(_, pixel)| pixel > &&threshold) - .filter(move |_| { - let mut rng = rand::rng(); - rng.random::() < max_rng - }) - .map(move |(i, _)| { - vec![ i as f64 % width as f64 - width_2, i as f64 / width as f64 ] - }); +fn create_extract_thread(image_rx: Receiver>>, width: u32, threshold: u8, downsample: f64) -> Receiver>>> { + let (tx, rx) = mpsc::sync_channel::>>>(1); + thread::spawn(move || { + for image in image_rx { + let max_rng = (u32::MAX as f64 * downsample) as u32; + let width_2 = width as f64 / 2.0; + let poi = image + .par_iter() + .enumerate() + .filter(move |(_, pixel)| pixel > &&threshold) + .filter(move |_| { + let mut rng = rand::rng(); + rng.random::() < max_rng + }) + .map(move |(i, _)| { + vec![ i as f64 % width as f64 - width_2, i as f64 / width as f64 ] + }); - let mut vec = Vec::new(); - vec.par_extend(poi); - vec + let mut vec = Vec::new(); + vec.par_extend(poi); + tx.send(Arc::new(vec)).expect("TODO: panic message"); + } + }); + rx +} + +fn create_cluster_labels_thread(pointcloud_rx: Receiver>>>) -> Receiver<(Arc>>, Arc>)> { + let (clusters_tx, clusters_rx) = mpsc::sync_channel::<(Arc>>, Arc>)>(1); + + thread::spawn(move || { + for pointcloud in pointcloud_rx { + let params = HdbscanHyperParams::builder() + .epsilon(100000.0) + .min_samples(3) + .allow_single_cluster(false) + .min_cluster_size(pointcloud.len() / 8) + .build(); + let labels = Arc::new(Hdbscan::new(&pointcloud, params).cluster().unwrap()); + clusters_tx.send((pointcloud, labels)).unwrap() ; + } + }); + + clusters_rx +} + +fn create_transform_thread() { + thread::spawn(move || { + //let pts :Vec> = Vec::new(x_points, y_points, 1-array) + //let X = H * pts + + }); +} + +fn create_filter_thread() { + +} + +fn dummy_image_spawner_thread() -> Receiver>>{ + let img: DynamicImage = ImageReader::open("./images/lane_detection_loop_80.png").unwrap().decode().unwrap(); + let img_data: Vec = img.clone().into_bytes(); + + let (img_tx, img_rx) = mpsc::sync_channel::>>(1); + + thread::spawn(move || { + loop { + img_tx.send(Arc::new(img_data.clone())).unwrap(); + } + }); + + img_rx } #[show_image::main] fn main() { - - let img: DynamicImage = ImageReader::open("./images/lane_detection_loop_80.png").unwrap().decode().unwrap(); - let width: u32 = img.width(); - let height: u32 = img.height(); - let img_data: Vec = img.clone().into_bytes(); + let image_rx = dummy_image_spawner_thread(); + let pointcloud_rx = create_extract_thread(image_rx, 800, 196, 0.05); + let clusters_rx = create_cluster_labels_thread(pointcloud_rx); let window = create_window("image", Default::default()).unwrap(); let mut t: VecDeque = VecDeque::with_capacity(25); - let params = HdbscanHyperParams::builder() - .epsilon(5.0) - .min_samples(5) - .min_cluster_size(100) - .build(); + let mut now: Instant = Instant::now(); - loop { - let start = Instant::now(); - let poi = extract_highlights_and_distort(&img_data, width, 196, 0.05); - - let clusterer = Hdbscan::new(&poi, params.clone()); - let labels = clusterer.cluster().unwrap(); - - let mut rgb_image = RgbImage::new(width, height); - - zip(poi, labels).for_each(|(pixel, label)| { - if label != -1 { - let color = vec![Rgb([255, 0, 0]), Rgb([0, 255, 0]), Rgb([0, 0, 255]), Rgb([0, 0, 0])][label as usize]; - let x = (pixel[0] + width as f64 / 2.0) as u32; + for (image, labels) in clusters_rx { + let mut rgb_image = RgbImage::new(800, 800); + zip(image.iter(), labels.iter()).for_each(|(pixel, label)| { + if *label != -1 { + let color = vec![Rgb([255, 0, 0]), Rgb([0, 255, 0]), Rgb([0, 0, 255]), Rgb([0, 0, 0])][*label as usize]; + let x = (pixel[0] + 400f64) as u32; rgb_image.put_pixel(x, pixel[1] as u32, color); if pixel[0] > 0.0 { rgb_image.put_pixel(x - 1, pixel[1] as u32, color); } - if pixel[0] < width as f64 - 1.0 { + if pixel[0] < 399f64 { rgb_image.put_pixel(x + 1, pixel[1] as u32, color); } if pixel[1] > 0.0 { rgb_image.put_pixel(x, pixel[1] as u32 - 1, color); } - if pixel[1] < height as f64 - 1.0 { - rgb_image.put_pixel(x, pixel[1] as u32 + 1, Rgb([label as u8 * 8, 0, 0])); + if pixel[1] < 399f64 { + rgb_image.put_pixel(x, pixel[1] as u32 + 1, Rgb([*label as u8 * 8, 0, 0])); } } }); - - let image = ImageView::new(ImageInfo::new(PixelFormat::Rgb8, width, height), rgb_image.iter().as_slice()); + let image = ImageView::new(ImageInfo::new(PixelFormat::Rgb8, 800, 800), rgb_image.iter().as_slice()); window.set_image("camera", image).unwrap(); if t.len() == 25 { t.pop_front(); } - t.push_back(Instant::now() - start); - println!("Avg: {} FPS", 1.0 / (t.iter().map(|d| d.as_secs_f64()).sum::() / t.len() as f64)); + t.push_back(now.elapsed()); + println!("Avg: {:.6} s", (t.iter().map(|d| d.as_secs_f64()).sum::() / t.len() as f64)); + now = Instant::now(); } }