From fef7e1387b5cb52cbc535ed14a751dcdca23cb21 Mon Sep 17 00:00:00 2001 From: Lapin Raving Date: Thu, 21 Sep 2023 03:20:35 +0200 Subject: [PATCH 1/2] fix: save and load --- src/main.rs | 76 +++++++------- src/qualibration.rs | 51 +++++++--- src/qualibration/annalyse.rs | 3 +- src/qualibration/param.rs | 21 ++-- src/qualibration/sequence.rs | 2 + src/qualibration/sequence/init_border.rs | 71 +++++++------ src/qualibration/sequence/init_idcode.rs | 15 ++- src/qualibration/sequence/line_dotted.rs | 124 +++++++++++++---------- src/qualibration/sequence/load_image.rs | 13 ++- src/qualibration/sequence/save_image.rs | 13 ++- src/qualibration/sequence/wait_space.rs | 105 +++++-------------- 11 files changed, 267 insertions(+), 227 deletions(-) diff --git a/src/main.rs b/src/main.rs index c9e6f12..d4282cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,46 +87,36 @@ fn run_all() -> Result<(), Box> { )?; while running.load(Ordering::SeqCst) { - //let _t = _framerate_handler.handle_time()?; - ///////////////// - let key = highgui::wait_key(1)?; + let key = highgui::wait_key(20)?; + let v = qualibration.draw_sequence(); + + if key != -1 { + println!("key: {key}"); + // 81 <- -> 83 + } qualibration.param.key = key; if key == 27 { - 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.param.save_image()?; } - - qualibration.run_step()?; + break; + } else if v.is_none() { + continue; } - //qualibration.id = next_id; - //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); - //} + 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(); + con.set( + format!("/pl/{}/{}", config.client_id, config.laser_id), + format!("{:?}", pl), + )?; + } + + qualibration.run_step()?; } let _ = con.set( @@ -135,3 +125,21 @@ fn run_all() -> Result<(), Box> { )?; Ok(()) } + +//let _t = _framerate_handler.handle_time()?; +///////////////// +//qualibration.id = next_id; + +//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); +//} diff --git a/src/qualibration.rs b/src/qualibration.rs index 1737b67..228f824 100644 --- a/src/qualibration.rs +++ b/src/qualibration.rs @@ -37,7 +37,7 @@ pub struct Qualibration { } impl Qualibration { - pub fn new() -> Result { + pub fn new() -> Result> { //let v: Vec> = vec![]; let mut dir_name = "".to_string(); //"building.jpg".to_string(); // by default @@ -54,23 +54,25 @@ 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)); + // 9830400 -> r:150, v:0, b:0 + let beg = Point::from((0., 0., 9830400)); + let beg2 = Point::from((0., 4095., 9830400)); + let end = Point::from((4095., 4095., 9830400)); 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()), + Box::new(WaitSpace::new(beg, end, 400)), + Box::new(InitBorder::new(beg, end, 400)), + Box::new(LineDotted::new(beg, end, 2, true, false, 400)), + Box::new(InitIdcode::new(beg2, end, 400)), ]; - //let now = std::time::Instant::now(); + let seq_names = get_sequence_name(&seq); + let mut param = Param::new(dir_name.to_owned(), seq_names)?; + if !param.capture_mode { + param.load_image()?; + } Ok(Qualibration { seq, cam, - param: Param::new(dir_name.to_owned())?, + param, }) } @@ -92,7 +94,18 @@ impl Qualibration { } pub fn run_step(self: &mut Self) -> Result<(), Box> { + let seq_id = self.param.seq_id; + let seq_name = self.seq[seq_id].sequence_name(); + println!("seq[{seq_id}]: {seq_name}"); + + if self.param.capture_mode { + let millis_nb = self.seq[self.param.seq_id].wait_milis(); + let millis = std::time::Duration::from_millis(millis_nb); // TODO: find solution to know when change has been done + std::thread::sleep(millis); + } + let mut frame = Mat::default(); + //println!("sequence: {}:{:?}", self.param.seq_id, &self.seq[self.param.seq_id]); if self.param.capture_mode { self.cam.read(&mut frame)?; highgui::imshow("camera", &frame)?; @@ -108,4 +121,16 @@ impl Qualibration { Ok(()) } + } + +pub fn get_sequence_name(seq: &Vec>) -> Vec { + let mut v = vec![]; + + for i in 0..seq.len() { + v.push(seq[i].sequence_name()); + } + + v +} + diff --git a/src/qualibration/annalyse.rs b/src/qualibration/annalyse.rs index 05e2e37..366934e 100644 --- a/src/qualibration/annalyse.rs +++ b/src/qualibration/annalyse.rs @@ -819,6 +819,7 @@ pub fn trackbar_init_param(mem: &mut Param, winname: &str) -> Result<()> { 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("nb_wait", winname, Some(&mut mem.nb_wait), 40, 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)?; @@ -914,7 +915,7 @@ pub fn line_pos(mem: &mut Param, winname: &str) -> Result<()> { pub fn adding_trackbar(mem: &mut Param, _winname: &str) -> Result<()> { //println!("winname: {winname}"); //line_pos(&mut mem, "Play Line")?; - //trackbar_init_param(mem, "init_param")?; + trackbar_init_param(mem, "init_param")?; named_window("histo bgr", WINDOW_AUTOSIZE)?; associate_trackbar("histo bgr", &mut mem.tresh)?; diff --git a/src/qualibration/param.rs b/src/qualibration/param.rs index 52f4487..a21e363 100644 --- a/src/qualibration/param.rs +++ b/src/qualibration/param.rs @@ -10,6 +10,7 @@ use std::time::Instant; #[derive(Clone, Debug)] pub struct Param { pub seq_id: usize, + pub seq_names: Vec, pub imgs: Vec>, pub dst_size: i32, pub r: i32, @@ -35,7 +36,7 @@ pub struct Param { } impl Param { - pub fn new(dir_name: String) -> Result { + pub fn new(dir_name: String, seq_names: Vec) -> Result { Ok(Self { begin: std::time::Instant::now(), capture_mode: dir_name.len() == 0, @@ -43,6 +44,7 @@ impl Param { key: -1, imgs: vec![vec![]], seq_id: 0, + seq_names, dst_size: 900, r: 150, g: 0, @@ -50,7 +52,7 @@ impl Param { nb_all: 120, nb_visible: 40, nb_liss: 10, - nb_wait: 30, + nb_wait: 3, tresh: Treshold::new("histogram", 160, 255)?, canny_v1: 170, canny_v2: 255, @@ -80,11 +82,11 @@ impl Param { ); create_dir(&new_dir).unwrap_or(()); for (i, img_seq) in self.imgs.iter().enumerate() { - let seq_dir_name = format!("{new_dir}/{i}"); + let seq_dir_name = format!("{new_dir}/seq_{i}_{}", self.seq_names[i]); create_dir(&seq_dir_name).unwrap_or(()); - for img in img_seq { + for (id, img) in img_seq.iter().enumerate() { let mut name_img = format!("{seq_dir_name}/"); - name_img.push_str(&format!("img_{i}.png")); + name_img.push_str(&format!("img_{id}.png")); imwrite(&name_img, img, &Vector::from_slice(&[6, 6, 6, 0]))?; } } @@ -100,11 +102,16 @@ impl Param { 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()?; + let parts: Vec<&str> = names[names.len() - 1].split("_").collect(); + let nbr = parts[1]; + //println!("\t\t=> '{}'", names[names.len() - 1]); + let seq_id: usize = parts[1].parse()?; for entry in read_dir(&path)? { let sub_path = entry?.path(); - let names: Vec<&str> = path.to_str().unwrap().split("/").collect(); + let names: Vec<&str> = sub_path.to_str().unwrap().split("/").collect(); let img_name = names[names.len() - 1]; + //println!("all_names: {:?}", &names); + //println!("img_name: {}", img_name); 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)?, diff --git a/src/qualibration/sequence.rs b/src/qualibration/sequence.rs index 4d543be..75c6dec 100644 --- a/src/qualibration/sequence.rs +++ b/src/qualibration/sequence.rs @@ -18,6 +18,8 @@ pub trait Sequence { fn draw(&self, mem: &Param) -> Option>; fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box>; fn is_capture(&self) -> bool; + fn sequence_name(&self) -> String; + fn wait_milis(&self) -> u64; } impl std::fmt::Debug for dyn Sequence { diff --git a/src/qualibration/sequence/init_border.rs b/src/qualibration/sequence/init_border.rs index bcdd4e6..1079a28 100644 --- a/src/qualibration/sequence/init_border.rs +++ b/src/qualibration/sequence/init_border.rs @@ -7,14 +7,15 @@ use crate::qualibration::{ use crate::qualibration::annalyse::image_diff; use crate::qualibration::borders::{ - bord_mult, get_extermities, get_intersection, probabilistic_hough, + bord_mult, get_extermities, get_intersection, probabilistic_hough, mix_borders, }; use opencv::{ calib3d, - core::{Mat, Point as OcvPoint, Size, VecN, Vector}, - imgproc::{canny, cvt_color, COLOR_BGR2GRAY}, + core::{Mat, Point as OcvPoint, Size, VecN, Vector, Scalar, BORDER_CONSTANT}, + imgproc::{self, canny, cvt_color, COLOR_BGR2GRAY, line}, Result, + highgui, }; opencv::opencv_branch_4! { @@ -30,10 +31,11 @@ pub struct InitBorder { finished: bool, cnt: usize, borders: [Point; 4], + nb_millis: u64, } impl InitBorder { - pub fn new(beg: Point, end: Point) -> Self { + pub fn new(beg: Point, end: Point, nb_millis: u64) -> Self { InitBorder { borders: [ Point { @@ -57,6 +59,7 @@ impl InitBorder { color: end.color, }, ], + nb_millis, cnt: 0, finished: false, } @@ -67,7 +70,7 @@ impl Sequence for InitBorder { //type Obj = Self; fn draw(&self, mem: &Param) -> Option> { - if self.cnt > self.borders.len() { + if self.cnt > self.borders.len() || self.finished { return None; } if self.cnt == self.borders.len() { @@ -126,19 +129,19 @@ impl Sequence for InitBorder { 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 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; @@ -150,7 +153,7 @@ impl Sequence for InitBorder { .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 = [(size, size), (size, 0), (0, 0), (0, 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)?; @@ -163,17 +166,17 @@ impl Sequence for InitBorder { )?; //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)?; + 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 + BORDER_CONSTANT, + Scalar::default(), + )?; // do perspective transformation + highgui::imshow("Warped Image", &warped_image)?; self.finished = true; Ok(()) } @@ -181,6 +184,14 @@ impl Sequence for InitBorder { fn is_capture(&self) -> bool { true } + + fn sequence_name(&self) -> String { + "Init_Border".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } pub fn get_lines( diff --git a/src/qualibration/sequence/init_idcode.rs b/src/qualibration/sequence/init_idcode.rs index 1fbd900..fd2ab97 100644 --- a/src/qualibration/sequence/init_idcode.rs +++ b/src/qualibration/sequence/init_idcode.rs @@ -2,7 +2,7 @@ use crate::{ draw::draw_line_dotted, point::Point, qualibration::{ - annalyse::{get_horizontal_segment, image_diff}, + annalyse::{get_horizontal_segment, get_vertical_segment, image_diff}, compute_image::{image_treshold, image_warp}, param::Param, Sequence, @@ -29,15 +29,17 @@ pub struct InitIdcode { cnt: usize, beg: Point, end: Point, + nb_millis: u64, } impl InitIdcode { - pub fn new(beg: Point, end: Point) -> InitIdcode { + pub fn new(beg: Point, end: Point, nb_millis: u64) -> InitIdcode { InitIdcode { finished: false, cnt: 0, beg, end, + nb_millis, } } } @@ -99,7 +101,16 @@ impl Sequence for InitIdcode { self.finished = true; Ok(()) } + fn is_capture(&self) -> bool { true } + + fn sequence_name(&self) -> String { + "init_Id-Code".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } diff --git a/src/qualibration/sequence/line_dotted.rs b/src/qualibration/sequence/line_dotted.rs index b35a403..dc16c15 100644 --- a/src/qualibration/sequence/line_dotted.rs +++ b/src/qualibration/sequence/line_dotted.rs @@ -1,11 +1,14 @@ -use crate::point::{Color, Point}; -use crate::qualibration::{ - annalyse::{ - draw_histograme_bgr_tresh, get_horizontal_segment, get_vertical_segment, histogram_3d, - image_diff, +use crate::{ + point::{Color, Point}, + qualibration::{ + annalyse::{ + draw_histograme_bgr_tresh, get_horizontal_segment, get_vertical_segment, histogram_3d, + image_diff, + }, + compute_image::{image_treshold, image_warp}, + param::Param, + Sequence, }, - param::Param, - Sequence, }; use opencv::{ @@ -20,6 +23,7 @@ opencv::opencv_branch_4! { } opencv::not_opencv_branch_4! { use opencv::core::LINE_AA; + use opencv::imgproc::LINE_8; } #[derive(Debug, Clone)] @@ -30,10 +34,12 @@ pub struct LineDotted { end: Point, continuous_y: bool, continuous_x: bool, + nb_millis: u64, + factor: usize, } impl LineDotted { - pub fn new(beg: Point, end: Point, continuous_y: bool, continuous_x: bool) -> Self { + pub fn new(beg: Point, end: Point, factor: usize, continuous_y: bool, continuous_x: bool, nb_millis: u64) -> Self { Self { finished: false, cnt: 0, @@ -41,6 +47,8 @@ impl LineDotted { end, continuous_x, continuous_y, + factor, + nb_millis, } } } @@ -55,36 +63,47 @@ impl Sequence for LineDotted { } let nb_all = mem.nb_all; let nb_wait = mem.nb_wait as usize; - let nb_visible = mem.nb_visible as usize; + //let nb_visible = mem.nb_visible as usize; + let len = (self.factor * mem.line_pos.len() + nb_wait) as f32; let mut pl = vec![]; + let black = Color { r: 0, g: 0, b: 0 }; 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 }; + + // go to firsst point for _ in 0..nb_all { pl.push(Point { color: black, ..self.beg }); } - let len = (2 * mem.line_pos.len() + nb_wait) as f32; + + // go on the continus_axes in black to gain speed 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; + let val_x = self.end.x;//i as f32 / len * (self.end.x - self.beg.x) + self.beg.x; + let val_y = self.end.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) { + + // donne each pose lavue acording to the slide bar value and the continus axes + for i in 0..(mem.line_pos.len() * self.factor) { 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 val_x = mem.line_pos[i / self.factor] as f32 + self.beg.x; + let val_y = mem.line_pos[i / self.factor] as f32 + self.beg.y; + //let is_visible = (i + nb_wait) % 2 == 0;// && i < nb_visible; + let is_visible = match (self.cnt, i) { + (1, _) => true, + (2, i) => i & 1 == 0, + (cnt, i) => i & (1 << (cnt - 3)) != 0, + }; let c = if is_visible { color } else { black }; pl.push(Point { x: if self.continuous_x { val_cont_x } else { val_x }, @@ -97,52 +116,37 @@ impl Sequence for LineDotted { } fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { - if self.cnt < 1 { + if self.cnt <= ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 2 { self.cnt += 1; + return Ok(()) } - 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 len = ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 1; - 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)?; + //if self.cnt > ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 1 { + // if mem.capture_mode { + // self.finished = true; + // } else { + // self.cnt = 0; + // } + // return Ok(()) + //} + //println!("Groboulli: {}", line!()); + let ids = mem.seq_id; + let img_len = mem.imgs[ids].len(); + let img_id = 2;//(img_len-1).min(self.cnt); + + let background = mem.imgs[ids][0].to_owned(); + let line_dot = mem.imgs[ids][img_id].to_owned(); + let diff = image_diff(&line_dot, &background)?; + //highgui::imshow("lone dotted", &diff)?; + + let warped_image = image_warp(&diff, &mem.homography, mem.h_size)?; + let mut bord_treshed = image_treshold(&warped_image, &mem.tresh)?; + highgui::imshow("Warped and treshed Image", &bord_treshed)?; 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 { @@ -158,10 +162,18 @@ impl Sequence for LineDotted { line(&mut bord_treshed, a, b, color, 1, LINE_8, 0)?; } highgui::imshow("segemnt detector", &bord_treshed)?; + self.cnt += 1; self.finished = true; Ok(()) } fn is_capture(&self) -> bool { true } + fn sequence_name(&self) -> String { + "line_Dotted".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } diff --git a/src/qualibration/sequence/load_image.rs b/src/qualibration/sequence/load_image.rs index c723241..4afa7bc 100644 --- a/src/qualibration/sequence/load_image.rs +++ b/src/qualibration/sequence/load_image.rs @@ -5,11 +5,12 @@ use opencv::Result; #[derive(Debug, Clone, Copy)] pub struct LoadImage { finished: bool, + nb_millis: u64, } impl LoadImage { pub fn new() -> LoadImage { - LoadImage { finished: false } + LoadImage { finished: false, nb_millis: 0 } } } @@ -20,6 +21,7 @@ impl Sequence for LoadImage { } Some(vec![]) } + fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { if !mem.capture_mode { mem.load_image()?; @@ -27,7 +29,16 @@ impl Sequence for LoadImage { self.finished = true; Ok(()) } + fn is_capture(&self) -> bool { false } + + fn sequence_name(&self) -> String { + "Load_Image".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } diff --git a/src/qualibration/sequence/save_image.rs b/src/qualibration/sequence/save_image.rs index 1ddfec3..9edb1a7 100644 --- a/src/qualibration/sequence/save_image.rs +++ b/src/qualibration/sequence/save_image.rs @@ -5,11 +5,12 @@ use opencv::Result; #[derive(Debug, Clone, Copy)] pub struct SaveImage { finished: bool, + nb_millis: u64, } impl SaveImage { pub fn new() -> SaveImage { - SaveImage { finished: false } + SaveImage { finished: false, nb_millis: 0} } } @@ -20,12 +21,22 @@ impl Sequence for SaveImage { } 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 } + + fn sequence_name(&self) -> String { + "Save_Image".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } diff --git a/src/qualibration/sequence/wait_space.rs b/src/qualibration/sequence/wait_space.rs index db26bcf..c1d84e4 100644 --- a/src/qualibration/sequence/wait_space.rs +++ b/src/qualibration/sequence/wait_space.rs @@ -9,16 +9,13 @@ use opencv::Result; #[derive(Debug, Clone, Copy)] pub struct WaitSpace { borders: [Point; 4], - red: [Point; 2], - green: [Point; 2], - blue: [Point; 2], + mid: [Point; 2], + nb_millis: u64, } 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; + pub fn new(beg: Point, end: Point, nb_millis: u64) -> Self { + let mid = (end.y - beg.y) * 0.5 + beg.y; Self { borders: [ Point { @@ -42,42 +39,19 @@ impl WaitSpace { color: end.color, }, ], - red: [ + mid: [ Point { x: beg.x, - y: red_y, + y: mid, 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, + y: mid, color: end.color, }, ], + nb_millis, } } } @@ -94,21 +68,6 @@ impl Sequence for WaitSpace { 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 { @@ -126,44 +85,18 @@ impl Sequence for WaitSpace { mem.nb_visible as usize, )); pl.extend(draw_line_dotted( - &Point{ - color: blue, - ..self.blue[0] + &Point { + color, + ..self.mid[0] }, - &Point{ - color: blue, - ..self.blue[1] + &Point { + color, + ..self.mid[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) } @@ -173,4 +106,12 @@ impl Sequence for WaitSpace { fn is_capture(&self) -> bool { false } + + fn sequence_name(&self) -> String { + "Wait_Space".to_owned() + } + + fn wait_milis(&self) -> u64 { + self.nb_millis + } } From 7d5285748e9bfdd31d051e5e59860acc7319ecd8 Mon Sep 17 00:00:00 2001 From: Lapin Raving Date: Tue, 14 Nov 2023 17:35:09 +0100 Subject: [PATCH 2/2] just saving in middle of nowher` --- src/main.rs | 2 +- src/qualibration.rs | 17 +- src/qualibration/annalyse.rs | 661 ++++++++++++++++++++++- src/qualibration/param.rs | 4 +- src/qualibration/sequence/init_border.rs | 8 +- src/qualibration/sequence/line_dotted.rs | 70 ++- src/qualibration/sequence/load_image.rs | 5 +- src/qualibration/sequence/save_image.rs | 5 +- src/utils.rs | 6 + 9 files changed, 723 insertions(+), 55 deletions(-) diff --git a/src/main.rs b/src/main.rs index d4282cd..6ff052a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,7 +92,7 @@ fn run_all() -> Result<(), Box> { if key != -1 { println!("key: {key}"); - // 81 <- -> 83 + // 81 <- -> 83 } qualibration.param.key = key; if key == 27 { diff --git a/src/qualibration.rs b/src/qualibration.rs index 228f824..2641e82 100644 --- a/src/qualibration.rs +++ b/src/qualibration.rs @@ -62,18 +62,14 @@ impl Qualibration { Box::new(WaitSpace::new(beg, end, 400)), Box::new(InitBorder::new(beg, end, 400)), Box::new(LineDotted::new(beg, end, 2, true, false, 400)), - Box::new(InitIdcode::new(beg2, end, 400)), + //Box::new(InitIdcode::new(beg2, end, 400)), ]; let seq_names = get_sequence_name(&seq); let mut param = Param::new(dir_name.to_owned(), seq_names)?; if !param.capture_mode { param.load_image()?; } - Ok(Qualibration { - seq, - cam, - param, - }) + Ok(Qualibration { seq, cam, param }) } pub fn draw_sequence(&mut self) -> Option> { @@ -96,6 +92,11 @@ impl Qualibration { pub fn run_step(self: &mut Self) -> Result<(), Box> { let seq_id = self.param.seq_id; let seq_name = self.seq[seq_id].sequence_name(); + println!("\n\n\n\n\n\n\n\n"); + println!("\t\t=================================================================="); + println!("\t\t=================================================================="); + println!("\t\t=================================================================="); + println!("\n\n\n\n\n\n\n\n"); println!("seq[{seq_id}]: {seq_name}"); if self.param.capture_mode { @@ -103,7 +104,7 @@ impl Qualibration { let millis = std::time::Duration::from_millis(millis_nb); // TODO: find solution to know when change has been done std::thread::sleep(millis); } - + let mut frame = Mat::default(); //println!("sequence: {}:{:?}", self.param.seq_id, &self.seq[self.param.seq_id]); if self.param.capture_mode { @@ -121,7 +122,6 @@ impl Qualibration { Ok(()) } - } pub fn get_sequence_name(seq: &Vec>) -> Vec { @@ -133,4 +133,3 @@ pub fn get_sequence_name(seq: &Vec>) -> Vec { v } - diff --git a/src/qualibration/annalyse.rs b/src/qualibration/annalyse.rs index 366934e..2c98cec 100644 --- a/src/qualibration/annalyse.rs +++ b/src/qualibration/annalyse.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::HashSet; use std::f64::consts::PI; @@ -67,6 +68,45 @@ pub fn draw_histograme_dbg( Ok(()) } +#[allow(dead_code)] +pub fn draw_histograme_log(window_name: &str, histo: &Vec, is_log: bool) -> Result<()> { + let v: VecN = VecN::new(0., 0., 0., 255.); + let color: VecN = VecN::new(210., 210., 255., 255.); + let mut img = Mat::new_rows_cols_with_default( + histo.len() as i32 * 2, + histo.len() as i32 * 2, + CV_8UC3, + v, + )?; + + let mut max = f64::MIN; + for i in 0..histo.len() { + if histo[i] > max { + max = histo[i]; + } + } + + for i in 0..(histo.len() - 1) { + let x1 = ((i + 0) * 2) as i32; + let x2 = ((i + 1) * 2) as i32; + let (y1, y2); + if is_log { + y1 = ((1.-((histo[i + 0] as f64 + 1.).log10() / (max as f64).log10())) * 512.) as i32; + y2 = ((1.-((histo[i + 1] as f64 + 1.).log10() / (max as f64).log10())) * 512.) as i32; + } else { + y1 = ((1. - ((histo[i + 0] as f64) / (max as f64))) * 512.) as i32; + y2 = ((1. - ((histo[i + 1] as f64) / (max as f64))) * 512.) as i32; + } + let pt1 = OcvPoint::new(x1, y1); + let pt2 = OcvPoint::new(x2, y2); + line(&mut img, pt1, pt2, color, 1, LINE_AA, 0)?; + } + + highgui::imshow(window_name, &img)?; + + Ok(()) +} + #[allow(dead_code)] pub fn draw_histograme(window_name: &str, histo: &Vec) -> Result<()> { let v: VecN = VecN::new(0., 0., 0., 255.); @@ -379,6 +419,618 @@ pub fn get_horizontal_segment(m: &Mat) -> Result, + v_lst: Vec, + line: Vec, + nb_liss: i32, +} + +impl Line { + pub fn new( + pt_all: &mut HashSet<(i32, i32)>, + y_ordering: bool, + beg_lowest: bool, + nb_liss: i32, + ) -> Self { + let mut illand = Line { + h_lst: HashSet::new(), + v_lst: vec![], + line: vec![], + nb_liss, + }; + if pt_all.len() <= 0 { + return illand; + } + //dbg!(&pt_all); + illand.populate_hlst(pt_all); + + illand.define_line(); + //println!(""); + //illand.define_beg_end(false, beg_lowest); + //dbg!(&illand); + illand + } + + //fn define_beg_end(&mut self, y_ordering: bool, beg_lowest: bool) { + // // on a tout les point ordonner + // // on peut les re-ordonner selon un axes interne + //} + fn define_line(&mut self) { + // la ca va etre marant. + // + let mut last_id = 0; + let to_look = [ + (-1, -1), + (0, -1), + (1, -1), + (1, 0), + (1, 1), + (0, 1), + (-1, 1), + (-1, 0), + ]; + + if self.h_lst.len() == 0 { + return; + } + + // search botom-left point. + let mut first = (i32::MAX / 2, 0); + self.h_lst.iter().for_each(|(x, y)| { + if *y > first.1 || (*y == first.1 && *x < first.0) { + first = (*x, *y); + } + }); + + println!("\nfirst: {first:?}\n"); + + let mut ll = self.h_lst.clone(); + let mut l = vec![first]; + let (mut px, mut py) = first; + ll.remove(&first); + + // adding all borders point to a line + 'line: loop { + for k in 0..to_look.len() { + //let id = (k + last_id) % to_look.len(); + let (i, j) = to_look[(k + last_id) % to_look.len()]; + if ll.get(&(i + px, j + py)).is_some() { + l.push((i + px, j + py)); + ll.remove(&(i + px, j + py)); + (px, py) = (i + px, j + py); + last_id = (k + last_id + to_look.len() - 2) % to_look.len(); + continue 'line; + } + } + break; + } + + let (mut min_y, mut max_y) = (f64::MAX, f64::MIN); + let mut l_tmp: Vec = l + .iter() + .map(|(x, y)| { + min_y = (*y as f64).min(min_y); + max_y = (*y as f64).max(max_y); + Pt { + x: *x as f64, + y: *y as f64, + } + }) + .collect(); + + // lissage des point + let raw_pt = l_tmp.clone(); + //println!("[1]raw_pt:{:?}", &raw_pt); + let nb_liss = self.nb_liss * 2; + let (c1, c2) = (1., 48.); + for i in 0..nb_liss { + let mut nl = vec![]; + for i in 0..l_tmp.len() { + let (id_prev, id_next) = + ((i + l_tmp.len() - 1) % l_tmp.len(), (i + 1) % l_tmp.len()); + let (prev, pt, next) = (l_tmp[id_prev], l_tmp[i], l_tmp[id_next]); + + nl.push((prev * c1 + pt * c2 + next * c1) / (2. * c1 + c2)); + } + l_tmp = nl; + } + + let mut histo_ang = vec![0.; 256]; + let mut length_max = 0.; + for i in 0..l_tmp.len() { + let next = l_tmp[(i + 1) % l_tmp.len()]; + let diff = next - l_tmp[i]; + let ang = diff.y.atan2(diff.x); + let id = ((((ang + PI) / (2. * PI)) * 255.) as usize) % 256; + let length = (diff.x * diff.x + diff.y * diff.y).sqrt(); + length_max = length.max(length_max); + histo_ang[id] += 1.; + } + let _ = draw_histograme_log("histo ang", &histo_ang, false); + + let mut histo_ang_diff = vec![0.; 256]; + let mirange = 3; + let mut id_out = vec![0]; + for i in 0..l_tmp.len() { + let next = l_tmp[(i + 1) % l_tmp.len()]; + let next2 = l_tmp[(i + 2) % l_tmp.len()]; + let diff1 = next - l_tmp[i]; + let diff2 = next2 - next; + let ang1 = diff1.y.atan2(diff1.x); + let ang2 = diff2.y.atan2(diff2.x); + + let id = (((((ang2 - ang1) + PI) / (2. * PI)) * 255.) as usize) % 256; + if !(id >= 128 - mirange && id <= 128 + mirange) { + id_out.push(i); + //println!("id:{i}"); + } + histo_ang_diff[id] += 1.; + } + let _ = draw_histograme_log("histo ang diff", &histo_ang_diff, true); + + //let mut histo_lenght = vec![0.; 256]; + //for i in 0..l_tmp.len() { + // let next = l_tmp[(i + 1) % l_tmp.len()]; + // let diff = next - l_tmp[i]; + // //let ang = diff.y.atan2(diff.x); + // //let ang_id = ((ang / (2. * PI) * 256.) as usize) % 256; + // let length = (diff.x * diff.x + diff.y * diff.y).sqrt(); + // let id = (length / length_max * 255.) as usize % 256; + // histo_lenght[id] += 1.; + //} + // draw histo ang + // draw histo dst + //let _ = draw_histograme_log("histo length", &histo_lenght, false); + + // opposite side + // Le but c'est de trouver le point le plus proche mais pas un point voisin + // On va le dessiner pour une partie des point seulement + + + let mut diff = vec![]; + for i in 0..id_out.len()-1 { + let d = id_out[i+1] - id_out[i]; + diff.push((d, id_out[i], id_out[i+1])); + } + diff.sort_by(|a, b| { + match (a.0, b.0) { + (a, b) if a < b => Ordering::Greater, + (a, b) if a == b => Ordering::Equal, + _ => Ordering::Less, + } + }); + + if diff.len() < 2 { + return ; + } + let mut dio = vec![diff[0], diff[1]]; + dio.sort_by(|a, b| { + match (a.1, b.1) { + (a, b) if a > b => Ordering::Greater, + (a, b) if a == b => Ordering::Equal, + _ => Ordering::Less, + } + }); + + + //dbg!("diff:", &diff[..3]); + //dbg!(&id_out); + dbg!(&dio); + + //* + + ////println!("[2]raw_pt:{:?}", &raw_pt); + //let left: Vec = raw_pt[dio[0].1..=dio[0].2].into(); + //let mut right = vec![]; + //for i in (dio[1].1..=dio[1].2).rev() { + ////for i in (id_out[1]..=id_out[2]).rev() { + // right.push(raw_pt[i]); + //} + //println!("[2]raw_pt:{:?}", &raw_pt); + let left: Vec = l_tmp[dio[0].1..=dio[0].2].into(); + let mut right = vec![]; + for i in (dio[1].1..=dio[1].2).rev() { + //for i in (id_out[1]..=id_out[2]).rev() { + right.push(l_tmp[i]); + } + + let mut couple = vec!(); + let nb_jump = 10; + let mut id_last = 0; + let range_id = 20; + for i in 0..left.len() { + //if i % nb_jump == 0 { + let mut dist = vec![]; + let from = (id_last as i32 - range_id as i32).max(0) as usize; + let to = (id_last + range_id).min(right.len()-1); + for id in from..=to { + let df = right[id] - left[i]; + let dst = (df.cross(&df)).sqrt(); + dist.push((id, dst)); + } + dist.sort_by(|a, b| { + if a.1 > b.1 { + Ordering::Greater + } else if a.1 == b.1 { + Ordering::Equal + } else { + Ordering::Less + } + }); + //println!("closest: {:?}", &dist[0]); + id_last = dist[0].0; //dbg!(dist); + couple.push((left[i], right[id_last])); + //} + } + + let l3: Vec = couple.iter().map(|(l, r)| (*l+*r)/2.).collect(); + //*/ + + // + + //let space = 100; + //let dst = 30; + //for i in 0..l_tmp.len() { + // if i % space == 0 { + // // + // } + //} + + self.line = l3; + println!("rest:{}\t", ll.len()); + } + + /// the function also set: self.v_lst + fn populate_hlst(&mut self, pt_all: &mut HashSet<(i32, i32)>) { + let first = pt_all.iter().next().unwrap(); + let mut added = HashSet::from([(first.0, first.1)]); + let to_look = [ + (-1, 0), + (0, -1), + (1, 0), + (0, 1), + (-1, -1), + (-1, 1), + (1, 1), + (1, -1), + ]; + self.h_lst.extend(&added); + while added.len() > 0 { + let mut tmp = HashSet::new(); + for (x, y) in added { + for (i, j) in to_look { + if let Some(pt_new) = pt_all.get(&(x + i, y + j)) { + tmp.insert(*pt_new); + } + } + } + + self.h_lst.extend(tmp.clone()); + tmp.iter().for_each(|pt| { + pt_all.remove(pt); + }); + added = tmp; + } + + let mut tmp = HashSet::new(); + self.h_lst.iter().for_each(|(x, y)| { + for (i, j) in to_look[..4].iter() { + if self.h_lst.get(&(x + i, y + j)).is_none() { + tmp.insert((*x, *y)); + } + } + }); + self.h_lst = tmp; + + println!("\t\t\t\tfinal selecteted:{}", self.h_lst.len()); + + //dbg!(a); + //println!(I); + } +} + +pub fn get_lines( + m: &Mat, + y_ordering: bool, + beg_lowest: bool, + nb_liss: i32, +) -> Result>> { + // donc on va refaire un algo de detection de segement + // * on va chercher des illot: + // * chaque illo on lui definie des limit (min, max) sur x et y + // * on calcule le centre + let mut pt_inside = HashSet::new(); + let (cols, rows) = (m.cols(), m.rows()); + 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 { + pt_inside.insert((i, j)); + } + } + } + + println!("\tFlifou: {}\t\tpt_inserted:{}", line!(), pt_inside.len()); + + let mut lines = vec![]; + while pt_inside.len() > 0 { + lines.push(Line::new(&mut pt_inside, y_ordering, beg_lowest, nb_liss)); + } + + println!("\tFlifou: {}\t\tnb_line:{}", line!(), lines.len()); + + // pour chaque ligne + Ok(lines.iter().map(|line| line.line.clone()).collect()) +} + +#[derive(Debug)] +struct Seg { + h_lst: HashSet<(i32, i32)>, + v_lst: Vec, + min: Pt, + max: Pt, + center: Pt, + beg: Pt, + end: Pt, +} + +impl Seg { + pub fn new(pt_all: &mut HashSet<(i32, i32)>, y_ordering: bool, beg_lowest: bool) -> Self { + let mut illand = Seg { + min: Pt::from((f64::MAX, f64::MAX)), + max: Pt::from((f64::MIN, f64::MIN)), + center: Pt::from((0., 0.)), + beg: Pt::from((0., 0.)), + end: Pt::from((0., 0.)), + h_lst: HashSet::new(), + v_lst: vec![], + }; + if pt_all.len() <= 0 { + return illand; + } + //dbg!(&pt_all); + illand.populate_hlst(pt_all); + //println!(""); + illand.define_beg_end(false, beg_lowest); + //dbg!(&illand); + illand + } + + //fn define_beg_end(&mut self, y_ordering: bool, beg_lowest: bool) { + // // on a tout les point ordonner + // // on peut les re-ordonner selon un axes interne + //} + + /// the function also set: self.v_lst + fn populate_hlst(&mut self, pt_all: &mut HashSet<(i32, i32)>) { + let first = pt_all.iter().next().unwrap(); + let mut added = HashSet::from([(first.0, first.1)]); + let to_look = [ + (-1, 0), + (0, -1), + (1, 0), + (0, 1), + (-1, -1), + (-1, 1), + (1, 1), + (1, -1), + ]; + self.h_lst.extend(&added); + while added.len() > 0 { + let mut tmp = HashSet::new(); + for (x, y) in added { + for (i, j) in to_look { + if let Some(pt_new) = pt_all.get(&(x + i, y + j)) { + tmp.insert(*pt_new); + } + } + } + + self.h_lst.extend(tmp.clone()); + tmp.iter().for_each(|pt| { + pt_all.remove(pt); + }); + added = tmp; + } + + // calcule min, max, center + self.h_lst.iter().for_each(|(x, y)| { + self.min.x = (*x as f64).min(self.min.x); + self.max.x = (*x as f64).max(self.max.x); + self.min.y = (*y as f64).min(self.min.y); + self.max.y = (*y as f64).max(self.max.y); + + self.center.x += *x as f64; + self.center.y += *y as f64; + }); + + self.center /= self.h_lst.len() as f64; + + self.v_lst = self + .h_lst + .iter() + .map(|(x, y)| Pt { + x: (*x as f64), + y: (*y as f64), + }) + .collect(); + } + + /// y_ordering: means we ordering vertically. Else we ordering horizontay + /// beg_lowest: means first value are the lowset. Else first value are the biggest + fn define_beg_end(&mut self, y_ordering: bool, beg_lowest: bool) { + let pts: Vec = self + .h_lst + .iter() + .map(|(x, y)| { + Pt { + x: (*x as f64), + y: (*y as f64), + } - self.center + }) + .collect(); + + let y_cmp = |pt_a: &Pt, pt_b: &Pt| { + if (pt_a.y > pt_b.y) == beg_lowest { + Ordering::Greater + } else if pt_a.y == pt_b.y { + if pt_a.x.abs() > pt_b.x.abs() { + Ordering::Greater + } else if pt_a.x.abs() == pt_b.x.abs() { + Ordering::Equal + } else { + Ordering::Less + } + } else { + Ordering::Less + } + }; + let x_cmp = |pt_a: &Pt, pt_b: &Pt| { + if (pt_a.x > pt_b.x) == beg_lowest { + Ordering::Greater + } else if pt_a.x == pt_b.x { + if pt_a.y.abs() > pt_b.y.abs() { + Ordering::Greater + } else if pt_a.y.abs() == pt_b.y.abs() { + Ordering::Equal + } else { + Ordering::Less + } + } else { + Ordering::Less + } + }; + + //println!("\n\nserching axes:"); + // finding by dichotomie + // finding best central axes. + let mut begin = 0.; + let mut len = 8.; + let nb_deg = 8; + let nb_iter = 20; + let mut id_min = 0; + let mut v_max_x = vec![]; + for _iter in 0..nb_iter { + //println!("iter:{_iter}"); + v_max_x = vec![]; + for i in 0..(nb_deg + 2) { + let rad = (i as f64 - 1.) / len * PI + begin; + let axes_x = Pt::from((rad.cos(), rad.sin())); + let axes_y = Pt::from((-rad.sin(), rad.cos())); + let new_base: Vec = pts + .iter() + .map(|pt| Pt::from((pt.cross(&axes_x), pt.cross(&axes_y)))) + .collect(); + + let mut max_x = 0.; + new_base.iter().for_each(|pt| { + if pt.x.abs() > max_x { + max_x = pt.x.abs(); + } + }); + //println!("\t[i:{i}]rad:{rad:32.26}\tval: {max_x}"); + v_max_x.push((rad, max_x)); + } + + id_min = 0; + for i in 1..=nb_deg { + let (p, n, a) = (v_max_x[i - 1].1, v_max_x[i].1, v_max_x[i + 1].1); + let cnd = (y_ordering && n <= p && n <= a) || (!y_ordering && n >= p && n >= a); + id_min = if cnd { i - 1 } else { id_min }; + } + + begin = v_max_x[id_min].0; + len *= 4.; + } + + let rad = v_max_x[id_min + 1].0; + let axes_x = Pt::from((rad.cos(), rad.sin())); + let axes_y = Pt::from((-rad.sin(), rad.cos())); + let mut npts: Vec = pts + .iter() + .map(|pt| Pt::from((pt.cross(&axes_x), pt.cross(&axes_y)))) + .collect(); + + if y_ordering { + npts.sort_by(y_cmp); + } else { + npts.sort_by(x_cmp); + } + + let mut beg = Pt::from((0., 0.)); + for pt in npts[..(npts.len() / 2)].iter() { + beg += *pt; + } + beg /= (npts.len() / 2) as f64; + + let mut end = Pt::from((0., 0.)); + for pt in npts[(npts.len() / 2)..].iter() { + end += *pt; + } + end /= (npts.len() - (npts.len() / 2)) as f64; + + let beg_tmp = axes_x * beg.x + axes_y * beg.y + self.center; + let end_tmp = axes_x * end.x + axes_y * end.y + self.center; + + self.beg = (beg_tmp - end_tmp) * 1.5 + end_tmp; + self.end = (end_tmp - beg_tmp) * 1.5 + beg_tmp; + } +} + +pub fn get_segment( + m: &Mat, + y_ordering: bool, + beg_lowest: bool, +) -> Result> { + // donc on va refaire un algo de detection de segement + // * on va chercher des illot: + // * chaque illo on lui definie des limit (min, max) sur x et y + // * on calcule le centre + let mut pt_inside = HashSet::new(); + let (cols, rows) = (m.cols(), m.rows()); + 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 { + pt_inside.insert((i, j)); + } + } + } + + let mut illands = vec![]; + while pt_inside.len() > 0 { + illands.push(Seg::new(&mut pt_inside, y_ordering, beg_lowest)); + } + //todo!(); + if y_ordering { + illands.sort_by(|a, b| { + if beg_lowest && a.center.y > b.center.y || !beg_lowest && a.center.y < b.center.y { + Ordering::Greater + } else if a.center.y == b.center.y { + Ordering::Equal + } else { + Ordering::Less + } + }); + } else { + illands.sort_by(|a, b| { + if beg_lowest && a.center.x > b.center.x || !beg_lowest && a.center.x < b.center.x { + Ordering::Greater + } else if a.center.x == b.center.x { + Ordering::Equal + } else { + Ordering::Less + } + }); + } + let segments = illands + .iter() + .map(|illand| ((illand.beg.x, illand.beg.y), (illand.end.x, illand.end.y))) + .collect(); + 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> { @@ -463,7 +1115,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result Result Result Result Self { + pub fn new( + beg: Point, + end: Point, + factor: usize, + continuous_y: bool, + continuous_x: bool, + nb_millis: u64, + ) -> Self { Self { finished: false, cnt: 0, @@ -83,8 +90,8 @@ impl Sequence for LineDotted { // go on the continus_axes in black to gain speed for i in 0..nb_wait { - let val_x = self.end.x;//i as f32 / len * (self.end.x - self.beg.x) + self.beg.x; - let val_y = self.end.y;//i as f32 / len * (self.end.y - self.beg.y) + self.beg.y; + let val_x = self.end.x; //i as f32 / len * (self.end.x - self.beg.x) + self.beg.x; + let val_y = self.end.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 }, @@ -111,16 +118,18 @@ impl Sequence for LineDotted { color: c, }); } - + Some(pl) } fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box> { if self.cnt <= ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 2 { + println!("cnt: {}", self.cnt); self.cnt += 1; - return Ok(()) + return Ok(()); } - //let len = ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 1; + println!("Falgadouf :{} cnt:{}", line!(), self.cnt); + //let len = ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 1; //if self.cnt > ((self.factor * mem.line_pos.len()) as f64).log2() as usize + 1 { // if mem.capture_mode { @@ -133,7 +142,7 @@ impl Sequence for LineDotted { //println!("Groboulli: {}", line!()); let ids = mem.seq_id; let img_len = mem.imgs[ids].len(); - let img_id = 2;//(img_len-1).min(self.cnt); + let img_id = 2; //(img_len-1).min(self.cnt); let background = mem.imgs[ids][0].to_owned(); let line_dot = mem.imgs[ids][img_id].to_owned(); @@ -141,29 +150,32 @@ impl Sequence for LineDotted { //highgui::imshow("lone dotted", &diff)?; let warped_image = image_warp(&diff, &mem.homography, mem.h_size)?; - let mut bord_treshed = image_treshold(&warped_image, &mem.tresh)?; - highgui::imshow("Warped and treshed Image", &bord_treshed)?; + let mut seg_treshed = image_treshold(&warped_image, &mem.tresh)?; - let histo = histogram_3d(&warped_image, mem.nb_liss)?; + let histo = histogram_3d(&diff, mem.nb_liss)?; draw_histograme_bgr_tresh("histo bgr", &histo, &mem.tresh)?; + //let segs = get_segment(&seg_treshed, true, true)?; + //println!("Falgadouf: {} BEFORE", line!()); + let segs = get_lines(&seg_treshed, true, true, mem.nb_liss)?; + ////println!("Falgadouf: {} nb_seg:{}", line!(), segs.len()); - 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)?; + for seg in segs { + //println!("Falgadouf: {}", line!()); + for i in 0..(seg.len() - 1) { + //println!("Falgadouf: {}", line!()); + let ((x0, y0), (x1, y1)) = ((seg[i].x, seg[i].y), (seg[i + 1].x, seg[i + 1].y)); + let blue = (i as f64 / seg.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 seg_treshed, a, b, color, 1, LINE_8, 0)?; + } } - highgui::imshow("segemnt detector", &bord_treshed)?; - self.cnt += 1; - self.finished = true; + //println!("Falgadouf: {}", line!()); + highgui::imshow("Warped and treshed Image + segment", &seg_treshed)?; + //self.finished = true; Ok(()) } fn is_capture(&self) -> bool { diff --git a/src/qualibration/sequence/load_image.rs b/src/qualibration/sequence/load_image.rs index 4afa7bc..d2bacfd 100644 --- a/src/qualibration/sequence/load_image.rs +++ b/src/qualibration/sequence/load_image.rs @@ -10,7 +10,10 @@ pub struct LoadImage { impl LoadImage { pub fn new() -> LoadImage { - LoadImage { finished: false, nb_millis: 0 } + LoadImage { + finished: false, + nb_millis: 0, + } } } diff --git a/src/qualibration/sequence/save_image.rs b/src/qualibration/sequence/save_image.rs index 9edb1a7..322795c 100644 --- a/src/qualibration/sequence/save_image.rs +++ b/src/qualibration/sequence/save_image.rs @@ -10,7 +10,10 @@ pub struct SaveImage { impl SaveImage { pub fn new() -> SaveImage { - SaveImage { finished: false, nb_millis: 0} + SaveImage { + finished: false, + nb_millis: 0, + } } } diff --git a/src/utils.rs b/src/utils.rs index 1223c49..dc0b5bc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -87,6 +87,12 @@ impl From<(f64, f64)> for Pt { } } +//impl From for (f64, f64) { +// fn from(pt: Pt) -> Self { +// (pt.x, pt.y) +// } +//} + impl From<&(f64, f64)> for Pt { fn from((x, y): &(f64, f64)) -> Self { Pt { x: *x, y: *y }