diff --git a/src/draw.rs b/src/draw.rs index 7f85480..84165bf 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -11,10 +11,13 @@ pub fn draw_line_dotted( p2: &Point, nb_all: usize, nb_visible: usize, + first_on: bool, ) -> Result, Box> { let mut pl = vec![]; let black = Color { r: 0, g: 0, b: 0 }; + let cmp = if first_on { 0 } else { 1 }; + for _ in 0..nb_all { pl.push(Point { color: black, @@ -23,7 +26,7 @@ pub fn draw_line_dotted( } for i in 0..nb_visible { pl.push(Point { - color: if i % 2 == 0 { p2.color } else { black }, + color: if i % 2 == cmp { p2.color } else { black }, ..*p2 }); } diff --git a/src/qualibration.rs b/src/qualibration.rs index f8b0ca3..562a1a4 100644 --- a/src/qualibration.rs +++ b/src/qualibration.rs @@ -1,15 +1,17 @@ pub mod annalyse; pub mod borders; +pub mod compute_image; use annalyse::{ - annalyse_segment, draw_histograme_bgr_tresh, get_vertical_segment, histogram_3d, image_diff, - image_mean, is_same_frame, + draw_histograme_bgr_tresh, get_horizontal_segment, get_vertical_segment, histogram_3d, + image_diff, image_mean, }; // mean dans le sans moyenne des image use borders::{bord_mult, get_extermities, get_intersection, mix_borders, probabilistic_hough}; +use compute_image::{image_treshold, image_warp, image_warp_treshold}; use std::env::args; use std::time::Instant; -use crate::draw; +use crate::draw::{draw_line, draw_line_dotted}; use crate::point::{Color, Point}; use enum_iterator::{next, Sequence as Seq}; @@ -58,12 +60,14 @@ pub enum Sequence { RightBorder, ReadDir, ComputeArea, - PlayLineDotted, - TakeMultiple(u16), - TakeMultipleEmpty(u16), - ComputeLineDotted, + IdCode1, + IdCode2, Finish, + PlayLineDotted, + EmptyFrame, + ComputeLineDotted, + LinearConstSpeed, // [multiple test] JumpFromTo, @@ -76,6 +80,8 @@ pub enum Sequence { Horizontal(u16), SelectNbAll(u16), ComputeSelectNbAll, + TakeMultiple(u16), + TakeMultipleEmpty(u16), } #[derive(Debug)] @@ -105,6 +111,7 @@ pub struct Qualibration { pub h_size: Size_, pub line_pos: Vec, pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence + pub cnt: usize, } impl Qualibration { @@ -142,7 +149,7 @@ impl Qualibration { tresh: Treshold::new("histogram: 0", 150, 255)?, dir_name: dir_name.clone(), key: 10, - canny_v1: 150, + canny_v1: 170, canny_v2: 255, hough_param: HoughLine { rho: 100, @@ -156,6 +163,7 @@ impl Qualibration { h_size: Size::default(), line_pos: vec![4095; 34], multiple: 20, + cnt: 0, }) } @@ -186,6 +194,7 @@ impl Qualibration { } //println!("sequence: {:?}", self.id); self.frame_prev = self.frame.clone(); + self.cnt += 1; Ok(()) } @@ -202,81 +211,8 @@ impl Qualibration { b: self.b as u8, }; //let color = Color { r: 0, g: 0, b: 50 }; - let p0 = Point { - x: 0., - y: 0., - color, - }; - let p1 = Point { - x: 4095., - y: 0., - color, - }; - let p2 = Point { - x: 4095., - y: 4095., - color, - }; - let p3 = Point { - x: 0., - y: 4095., - color, - }; - let p4 = Point { - x: 0., - y: 1000., - 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, - }, - }; - let p6 = Point { - x: 0., - y: 2000., - 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, - }, - }; - let p8 = Point { - x: 0., - y: 3000., - 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, - }, - }; - + let (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb) = + get_point_to_draw(self.r as u8, self.g as u8, self.b as u8, color.clone()); let nb_all = self.nb_all as usize; let nb_visible = self.nb_visible as usize; let nb_wait = 30; // ca permet de prendre de la vitess en y. Et donc ca permet de @@ -284,11 +220,20 @@ impl Qualibration { if seq.is_some() { match seq.unwrap() { + Sequence::IdCode1 => { + // on va en haut a gauche + // on va a droite en clognotant sur les nombre pair + pl.extend(draw_line_dotted(&pa, &pb, nb_all, nb_visible, true)?); + } + Sequence::IdCode2 => { + // on va en haut a gauche + // on va a droite en clognotant sur les nombre impair + pl.extend(draw_line_dotted(&pa, &pb, nb_all, nb_visible, false)?); + } 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 { @@ -321,32 +266,32 @@ impl Qualibration { } } Sequence::WaitSpace => { - pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?; - pl.extend(draw::draw_line(&p1, &p2, nb_all, nb_visible)?); - pl.extend(draw::draw_line(&p3, &p0, nb_all, nb_visible)?); - pl.extend(draw::draw_line(&p2, &p3, nb_all, nb_visible)?); + pl = draw_line(&p0, &p1, nb_all, nb_visible)?; + pl.extend(draw_line(&p1, &p2, nb_all, nb_visible)?); + pl.extend(draw_line(&p3, &p0, nb_all, nb_visible)?); + pl.extend(draw_line(&p2, &p3, nb_all, nb_visible)?); - pl.extend(draw::draw_line_dotted(&p4, &p5, nb_all, nb_visible)?); - pl.extend(draw::draw_line_dotted(&p6, &p7, nb_all, nb_visible)?); - pl.extend(draw::draw_line_dotted(&p8, &p9, nb_all, nb_visible)?); + pl.extend(draw_line_dotted(&p4, &p5, nb_all, nb_visible, true)?); + pl.extend(draw_line_dotted(&p6, &p7, nb_all, nb_visible, true)?); + pl.extend(draw_line_dotted(&p8, &p9, nb_all, nb_visible, true)?); } Sequence::SelectNbAll(n) => { - pl = draw::draw_line(&p0, &p1, n as usize, n as usize)?; - pl.extend(draw::draw_line(&p1, &p2, n as usize, n as usize)?); - pl.extend(draw::draw_line(&p3, &p0, n as usize, n as usize)?); - pl.extend(draw::draw_line(&p2, &p3, n as usize, n as usize)?); + pl = draw_line(&p0, &p1, n as usize, n as usize)?; + pl.extend(draw_line(&p1, &p2, n as usize, n as usize)?); + pl.extend(draw_line(&p3, &p0, n as usize, n as usize)?); + pl.extend(draw_line(&p2, &p3, n as usize, n as usize)?); } Sequence::UpBorder => { - pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?; + pl = draw_line(&p0, &p1, nb_all, nb_visible)?; } Sequence::RightBorder => { - pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; } Sequence::DownBorder => { - pl = draw::draw_line(&p2, &p3, nb_all, nb_visible)?; + pl = draw_line(&p2, &p3, nb_all, nb_visible)?; } Sequence::LeftBorder => { - pl = draw::draw_line(&p3, &p0, nb_all, nb_visible)?; + pl = draw_line(&p3, &p0, nb_all, nb_visible)?; } Sequence::Vertical(n) => { let p1 = Point { @@ -359,7 +304,7 @@ impl Qualibration { y: 4095., color, }; - pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; } Sequence::Horizontal(n) => { let p1 = Point { @@ -372,7 +317,7 @@ impl Qualibration { y: n as f32, color, }; - pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; } _ => (), } @@ -447,177 +392,264 @@ impl Qualibration { } pub fn compute_sequence(&mut self) -> Result<(), Box> { - 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(); + if self.id.is_none() { + return Ok(()); + } + match self.id.unwrap() { + Sequence::IdCode2 => { + let mut id_code_1 = image_diff(&self.img[8], &self.img[1])?; - let background = image_mean(&backgrounds)?; - let line_dot = image_mean(&lines_dots)?; - let diff = image_diff(&background, &line_dot)?; + id_code_1 = image_warp(&id_code_1, &self.homography, self.h_size)?; + id_code_1 = image_treshold(&id_code_1, &self.tresh)?; - 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 code_seg_1 = get_horizontal_segment(&id_code_1)?; + let code_seg_1 = code_seg_1[1..(code_seg_1.len() - 1)].to_owned(); + //let l = code_seg_1.len(); + //let code_seg_1 = code_seg_1[(l-16)..(l-1)].to_owned(); - 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 = 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; - - background = self.img[1].clone(); - steps = self.img[2..6].into(); - - let mut angles: Vec = vec![]; - for (id, step) in steps.iter().enumerate() { - let lines = get_lines( - &background, - step, - id, - self.canny_v1, - self.canny_v2, - &self.hough_param, - )?; - - for l in lines { - let (x0, y0, x1, y1) = - (l[0] as f64, l[1] as f64, l[2] as f64, l[3] as f64); - - let ang = (y1 - y0).atan2(x1 - x0); - angles.push(ang); - } - println!("ang: {angles:?}"); - } - - // on compare ce qui doit l'etre - } - Sequence::ComputeArea => { - let background: Mat; - let borders: Vec; - - background = self.img[1].clone(); - borders = self.img[2..6].into(); - - // on recupere chaqu'un des 4 bord - let mut bords_pts = vec![]; - for (i, bord) in borders.iter().enumerate() { - let bord_pt = self.get_one_border(&background, &bord, i)?; - bords_pts.push(bord_pt); - } - - //for (i, m) in self.img.iter().enumerate() { - // highgui::imshow(format!("img[{i}]").as_str(), m)?; + //let blue = (i as f64 / code_seg_1.len() as f64) * 255.; + let color_1: VecN = VecN::new(255., 0., 0., 255.); + // on dessine + for i in 0..code_seg_1.len() { + let (((x0, y0), (x1, y1)), size) = code_seg_1[i]; + //line(&mut id_code_1, ); + let s = size as i32; + let x = ((x0 + x1) / 2.) as i32; + let y = ((y0 + y1) / 2.) as i32; + let a = OcvPoint::from_vec2(VecN::from_array([x, y - s])); + let b = OcvPoint::from_vec2(VecN::from_array([x, y + s])); + line(&mut id_code_1, a, b, color_1, 1, LINE_8, 0)?; + //if i < (code_seg_1.len() - 1) { + // let (((x2, y2), _), size) = code_seg_1[i + 1]; + // let x = ((x1 + x2) / 2.) as i32; + // let y = ((y0 + y1) / 2.) as i32; + // let a = OcvPoint::from_vec2(VecN::from_array([x, y - s])); + // let b = OcvPoint::from_vec2(VecN::from_array([x, y + s])); + // line(&mut id_code_1, a, b, color_1, 1, LINE_8, 0)?; //} + } - // on calcul le cadre - let border_pt = get_intersection(&bords_pts); - self.border_pt = bord_mult(border_pt, 1.1); - let color: VecN = VecN::new(255., 128., 0., 255.); - let mut mixed = mix_borders(&background, borders)?; - let b = &self.border_pt; - for i in 0..b.len() { - let j = (i + 1) % self.border_pt.len(); - let pa = VecN::from_array([b[i].0 as i32, b[i].1 as i32]); - let pb = VecN::from_array([b[j].0 as i32, b[j].1 as i32]); - let a = OcvPoint::from_vec2(pa); - let b = OcvPoint::from_vec2(pb); - line(&mut mixed, a, b, color, 1, LINE_AA, 0)?; - } - highgui::imshow("mixed bored", &mixed)?; + let mut id_code_2 = image_diff(&self.img[9], &self.img[1])?; + id_code_2 = image_warp(&id_code_2, &self.homography, self.h_size)?; + id_code_2 = image_treshold(&id_code_2, &self.tresh)?; + let code_seg_2 = get_horizontal_segment(&id_code_2)?; + let l = code_seg_2.len(); + let code_seg_2 = code_seg_2[(l - 16)..(l - 1)].to_owned(); + //highgui::imshow("code 2", &id_code_2)?; + let color_2: VecN = VecN::new(0., 255., 0., 255.); + // on dessine + for i in 0..code_seg_2.len() { + let (((x0, y0), (x1, y1)), size) = code_seg_2[i]; + //line(&mut id_code_2, ); + let s = size as i32; + let x = ((x0 + x1) / 2.) as i32; + let y = ((y0 + y1) / 2.) as i32; + let a = OcvPoint::from_vec2(VecN::from_array([x, y - s])); + let b = OcvPoint::from_vec2(VecN::from_array([x, y + s])); + line(&mut id_code_1, a, b, color_2, 1, LINE_8, 0)?; + //if i < (code_seg_2.len() - 1) { + // let (((x2, y2), _), size) = code_seg_2[i + 1]; + // let x = ((x1 + x2) / 2.) as i32; + // let y = ((y0 + y1) / 2.) as i32; + // let a = OcvPoint::from_vec2(VecN::from_array([x, y - s])); + // let b = OcvPoint::from_vec2(VecN::from_array([x, y + s])); + // line(&mut id_code_2, a, b, color_2, 1, LINE_8, 0)?; + //} + } - let size = self.dst_size; - // ici on va requadrer la partie de la projection laser de l'image - let warped_image_size = Size::new(size, size); - let roi_corners: Vec = self - .border_pt - .iter() - .map(|(x, y)| OcvPoint::new(*x as i32, *y as i32)) - .collect(); - //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 = - dst.iter().map(|(x, y)| OcvPoint::new(*x, *y)).collect(); - let roi_corners_mat = Mat::from_slice(&roi_corners[..])?; - let dst_corners_mat = Mat::from_slice(&dst_corners)?; - let h = calib3d::find_homography( - &roi_corners_mat, - &dst_corners_mat, - &mut Mat::default(), - 0, - 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_CUBIC, // I dont see difference with INTER_CUBIC - core::BORDER_CONSTANT, - Scalar::default(), - )?; // do perspective transformation - highgui::imshow("Warped Image", &warped_image)?; - } - Sequence::ReadDir => { - if !self.capture_mode { - self.load_image()?; - } - } - Sequence::Finish => { - if self.capture_mode { - self.save_image()? - } - } - _ => (), + // on va faire des ligne sur les endroit de scanne + + highgui::imshow("code 1", &id_code_1)?; + + // si on garde les [(len-16)..(len-1)] + + //let mean = image_mean(&[id_code_1, id_code_2])?; + //highgui::imshow("image mean", &mean)?; + + // la on pourrait aussi mettre les segment + + // On va regarder au milieux de code_2 pour voir si on voi un truc sur code_1 + + // fonction warp image + // fonction select thresh + // BOUUUUUH !!! ... t'as eut peur? + // + //let mut id_code_2 = image_diff(&self.img[9], &self.img[1])?; + //id_code_2 = image_warp(&id_code_2, &self.homography, self.h_size)?; + //id_code_2 = image_treshold(&id_code_2, &self.tresh)?; + //highgui::imshow("code 2", &id_code_2)?; } + Sequence::ComputeLineDotted => { + let id1 = 7 + (self.cnt % 22); + let id2 = 30 + (self.cnt % 22); + //let backgrounds = self.img[7..30].to_owned(); + //let lines_dots = self.img[30..52].to_owned(); + let backgrounds = self.img[id1..(id1 + 1)].to_owned(); + let lines_dots = self.img[id2..(id2 + 1)].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_CUBIC, // 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 = 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; + + background = self.img[1].clone(); + steps = self.img[2..6].into(); + + let mut angles: Vec = vec![]; + for (id, step) in steps.iter().enumerate() { + let lines = get_lines( + &background, + step, + id, + self.canny_v1, + self.canny_v2, + &self.hough_param, + )?; + + for l in lines { + let (x0, y0, x1, y1) = (l[0] as f64, l[1] as f64, l[2] as f64, l[3] as f64); + + let ang = (y1 - y0).atan2(x1 - x0); + angles.push(ang); + } + println!("ang: {angles:?}"); + } + + // on compare ce qui doit l'etre + } + Sequence::ComputeArea => { + let background: Mat; + let borders: Vec; + + background = self.img[1].clone(); + borders = self.img[2..6].into(); + + // on recupere chaqu'un des 4 bord + let mut bords_pts = vec![]; + for (i, bord) in borders.iter().enumerate() { + let bord_pt = self.get_one_border(&background, &bord, i)?; + bords_pts.push(bord_pt); + } + + //for (i, m) in self.img.iter().enumerate() { + // highgui::imshow(format!("img[{i}]").as_str(), m)?; + //} + + // on calcul le cadre + let border_pt = get_intersection(&bords_pts); + self.border_pt = bord_mult(border_pt, 1.1); + let color: VecN = VecN::new(255., 128., 0., 255.); + let mut mixed = mix_borders(&background, borders)?; + let b = &self.border_pt; + for i in 0..b.len() { + let j = (i + 1) % self.border_pt.len(); + let pa = VecN::from_array([b[i].0 as i32, b[i].1 as i32]); + let pb = VecN::from_array([b[j].0 as i32, b[j].1 as i32]); + let a = OcvPoint::from_vec2(pa); + let b = OcvPoint::from_vec2(pb); + line(&mut mixed, a, b, color, 1, LINE_AA, 0)?; + } + //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(size, size); + let roi_corners: Vec = self + .border_pt + .iter() + .map(|(x, y)| OcvPoint::new(*x as i32, *y as i32)) + .collect(); + //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 = + dst.iter().map(|(x, y)| OcvPoint::new(*x, *y)).collect(); + let roi_corners_mat = Mat::from_slice(&roi_corners[..])?; + let dst_corners_mat = Mat::from_slice(&dst_corners)?; + let h = calib3d::find_homography( + &roi_corners_mat, + &dst_corners_mat, + &mut Mat::default(), + 0, + 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_CUBIC, // I dont see difference with INTER_CUBIC + core::BORDER_CONSTANT, + Scalar::default(), + )?; // do perspective transformation + //highgui::imshow("Warped Image", &warped_image)?; + } + Sequence::ReadDir => { + if !self.capture_mode { + self.load_image()?; + } + } + Sequence::Finish => { + if self.capture_mode { + self.save_image()? + } + } + _ => (), } Ok(()) } @@ -743,6 +775,89 @@ impl Qualibration { } } +fn get_point_to_draw( + r: u8, + g: u8, + b: u8, + color: Color, +) -> ( + Point, + Point, + Point, + Point, + Point, + Point, + Point, + Point, + Point, + Point, + Point, + Point, +) { + let p0 = Point { + x: 0., + y: 0., + color, + }; + let p1 = Point { + x: 4095., + y: 0., + color, + }; + let p2 = Point { + x: 4095., + y: 4095., + color, + }; + let p3 = Point { + x: 0., + y: 4095., + color, + }; + let p4 = Point { + x: 0., + y: 1000., + color: Color { r, g: 0, b: 0 }, + }; + let p5 = Point { + x: 4095., + y: 1000., + color: Color { r, g: 0, b: 0 }, + }; + let p6 = Point { + x: 0., + y: 2000., + color: Color { r: 0, g, b: 0 }, + }; + let p7 = Point { + x: 4095., + y: 2000., + color: Color { r: 0, g, b: 0 }, + }; + let p8 = Point { + x: 0., + y: 3000., + color: Color { r: 0, g: 0, b }, + }; + let p9 = Point { + x: 4095., + y: 3000., + color: Color { r: 0, g: 0, b }, + }; + + let pa = Point { + x: 0., + y: 4095., + color, + }; + let pb = Point { + x: 4095., + y: 4095., + color, + }; + (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb) +} + // ca c'est les donner manipuler par les slider #[derive(Debug, Clone)] pub struct HoughLine { diff --git a/src/qualibration/annalyse.rs b/src/qualibration/annalyse.rs index 0cfc2ed..4e82325 100644 --- a/src/qualibration/annalyse.rs +++ b/src/qualibration/annalyse.rs @@ -230,6 +230,151 @@ pub fn is_same_frame(frame: &Mat, frame_prev: &Mat) -> Result { } } +// 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_horizontal_segment(m: &Mat) -> Result> { + // 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_x = vec![0.; cols.max(rows) as usize]; + for j in 0..rows { + for i in 0..cols { + let v: &Point3_ = m.at_2d(j, i)?; + if v.x != 0 && v.y != 0 && v.z != 0 { + seg_pt.insert((i, j)); + histo_x[i as usize] += 1.; + } + } + } + + // on determine le debut et la fin de ces plage de valeur en x + let mut histo_limit = vec![]; + for i in (0..(histo_x.len() - 1)).rev() { + if histo_x[i] != 0. && histo_x[i + 1] == 0. { + histo_limit.push(Cnt::End(i)); + } + if histo_x[i] == 0. && histo_x[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, x 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> = segment_iland + .iter() + .map(|iland| { + iland + .iter() + .map(|(x, y)| Pt { + x: *x as f64, + y: *y as f64, + }) + .collect() + }) + .collect(); + + 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 rad_min, mut y_min) = (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 tmp_iland = vec![]; + let mut y_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), + }; + tmp_iland.push(p); + if y_abs_max < p.y.abs() { + y_abs_max = p.y.abs(); + } + } + if y_abs_max < y_min { + y_min = y_abs_max; + 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_r = Pt::mean(&iland_min[..id1]); + let mean_l = Pt::mean(&iland_min[id2..]); + //let mean_r = iland_min[0]; + //let mean_l = 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_r = center + (y_axis * mean_r.y) + (x_axis * mean_r.x); + let pt_l = center + (y_axis * mean_l.y) + (x_axis * mean_l.x); + //segments.push(((pt_l.x as f32, pt_l.y as f32), (pt_r.x as f32, pt_r.y as f32))); + let pt_r_2 = pt_l + (pt_r - pt_l) * 1.5; + let pt_l_2 = pt_r + (pt_l - pt_r) * 1.5; + segments.push(( + ( + ((pt_l_2.x as f32, pt_l_2.y as f32)), + ((pt_r_2.x as f32, pt_r_2.y as f32)), + ), + y_min as f32, + )); + } + + Ok(segments) +} + // 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> { @@ -251,7 +396,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { // 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() { + 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)); } @@ -266,7 +411,6 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { } } - // on regroupe les point par illot. let mut segment_iland = vec![vec![]; limits.len()]; for (x, y) in seg_pt { @@ -296,7 +440,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { // 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. + // 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 @@ -309,28 +453,37 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { // 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.}; + 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 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)}; + 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(){ + if x_abs_max < p.x.abs() { x_abs_max = p.x.abs(); } } @@ -345,7 +498,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { // iland_min = tmp_iland; //} } - iland_min.sort_by(|pta, ptb|{ + iland_min.sort_by(|pta, ptb| { if pta.y < ptb.y { std::cmp::Ordering::Greater } else if pta.y == ptb.y { @@ -367,14 +520,23 @@ pub fn get_vertical_segment(m: &Mat) -> Result> { //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 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))); + 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) diff --git a/src/qualibration/compute_image.rs b/src/qualibration/compute_image.rs new file mode 100644 index 0000000..910047b --- /dev/null +++ b/src/qualibration/compute_image.rs @@ -0,0 +1,43 @@ +use super::Treshold; +use opencv::core::{self, bitwise_and, in_range, Mat, Scalar, Size_}; +use opencv::imgproc; +use opencv::Result; + +pub fn image_warp(img: &Mat, homography: &Mat, h_size: Size_) -> Result { + let mut warped_image = Mat::default(); + imgproc::warp_perspective( + &img, + &mut warped_image, + homography, + h_size, + imgproc::INTER_CUBIC, // I dont see difference with INTER_CUBIC + core::BORDER_CONSTANT, + Scalar::default(), + )?; + + Ok(warped_image) +} + +pub fn image_treshold(img: &Mat, tresh: &Treshold) -> Result { + let (t1, s1, l1) = (tresh.min_0 as f64, tresh.min_1 as f64, tresh.min_2 as f64); + let (t2, s2, l2) = (tresh.max_0 as f64, tresh.max_1 as f64, 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(img, &min, &max, &mut color_selected); + let mut bord_treshed = Mat::default(); + bitwise_and(&img, &img, &mut bord_treshed, &color_selected)?; + + Ok(bord_treshed) +} + +pub fn image_warp_treshold( + img: &Mat, + homography: &Mat, + h_size: Size_, + tresh: &Treshold, +) -> Result { + let warped = image_warp(img, homography, h_size)?; + let treshed = image_treshold(&warped, tresh)?; + Ok(treshed) +} diff --git a/src/utils.rs b/src/utils.rs index 0bfe6b1..b55aa46 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -3,11 +3,11 @@ static NEAR_ZERO: f64 = 0.000001; use std::ops::Add; use std::ops::AddAssign; +use std::ops::Div; +use std::ops::DivAssign; 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 { @@ -28,7 +28,6 @@ impl AddAssign for Pt { } } - impl Sub for Pt { type Output = Self; @@ -110,7 +109,7 @@ impl Pt { } pub fn mean(pts: &[Pt]) -> Pt { - let mut mean = Pt{x: 0., y: 0.}; + let mut mean = Pt { x: 0., y: 0. }; for pt in pts { mean += *pt; }