diff --git a/.gitignore b/.gitignore index 5ea1abc..b2706ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ *.png image target -settings.toml diff --git a/src/draw.rs b/src/draw.rs index f904f30..84165bf 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -7,12 +7,12 @@ const X_CENTER: f32 = 2047.0; const Y_CENTER: f32 = 2047.0; pub fn draw_line_dotted( - p0: &Point, p1: &Point, + p2: &Point, nb_all: usize, nb_visible: usize, first_on: bool, -) -> Vec { +) -> Result, Box> { let mut pl = vec![]; let black = Color { r: 0, g: 0, b: 0 }; @@ -21,56 +21,61 @@ pub fn draw_line_dotted( for _ in 0..nb_all { pl.push(Point { color: black, - ..*p0 + ..*p1 }); } for i in 0..nb_visible { pl.push(Point { - color: if i % 2 == cmp { p1.color } else { black }, - ..*p1 + color: if i % 2 == cmp { p2.color } else { black }, + ..*p2 }); } if nb_visible > nb_all { - return pl; + return Ok(pl); } for _ in 0..(nb_all - nb_visible) { pl.push(Point { color: black, - ..*p1 + ..*p2 }); } - pl + Ok(pl) } -pub fn draw_line(p0: &Point, p1: &Point, nb_all: usize, nb_visible: usize) -> Vec { +pub fn draw_line( + p1: &Point, + p2: &Point, + nb_all: usize, + nb_visible: usize, +) -> Result, Box> { let mut pl = vec![]; let black = Color { r: 0, g: 0, b: 0 }; for _ in 0..nb_all { pl.push(Point { color: black, - ..*p0 + ..*p1 }); } for _ in 0..nb_visible { - pl.push(*p1); + pl.push(*p2); } if nb_visible > nb_all { - return pl; + return Ok(pl); } for _ in 0..(nb_all - nb_visible) { pl.push(Point { color: black, - ..*p1 + ..*p2 }); } - pl + Ok(pl) } #[allow(dead_code)] -pub fn draw(_time: f64) -> Vec { +pub fn draw(_time: f64) -> Result, Box> { let mut v: Vec = vec![]; for i in 0..128 { let a = i as f32 / 128.0 * std::f32::consts::PI * 2.0; @@ -84,5 +89,5 @@ pub fn draw(_time: f64) -> Vec { }, }); } - v + Ok(v) } diff --git a/src/framerate.rs b/src/framerate.rs index 5b55ebe..cfca9f6 100644 --- a/src/framerate.rs +++ b/src/framerate.rs @@ -1,10 +1,8 @@ -#[allow(unused)] use log::{debug, warn}; use std::thread; use std::time::{Duration, Instant}; /// Converts helios Geometry to Helios -#[allow(dead_code)] #[derive(Debug, Clone, Copy)] pub struct Framerate { start: Instant, @@ -12,7 +10,6 @@ pub struct Framerate { framerate: u8, } -#[allow(dead_code)] impl Framerate { pub fn new(framerate: u8) -> Result> { Ok(Framerate { @@ -21,7 +18,7 @@ impl Framerate { framerate, }) } - pub fn handle_time(&mut self) -> Result> { + pub fn handle_time(&mut self) -> Result<(f64), Box> { let frame_time = 1000000000 / self.framerate as u128; let now = Instant::now(); // How long since last loop ? diff --git a/src/main.rs b/src/main.rs index c9e6f12..011300e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ mod point; mod qualibration; mod utils; -use qualibration::{annalyse::adding_trackbar, Qualibration}; +use qualibration::{annalyse::adding_trackbar, Qualibration, Sequence}; use conf::Conf; use log::{/*debug, warn, */ error, info}; @@ -57,7 +57,7 @@ fn run_all() -> Result<(), Box> { let client = Client::open(config.redis_url.clone())?; let mut con: Connection = client.get_connection()?; - let mut _framerate_handler = framerate::Framerate::new(config.framerate)?; + let mut framerate_handler = framerate::Framerate::new(config.framerate)?; // Setup handler for interrupt Signals let running = Arc::new(AtomicBool::new(true)); @@ -78,7 +78,7 @@ fn run_all() -> Result<(), Box> { info!("{:?}", config); let mut qualibration = Qualibration::new()?; - adding_trackbar(&mut qualibration.param, "histogram: 0")?; + adding_trackbar(&mut qualibration, "histogram: 0")?; let _a: () = con.set(format!("/kpps/{}", conf2.laser_id), 65535)?; let _a: () = con.set( @@ -87,46 +87,44 @@ fn run_all() -> Result<(), Box> { )?; while running.load(Ordering::SeqCst) { - //let _t = _framerate_handler.handle_time()?; + //let _t = framerate_handler.handle_time()?; ///////////////// let key = highgui::wait_key(1)?; - qualibration.param.key = key; + //if key != -1 { + qualibration.key = key; + //} if key == 27 { + // esc in my case break; } - let v = qualibration.draw_sequence(); - if v.is_some() { - if qualibration.param.capture_mode { - let pl: Vec<(f32, f32, u32)> = v - .unwrap() - .iter() - .map(|pt| (pt.x, pt.y, u32::from(pt.color))) - .collect(); - - let _ = con.set( - format!("/pl/{}/{}", config.client_id, config.laser_id), - format!("{:?}", pl), - )?; - } - - qualibration.run_step()?; - } //qualibration.id = next_id; + let v: Vec<(f32, f32, u32)> = qualibration + .draw_sequence()? + .iter() + .map(|pt| (pt.x, pt.y, u32::from(pt.color))) + .collect(); + // println!("{:?}", v); + let _ = con.set( + format!("/pl/{}/{}", config.client_id, config.laser_id), + format!("{:?}", v), + )?; - //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); - //} + qualibration.run_step()?; + + 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); + } } let _ = con.set( diff --git a/src/point.rs b/src/point.rs index c720627..36f13b8 100644 --- a/src/point.rs +++ b/src/point.rs @@ -1,4 +1,3 @@ -#[allow(dead_code)] pub type Line = Vec<(f32, f32, u32)>; #[derive(Debug, Clone, Copy, Default, PartialEq)] diff --git a/src/qualibration.rs b/src/qualibration.rs index 1737b67..562a1a4 100644 --- a/src/qualibration.rs +++ b/src/qualibration.rs @@ -1,45 +1,121 @@ -//use opencv::Result; -//use opencv::core::{self, Mat}; - -#[allow(dead_code)] -static DEBUG: bool = true; - pub mod annalyse; pub mod borders; pub mod compute_image; +use annalyse::{ + 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::point::Point; +use crate::draw::{draw_line, draw_line_dotted}; +use crate::point::{Color, Point}; +use enum_iterator::{next, Sequence as Seq}; use opencv::core::Mat; use opencv::Result; -//use std::f64::consts::PI; +use std::f64::consts::PI; +use opencv::core::{bitwise_and, find_file, in_range, Point as OcvPoint, Scalar, Size_}; +use opencv::core::{VecN, Vector}; +use opencv::imgcodecs::imwrite; +use opencv::imgcodecs::{imread, IMREAD_COLOR}; +use opencv::imgproc::{canny, cvt_color, line, COLOR_BGR2GRAY}; use opencv::prelude::*; use opencv::{ highgui, videoio::{self, VideoCapture}, }; +use std::fs::create_dir; +use std::fs::read_dir; -mod param; -use param::Param; +use opencv::{ + calib3d, + core::{self, Size}, + imgproc, +}; -mod sequence; -pub use sequence::{InitBorder, InitIdcode, LineDotted, LoadImage, SaveImage, Sequence, WaitSpace}; +opencv::opencv_branch_4! { + use opencv::imgproc::LINE_AA; + use opencv::imgproc::LINE_8; +} +opencv::not_opencv_branch_4! { + use opencv::core::LINE_AA; +} + +const DEBUG: bool = true; + +#[derive(Debug, PartialEq, Seq, Copy, Clone)] +pub enum Sequence { + //TODO: avoir le meme nombre d'image en mode capture ET en mode replay + FirstState, + WaitSpace, + BackGround, + UpBorder, + LeftBorder, + DownBorder, + RightBorder, + ReadDir, + ComputeArea, + IdCode1, + IdCode2, + Finish, + + PlayLineDotted, + EmptyFrame, + ComputeLineDotted, + + LinearConstSpeed, // [multiple test] + JumpFromTo, + + AdaptLineSeg(u16), // [multiple test] find the correct distense + AdaptLineLum, // [multiple test] try minimu, medium, maximum. + // + SelectSpeedestColor, // on pourait mettre a jour les valeur a chaque passage + + Vertical(u16), + Horizontal(u16), + SelectNbAll(u16), + ComputeSelectNbAll, + TakeMultiple(u16), + TakeMultipleEmpty(u16), +} #[derive(Debug)] pub struct Qualibration { - seq: Vec>, - cam: VideoCapture, - - pub param: Param, + pub begin: Instant, + pub dst_size: i32, + pub cam: VideoCapture, + pub r: i32, + pub g: i32, + pub b: i32, + pub capture_mode: bool, + pub frame: Mat, + pub frame_prev: Mat, + pub img: Vec, + pub id: Option, + pub nb_all: i32, + pub nb_visible: i32, + pub nb_liss: i32, + pub tresh: Treshold, + pub dir_name: String, + pub key: i32, + pub canny_v1: i32, + pub canny_v2: i32, + pub hough_param: HoughLine, + pub border_pt: Vec<(f64, f64)>, + pub homography: Mat, + 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 { pub fn new() -> Result { - //let v: Vec> = vec![]; - let mut dir_name = "".to_string(); //"building.jpg".to_string(); // by default if let Some(dir_name_arg) = args().nth(1) { dir_name = dir_name_arg; @@ -54,58 +130,816 @@ impl Qualibration { let mut frame = Mat::default(); cam.read(&mut frame)?; - // 38400 -> r:150, v:0, b:0 - let beg = Point::from((0., 0., 38400)); - let beg2 = Point::from((4095., 0., 38400)); - let end = Point::from((4095., 4095., 38400)); - let seq: Vec> = vec![ - Box::new(LoadImage::new()), - Box::new(WaitSpace::new(beg, end)), - Box::new(InitBorder::new(beg, end)), - Box::new(LineDotted::new(beg, end, true, false)), - Box::new(InitIdcode::new(beg2, end)), - Box::new(SaveImage::new()), - ]; //let now = std::time::Instant::now(); Ok(Qualibration { - seq, + begin: std::time::Instant::now(), + dst_size: 900, cam, - param: Param::new(dir_name.to_owned())?, + r: 150, + g: 0, + b: 0, + capture_mode: dir_name.len() == 0, + img: vec![], + frame: Mat::default(), // TODO: init with frame from cam + frame_prev: Mat::default(), + id: Some(Sequence::FirstState), + nb_all: 120, + nb_visible: 40, + nb_liss: 10, + tresh: Treshold::new("histogram: 0", 150, 255)?, + dir_name: dir_name.clone(), + key: 10, + canny_v1: 170, + canny_v2: 255, + hough_param: HoughLine { + rho: 100, + theta: 100, + treshold: 30, + min_length: 0, + max_line_gap: 50000, + }, + border_pt: vec![], + homography: Mat::default(), + h_size: Size::default(), + line_pos: vec![4095; 34], + multiple: 20, + cnt: 0, }) } - pub fn draw_sequence(&mut self) -> Option> { - if self.param.seq_id >= self.seq.len() { + pub fn run_step(&mut self) -> Result<(), Box> { + if self.capture_mode && self.id != Some(Sequence::PlayLineDotted) { + //println!("capture"); + self.cam.read(&mut self.frame)?; + highgui::imshow("camera", &self.frame)?; + } + + if self.frame.size()?.width > 0 && self.frame_prev.size()?.width > 0 || !self.capture_mode { + if self.id.is_some() { + self.id = if true { + //self.capture_mode || self.id == Some(Sequence::WaitSpace) || is_same_frame(&self.frame, &self.frame_prev)? { + if self.id != Some(Sequence::WaitSpace) + && self.id != Some(Sequence::FirstState) + && self.id != Some(Sequence::PlayLineDotted) + && self.capture_mode + { + self.img.push(self.frame.clone()); + } + self.compute_sequence()?; + self.get_next_id_seq() + } else { + self.id + }; + } + } + //println!("sequence: {:?}", self.id); + self.frame_prev = self.frame.clone(); + self.cnt += 1; + Ok(()) + } + + pub fn draw_sequence(&self) -> Result, Box> { + if !self.capture_mode { + return Ok(vec![]); + } + let seq = self.id; + let mut pl = vec![]; + //let color = Color { r: 0, g: 30, b: 0 }; + let color = Color { + r: self.r as u8, + g: self.g as u8, + b: self.b as u8, + }; + //let color = Color { r: 0, g: 0, b: 50 }; + 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 + // mieux voir les segment qui bouge peut au debut. + + 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 + let black = Color { r: 0, g: 0, b: 0 }; + for _ in 0..nb_all { + 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, + }); + } + 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, + }); + } + } + Sequence::WaitSpace => { + 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_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_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_line(&p0, &p1, nb_all, nb_visible)?; + } + Sequence::RightBorder => { + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; + } + Sequence::DownBorder => { + pl = draw_line(&p2, &p3, nb_all, nb_visible)?; + } + Sequence::LeftBorder => { + pl = draw_line(&p3, &p0, nb_all, nb_visible)?; + } + Sequence::Vertical(n) => { + let p1 = Point { + x: n as f32, + y: 0., + color, + }; + let p2 = Point { + x: n as f32, + y: 4095., + color, + }; + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; + } + Sequence::Horizontal(n) => { + let p1 = Point { + x: 0., + y: n as f32, + color, + }; + let p2 = Point { + x: 4095., + y: n as f32, + color, + }; + pl = draw_line(&p1, &p2, nb_all, nb_visible)?; + } + _ => (), + } + } + + Ok(pl) + } + + pub fn get_next_id_seq(&self) -> Option { + let line_max = 4095; + let line_add = 100; + + if self.id.is_none() { return None; } - let pl = self.seq[self.param.seq_id].draw(&self.param); - - if pl.is_none() { - self.param.seq_id += 1; - if self.param.capture_mode { - self.param.imgs.push(vec![]); + //println!("Hey"); + 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)) + } else if (2 * n) > line_max as u16 { + next(&Sequence::SelectNbAll(u16::MAX)) + } else { + next(&Sequence::SelectNbAll(n * 2 - 1)) + } + } + Sequence::WaitSpace => { + //println!("key: {}", self.key); + if self.key == 32 || !self.capture_mode { + next(&Sequence::WaitSpace) + } else { + Some(Sequence::WaitSpace) + } + } + Sequence::PlayLineDotted => { + //println!("key: {}", self.key); + if self.key == 32 || !self.capture_mode { + next(&Sequence::PlayLineDotted) + } else { + Some(Sequence::PlayLineDotted) + } + } + Sequence::Vertical(n) => { + let after = if n > line_max { u16::MAX } else { n + line_add }; + next(&Sequence::Vertical(after)) + } + Sequence::Horizontal(n) => { + let after = if n > line_max { u16::MAX } else { n + line_add }; + next(&Sequence::Horizontal(after)) + } + //Sequence::ComputeArea => Some(Sequence::ComputeArea), // + id => next(&id), } - - pl } - pub fn run_step(self: &mut Self) -> Result<(), Box> { - let mut frame = Mat::default(); - if self.param.capture_mode { - self.cam.read(&mut frame)?; - highgui::imshow("camera", &frame)?; - - if frame.size()?.width > 0 && self.seq[self.param.seq_id].is_capture() { - self.param.imgs[self.param.seq_id].push(frame.clone()); - } + pub fn compute_sequence(&mut self) -> Result<(), Box> { + 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])?; - if frame.size()?.width > 0 || !self.param.capture_mode { - self.seq[self.param.seq_id].compute_sequence(&mut self.param)?; + id_code_1 = image_warp(&id_code_1, &self.homography, self.h_size)?; + id_code_1 = image_treshold(&id_code_1, &self.tresh)?; + + 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 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)?; + //} + } + + 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)?; + //} + } + + // 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(()) + } + + fn save_image(&self) -> Result<()> { + // on fait le nom de dossier general au cas ou + // on fait un nom de dossier avec le temps + // on sauvgarde toutes les image + 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() + ); + 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:?}/"); + + // + for (i, img) in self.img.iter().enumerate() { + let mut name_img = name.clone(); + name_img.push_str(&format!("img_{i}.png")); + imwrite(&name_img, img, &Vector::from_slice(&[6, 6, 6, 0]))?; } Ok(()) } + + //use std::cmp::Ordering; + fn load_image(&mut self) -> Result<(), Box> { + let mut imgs = vec![]; + let paths = read_dir(&self.dir_name)?; + //let len = paths.size_hint(); + for entry in paths { + let dir = entry?; + let path = dir.path(); + let c: Vec<&str> = path.to_str().unwrap().split("/").collect(); + let d: Vec<_> = c[c.len() - 1].chars().collect(); + let e: String = d[4..d.len() - 4].iter().collect(); + let img_id: i32 = e.parse()?; + //println!("c: {c:?}"); + //let a: Vec<_> = path.to_str().unwrap().to_string().chars().collect(); + //let b: String = a[27..(a.len() - 4)].iter().collect(); + //let img_id: i32 = b.parse()?; + let path = format!("{path:?}"); + let path = path[1..(path.len() - 1)].to_owned(); + let img: Mat = imread(&find_file(&path, false, false)?, IMREAD_COLOR)?; + // highgui::imshow(&path, &img)?; + imgs.push((img_id, img)); + } + + imgs.sort_by(|v1, v2| { + if v1.0 > v2.0 { + std::cmp::Ordering::Greater + } else if v1.0 == v2.0 { + std::cmp::Ordering::Equal + } else { + std::cmp::Ordering::Less + } + }); + + //println!("Youpi"); + + for (i, m) in imgs.iter().enumerate() { + self.img.push(m.1.clone()); + //highgui::imshow(format!("img: {i}").as_str(), &m.1)?; + } + + //loop {} + + //prointln!(""); + + Ok(()) + } + + pub fn get_one_border( + &self, + background: &Mat, + bord: &Mat, + id: usize, + ) -> 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, + // 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(&diff, &min, &max, &mut color_selected); + ////highgui::imshow(format!("mask: {id}").as_str(), &color_selected)?; + //let mut bord_treshed = Mat::default(); + //bitwise_and(&diff, &diff, &mut bord_treshed, &color_selected)?; + ////highgui::imshow(format!("diff & mask: {id}").as_str(), &bord_treshed)?; + + // Pass the image to gray + let mut diff_gray = Mat::default(); + cvt_color(&diff, &mut diff_gray, COLOR_BGR2GRAY, 0)?; + //cvt_color(&bord_treshed, &mut diff_gray, COLOR_BGR2GRAY, 0)?; + + // Apply Canny edge detector + let mut edges = Mat::default(); + canny( + &diff_gray, + &mut edges, + self.canny_v1 as f64, + self.canny_v2 as f64, + 3, + false, + )?; + let lines = probabilistic_hough(&edges, &self.hough_param, id)?; + //let ((x1, y1), (x2, y2)) = get_extermities(&lines, id); + Ok(get_extermities(&lines, id)) + } +} + +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 { + pub rho: i32, + pub theta: i32, + pub treshold: i32, + pub min_length: i32, + pub max_line_gap: i32, +} + +// ca c'est les donner qu'on envoie a la fonction +pub struct HoughLineValue { + pub rho: f64, + pub theta: f64, + pub treshold: i32, + pub min_length: f64, + pub max_line_gap: f64, +} + +impl HoughLine { + pub fn get_param(&self) -> HoughLineValue { + HoughLineValue { + rho: self.rho as f64 / 100., + theta: self.theta as f64 / 100. * PI / 180., + treshold: self.treshold, + min_length: self.min_length as f64 / 100., + max_line_gap: self.max_line_gap as f64 / 100., + } + } +} + +#[derive(Clone, Debug)] +pub struct Treshold { + pub win_name: String, + pub min_0: i32, + pub min_1: i32, + pub min_2: i32, + pub max_0: i32, + pub max_1: i32, + pub max_2: i32, +} + +impl Treshold { + pub fn new(name: &str, min: i32, max: i32) -> Result { + let tresh = Treshold { + win_name: name.to_owned(), + min_0: min, + min_1: min, + min_2: min, + max_0: max, + max_1: max, + max_2: max, + }; + + Ok(tresh) + } +} + +pub fn get_lines( + background: &Mat, + bord: &Mat, + id: usize, + canny_v1: i32, + canny_v2: i32, + hough_param: &HoughLine, +) -> Result>> { + let diff: Mat = image_diff(bord, background)?; + + // Pass the image to gray + let mut diff_gray = Mat::default(); + cvt_color(&diff, &mut diff_gray, COLOR_BGR2GRAY, 0)?; + // Apply Canny edge detector + let mut edges = Mat::default(); + canny( + &diff_gray, + &mut edges, + canny_v1 as f64, + canny_v2 as f64, + 3, + false, + )?; + let lines = probabilistic_hough(&edges, hough_param, id)?; + //let ((x1, y1), (x2, y2)) = get_extermities(&lines, id); + Ok(lines) } diff --git a/src/qualibration/annalyse.rs b/src/qualibration/annalyse.rs index 05e2e37..4e82325 100644 --- a/src/qualibration/annalyse.rs +++ b/src/qualibration/annalyse.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use std::f64::consts::PI; -use super::Param; +use super::Qualibration; use super::DEBUG; use crate::utils::Pt; //use opencv::prelude::MatTraitConst; @@ -25,10 +25,9 @@ opencv::not_opencv_branch_4! { use opencv::core::LINE_AA; } -use super::param::Treshold; +use super::Treshold; const MAX_TRACKBAR: i32 = 255; -#[allow(dead_code)] pub fn draw_histograme_dbg( window_name: &str, histo: &Vec, @@ -67,7 +66,6 @@ pub fn draw_histograme_dbg( Ok(()) } -#[allow(dead_code)] pub fn draw_histograme(window_name: &str, histo: &Vec) -> Result<()> { let v: VecN = VecN::new(0., 0., 0., 255.); let color: VecN = VecN::new(255., 255., 255., 255.); @@ -106,7 +104,6 @@ pub fn draw_histograme(window_name: &str, histo: &Vec) -> Result<()> { Ok(()) } -#[allow(dead_code)] pub fn draw_histograme_bgr(window_name: &str, histo: &Vec>) -> Result<()> { let v: VecN = VecN::new(0., 0., 0., 255.); let b: VecN = VecN::new(255., 0., 0., 255.); @@ -199,7 +196,6 @@ pub fn draw_histograme_bgr_tresh( } // limit = 0.35 c'est bien -#[allow(dead_code)] pub fn is_same_frame(frame: &Mat, frame_prev: &Mat) -> Result { let nb_liss: i32 = 50; // plus on lisse la courbe plus on attein la limite facilement let limit = 0.45; // plus c'est haut, plus on tolere de changement entre 2 image @@ -293,7 +289,7 @@ pub fn get_horizontal_segment(m: &Mat) -> Result Result Result> { +pub fn get_vertical_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 @@ -456,7 +452,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result Result Result Result Result Result (f32, f32) { let (mut mean_x, mut mean_y) = (0., 0.); let len = vals.len() as f32; @@ -571,7 +563,6 @@ fn get_id_groups(limits: &Vec<(usize, usize)>, id: usize) -> Option { //return usize::MAX; // im lazy to have Option return... } -#[allow(dead_code)] pub fn annalyse_segment(m: &Mat) -> Result>> { // on recupere les coordoner des point selectioner let mut seg_pt = HashSet::from([]); @@ -591,7 +582,7 @@ pub fn annalyse_segment(m: &Mat) -> Result>> { let mut selected: HashSet<(i32, i32)> = seg_pt .iter() .filter_map(|(x, y)| { - for (_k, (i, j)) in around_all.iter().enumerate() { + for (k, (i, j)) in around_all.iter().enumerate() { if seg_pt.get(&(*x + i, *y + j)).is_none() { return Some((*x, *y)); } @@ -648,7 +639,6 @@ pub fn annalyse_segment(m: &Mat) -> Result>> { Ok(lines) } -#[allow(dead_code)] pub fn image_mean(frames: &[Mat]) -> Result { /* * Il faudrait pouvoir changer les matrice de type pour avoir des valeur plus grande @@ -809,8 +799,7 @@ pub fn first_invert(histo: &Vec) -> ((usize, f64), (usize, f64)) { ) } -#[allow(dead_code)] -pub fn trackbar_init_param(mem: &mut Param, winname: &str) -> Result<()> { +pub fn trackbar_init_param(mem: &mut Qualibration, winname: &str) -> Result<()> { named_window(winname, WINDOW_AUTOSIZE)?; highgui::move_window(winname, 20, 20)?; let v: VecN = VecN::new(0., 0., 0., 255.); @@ -826,8 +815,7 @@ pub fn trackbar_init_param(mem: &mut Param, winname: &str) -> Result<()> { Ok(()) } -#[allow(dead_code)] -pub fn trackbar_line_segment(mem: &mut Param, winname: &str) -> Result<()> { +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)?; @@ -890,8 +878,7 @@ pub fn trackbar_line_segment(mem: &mut Param, winname: &str) -> Result<()> { Ok(()) } -#[allow(dead_code)] -pub fn line_pos(mem: &mut Param, winname: &str) -> Result<()> { +pub fn line_pos(mem: &mut Qualibration, winname: &str) -> Result<()> { named_window(winname, WINDOW_AUTOSIZE)?; highgui::move_window(winname, 20, 20)?; let v: VecN = VecN::new(0., 0., 0., 255.); @@ -911,7 +898,7 @@ pub fn line_pos(mem: &mut Param, winname: &str) -> Result<()> { Ok(()) } -pub fn adding_trackbar(mem: &mut Param, _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")?; diff --git a/src/qualibration/borders.rs b/src/qualibration/borders.rs index 78543b2..1302317 100644 --- a/src/qualibration/borders.rs +++ b/src/qualibration/borders.rs @@ -1,4 +1,4 @@ -use super::param::HoughLine; +use super::HoughLine; use crate::utils::{CartesianEquation, EqAffine, Pt}; use opencv::core::{add, subtract, Mat, VecN, Vector, CV_8UC3}; //use opencv::prelude::MatTraitConst; @@ -7,7 +7,6 @@ use opencv::prelude::*; //MatTraitConst; use opencv::types::VectorOfVec4i; use opencv::Result; -#[allow(dead_code)] pub fn mix_borders(background: &Mat, borders: Vec) -> Result { let (row, col) = (background.rows(), background.cols()); //let mask = Mat::default(); @@ -75,9 +74,8 @@ pub fn bord_mult(pt: Vec<(f64, f64)>, factor: f64) -> Vec<(f64, f64)> { } // en fait ca marche pas dutout...next time -#[allow(dead_code)] pub fn bord_mult_v2(pt: Vec<(f64, f64)>, factor: f64) -> Vec<(f64, f64)> { - let pt: Vec = pt.iter().map(|p| Pt::from(p)).collect(); + let mut pt: Vec = pt.iter().map(|p| Pt::from(p)).collect(); let mut pn = vec![]; for i in 0..pt.len() { @@ -161,7 +159,7 @@ pub fn get_extermities(lines: &Vector>, id: usize) -> ((f64, f64), pub fn probabilistic_hough( edges: &Mat, hough_param: &HoughLine, - _id: usize, + id: usize, ) -> Result>> { let mut p_lines = VectorOfVec4i::new(); let mut probabalistic_hough = Mat::default(); diff --git a/src/qualibration/compute_image.rs b/src/qualibration/compute_image.rs index ebee19b..910047b 100644 --- a/src/qualibration/compute_image.rs +++ b/src/qualibration/compute_image.rs @@ -1,4 +1,4 @@ -use super::param::Treshold; +use super::Treshold; use opencv::core::{self, bitwise_and, in_range, Mat, Scalar, Size_}; use opencv::imgproc; use opencv::Result; @@ -31,7 +31,6 @@ pub fn image_treshold(img: &Mat, tresh: &Treshold) -> Result { Ok(bord_treshed) } -#[allow(dead_code)] pub fn image_warp_treshold( img: &Mat, homography: &Mat, diff --git a/src/qualibration/param.rs b/src/qualibration/param.rs deleted file mode 100644 index 52f4487..0000000 --- a/src/qualibration/param.rs +++ /dev/null @@ -1,185 +0,0 @@ -use opencv::imgcodecs::{imread, imwrite, IMREAD_COLOR}; -use opencv::{ - core::{find_file, Mat, Size, Size_, Vector}, - Result, -}; -use std::f64::consts::PI; -use std::fs::{create_dir, read_dir}; -use std::time::Instant; - -#[derive(Clone, Debug)] -pub struct Param { - pub seq_id: usize, - pub imgs: Vec>, - pub dst_size: i32, - pub r: i32, - pub g: i32, - pub b: i32, - pub nb_all: i32, - pub nb_visible: i32, - pub nb_wait: i32, - pub nb_liss: i32, - pub tresh: Treshold, - pub canny_v1: i32, - pub canny_v2: i32, - pub hough_param: HoughLine, - pub border_pt: Vec<(f64, f64)>, - pub homography: Mat, - pub h_size: Size_, - pub line_pos: Vec, - pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence - pub key: i32, - pub dir_name: String, - pub begin: Instant, - pub capture_mode: bool, -} - -impl Param { - pub fn new(dir_name: String) -> Result { - Ok(Self { - begin: std::time::Instant::now(), - capture_mode: dir_name.len() == 0, - dir_name, - key: -1, - imgs: vec![vec![]], - seq_id: 0, - dst_size: 900, - r: 150, - g: 0, - b: 0, - nb_all: 120, - nb_visible: 40, - nb_liss: 10, - nb_wait: 30, - tresh: Treshold::new("histogram", 160, 255)?, - canny_v1: 170, - canny_v2: 255, - hough_param: HoughLine { - rho: 100, - theta: 100, - treshold: 30, - min_length: 0, - max_line_gap: 50000, - }, - border_pt: vec![], - homography: Mat::default(), - h_size: Size::default(), - line_pos: vec![4095; 34], - multiple: 20, - }) - } - - pub fn save_image(&self) -> Result<()> { - let now = self.begin; - let img_root = format!("image"); - create_dir(&img_root).unwrap_or(()); - let new_dir = format!( - "{img_root}/{:0>6?}_{:0>9?}", - now.elapsed().as_millis(), - now.elapsed().as_nanos() - ); - create_dir(&new_dir).unwrap_or(()); - for (i, img_seq) in self.imgs.iter().enumerate() { - let seq_dir_name = format!("{new_dir}/{i}"); - create_dir(&seq_dir_name).unwrap_or(()); - for img in img_seq { - let mut name_img = format!("{seq_dir_name}/"); - name_img.push_str(&format!("img_{i}.png")); - imwrite(&name_img, img, &Vector::from_slice(&[6, 6, 6, 0]))?; - } - } - - Ok(()) - } - - pub fn load_image(&mut self) -> Result<(), Box> { - let mut imgs = vec![]; - let paths = read_dir(&self.dir_name)?; - for entry in paths { - let mut seq_img = vec![]; - let dir = entry?; - let path = dir.path(); // sequence directory - let names: Vec<&str> = path.to_str().unwrap().split("/").collect(); - let seq_id: usize = names[names.len() - 1].parse()?; - for entry in read_dir(&path)? { - let sub_path = entry?.path(); - let names: Vec<&str> = path.to_str().unwrap().split("/").collect(); - let img_name = names[names.len() - 1]; - let img_id: usize = img_name[4..img_name.len() - 4].parse()?; - let img: Mat = imread( - &find_file(&sub_path.to_str().unwrap(), false, false)?, - IMREAD_COLOR, - )?; - seq_img.push((img_id, img)); - } - imgs.push((seq_id, seq_img)); - } - - self.imgs = vec![vec![]; imgs.len()]; - for (seq_id, seq_img) in imgs { - self.imgs[seq_id] = vec![Mat::default(); seq_img.len()]; - for (img_id, img) in seq_img { - self.imgs[seq_id][img_id] = img; - } - } - - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub struct HoughLine { - pub rho: i32, - pub theta: i32, - pub treshold: i32, - pub min_length: i32, - pub max_line_gap: i32, -} - -// ca c'est les donner qu'on envoie a la fonction -pub struct HoughLineValue { - pub rho: f64, - pub theta: f64, - pub treshold: i32, - pub min_length: f64, - pub max_line_gap: f64, -} - -impl HoughLine { - pub fn get_param(&self) -> HoughLineValue { - HoughLineValue { - rho: self.rho as f64 / 100., - theta: self.theta as f64 / 100. * PI / 180., - treshold: self.treshold, - min_length: self.min_length as f64 / 100., - max_line_gap: self.max_line_gap as f64 / 100., - } - } -} - -#[derive(Clone, Debug)] -pub struct Treshold { - pub win_name: String, - pub min_0: i32, - pub min_1: i32, - pub min_2: i32, - pub max_0: i32, - pub max_1: i32, - pub max_2: i32, -} - -impl Treshold { - pub fn new(name: &str, min: i32, max: i32) -> Result { - let tresh = Treshold { - win_name: name.to_owned(), - min_0: min, - min_1: min, - min_2: min, - max_0: max, - max_1: max, - max_2: max, - }; - - Ok(tresh) - } -} diff --git a/src/qualibration/sequence.rs b/src/qualibration/sequence.rs deleted file mode 100644 index 4d543be..0000000 --- a/src/qualibration/sequence.rs +++ /dev/null @@ -1,27 +0,0 @@ -use super::Param; -use crate::point::Point; - -mod init_border; -mod init_idcode; -mod line_dotted; -mod load_image; -mod save_image; -mod wait_space; -pub use init_border::InitBorder; -pub use init_idcode::InitIdcode; -pub use line_dotted::LineDotted; -pub use load_image::LoadImage; -pub use save_image::SaveImage; -pub use wait_space::WaitSpace; - -pub trait Sequence { - fn draw(&self, mem: &Param) -> Option>; - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box>; - fn is_capture(&self) -> bool; -} - -impl std::fmt::Debug for dyn Sequence { - fn fmt(self: &Self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{self:?}") - } -} diff --git a/src/qualibration/sequence/init_border.rs b/src/qualibration/sequence/init_border.rs deleted file mode 100644 index bcdd4e6..0000000 --- a/src/qualibration/sequence/init_border.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::draw::draw_line; -use crate::point::{Color, Point}; -use crate::qualibration::{ - param::{HoughLine, Param}, - Sequence, -}; - -use crate::qualibration::annalyse::image_diff; -use crate::qualibration::borders::{ - bord_mult, get_extermities, get_intersection, probabilistic_hough, -}; - -use opencv::{ - calib3d, - core::{Mat, Point as OcvPoint, Size, VecN, Vector}, - imgproc::{canny, cvt_color, COLOR_BGR2GRAY}, - Result, -}; - -opencv::opencv_branch_4! { - #[allow(unused)] - use opencv::imgproc::LINE_AA; -} -opencv::not_opencv_branch_4! { - use opencv::core::LINE_AA; -} - -#[derive(Debug, Clone, Copy)] -pub struct InitBorder { - finished: bool, - cnt: usize, - borders: [Point; 4], -} - -impl InitBorder { - pub fn new(beg: Point, end: Point) -> Self { - InitBorder { - borders: [ - Point { - x: beg.x, - y: beg.y, - color: end.color, - }, - Point { - x: end.x, - y: beg.y, - color: end.color, - }, - Point { - x: end.x, - y: end.y, - color: end.color, - }, - Point { - x: beg.x, - y: end.y, - color: end.color, - }, - ], - cnt: 0, - finished: false, - } - } -} - -impl Sequence for InitBorder { - //type Obj = Self; - - fn draw(&self, mem: &Param) -> Option> { - if self.cnt > self.borders.len() { - return None; - } - if self.cnt == self.borders.len() { - return Some(vec![]); - } - - let color = Color { - r: mem.r as u8, - g: mem.g as u8, - b: mem.b as u8, - }; - let id1 = (self.cnt + 1) % self.borders.len(); - let p0 = Point { - color, - ..self.borders[self.cnt] - }; - let p1 = Point { - color, - ..self.borders[id1] - }; - Some(draw_line( - &p0, - &p1, - mem.nb_all as usize, - mem.nb_visible as usize, - )) - } - - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - if self.cnt < self.borders.len() { - self.cnt += 1; - return Ok(()); - } - - let len = self.borders.len(); - let imgs = mem.imgs[mem.seq_id].clone(); - let borders: Vec = imgs[..len].into(); - let background = imgs[len].clone(); - - // on recupere chaqu'un des 4 bord - let mut bords_pts = vec![]; - for (id, bord) in borders.iter().enumerate() { - let lines = get_lines( - &background, - &bord, - id, - mem.canny_v1, - mem.canny_v2, - &mem.hough_param, - )?; - let bord_pt = get_extermities(&lines, id); - bords_pts.push(bord_pt); - } - - // on calcul le cadre - let border_pt = get_intersection(&bords_pts); - mem.border_pt = bord_mult(border_pt, 1.1); - - //// on dessine le cadre - //let color: VecN = VecN::new(255., 128., 0., 255.); - //let mut mixed = mix_borders(&background, borders)?; - //let b = &mem.border_pt; - //for i in 0..b.len() { - // let j = (i + 1) % mem.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)?; - - // on calcule l'homography - let size = mem.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 = mem - .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 - mem.homography = h.clone(); - mem.h_size = warped_image_size.clone(); - //let mut warped_image = Mat::default(); - //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)?; - self.finished = true; - Ok(()) - } - - fn is_capture(&self) -> bool { - true - } -} - -pub fn get_lines( - background: &Mat, - bord: &Mat, - id: usize, - canny_v1: i32, - canny_v2: i32, - hough_param: &HoughLine, -) -> Result>> { - let diff: Mat = image_diff(bord, background)?; - - // Pass the image to gray - let mut diff_gray = Mat::default(); - cvt_color(&diff, &mut diff_gray, COLOR_BGR2GRAY, 0)?; - // Apply Canny edge detector - let mut edges = Mat::default(); - canny( - &diff_gray, - &mut edges, - canny_v1 as f64, - canny_v2 as f64, - 3, - false, - )?; - let lines = probabilistic_hough(&edges, hough_param, id)?; - //let ((x1, y1), (x2, y2)) = get_extermities(&lines, id); - Ok(lines) -} diff --git a/src/qualibration/sequence/init_idcode.rs b/src/qualibration/sequence/init_idcode.rs deleted file mode 100644 index 1fbd900..0000000 --- a/src/qualibration/sequence/init_idcode.rs +++ /dev/null @@ -1,105 +0,0 @@ -use crate::{ - draw::draw_line_dotted, - point::Point, - qualibration::{ - annalyse::{get_horizontal_segment, image_diff}, - compute_image::{image_treshold, image_warp}, - param::Param, - Sequence, - }, -}; - -use opencv::{ - core::{Point as OcvPoint, VecN}, - highgui, - imgproc::line, - Result, -}; - -opencv::opencv_branch_4! { - use opencv::imgproc::LINE_8; -} -opencv::not_opencv_branch_4! { - use opencv::core::LINE_AA; -} - -#[derive(Debug, Clone, Copy)] -pub struct InitIdcode { - finished: bool, - cnt: usize, - beg: Point, - end: Point, -} - -impl InitIdcode { - pub fn new(beg: Point, end: Point) -> InitIdcode { - InitIdcode { - finished: false, - cnt: 0, - beg, - end, - } - } -} - -impl Sequence for InitIdcode { - fn draw(&self, mem: &Param) -> Option> { - if self.finished { - return None; - } - if self.cnt == 0 { - return Some(vec![]); - } - let mut pl = vec![]; - pl.extend(draw_line_dotted( - &self.beg, - &self.end, - mem.nb_all as usize, - mem.nb_visible as usize, - true, - )); - Some(pl) - } - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - if self.cnt == 0 { - self.cnt += 1; - return Ok(()); - } - let id = mem.seq_id; - let mut id_code_1 = image_diff(&mem.imgs[id][1], &mem.imgs[id][0])?; - - id_code_1 = image_warp(&id_code_1, &mem.homography, mem.h_size)?; - id_code_1 = image_treshold(&id_code_1, &mem.tresh)?; - - 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(); - - // on dessine - let color_1: VecN = VecN::new(255., 0., 0., 255.); - 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, _), _), _) = 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)?; - } - } - - highgui::imshow("code 1", &id_code_1)?; - self.finished = true; - Ok(()) - } - fn is_capture(&self) -> bool { - true - } -} diff --git a/src/qualibration/sequence/line_dotted.rs b/src/qualibration/sequence/line_dotted.rs deleted file mode 100644 index b35a403..0000000 --- a/src/qualibration/sequence/line_dotted.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::point::{Color, Point}; -use crate::qualibration::{ - annalyse::{ - draw_histograme_bgr_tresh, get_horizontal_segment, get_vertical_segment, histogram_3d, - image_diff, - }, - param::Param, - Sequence, -}; - -use opencv::{ - core::{bitwise_and, in_range, Mat, Point as OcvPoint, Scalar, VecN, BORDER_CONSTANT}, - highgui, - imgproc::{self, line}, - Result, -}; - -opencv::opencv_branch_4! { - use opencv::imgproc::LINE_8; -} -opencv::not_opencv_branch_4! { - use opencv::core::LINE_AA; -} - -#[derive(Debug, Clone)] -pub struct LineDotted { - finished: bool, - cnt: usize, - beg: Point, - end: Point, - continuous_y: bool, - continuous_x: bool, -} - -impl LineDotted { - pub fn new(beg: Point, end: Point, continuous_y: bool, continuous_x: bool) -> Self { - Self { - finished: false, - cnt: 0, - beg, - end, - continuous_x, - continuous_y, - } - } -} - -impl Sequence for LineDotted { - fn draw(&self, mem: &Param) -> Option> { - if self.finished { - return None; - } - if self.cnt == 0 { - return Some(vec![]); - } - let nb_all = mem.nb_all; - let nb_wait = mem.nb_wait as usize; - let nb_visible = mem.nb_visible as usize; - let mut pl = vec![]; - let color = Color { - r: mem.r as u8, - g: mem.g as u8, - b: mem.b as u8, - }; - let black = Color { r: 0, g: 0, b: 0 }; - for _ in 0..nb_all { - pl.push(Point { - color: black, - ..self.beg - }); - } - let len = (2 * mem.line_pos.len() + nb_wait) as f32; - for i in 0..nb_wait { - let val_x = i as f32 / len * (self.end.x - self.beg.x) + self.beg.x; - let val_y = i as f32 / len * (self.end.y - self.beg.y) + self.beg.y; - pl.push(Point { - x: if self.continuous_x { val_x } else { self.beg.x }, - y: if self.continuous_y { val_y } else { self.beg.y }, - color: black, - }); - } - for i in 0..(mem.line_pos.len() * 2) { - let val_cont_x = (i + nb_wait) as f32 / len * (self.end.x - self.beg.x) + self.beg.x; - let val_cont_y = (i + nb_wait) as f32 / len * (self.end.y - self.beg.y) + self.beg.y; - let val_x = mem.line_pos[i / 2] as f32 + self.beg.x; - let val_y = mem.line_pos[i / 2] as f32 + self.beg.y; - let is_visible = (i + nb_wait) % 2 == 0 && i < nb_visible; - let c = if is_visible { color } else { black }; - pl.push(Point { - x: if self.continuous_x { val_cont_x } else { val_x }, - y: if self.continuous_y { val_cont_y } else { val_y }, - color: c, - }); - } - - Some(pl) - } - - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - if self.cnt < 1 { - self.cnt += 1; - } - let ids = mem.seq_id; - let background = mem.imgs[ids][0].to_owned(); - let line_dot = mem.imgs[ids][1].to_owned(); - let diff = image_diff(&background, &line_dot)?; - - let mut warped_image = Mat::default(); - imgproc::warp_perspective( - &diff, - &mut warped_image, - &mem.homography, - mem.h_size, - imgproc::INTER_CUBIC, // I dont see difference with INTER_CUBIC - BORDER_CONSTANT, - Scalar::default(), - )?; - //highgui::imshow("Warped Image", &warped_image)?; - - let histo = histogram_3d(&warped_image, mem.nb_liss)?; - draw_histograme_bgr_tresh("histo bgr", &histo, &mem.tresh)?; - - let (t1, s1, l1) = ( - mem.tresh.min_0 as f64, - mem.tresh.min_1 as f64, - mem.tresh.min_2 as f64, - ); - let (t2, s2, l2) = ( - mem.tresh.max_0 as f64, - mem.tresh.max_1 as f64, - mem.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 = if self.continuous_y { - get_vertical_segment(&bord_treshed)? - } else { - get_horizontal_segment(&bord_treshed)? - }; - for (i, (((x0, y0), (x1, y1)), _size)) 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)?; - self.finished = true; - Ok(()) - } - fn is_capture(&self) -> bool { - true - } -} diff --git a/src/qualibration/sequence/load_image.rs b/src/qualibration/sequence/load_image.rs deleted file mode 100644 index c723241..0000000 --- a/src/qualibration/sequence/load_image.rs +++ /dev/null @@ -1,33 +0,0 @@ -use super::{super::Param, Sequence}; -use crate::point::Point; -use opencv::Result; - -#[derive(Debug, Clone, Copy)] -pub struct LoadImage { - finished: bool, -} - -impl LoadImage { - pub fn new() -> LoadImage { - LoadImage { finished: false } - } -} - -impl Sequence for LoadImage { - fn draw(&self, _mem: &Param) -> Option> { - if self.finished { - return None; - } - Some(vec![]) - } - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - if !mem.capture_mode { - mem.load_image()?; - } - self.finished = true; - Ok(()) - } - fn is_capture(&self) -> bool { - false - } -} diff --git a/src/qualibration/sequence/save_image.rs b/src/qualibration/sequence/save_image.rs deleted file mode 100644 index 1ddfec3..0000000 --- a/src/qualibration/sequence/save_image.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::{super::Param, Sequence}; -use crate::point::Point; -use opencv::Result; - -#[derive(Debug, Clone, Copy)] -pub struct SaveImage { - finished: bool, -} - -impl SaveImage { - pub fn new() -> SaveImage { - SaveImage { finished: false } - } -} - -impl Sequence for SaveImage { - fn draw(&self, _mem: &Param) -> Option> { - if self.finished { - return None; - } - Some(vec![]) - } - fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - mem.save_image()?; - self.finished = true; - Ok(()) - } - fn is_capture(&self) -> bool { - false - } -} diff --git a/src/qualibration/sequence/wait_space.rs b/src/qualibration/sequence/wait_space.rs deleted file mode 100644 index db26bcf..0000000 --- a/src/qualibration/sequence/wait_space.rs +++ /dev/null @@ -1,176 +0,0 @@ -use super::{super::Param, Sequence}; -use crate::{ - draw::{draw_line, draw_line_dotted}, - point::{Color, Point}, -}; - -use opencv::Result; - -#[derive(Debug, Clone, Copy)] -pub struct WaitSpace { - borders: [Point; 4], - red: [Point; 2], - green: [Point; 2], - blue: [Point; 2], -} - -impl WaitSpace { - pub fn new(beg: Point, end: Point) -> Self { - let red_y = (end.y - beg.y) * 1./5. + beg.y; - let green_y = (end.y - beg.y) * 2./5. + beg.y; - let blue_y = (end.y - beg.y) * 3./5. + beg.y; - Self { - borders: [ - Point { - x: beg.x, - y: beg.y, - color: end.color, - }, - Point { - x: end.x, - y: beg.y, - color: end.color, - }, - Point { - x: end.x, - y: end.y, - color: end.color, - }, - Point { - x: beg.x, - y: end.y, - color: end.color, - }, - ], - red: [ - Point { - x: beg.x, - y: red_y, - color: end.color, - }, - Point { - x: end.x, - y: red_y, - color: end.color, - }, - ], - blue: [ - Point { - x: beg.x, - y: blue_y, - color: end.color, - }, - Point { - x: end.x, - y: blue_y, - color: end.color, - }, - ], - green: [ - Point { - x: beg.x, - y: green_y, - color: end.color, - }, - Point { - x: end.x, - y: green_y, - color: end.color, - }, - ], - } - } -} - -impl Sequence for WaitSpace { - fn draw(&self, mem: &Param) -> Option> { - if mem.key == 32 || !mem.capture_mode { - return None; - } - - let mut pl = vec![]; - let color = Color { - r: mem.r as u8, - g: mem.g as u8, - b: mem.b as u8, - }; - let red = Color { - r: mem.r as u8, - g: 0, - b: 0, - }; - let green = Color { - r: 0, - g: mem.g as u8, - b: 0, - }; - let blue = Color { - r: 0, - g: 0, - b: mem.b as u8, - }; - for i in 0..self.borders.len() { - let id1 = (i + 1) % self.borders.len(); - let p0 = Point { - color, - ..self.borders[i] - }; - let p1 = Point { - color, - ..self.borders[id1] - }; - pl.extend(draw_line( - &p0, - &p1, - mem.nb_all as usize, - mem.nb_visible as usize, - )); - pl.extend(draw_line_dotted( - &Point{ - color: blue, - ..self.blue[0] - }, - &Point{ - color: blue, - ..self.blue[1] - }, - mem.nb_all as usize, - mem.nb_visible as usize, - true, - )); - pl.extend(draw_line_dotted( - &Point{ - color: green, - ..self.green[0] - }, - &Point{ - color: green, - ..self.green[1] - }, - mem.nb_all as usize, - mem.nb_visible as usize, - true, - )); - pl.extend(draw_line_dotted( - &Point{ - color: red, - ..self.red[0] - }, - &Point{ - color: red, - ..self.red[1] - }, - mem.nb_all as usize, - mem.nb_visible as usize, - true, - )); - } - Some(pl) - } - fn compute_sequence(&mut self, _mem: &mut Param) -> Result<(), Box> { - Ok(()) - } - fn is_capture(&self) -> bool { - false - } -} diff --git a/src/utils.rs b/src/utils.rs index 1223c49..b55aa46 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,13 @@ use crate::point::Point; static NEAR_ZERO: f64 = 0.000001; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub}; +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::BitXor impl Add for Pt {