diff --git a/src/draw.rs b/src/draw.rs index d231035..7f85480 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -6,25 +6,62 @@ const RADIUS: f32 = 2000.0; const X_CENTER: f32 = 2047.0; const Y_CENTER: f32 = 2047.0; -pub fn draw_line( +pub fn draw_line_dotted( p1: &Point, p2: &Point, - nb1: usize, - nb2: usize, + nb_all: usize, + nb_visible: usize, ) -> Result, Box> { let mut pl = vec![]; let black = Color { r: 0, g: 0, b: 0 }; - for _ in 0..nb1 { + for _ in 0..nb_all { pl.push(Point { color: black, ..*p1 }); } - for _ in 0..nb2 { + for i in 0..nb_visible { + pl.push(Point { + color: if i % 2 == 0 { p2.color } else { black }, + ..*p2 + }); + } + if nb_visible > nb_all { + return Ok(pl); + } + for _ in 0..(nb_all - nb_visible) { + pl.push(Point { + color: black, + ..*p2 + }); + } + + Ok(pl) +} + +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, + ..*p1 + }); + } + for _ in 0..nb_visible { pl.push(*p2); } - for _ in 0..(nb1 - nb2) { + if nb_visible > nb_all { + return Ok(pl); + } + for _ in 0..(nb_all - nb_visible) { pl.push(Point { color: black, ..*p2 diff --git a/src/main.rs b/src/main.rs index d375fca..3305830 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,21 +8,23 @@ mod framerate; mod logs; mod point; -mod utils; mod qualibration; +mod utils; -use qualibration::{Qualibration, annalyse::adding_trackbar}; +use qualibration::{annalyse::adding_trackbar, Qualibration}; use conf::Conf; use log::{/*debug, warn, */ error, info}; use logs::init_logging; use point::{Color, Point}; use redis::{Client, Commands, Connection}; -use std::sync::{Arc, atomic::{AtomicBool, Ordering}}; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; - -use opencv::Result; use opencv::highgui; +use opencv::Result; opencv::opencv_branch_4! { #[allow(unused_imports)] @@ -33,7 +35,6 @@ opencv::not_opencv_branch_4! { use opencv::core::LINE_AA; } - const DEFAULT_CONF_FILE: &str = "settings.toml"; pub fn main() { @@ -86,20 +87,20 @@ fn run_all() -> Result<(), Box> { )?; while running.load(Ordering::SeqCst) { - let _t = framerate_handler.handle_time()?; + //let _t = framerate_handler.handle_time()?; ///////////////// - qualibration.run_step()?; let key = highgui::wait_key(1)?; if key != -1 { qualibration.key = key; } - if key == 27 { // esc in my case + if key == 27 { + // esc in my case break; } - let points_list: Vec = qualibration.draw_sequence()?; //draw::draw(_t)?; - //qualibration.id = next_id; - let v: Vec<(f32, f32, u32)> = points_list + //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(); @@ -109,8 +110,10 @@ fn run_all() -> Result<(), Box> { format!("{:?}", v), )?; + qualibration.run_step()?; + if qualibration.capture_mode { - let millis = std::time::Duration::from_millis(300); // TODO: find solution to know when change has been done + let millis = std::time::Duration::from_millis(1000); // TODO: find solution to know when change has been done std::thread::sleep(millis); } } diff --git a/src/qualibration.rs b/src/qualibration.rs index e63d8ae..2d6c5df 100644 --- a/src/qualibration.rs +++ b/src/qualibration.rs @@ -13,7 +13,7 @@ use opencv::core::Mat; use opencv::Result; use std::f64::consts::PI; -use opencv::core::{bitwise_and, find_file, in_range, Point as OcvPoint, Scalar}; +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}; @@ -43,44 +43,48 @@ 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 + //TODO: avoir le meme nombre d'image en mode capture ET en mode replay FirstState, - ReadDir, - ComputeArea, WaitSpace, - Finish, - - LinearConstSpeed, // [multiple test] - JumpFromTo, - - AdaptLineSeg(u16), // [multiple test] find the correct distense - AdaptLineLum, // [multiple test] try minimu, medium, maximum. - // - TestRedSpeed, - TestGreenSpeed, - TestBlueSpeed, - SelectSpeedestColor, // on pourait mettre a jour les valeur a chaque passage - - BackGround, UpBorder, LeftBorder, DownBorder, RightBorder, + ReadDir, + ComputeArea, + Finish, + + WaitQ, + + + 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, } #[derive(Debug)] pub struct Qualibration { 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_pt_1: usize, - pub nb_pt_2: usize, + pub nb_all: i32, + pub nb_visible: i32, pub nb_liss: i32, pub tresh: Treshold, pub dir_name: String, @@ -89,6 +93,8 @@ pub struct Qualibration { pub canny_v2: i32, pub hough_param: HoughLine, pub border_pt: Vec<(f64, f64)>, + pub homography: Mat, + pub h_size: Size_, } impl Qualibration { @@ -109,13 +115,16 @@ impl Qualibration { Ok(Qualibration { cam, + 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_pt_1: 130, - nb_pt_2: 40, + nb_all: 120, + nb_visible: 40, nb_liss: 10, tresh: Treshold::new("histogram: 0", 0, 255)?, dir_name: dir_name.clone(), @@ -130,18 +139,34 @@ impl Qualibration { max_line_gap: 50000, }, border_pt: vec![], + homography: Mat::default(), + h_size: Size::default(), }) } pub fn run_step(&mut self) -> Result<(), Box> { if self.capture_mode { - //println!("pouette: >{}<\n:self{:?}", self.dir_name, self); + //println!("capture"); self.cam.read(&mut self.frame)?; + highgui::imshow("camera", &self.frame)?; } + + + //println!( + // "frame.size:{} \tframe_prev.size:{}", + // self.frame.size()?.width, + // self.frame_prev.size()?.width + //); if self.frame.size()?.width > 0 && self.frame_prev.size()?.width > 0 || !self.capture_mode { + //println!("plif: {}", line!()); if self.id.is_some() { - self.id = if !self.capture_mode || is_same_frame(&self.frame, &self.frame_prev)? { - if self.id != Some(Sequence::WaitSpace) && self.capture_mode { + // println!("plif: {}", line!()); + 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.capture_mode + { self.img.push(self.frame.clone()); } self.compute_sequence()?; @@ -157,10 +182,17 @@ impl Qualibration { } 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: 60, g: 0, 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 = Point { x: 0., @@ -182,33 +214,70 @@ impl Qualibration { y: 4095., color, }; - let nb1 = self.nb_pt_1; - let nb2 = self.nb_pt_2; + + 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 nb_all = self.nb_all as usize; + let nb_visible = self.nb_visible as usize; if seq.is_some() { match seq.unwrap() { Sequence::WaitSpace => { - ////let l1 = draw::draw_line(&p0, &p1, nb1, nb2)?; - //let l0 = draw::draw_line(&p0, &p1, nb1, nb2)?; - //let l1 = draw::draw_line(&p1, &p2, nb1, nb2)?; - //let l2 = draw::draw_line(&p3, &p0, nb1, nb2)?; - //let l3 = draw::draw_line(&p2, &p3, nb1, nb2)?; - //pl.extend(l0); - //pl.extend(l1); - //pl.extend(l2); - //pl.extend(l3); + 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.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)?); + } + 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)?); } Sequence::UpBorder => { - pl = draw::draw_line(&p0, &p1, nb1, nb2)?; + pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?; } Sequence::RightBorder => { - pl = draw::draw_line(&p1, &p2, nb1, nb2)?; + pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; } Sequence::DownBorder => { - pl = draw::draw_line(&p2, &p3, nb1, nb2)?; + pl = draw::draw_line(&p2, &p3, nb_all, nb_visible)?; } Sequence::LeftBorder => { - pl = draw::draw_line(&p3, &p0, nb1, nb2)?; + pl = draw::draw_line(&p3, &p0, nb_all, nb_visible)?; } Sequence::Vertical(n) => { let p1 = Point { @@ -221,7 +290,7 @@ impl Qualibration { y: 4095., color, }; - pl = draw::draw_line(&p1, &p2, nb1, nb2)?; + pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; } Sequence::Horizontal(n) => { let p1 = Point { @@ -234,7 +303,7 @@ impl Qualibration { y: n as f32, color, }; - pl = draw::draw_line(&p1, &p2, nb1, nb2)?; + pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?; } _ => (), } @@ -251,9 +320,19 @@ impl Qualibration { return None; } + println!("Hey"); match self.id.unwrap() { //Sequence::Finish => Some(Sequence::Finish), Sequence::Finish => None, + Sequence::SelectNbAll(mut 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 { @@ -262,6 +341,14 @@ impl Qualibration { Some(Sequence::WaitSpace) } } + Sequence::WaitQ => { + //println!("key: {}", self.key); + if self.key == 113 { + next(&Sequence::WaitQ) + } else { + Some(Sequence::WaitQ) + } + } Sequence::Vertical(n) => { let after = if n > line_max { u16::MAX } else { n + line_add }; next(&Sequence::Vertical(after)) @@ -270,7 +357,7 @@ impl Qualibration { let after = if n > line_max { u16::MAX } else { n + line_add }; next(&Sequence::Horizontal(after)) } - Sequence::ComputeArea => Some(Sequence::ComputeArea), // + //Sequence::ComputeArea => Some(Sequence::ComputeArea), // id => next(&id), } } @@ -278,27 +365,54 @@ impl Qualibration { pub fn compute_sequence(&mut self) -> Result<(), Box> { if self.id.is_some() { match self.id.unwrap() { + 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; - // on recupere les image en fonction de mode: capture/dossier - if !self.capture_mode { - background = self.img[1].clone(); - borders = self.img[2..6].into(); - } else { - background = self.img[0].clone(); - borders = self.img[1..].into(); - } + 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)?; + 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); @@ -367,10 +481,12 @@ impl Qualibration { // on fait un nom de dossier avec le temps // on sauvgarde toutes les image let now = std::time::Instant::now(); - let mut name = "image/".to_owned(); + let name = format!("image/"); create_dir(&name).unwrap_or(()); - name.push_str(format!("testouille_{now:?}/").as_str()); - let name = format!("testouille_{now:?}"); + let name = format!("image/{:0>6?}_{:0>9?}/", now.elapsed().as_millis(), 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() { @@ -391,7 +507,7 @@ impl Qualibration { let dir = entry?; let path = dir.path(); let a: Vec<_> = path.to_str().unwrap().to_string().chars().collect(); - let b: String = a[21..(a.len() - 4)].iter().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(); @@ -410,10 +526,17 @@ impl Qualibration { } }); - for m in imgs { - self.img.push(m.1); + //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(()) } @@ -423,22 +546,33 @@ impl Qualibration { bord: &Mat, id: usize, ) -> Result<((f64, f64), (f64, f64))> { - 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 diff: Mat = image_diff(bord, background)?; - 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)?; + //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( @@ -512,3 +646,31 @@ impl Treshold { 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 ffebf1e..5871d55 100644 --- a/src/qualibration/annalyse.rs +++ b/src/qualibration/annalyse.rs @@ -336,18 +336,23 @@ fn first_invert(histo: &Vec) -> ((usize, f64), (usize, f64)) { ) } -pub fn adding_trackbar(mem: &mut Qualibration, winname: &str) -> Result<()> { - //println!("winname: {winname}"); +pub fn trackbar_init_param(mem: &mut Qualibration, winname: &str) -> Result<()> { named_window(winname, WINDOW_AUTOSIZE)?; - associate_trackbar(winname, &mut mem.tresh)?; - create_trackbar( - "nb_liss", - winname, - Some(&mut mem.nb_liss), - MAX_TRACKBAR, - None, - )?; + highgui::move_window(winname, 20, 20)?; + let v: VecN = VecN::new(0., 0., 0., 255.); + let m = Mat::new_rows_cols_with_default(1, 512, CV_8UC3, v)?; + highgui::imshow(winname, &m)?; + create_trackbar("nb_all", winname, Some(&mut mem.nb_all), 400, None)?; + create_trackbar("nb_visible", winname, Some(&mut mem.nb_visible), 400, None)?; + create_trackbar("r", winname, Some(&mut mem.r), MAX_TRACKBAR, None)?; + create_trackbar("g", winname, Some(&mut mem.g), MAX_TRACKBAR, None)?; + create_trackbar("b", winname, Some(&mut mem.b), MAX_TRACKBAR, None)?; + + Ok(()) +} + +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)?; @@ -403,15 +408,23 @@ pub fn adding_trackbar(mem: &mut Qualibration, winname: &str) -> Result<()> { 500000, None, )?; + Ok(()) +} + +pub fn adding_trackbar(mem: &mut Qualibration, winname: &str) -> Result<()> { + //println!("winname: {winname}"); + 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)?; - //let winname = "bord selected: 0"; - //create_trackbar("scale : ", winname, Some(&mut mem.lsd_param.scale ), 1000, None)?; - //create_trackbar("sigma_scal", winname, Some(&mut mem.lsd_param.sigma_scale), 1000, None)?; - //create_trackbar("quant : ", winname, Some(&mut mem.lsd_param.quant ), 1000, None)?; - //create_trackbar("ang_th : ", winname, Some(&mut mem.lsd_param.ang_th ), 1000, None)?; - //create_trackbar("log_eps : ", winname, Some(&mut mem.lsd_param.log_eps ), 1000, None)?; - //create_trackbar("density_th", winname, Some(&mut mem.lsd_param.density_th ), 1000, None)?; - //create_trackbar("n_bins : ", winname, Some(&mut mem.lsd_param.n_bins ), 1000, None)?; Ok(()) }