commit 621a3984d11fdbafba44d9b2146c0456ed909afb Author: Timo Schneider Date: Sun May 4 16:22:49 2025 +0200 init diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d74896c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "line_detection_ros2" +version = "0.1.0" +edition = "2024" + +[profile.release] +opt-level = 2 # Maximum optimization for release + +[dependencies] +image = "0.25.6" +show-image = "0.14.1" +rand = "0.9.1" +rayon = "1.10.0" +linfa = "0.7.1" +linfa-clustering = "0.7.1" +ndarray = "0.16.1" \ No newline at end of file diff --git a/images/lane_detection_loop_20.png b/images/lane_detection_loop_20.png new file mode 100644 index 0000000..e8c5471 Binary files /dev/null and b/images/lane_detection_loop_20.png differ diff --git a/images/lane_detection_loop_60.png b/images/lane_detection_loop_60.png new file mode 100644 index 0000000..ae81d5f Binary files /dev/null and b/images/lane_detection_loop_60.png differ diff --git a/images/lane_detection_loop_80.png b/images/lane_detection_loop_80.png new file mode 100644 index 0000000..8a07822 Binary files /dev/null and b/images/lane_detection_loop_80.png differ diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..fab0196 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,63 @@ +use linfa::traits::Transformer; +use std::collections::VecDeque; +use std::time::{Duration, Instant}; +use image::{DynamicImage, ImageReader, Rgb}; +use linfa_clustering::Dbscan; +use rand::{Rng}; +use show_image::{create_window, ImageInfo, ImageView, PixelFormat}; +use rayon::prelude::*; +use ndarray::{Array2, Axis}; + +use linfa::prelude::*; +// We'll build our dataset on our own using ndarray and rand +use ndarray::prelude::*; + + +fn extract_highlights(image: &Vec, width: u32, threshold: u8, downsample: f64) -> Array2 { + let max_rng = (u32::MAX as f64 * downsample) as u32; + 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, _)| [ i as u32 % width, i as u32 / width ]); + + let mut vec = Vec::new(); + vec.par_extend(poi); + Array2::from(vec) +} + +#[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 window = create_window("image", Default::default()).unwrap(); + let mut t: VecDeque = VecDeque::with_capacity(25); + loop { + let start = Instant::now(); + let poi = extract_highlights(&img_data, width, 196, 1.0); + + let mut rgb_image = img.to_rgb8(); + + + poi.outer_iter().for_each(|pixel| { + rgb_image.put_pixel(pixel[0], pixel[1], Rgb([255, 0, 0])) + }); + + let image = ImageView::new(ImageInfo::new(PixelFormat::Rgb8, width, height), 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)); + } +}