feat: adding segment detection for the laser
The feature need to be better but it's usable.
This commit is contained in:
		
							parent
							
								
									550021a014
								
							
						
					
					
						commit
						6145b585f4
					
				
							
								
								
									
										11
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/main.rs
									
									
									
									
									
								
							| @ -112,7 +112,16 @@ fn run_all() -> Result<(), Box<dyn std::error::Error>> { | ||||
| 
 | ||||
|         qualibration.run_step()?; | ||||
| 
 | ||||
|         if qualibration.capture_mode && (qualibration.id != Some(Sequence::WaitSpace) || qualibration.id != Some(Sequence::PlayLineDotted)) { | ||||
|         let q_id = qualibration.id.clone(); | ||||
|         let mut n = 65534; | ||||
|         if let Sequence::TakeMultiple(m) = q_id.clone().unwrap_or(Sequence::Finish) { | ||||
|             n = m; | ||||
|         }; | ||||
|         if qualibration.capture_mode | ||||
|             && (q_id != Some(Sequence::WaitSpace) | ||||
|                 || q_id != Some(Sequence::PlayLineDotted) | ||||
|                 || n != 65534) | ||||
|         { | ||||
|             let millis = std::time::Duration::from_millis(400); // TODO: find solution to know when change has been done
 | ||||
|             std::thread::sleep(millis); | ||||
|         } | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| pub mod annalyse; | ||||
| pub mod borders; | ||||
| 
 | ||||
| use std::time::Instant; | ||||
| use annalyse::{image_diff, is_same_frame}; | ||||
| use annalyse::{ | ||||
|     annalyse_segment, draw_histograme_bgr_tresh, get_vertical_segment, histogram_3d, image_diff, | ||||
|     image_mean, is_same_frame, | ||||
| }; // mean dans le sans moyenne des image
 | ||||
| use borders::{bord_mult, get_extermities, get_intersection, mix_borders, probabilistic_hough}; | ||||
| use std::env::args; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| use crate::draw; | ||||
| use crate::point::{Color, Point}; | ||||
| @ -35,6 +38,7 @@ use opencv::{ | ||||
| 
 | ||||
| opencv::opencv_branch_4! { | ||||
|     use opencv::imgproc::LINE_AA; | ||||
|     use opencv::imgproc::LINE_8; | ||||
| } | ||||
| opencv::not_opencv_branch_4! { | ||||
|     use opencv::core::LINE_AA; | ||||
| @ -55,10 +59,11 @@ pub enum Sequence { | ||||
|     ReadDir, | ||||
|     ComputeArea, | ||||
|     PlayLineDotted, | ||||
|     TakeMultiple(u16), | ||||
|     TakeMultipleEmpty(u16), | ||||
|     ComputeLineDotted, | ||||
|     Finish, | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     LinearConstSpeed, // [multiple test]
 | ||||
|     JumpFromTo, | ||||
| 
 | ||||
| @ -76,6 +81,7 @@ pub enum Sequence { | ||||
| #[derive(Debug)] | ||||
| pub struct Qualibration { | ||||
|     pub begin: Instant, | ||||
|     pub dst_size: i32, | ||||
|     pub cam: VideoCapture, | ||||
|     pub r: i32, | ||||
|     pub g: i32, | ||||
| @ -98,6 +104,7 @@ pub struct Qualibration { | ||||
|     pub homography: Mat, | ||||
|     pub h_size: Size_<i32>, | ||||
|     pub line_pos: Vec<i32>, | ||||
|     pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence
 | ||||
| } | ||||
| 
 | ||||
| impl Qualibration { | ||||
| @ -119,6 +126,7 @@ impl Qualibration { | ||||
|         //let now = std::time::Instant::now();
 | ||||
|         Ok(Qualibration { | ||||
|             begin: std::time::Instant::now(), | ||||
|             dst_size: 900, | ||||
|             cam, | ||||
|             r: 150, | ||||
|             g: 0, | ||||
| @ -131,7 +139,7 @@ impl Qualibration { | ||||
|             nb_all: 120, | ||||
|             nb_visible: 40, | ||||
|             nb_liss: 10, | ||||
|             tresh: Treshold::new("histogram: 0", 0, 255)?, | ||||
|             tresh: Treshold::new("histogram: 0", 150, 255)?, | ||||
|             dir_name: dir_name.clone(), | ||||
|             key: 10, | ||||
|             canny_v1: 150, | ||||
| @ -147,6 +155,7 @@ impl Qualibration { | ||||
|             homography: Mat::default(), | ||||
|             h_size: Size::default(), | ||||
|             line_pos: vec![4095; 34], | ||||
|             multiple: 20, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
| @ -182,7 +191,7 @@ impl Qualibration { | ||||
| 
 | ||||
|     pub fn draw_sequence(&self) -> Result<Vec<Point>, Box<dyn std::error::Error>> { | ||||
|         if !self.capture_mode { | ||||
|             return Ok(vec![]) | ||||
|             return Ok(vec![]); | ||||
|         } | ||||
|         let seq = self.id; | ||||
|         let mut pl = vec![]; | ||||
| @ -213,62 +222,103 @@ impl Qualibration { | ||||
|             y: 4095., | ||||
|             color, | ||||
|         }; | ||||
| 
 | ||||
|         let p4 = Point { | ||||
|             x: 0., | ||||
|             y: 1000., | ||||
|             color: Color {r: self.r as u8, g:0, b:0}, | ||||
|             color: Color { | ||||
|                 r: self.r as u8, | ||||
|                 g: 0, | ||||
|                 b: 0, | ||||
|             }, | ||||
|         }; | ||||
|         let p5 = Point { | ||||
|             x: 4095., | ||||
|             y: 1000., | ||||
|             color: Color {r: self.r as u8, g:0, b:0}, | ||||
|             color: Color { | ||||
|                 r: self.r as u8, | ||||
|                 g: 0, | ||||
|                 b: 0, | ||||
|             }, | ||||
|         }; | ||||
|         let p6 = Point { | ||||
|             x: 0., | ||||
|             y: 2000., | ||||
|             color: Color {r: 0, g:self.g as u8, b:0}, | ||||
|             color: Color { | ||||
|                 r: 0, | ||||
|                 g: self.g as u8, | ||||
|                 b: 0, | ||||
|             }, | ||||
|         }; | ||||
|         let p7 = Point { | ||||
|             x: 4095., | ||||
|             y: 2000., | ||||
|             color: Color {r: 0, g:self.g as u8, b:0}, | ||||
|             color: Color { | ||||
|                 r: 0, | ||||
|                 g: self.g as u8, | ||||
|                 b: 0, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|         let p8 = Point { | ||||
|             x: 0., | ||||
|             y: 3000., | ||||
|             color: Color {r: 0, g:0, b:self.b as u8}, | ||||
|             color: Color { | ||||
|                 r: 0, | ||||
|                 g: 0, | ||||
|                 b: self.b as u8, | ||||
|             }, | ||||
|         }; | ||||
|         let p9 = Point { | ||||
|             x: 4095., | ||||
|             y: 3000., | ||||
|             color: Color {r: 0, g:0, b:self.b as u8}, | ||||
|             color: Color { | ||||
|                 r: 0, | ||||
|                 g: 0, | ||||
|                 b: self.b as u8, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|         let nb_all = self.nb_all as usize; | ||||
|         let nb_visible = self.nb_visible as usize; | ||||
|         let nb_wait = 20; | ||||
|         let nb_wait = 30; // ca permet de prendre de la vitess en y. Et donc ca permet de
 | ||||
|                           // mieux voir les segment qui bouge peut au debut.
 | ||||
| 
 | ||||
|         if seq.is_some() { | ||||
|             match seq.unwrap() { | ||||
|                 Sequence::PlayLineDotted => { | ||||
|                 Sequence::PlayLineDotted | ||||
|                 | Sequence::TakeMultiple(_) | ||||
|                 | Sequence::ComputeLineDotted => { | ||||
|                     // la on va faire une ligne qu'on peut observer
 | ||||
|                     pl = vec![]; | ||||
|                     let black = Color { r: 0, g: 0, b: 0 }; | ||||
|                     for _ in 0..nb_all { | ||||
|                         pl.push(Point{x: 0., y: 0., color: black}); | ||||
|                         pl.push(Point { | ||||
|                             x: 0., | ||||
|                             y: 0., | ||||
|                             color: black, | ||||
|                         }); | ||||
|                     } | ||||
|                     let len = (2 * self.line_pos.len() + nb_wait) as f32; | ||||
|                     for i in 0..nb_wait { | ||||
|                         let y = i as f32 * 4095. / len; | ||||
|                         pl.push(Point{x: 0., y, color: black}); | ||||
|                         pl.push(Point { | ||||
|                             x: 0., | ||||
|                             y, | ||||
|                             color: black, | ||||
|                         }); | ||||
|                     } | ||||
|                     for i in 0..(self.line_pos.len() * 2) { | ||||
|                         let y = (i + nb_wait) as f32 * 4095. / len; | ||||
|                         let c = if (i + nb_wait) % 2 == 0 && i < nb_visible {color} else {black}; | ||||
|                         pl.push(Point{x: self.line_pos[i/2] as f32, y, color: c}); | ||||
|                         let c = if (i + nb_wait) % 2 == 0 && i < nb_visible { | ||||
|                             color | ||||
|                         } else { | ||||
|                             black | ||||
|                         }; | ||||
|                         pl.push(Point { | ||||
|                             x: self.line_pos[i / 2] as f32, | ||||
|                             y, | ||||
|                             color: c, | ||||
|                         }); | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
|                 Sequence::WaitSpace => { | ||||
|                     pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?; | ||||
| @ -343,6 +393,21 @@ impl Qualibration { | ||||
|         match self.id.unwrap() { | ||||
|             //Sequence::Finish => Some(Sequence::Finish),
 | ||||
|             Sequence::Finish => None, | ||||
|             Sequence::ComputeLineDotted => Some(Sequence::ComputeLineDotted), | ||||
|             Sequence::TakeMultiple(n) => { | ||||
|                 if n > self.multiple { | ||||
|                     next(&Sequence::TakeMultiple(u16::MAX)) | ||||
|                 } else { | ||||
|                     next(&Sequence::TakeMultiple(n)) | ||||
|                 } | ||||
|             } | ||||
|             Sequence::TakeMultipleEmpty(n) => { | ||||
|                 if n > self.multiple { | ||||
|                     next(&Sequence::TakeMultipleEmpty(u16::MAX)) | ||||
|                 } else { | ||||
|                     next(&Sequence::TakeMultipleEmpty(n)) | ||||
|                 } | ||||
|             } | ||||
|             Sequence::SelectNbAll(n) => { | ||||
|                 if n == 0 { | ||||
|                     Some(Sequence::SelectNbAll(2 - 1)) | ||||
| @ -362,7 +427,7 @@ impl Qualibration { | ||||
|             } | ||||
|             Sequence::PlayLineDotted => { | ||||
|                 //println!("key: {}", self.key);
 | ||||
|                 if self.key == 32 { | ||||
|                 if self.key == 32 || !self.capture_mode { | ||||
|                     next(&Sequence::PlayLineDotted) | ||||
|                 } else { | ||||
|                     Some(Sequence::PlayLineDotted) | ||||
| @ -384,6 +449,64 @@ impl Qualibration { | ||||
|     pub fn compute_sequence(&mut self) -> Result<(), Box<dyn std::error::Error>> { | ||||
|         if self.id.is_some() { | ||||
|             match self.id.unwrap() { | ||||
|                 Sequence::ComputeLineDotted => { | ||||
|                     let backgrounds = self.img[7..30].to_owned(); | ||||
|                     let lines_dots = self.img[30..52].to_owned(); | ||||
| 
 | ||||
|                     let background = image_mean(&backgrounds)?; | ||||
|                     let line_dot = image_mean(&lines_dots)?; | ||||
|                     let diff = image_diff(&background, &line_dot)?; | ||||
| 
 | ||||
|                     let mut warped_image = Mat::default(); | ||||
|                     imgproc::warp_perspective( | ||||
|                         &diff, | ||||
|                         &mut warped_image, | ||||
|                         &self.homography, | ||||
|                         self.h_size, | ||||
|                         imgproc::INTER_LINEAR, // I dont see difference with INTER_CUBIC
 | ||||
|                         core::BORDER_CONSTANT, | ||||
|                         Scalar::default(), | ||||
|                     )?; | ||||
|                     //highgui::imshow("Warped Image", &warped_image)?;
 | ||||
| 
 | ||||
|                     let histo = histogram_3d(&warped_image, self.nb_liss)?; | ||||
|                     draw_histograme_bgr_tresh("histo bgr", &histo, &self.tresh)?; | ||||
| 
 | ||||
|                     let (t1, s1, l1) = ( | ||||
|                         self.tresh.min_0 as f64, | ||||
|                         self.tresh.min_1 as f64, | ||||
|                         self.tresh.min_2 as f64, | ||||
|                     ); | ||||
|                     let (t2, s2, l2) = ( | ||||
|                         self.tresh.max_0 as f64, | ||||
|                         self.tresh.max_1 as f64, | ||||
|                         self.tresh.max_2 as f64, | ||||
|                     ); | ||||
|                     let min = Mat::from_slice(&[t1, s1, l1])?; | ||||
|                     let max = Mat::from_slice(&[t2, s2, l2])?; | ||||
|                     let mut color_selected = Mat::default(); | ||||
|                     let _ = in_range(&warped_image, &min, &max, &mut color_selected); | ||||
|                     let mut bord_treshed = Mat::default(); | ||||
|                     bitwise_and( | ||||
|                         &warped_image, | ||||
|                         &warped_image, | ||||
|                         &mut bord_treshed, | ||||
|                         &color_selected, | ||||
|                     )?; | ||||
|                     //highgui::imshow(format!("warped_image & mask").as_str(), &bord_treshed)?;
 | ||||
| 
 | ||||
|                     let segments = get_vertical_segment(&bord_treshed)?; | ||||
|                     for (i, ((x0, y0), (x1, y1))) in segments.iter().enumerate() { | ||||
|                         let blue = (i as f64 / segments.len() as f64) * 255.; | ||||
|                         let color: VecN<f64, 4> = VecN::new(blue, 128., 0., 255.); | ||||
|                         let pa = VecN::from_array([*x0 as i32, *y0 as i32]); | ||||
|                         let pb = VecN::from_array([*x1 as i32, *y1 as i32]); | ||||
|                         let a = OcvPoint::from_vec2(pa); | ||||
|                         let b = OcvPoint::from_vec2(pb); | ||||
|                         line(&mut bord_treshed, a, b, color, 1, LINE_8, 0)?; | ||||
|                     } | ||||
|                     highgui::imshow("segemnt detector", &bord_treshed)?; | ||||
|                 } | ||||
|                 Sequence::ComputeSelectNbAll => { | ||||
|                     let background: Mat; | ||||
|                     let steps: Vec<Mat>; | ||||
| @ -448,14 +571,16 @@ impl Qualibration { | ||||
|                     } | ||||
|                     highgui::imshow("mixed bored", &mixed)?; | ||||
| 
 | ||||
|                     let size = self.dst_size; | ||||
|                     // ici on va requadrer la partie de la projection laser de l'image
 | ||||
|                     let warped_image_size = Size::new(1024, 1024); | ||||
|                     let warped_image_size = Size::new(size, size); | ||||
|                     let roi_corners: Vec<OcvPoint> = self | ||||
|                         .border_pt | ||||
|                         .iter() | ||||
|                         .map(|(x, y)| OcvPoint::new(*x as i32, *y as i32)) | ||||
|                         .collect(); | ||||
|                     let dst = [(0, 0), (0, 1024), (1024, 1024), (1024, 0)]; | ||||
|                     //let dst = [(0, 0), (0, size), (size, size), (size, 0)]; // in: laser repere
 | ||||
|                     let dst = [(0, size), (0, 0), (size, 0), (size, size)]; | ||||
|                     let dst_corners: Vec<OcvPoint> = | ||||
|                         dst.iter().map(|(x, y)| OcvPoint::new(*x, *y)).collect(); | ||||
|                     let roi_corners_mat = Mat::from_slice(&roi_corners[..])?; | ||||
| @ -468,12 +593,14 @@ impl Qualibration { | ||||
|                         3., | ||||
|                     )?; //get homography
 | ||||
|                     let mut warped_image = Mat::default(); | ||||
|                     self.homography = h.clone(); | ||||
|                     self.h_size = warped_image_size.clone(); | ||||
|                     imgproc::warp_perspective( | ||||
|                         &mixed, | ||||
|                         &mut warped_image, | ||||
|                         &h, | ||||
|                         warped_image_size, | ||||
|                         imgproc::INTER_LINEAR, // I dont see difference with INTER_CUBIC
 | ||||
|                         imgproc::INTER_CUBIC, // I dont see difference with INTER_CUBIC
 | ||||
|                         core::BORDER_CONSTANT, | ||||
|                         Scalar::default(), | ||||
|                     )?; // do perspective transformation
 | ||||
| @ -502,7 +629,11 @@ impl Qualibration { | ||||
|         let now = self.begin; | ||||
|         let name = format!("image/"); | ||||
|         create_dir(&name).unwrap_or(()); | ||||
|         let name = format!("image/{:0>6?}_{:0>9?}/", now.elapsed().as_secs(), now.elapsed().as_nanos()); | ||||
|         let name = format!( | ||||
|             "image/{:0>6?}_{:0>9?}/", | ||||
|             now.elapsed().as_secs(), | ||||
|             now.elapsed().as_nanos() | ||||
|         ); | ||||
|         create_dir(&name).unwrap_or(()); | ||||
|         //name.push_str(format!("image/{}_{}/", now.elapsed().as_secs(), now.elapsed().as_nanos()).as_str());
 | ||||
|         //let name = format!("image/{now:?}/");
 | ||||
| @ -572,7 +703,6 @@ impl Qualibration { | ||||
|     ) -> Result<((f64, f64), (f64, f64))> { | ||||
|         let diff: Mat = image_diff(bord, background)?; | ||||
| 
 | ||||
| 
 | ||||
|         //let (t1, s1, l1) = (
 | ||||
|         //    self.tresh.min_0 as f64,
 | ||||
|         //    self.tresh.min_1 as f64,
 | ||||
|  | ||||
| @ -1,5 +1,9 @@ | ||||
| use std::collections::HashSet; | ||||
| use std::f64::consts::PI; | ||||
| 
 | ||||
| use super::Qualibration; | ||||
| use super::DEBUG; | ||||
| use crate::utils::Pt; | ||||
| //use opencv::prelude::MatTraitConst;
 | ||||
| use opencv::prelude::*; //MatTraitConst;
 | ||||
| 
 | ||||
| @ -8,6 +12,12 @@ use opencv::highgui::{self, create_trackbar, named_window, WINDOW_AUTOSIZE}; | ||||
| use opencv::imgproc::{cvt_color, line, COLOR_BGR2GRAY}; | ||||
| use opencv::Result; | ||||
| 
 | ||||
| #[derive(Clone, Copy)] | ||||
| enum Cnt { | ||||
|     Beg(usize), | ||||
|     End(usize), | ||||
| } | ||||
| 
 | ||||
| opencv::opencv_branch_4! { | ||||
|     use opencv::imgproc::LINE_AA; | ||||
| } | ||||
| @ -18,7 +28,7 @@ opencv::not_opencv_branch_4! { | ||||
| use super::Treshold; | ||||
| const MAX_TRACKBAR: i32 = 255; | ||||
| 
 | ||||
| fn draw_histograme_dbg( | ||||
| pub fn draw_histograme_dbg( | ||||
|     window_name: &str, | ||||
|     histo: &Vec<f64>, | ||||
|     (from, to): (usize, usize), | ||||
| @ -56,13 +66,18 @@ fn draw_histograme_dbg( | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn draw_histograme(window_name: &str, histo: &Vec<f64>) -> Result<()> { | ||||
| pub fn draw_histograme(window_name: &str, histo: &Vec<f64>) -> Result<()> { | ||||
|     let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.); | ||||
|     let color: VecN<f64, 4> = VecN::new(255., 255., 255., 255.); | ||||
|     let mut img = Mat::new_rows_cols_with_default(256 * 2, 256 * 2, CV_8UC3, v)?; | ||||
|     let mut img = Mat::new_rows_cols_with_default( | ||||
|         histo.len() as i32 * 2, | ||||
|         histo.len() as i32 * 2, | ||||
|         CV_8UC3, | ||||
|         v, | ||||
|     )?; | ||||
| 
 | ||||
|     let mut max = 0.; | ||||
|     for i in 0..256 { | ||||
|     for i in 0..(histo.len() - 1) { | ||||
|         if histo[i] > max { | ||||
|             max = histo[i]; | ||||
|         } | ||||
| @ -70,13 +85,15 @@ fn draw_histograme(window_name: &str, histo: &Vec<f64>) -> Result<()> { | ||||
| 
 | ||||
|     let v_log = 10.; | ||||
| 
 | ||||
|     for i in 0..255 { | ||||
|     for i in 0..(histo.len() - 1) { | ||||
|         let x1 = ((i + 0) * 2) as i32; | ||||
|         let x2 = ((i + 1) * 2) as i32; | ||||
|         let y1 = | ||||
|             ((histo[i + 0] as f64 + 1.).log(v_log) / (max as f64).log(v_log) * 2. * 256.) as i32; | ||||
|         let y2 = | ||||
|             ((histo[i + 1] as f64 + 1.).log(v_log) / (max as f64).log(v_log) * 2. * 256.) as i32; | ||||
|         let y1 = ((histo[i + 0] as f64 + 1.).log(v_log) / (max as f64).log(v_log) | ||||
|             * 2. | ||||
|             * histo.len() as f64) as i32; | ||||
|         let y2 = ((histo[i + 1] as f64 + 1.).log(v_log) / (max as f64).log(v_log) | ||||
|             * 2. | ||||
|             * histo.len() as f64) as i32; | ||||
|         let pt1 = OcvPoint::new(x1, y1); | ||||
|         let pt2 = OcvPoint::new(x2, y2); | ||||
|         line(&mut img, pt1, pt2, color, 1, LINE_AA, 0)?; | ||||
| @ -87,7 +104,7 @@ fn draw_histograme(window_name: &str, histo: &Vec<f64>) -> Result<()> { | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn draw_histograme_bgr(window_name: &str, histo: &Vec<Vec<f64>>) -> Result<()> { | ||||
| pub fn draw_histograme_bgr(window_name: &str, histo: &Vec<Vec<f64>>) -> Result<()> { | ||||
|     let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.); | ||||
|     let b: VecN<f64, 4> = VecN::new(255., 0., 0., 255.); | ||||
|     let g: VecN<f64, 4> = VecN::new(0., 255., 0., 255.); | ||||
| @ -126,7 +143,7 @@ fn draw_histograme_bgr(window_name: &str, histo: &Vec<Vec<f64>>) -> Result<()> { | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn draw_histograme_bgr_tresh( | ||||
| pub fn draw_histograme_bgr_tresh( | ||||
|     window_name: &str, | ||||
|     histo: &Vec<Vec<f64>>, | ||||
|     tresh: &Treshold, | ||||
| @ -213,6 +230,290 @@ pub fn is_same_frame(frame: &Mat, frame_prev: &Mat) -> Result<bool> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // On cherche des segment regourper par ilot de point. chaque illot a une plage de valeur en y qui
 | ||||
| // lui est propre, aucun autre ilot aura des point dans une plage de valeurs d'un autre illot.
 | ||||
| pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> { | ||||
|     // on va faire un histogram des point selon leur position en y
 | ||||
|     //  ca permetera des les differencier
 | ||||
|     //  on fait cette histo gramme pour connaitre ces plage de valeur en y
 | ||||
|     let mut seg_pt = HashSet::from([]); | ||||
|     let (cols, rows) = (m.cols(), m.rows()); | ||||
|     let mut histo_y = vec![0.; cols.max(rows) as usize]; | ||||
|     for j in 0..rows { | ||||
|         for i in 0..cols { | ||||
|             let v: &Point3_<u8> = m.at_2d(j, i)?; | ||||
|             if v.x != 0 && v.y != 0 && v.z != 0 { | ||||
|                 seg_pt.insert((i, j)); | ||||
|                 histo_y[j as usize] += 1.; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // on determine le debut et la fin de ces palge de l=valeur en y
 | ||||
|     let mut histo_limit = vec![]; | ||||
|     for i in (0..(histo_y.len()-1)).rev() { | ||||
|         if histo_y[i] != 0. && histo_y[i + 1] == 0. { | ||||
|             histo_limit.push(Cnt::End(i)); | ||||
|         } | ||||
|         if histo_y[i] == 0. && histo_y[i + 1] != 0. { | ||||
|             histo_limit.push(Cnt::Beg(i + 1)); | ||||
|         } | ||||
|     } | ||||
|     let mut limits = vec![]; | ||||
|     for k in 0..(histo_limit.len() / 2) { | ||||
|         if let (Cnt::Beg(a), Cnt::End(b)) = (histo_limit[2 * k + 1], histo_limit[2 * k]) { | ||||
|             limits.push((a, b)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // on regroupe les point par illot.
 | ||||
|     let mut segment_iland = vec![vec![]; limits.len()]; | ||||
|     for (x, y) in seg_pt { | ||||
|         let id = get_id_groups(&limits, y as usize).unwrap(); | ||||
|         segment_iland[id].push((x, y)); | ||||
|     } | ||||
| 
 | ||||
|     // on transforme chaque point en pt: (f32, f32) -> Pt
 | ||||
|     // toujours avec la meme structure d'ilot.
 | ||||
|     let segment_iland_pt: Vec<Vec<Pt>> = segment_iland | ||||
|         .iter() | ||||
|         .map(|iland| { | ||||
|             iland | ||||
|                 .iter() | ||||
|                 .map(|(x, y)| Pt { | ||||
|                     x: *x as f64, | ||||
|                     y: *y as f64, | ||||
|                 }) | ||||
|                 .collect() | ||||
|         }) | ||||
|         .collect(); | ||||
| 
 | ||||
|     //  Pour chaque ilot de pixel: on prend le centre, on cherche l'axe qui passe le plus au centre
 | ||||
|     //  de l'illot. Pour trouver cet axe, pour chaque pixel de l'ilot, on va calculer l'eccart au
 | ||||
|     //  carree avec cet axe. On selectionne l'axe qui a l'erreur la plus faible
 | ||||
|     //      TODO: peut etre un meileur algo de recheche de l'axe (dicotomie en partie)
 | ||||
|     //  En suite on tris ces pixel et on prend la moiter la plus haute et la moiter la plus basse
 | ||||
|     //  part raport a l'axe. On fait la mayenne des ces 2 groupe et on a les extremiter haute et
 | ||||
|     //  basse pour cet ilot de pixel. En suite on multiplie par 2 ce segement pour qui soit de la
 | ||||
|     //  taille de l'ilots. 
 | ||||
|     //
 | ||||
|     //  TODO: La selection de l'axe qui passe au centre de l'ilot pourrauiut aussi etre meilleur
 | ||||
|     //          au lieux d'utiliser l'arreur, on pourrait regarder la valeur absolue de la coordoner x la plus petit
 | ||||
|     //          DONE=> j'ai tester une autre methode mais il y a plus d'erreur... mais
 | ||||
|     //          l'orientation des segment est pas mal. En gros l'orientation de l'axe n'est pas
 | ||||
|     //          toujours la meme. C'est du a la fonction de tris. La fonction ne s'execute pas dans
 | ||||
|     //          le meme ordre sur les valeur, Et quand 2 valeurs sont identique, elle peuvent etre
 | ||||
|     //          inter changer.
 | ||||
|     //  TODO: La selection des pixel pour chaque illot pourrait etre ameliorer
 | ||||
|     //          En fait elle me va bien. C'est vrai que il ne sont pas ouf mais bon...
 | ||||
|     let mut segments = vec![]; | ||||
|     for (i, iland) in segment_iland_pt.iter().enumerate() { | ||||
|         let mut center = Pt{x: 0., y: 0.}; | ||||
|         for p in iland { | ||||
|             center += *p; | ||||
|         } | ||||
|         center /= iland.len() as f64; | ||||
|         
 | ||||
|         let max_deg = 360; | ||||
|         let (mut err_min, mut rad_min, mut x_min) = (f64::MAX, 0., f64::MAX); | ||||
|         let mut iland_min = vec![]; | ||||
|         for deg in 0..max_deg { | ||||
|             let rad = (deg as f64) / (max_deg as f64) * PI * 2.; | ||||
|             let y_axis = Pt{x: rad.sin(), y: rad.cos()}; | ||||
|             let x_axis = Pt{x: -y_axis.y, y: y_axis.x}; | ||||
|             let mut err = 0.; | ||||
|             let mut tmp_iland = vec![]; | ||||
|             let mut x_abs_max = f64::MIN; | ||||
|             for pt in iland { | ||||
|                 let mut p = *pt - center; | ||||
|                 p = Pt{x: p.cross(&x_axis), y: p.cross(&y_axis)}; | ||||
|                 err += p.x * p.x; | ||||
|                 tmp_iland.push(p); | ||||
|                 if x_abs_max < p.x.abs(){ | ||||
|                     x_abs_max = p.x.abs(); | ||||
|                 } | ||||
|             } | ||||
|             if x_abs_max < x_min { | ||||
|                 x_min = x_abs_max; | ||||
|                 rad_min = rad; | ||||
|                 iland_min = tmp_iland; | ||||
|             } | ||||
|             //if err < err_min {
 | ||||
|             //    err_min = err;
 | ||||
|             //    rad_min = rad;
 | ||||
|             //    iland_min = tmp_iland;
 | ||||
|             //}
 | ||||
|         } | ||||
|         iland_min.sort_by(|pta, ptb|{ | ||||
|             if pta.y < ptb.y { | ||||
|                 std::cmp::Ordering::Greater | ||||
|             } else if pta.y == ptb.y { | ||||
|                 if pta.x.abs() < ptb.x.abs() { | ||||
|                     std::cmp::Ordering::Greater | ||||
|                 } else if pta.x.abs() == ptb.x.abs() { | ||||
|                     std::cmp::Ordering::Equal | ||||
|                 } else { | ||||
|                     std::cmp::Ordering::Less | ||||
|                 } | ||||
|             } else { | ||||
|                 std::cmp::Ordering::Less | ||||
|             } | ||||
|         }); | ||||
|         let id1 = iland_min.len() / 2; | ||||
|         let id2 = iland_min.len() - id1; | ||||
|         let mean_up = Pt::mean(&iland_min[..id1]); | ||||
|         let mean_down = Pt::mean(&iland_min[id2..]); | ||||
|         //let mean_up = iland_min[0];
 | ||||
|         //let mean_down = iland_min.last().unwrap();
 | ||||
| 
 | ||||
|         let y_axis = Pt{x: rad_min.sin(), y: rad_min.cos()}; | ||||
|         let x_axis = Pt{x: -y_axis.y, y: y_axis.x}; | ||||
|         let pt_up = center + (y_axis * mean_up.y) + (x_axis * mean_up.x); | ||||
|         let pt_down = center + (y_axis * mean_down.y) + (x_axis * mean_down.x); | ||||
|         //segments.push(((pt_down.x as f32, pt_down.y as f32), (pt_up.x as f32, pt_up.y as f32)));
 | ||||
|         let pt_up_2 = pt_down + (pt_up - pt_down)*1.5; | ||||
|         let pt_down_2 = pt_up + (pt_down - pt_up)*1.5; | ||||
|         segments.push(((pt_down_2.x as f32, pt_down_2.y as f32), (pt_up_2.x as f32, pt_up_2.y as f32))); | ||||
|     } | ||||
| 
 | ||||
|     Ok(segments) | ||||
| } | ||||
| 
 | ||||
| fn average_pt_i32(vals: &[(i32, i32)]) -> (f32, f32) { | ||||
|     let (mut mean_x, mut mean_y) = (0., 0.); | ||||
|     let len = vals.len() as f32; | ||||
| 
 | ||||
|     for (x, y) in vals { | ||||
|         mean_x += *x as f32; | ||||
|         mean_y += *y as f32; | ||||
|     } | ||||
|     (mean_x / len, mean_y / len) | ||||
| } | ||||
| 
 | ||||
| fn get_id_groups(limits: &Vec<(usize, usize)>, id: usize) -> Option<usize> { | ||||
|     for (id_seg, (min, max)) in limits.iter().enumerate() { | ||||
|         if id >= *min && id <= *max { | ||||
|             return Some(id_seg); | ||||
|         } | ||||
|     } | ||||
|     None | ||||
|     //return usize::MAX; // im lazy to have Option return...
 | ||||
| } | ||||
| 
 | ||||
| pub fn annalyse_segment(m: &Mat) -> Result<Vec<Vec<(i32, i32)>>> { | ||||
|     // on recupere les coordoner des point selectioner
 | ||||
|     let mut seg_pt = HashSet::from([]); | ||||
|     let (cols, rows) = (m.cols(), m.rows()); | ||||
|     for j in 0..rows { | ||||
|         for i in 0..cols { | ||||
|             let v: &Point3_<u8> = m.at_2d(j, i)?; | ||||
|             if v.x != 0 && v.y != 0 && v.z != 0 { | ||||
|                 seg_pt.insert((i, j)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // on garde que ceux qui sont frontiere
 | ||||
|     //let around_all = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)];
 | ||||
|     let around_all = [(-1, 0), (0, 1), (1, 0), (0, -1)]; | ||||
|     let mut selected: HashSet<(i32, i32)> = seg_pt | ||||
|         .iter() | ||||
|         .filter_map(|(x, y)| { | ||||
|             for (k, (i, j)) in around_all.iter().enumerate() { | ||||
|                 if seg_pt.get(&(*x + i, *y + j)).is_none() { | ||||
|                     return Some((*x, *y)); | ||||
|                 } | ||||
|             } | ||||
|             None | ||||
|         }) | ||||
|         .collect(); | ||||
| 
 | ||||
|     //let around = [(-1, 0), (0, -1), (1, 0), (0, 1), (-1, -1), (1, -1), (1, 1), (-1, 1)];
 | ||||
|     let around = [ | ||||
|         (-1, 1), | ||||
|         (0, 1), | ||||
|         (1, 1), | ||||
|         (1, 0), | ||||
|         (1, -1), | ||||
|         (0, -1), | ||||
|         (-1, -1), | ||||
|         (-1, 0), | ||||
|     ]; | ||||
|     let mut lines = vec![]; | ||||
|     while selected.len() > 0 { | ||||
|         let mut outed: HashSet<(i32, i32)> = HashSet::from([]); | ||||
|         let (x, y) = selected.iter().next().unwrap(); | ||||
|         let mut line = vec![(*x, *y)]; | ||||
| 
 | ||||
|         outed.insert((*x, *y)); | ||||
|         let mut last = 0; | ||||
|         'line: loop { | ||||
|             let (x, y) = line[line.len() - 1]; | ||||
|             for k in 0..around.len() { | ||||
|                 let (i, j) = around[(k + last) % around.len()]; | ||||
|                 if seg_pt.get(&(x + i, y + j)).is_some() && outed.get(&(x + i, y + j)).is_none() { | ||||
|                     line.push((x + i, y + j)); | ||||
|                     outed.insert((x + i, y + j)); | ||||
|                     last = k + last + around.len() - 2; | ||||
|                     // ici on pourrait cleaner le rest
 | ||||
|                     //for l in (k+1)..around.len() {
 | ||||
|                     //    let (i, j) = around[(l+last)%around.len()];
 | ||||
|                     //    outed.insert((x+i, y+j));
 | ||||
|                     //    //
 | ||||
|                     //}
 | ||||
|                     continue 'line; | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         lines.push(line); | ||||
|         for (x, y) in outed { | ||||
|             selected.remove(&(x, y)); | ||||
|         } | ||||
|     } | ||||
|     println!("\nseg: {}", lines.len()); | ||||
|     Ok(lines) | ||||
| } | ||||
| 
 | ||||
| pub fn image_mean(frames: &[Mat]) -> Result<Mat> { | ||||
|     /* | ||||
|      * Il faudrait pouvoir changer les matrice de type pour avoir des valeur plus grande | ||||
|      * */ | ||||
|     let mut frames_big: Vec<Mat> = vec![]; | ||||
|     let len = frames.len() as i16; | ||||
| 
 | ||||
|     for frame in frames { | ||||
|         let mut tmp = Mat::default(); | ||||
|         frame.convert_to(&mut tmp, 19, 1., 0.)?; // 19 is for: CV_16SC3
 | ||||
|         frames_big.push(tmp); | ||||
|     } | ||||
| 
 | ||||
|     let mut img_sum: Mat = frames_big[0].clone(); | ||||
|     let mask = Mat::default(); | ||||
|     for frame in frames_big[1..].iter() { | ||||
|         let mut tmp = Mat::default(); | ||||
|         add(&img_sum, &frame, &mut tmp, &mask, -1)?; | ||||
|         img_sum = tmp; | ||||
|     } | ||||
| 
 | ||||
|     let (cols, rows) = (img_sum.cols(), img_sum.rows()); | ||||
|     for j in 0..rows { | ||||
|         for i in 0..cols { | ||||
|             let v: &mut Point3_<i16> = img_sum.at_2d_mut(j, i)?; | ||||
|             v.x /= len; | ||||
|             v.y /= len; | ||||
|             v.z /= len; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     let mut mean = Mat::default(); | ||||
|     img_sum.convert_to(&mut mean, 16, 1., 0.)?; // 16 is for: CV_8UC3
 | ||||
| 
 | ||||
|     Ok(mean) | ||||
| } | ||||
| 
 | ||||
| pub fn image_diff(frame: &Mat, frame_prev: &Mat) -> Result<Mat> { | ||||
|     let mut diff_bgr = Mat::default(); | ||||
|     let mut diff_bgr_2 = Mat::default(); | ||||
| @ -233,7 +534,7 @@ pub fn image_diff(frame: &Mat, frame_prev: &Mat) -> Result<Mat> { | ||||
|     Ok(d_bgr) | ||||
| } | ||||
| 
 | ||||
| fn histogram_3d(m: &Mat, nb_liss: i32) -> Result<Vec<Vec<f64>>> { | ||||
| pub fn histogram_3d(m: &Mat, nb_liss: i32) -> Result<Vec<Vec<f64>>> { | ||||
|     let (cols, rows) = (m.cols(), m.rows()); | ||||
|     let mut histo = vec![vec![0.; 256]; 3]; | ||||
| 
 | ||||
| @ -262,7 +563,7 @@ fn histogram_3d(m: &Mat, nb_liss: i32) -> Result<Vec<Vec<f64>>> { | ||||
|     Ok(histo) | ||||
| } | ||||
| 
 | ||||
| fn histogram_1d(m: &Mat, nb_liss: i32) -> Result<Vec<f64>> { | ||||
| pub fn histogram_1d(m: &Mat, nb_liss: i32) -> Result<Vec<f64>> { | ||||
|     let (cols, rows) = (m.cols(), m.rows()); | ||||
|     let mut histo = vec![0; 256]; | ||||
|     let mut m_gray = Mat::default(); | ||||
| @ -291,7 +592,7 @@ fn histogram_1d(m: &Mat, nb_liss: i32) -> Result<Vec<f64>> { | ||||
|     Ok(histo) | ||||
| } | ||||
| 
 | ||||
| fn first_invert(histo: &Vec<f64>) -> ((usize, f64), (usize, f64)) { | ||||
| pub fn first_invert(histo: &Vec<f64>) -> ((usize, f64), (usize, f64)) { | ||||
|     // on applique un log puis on normalise mar le log du max
 | ||||
|     let mut normalised = vec![0.; histo.len()]; | ||||
|     let mut p1 = vec![0.; histo.len() / 2]; | ||||
| @ -356,7 +657,11 @@ pub fn trackbar_line_segment(mem: &mut Qualibration, winname: &str) -> Result<() | ||||
|     //highgui
 | ||||
|     let winname = format!("{}: {}", winname, 0); //"bord selected: 0";
 | ||||
|     named_window(winname.as_str(), WINDOW_AUTOSIZE)?; | ||||
|     highgui::move_window(winname.as_str(), 20, 20)?; | ||||
|     highgui::move_window(winname.as_str(), 20, 520)?; | ||||
|     //highgui::move_window(winname, 20, 20)?;
 | ||||
|     let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.); | ||||
|     let m = Mat::new_rows_cols_with_default(1, 1800, CV_8UC3, v)?; | ||||
|     highgui::imshow(winname.as_str(), &m)?; | ||||
|     //
 | ||||
|     create_trackbar( | ||||
|         "canny min", | ||||
| @ -405,7 +710,7 @@ pub fn trackbar_line_segment(mem: &mut Qualibration, winname: &str) -> Result<() | ||||
|         "max_gap : ", | ||||
|         winname.as_str(), | ||||
|         Some(&mut mem.hough_param.max_line_gap), | ||||
|         500000, | ||||
|         50000, | ||||
|         None, | ||||
|     )?; | ||||
|     Ok(()) | ||||
| @ -433,23 +738,25 @@ pub fn line_pos(mem: &mut Qualibration, winname: &str) -> Result<()> { | ||||
| 
 | ||||
| pub fn adding_trackbar(mut mem: &mut Qualibration, winname: &str) -> Result<()> { | ||||
|     //println!("winname: {winname}");
 | ||||
|     line_pos(&mut mem , "Play Line")?; | ||||
|     trackbar_init_param(mem, "init_param")?; | ||||
|     //named_window(winname, WINDOW_AUTOSIZE)?;
 | ||||
|     //associate_trackbar(winname, &mut mem.tresh)?;
 | ||||
|     //create_trackbar(
 | ||||
|     //    "nb_liss",
 | ||||
|     //    winname,
 | ||||
|     //    Some(&mut mem.nb_liss),
 | ||||
|     //    MAX_TRACKBAR,
 | ||||
|     //    None,
 | ||||
|     //)?;
 | ||||
|     //trackbar_line_segment(mem, winname)?;
 | ||||
|     //line_pos(&mut mem, "Play Line")?;
 | ||||
|     //trackbar_init_param(mem, "init_param")?;
 | ||||
| 
 | ||||
|     named_window("histo bgr", WINDOW_AUTOSIZE)?; | ||||
|     associate_trackbar("histo bgr", &mut mem.tresh)?; | ||||
|     create_trackbar( | ||||
|         "nb_liss", | ||||
|         "histo bgr", | ||||
|         Some(&mut mem.nb_liss), | ||||
|         MAX_TRACKBAR, | ||||
|         None, | ||||
|     )?; | ||||
| 
 | ||||
|     //trackbar_line_segment(mem, "line detector")?;
 | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| fn associate_trackbar(winname: &str, tresh: &mut Treshold) -> Result<()> { | ||||
| pub fn associate_trackbar(winname: &str, tresh: &mut Treshold) -> Result<()> { | ||||
|     create_trackbar( | ||||
|         "blue min: ", | ||||
|         winname, | ||||
|  | ||||
							
								
								
									
										43
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/utils.rs
									
									
									
									
									
								
							| @ -2,9 +2,13 @@ use crate::point::Point; | ||||
| static NEAR_ZERO: f64 = 0.000001; | ||||
| 
 | ||||
| use std::ops::Add; | ||||
| use std::ops::AddAssign; | ||||
| use std::ops::Mul; | ||||
| use std::ops::MulAssign; | ||||
| use std::ops::Sub; | ||||
| use std::ops::Div; | ||||
| use std::ops::DivAssign; | ||||
| //use std::ops::BitXor
 | ||||
| 
 | ||||
| impl Add for Pt { | ||||
|     type Output = Self; | ||||
| @ -17,6 +21,14 @@ impl Add for Pt { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl AddAssign for Pt { | ||||
|     fn add_assign(&mut self, other: Self) { | ||||
|         self.x += other.x; | ||||
|         self.y += other.y; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| impl Sub for Pt { | ||||
|     type Output = Self; | ||||
| 
 | ||||
| @ -46,6 +58,24 @@ impl Mul<f64> for Pt { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Div<f64> for Pt { | ||||
|     type Output = Self; | ||||
| 
 | ||||
|     fn div(self, rhs: f64) -> Self { | ||||
|         Pt { | ||||
|             x: self.x / rhs, | ||||
|             y: self.y / rhs, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl DivAssign<f64> for Pt { | ||||
|     fn div_assign(&mut self, rhs: f64) { | ||||
|         self.x /= rhs; | ||||
|         self.y /= rhs; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] | ||||
| pub struct Pt { | ||||
|     pub x: f64, | ||||
| @ -75,9 +105,16 @@ impl Pt { | ||||
|         Self { x, y } | ||||
|     } | ||||
| 
 | ||||
|     pub fn mul_assign(&mut self, rhs: f64) { | ||||
|         self.x *= rhs; | ||||
|         self.y *= rhs; | ||||
|     pub fn cross(&self, other: &Pt) -> f64 { | ||||
|         self.x * other.x + self.y * other.y | ||||
|     } | ||||
| 
 | ||||
|     pub fn mean(pts: &[Pt]) -> Pt { | ||||
|         let mut mean = Pt{x: 0., y: 0.}; | ||||
|         for pt in pts { | ||||
|             mean += *pt; | ||||
|         } | ||||
|         mean / (pts.len() as f64) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user