feat: refactoring Qualibration and Seqence is DONE
This commit is contained in:
parent
a27e340de7
commit
97f29960ce
12
src/main.rs
12
src/main.rs
@ -1,7 +1,3 @@
|
||||
//mod qualib_refacto;
|
||||
//use qualib_refacto;
|
||||
//use qualib_refacto::{self, Qualibration as Qualib};
|
||||
|
||||
///
|
||||
/// Configure udev:
|
||||
/// https://github.com/Grix/helios_dac/blob/master/docs/udev_rules_for_linux.md
|
||||
@ -12,10 +8,10 @@ mod framerate;
|
||||
mod logs;
|
||||
mod point;
|
||||
|
||||
mod qualib_refacto;
|
||||
mod qualibration;
|
||||
mod utils;
|
||||
|
||||
use qualib_refacto::{annalyse::adding_trackbar, Qualibration, Sequence};
|
||||
use qualibration::{annalyse::adding_trackbar, Qualibration};
|
||||
|
||||
use conf::Conf;
|
||||
use log::{/*debug, warn, */ error, info};
|
||||
@ -61,7 +57,7 @@ fn run_all() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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));
|
||||
@ -91,7 +87,7 @@ fn run_all() -> Result<(), Box<dyn std::error::Error>> {
|
||||
)?;
|
||||
|
||||
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;
|
||||
|
@ -1,127 +0,0 @@
|
||||
//use opencv::Result;
|
||||
//use opencv::core::{self, Mat};
|
||||
|
||||
static DEBUG: bool = true;
|
||||
|
||||
pub mod annalyse;
|
||||
pub mod borders;
|
||||
pub mod compute_image;
|
||||
|
||||
use std::env::args;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::draw::{draw_line, draw_line_dotted};
|
||||
use crate::point::{Color, Point};
|
||||
|
||||
use opencv::core::Mat;
|
||||
use opencv::Result;
|
||||
//use std::f64::consts::PI;
|
||||
|
||||
use opencv::prelude::*;
|
||||
use opencv::{
|
||||
highgui,
|
||||
videoio::{self, VideoCapture},
|
||||
};
|
||||
|
||||
mod param;
|
||||
use param::Param;
|
||||
|
||||
mod init_border;
|
||||
mod load_image;
|
||||
mod save_image;
|
||||
mod wait_space;
|
||||
use init_border::InitBorder;
|
||||
use load_image::LoadImage;
|
||||
use save_image::SaveImage;
|
||||
use wait_space::WaitSpace;
|
||||
|
||||
pub trait Sequence {
|
||||
fn draw(&self, mem: &Param) -> Option<Vec<Point>>;
|
||||
fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box<dyn std::error::Error>>;
|
||||
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:?}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Qualibration {
|
||||
seq: Vec<Box<dyn Sequence>>,
|
||||
cam: VideoCapture,
|
||||
|
||||
pub param: Param,
|
||||
}
|
||||
|
||||
impl Qualibration {
|
||||
pub fn new() -> Result<Self> {
|
||||
//let v: Vec<Box<dyn Sequence>> = 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;
|
||||
}
|
||||
|
||||
let mut cam = videoio::VideoCapture::new(0, videoio::CAP_ANY)?; // 0 is the default camera ;
|
||||
let opened_cam = videoio::VideoCapture::is_opened(&cam)?;
|
||||
if !opened_cam {
|
||||
panic!("Unable to open default camera!");
|
||||
}
|
||||
|
||||
let mut frame = Mat::default();
|
||||
cam.read(&mut frame)?;
|
||||
|
||||
let beg = Point::from((0., 0., 38400)); // r:150, v:0, b:0
|
||||
let end = Point::from((4095., 4095., 38400)); // r:150, v:0, b:0
|
||||
let seq: Vec<Box<dyn Sequence>> = vec![
|
||||
Box::new(LoadImage::new()),
|
||||
Box::new(WaitSpace::new()),
|
||||
Box::new(InitBorder::new(beg, end)),
|
||||
Box::new(SaveImage::new()),
|
||||
];
|
||||
//let now = std::time::Instant::now();
|
||||
Ok(Qualibration {
|
||||
seq,
|
||||
cam,
|
||||
param: Param::new(dir_name.to_owned())?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn draw_sequence(&mut self) -> Option<Vec<Point>> {
|
||||
if self.param.seq_id >= self.seq.len() {
|
||||
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![]);
|
||||
}
|
||||
}
|
||||
|
||||
pl
|
||||
}
|
||||
|
||||
pub fn run_step(self: &mut Self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
if frame.size()?.width > 0 || !self.param.capture_mode {
|
||||
self.seq[self.param.seq_id].compute_sequence(&mut self.param)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,968 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
use std::f64::consts::PI;
|
||||
|
||||
use super::Param;
|
||||
use super::DEBUG;
|
||||
use crate::utils::Pt;
|
||||
//use opencv::prelude::MatTraitConst;
|
||||
use opencv::prelude::*; //MatTraitConst;
|
||||
|
||||
use opencv::core::{add, subtract, Mat, Point as OcvPoint, Point3_, VecN, CV_8UC3};
|
||||
use opencv::highgui::{self, create_trackbar, named_window, WINDOW_AUTOSIZE};
|
||||
use opencv::imgproc::{cvt_color, line, COLOR_BGR2GRAY};
|
||||
use opencv::Result;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Cnt {
|
||||
Beg(usize),
|
||||
End(usize),
|
||||
}
|
||||
|
||||
opencv::opencv_branch_4! {
|
||||
use opencv::imgproc::LINE_AA;
|
||||
}
|
||||
opencv::not_opencv_branch_4! {
|
||||
use opencv::core::LINE_AA;
|
||||
}
|
||||
|
||||
use super::param::Treshold;
|
||||
const MAX_TRACKBAR: i32 = 255;
|
||||
|
||||
pub fn draw_histograme_dbg(
|
||||
window_name: &str,
|
||||
histo: &Vec<f64>,
|
||||
(from, to): (usize, usize),
|
||||
) -> Result<()> {
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let c1: VecN<f64, 4> = VecN::new(128., 128., 128., 255.);
|
||||
let c2: VecN<f64, 4> = VecN::new(255., 255., 255., 255.);
|
||||
//let color: VecN<f64, 4> = VecN::new(255., 255., 255., 255.);
|
||||
let mut img = Mat::new_rows_cols_with_default(256 * 2, 256 * 2, CV_8UC3, v)?;
|
||||
|
||||
let mut max = 0.;
|
||||
for i in 0..256 {
|
||||
if histo[i] > max {
|
||||
max = histo[i];
|
||||
}
|
||||
}
|
||||
|
||||
let v_log = 10.;
|
||||
|
||||
for i in 0..255 {
|
||||
let x1 = ((i + 0) * 2) as i32;
|
||||
let x2 = ((i + 1) * 2) as i32;
|
||||
let y1 =
|
||||
((histo[i + 0] as f64 + 1.).log(v_log) / (max as f64).log(v_log) * 2. * 256.) as i32;
|
||||
let y2 =
|
||||
((histo[i + 1] as f64 + 1.).log(v_log) / (max as f64).log(v_log) * 2. * 256.) as i32;
|
||||
let color = if i >= from && i <= to { c2 } else { c1 };
|
||||
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(())
|
||||
}
|
||||
|
||||
pub fn draw_histograme(window_name: &str, histo: &Vec<f64>) -> Result<()> {
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let color: VecN<f64, 4> = VecN::new(255., 255., 255., 255.);
|
||||
let mut img = Mat::new_rows_cols_with_default(
|
||||
histo.len() as i32 * 2,
|
||||
histo.len() as i32 * 2,
|
||||
CV_8UC3,
|
||||
v,
|
||||
)?;
|
||||
|
||||
let mut max = 0.;
|
||||
for i in 0..(histo.len() - 1) {
|
||||
if histo[i] > max {
|
||||
max = histo[i];
|
||||
}
|
||||
}
|
||||
|
||||
let v_log = 10.;
|
||||
|
||||
for i in 0..(histo.len() - 1) {
|
||||
let x1 = ((i + 0) * 2) as i32;
|
||||
let x2 = ((i + 1) * 2) as i32;
|
||||
let y1 = ((histo[i + 0] as f64 + 1.).log(v_log) / (max as f64).log(v_log)
|
||||
* 2.
|
||||
* histo.len() as f64) as i32;
|
||||
let y2 = ((histo[i + 1] as f64 + 1.).log(v_log) / (max as f64).log(v_log)
|
||||
* 2.
|
||||
* histo.len() as f64) as i32;
|
||||
let pt1 = OcvPoint::new(x1, y1);
|
||||
let pt2 = OcvPoint::new(x2, y2);
|
||||
line(&mut img, pt1, pt2, color, 1, LINE_AA, 0)?;
|
||||
}
|
||||
|
||||
highgui::imshow(window_name, &img)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw_histograme_bgr(window_name: &str, histo: &Vec<Vec<f64>>) -> Result<()> {
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let b: VecN<f64, 4> = VecN::new(255., 0., 0., 255.);
|
||||
let g: VecN<f64, 4> = VecN::new(0., 255., 0., 255.);
|
||||
let r: VecN<f64, 4> = VecN::new(0., 0., 255., 255.);
|
||||
let color = vec![b, g, r];
|
||||
let mut img = Mat::new_rows_cols_with_default(256 * 2, 256 * 2, CV_8UC3, v)?;
|
||||
|
||||
let mut range = vec![vec![f64::MAX, f64::MIN]; 3];
|
||||
for j in 0..3 {
|
||||
for i in 0..256 {
|
||||
if histo[j][i] > range[j][1] {
|
||||
range[j][1] = histo[j][i];
|
||||
}
|
||||
if histo[j][i] < range[j][0] {
|
||||
range[j][0] = histo[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//let v_log = 10.;
|
||||
|
||||
for j in 0..3 {
|
||||
for i in 0..255 {
|
||||
let x1 = ((i + 0) * 2) as i32;
|
||||
let x2 = ((i + 1) * 2) as i32;
|
||||
let y1 = ((histo[j][i + 0] + 1.).log10() / range[j][1].log10() * 2. * 256.) as i32;
|
||||
let y2 = ((histo[j][i + 1] + 1.).log10() / range[j][1].log10() * 2. * 256.) as i32;
|
||||
let pt1 = OcvPoint::new(x1, y1);
|
||||
let pt2 = OcvPoint::new(x2, y2);
|
||||
line(&mut img, pt1, pt2, color[j], 1, LINE_AA, 0)?;
|
||||
}
|
||||
}
|
||||
|
||||
highgui::imshow(window_name, &img)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn draw_histograme_bgr_tresh(
|
||||
window_name: &str,
|
||||
histo: &Vec<Vec<f64>>,
|
||||
tresh: &Treshold,
|
||||
) -> Result<()> {
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let b: VecN<f64, 4> = VecN::new(255., 0., 0., 255.);
|
||||
let g: VecN<f64, 4> = VecN::new(0., 255., 0., 255.);
|
||||
let r: VecN<f64, 4> = VecN::new(0., 0., 255., 255.);
|
||||
let color1 = vec![b, g, r];
|
||||
let color2 = vec![b / 2., g / 2., r / 2.];
|
||||
let mut img = Mat::new_rows_cols_with_default(256 * 2, 256 * 2, CV_8UC3, v)?;
|
||||
|
||||
let mut vmax = vec![f64::MIN; 3];
|
||||
for j in 0..histo.len() {
|
||||
for i in 0..histo[j].len() {
|
||||
if histo[j][i] > vmax[j] {
|
||||
vmax[j] = histo[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//let v_log = 10.;
|
||||
let max: Vec<f64> = [tresh.max_0 as f64, tresh.max_1 as f64, tresh.max_2 as f64].into();
|
||||
let min: Vec<f64> = [tresh.min_0 as f64, tresh.min_1 as f64, tresh.min_2 as f64].into();
|
||||
|
||||
//println!("min: {min:?}\tmax: {max:?}");
|
||||
|
||||
for j in 0..3 {
|
||||
for i in 0..255 {
|
||||
let x1 = ((i + 0) * 2) as i32;
|
||||
let x2 = ((i + 1) * 2) as i32;
|
||||
let y1 = ((histo[j][i + 0] + 1.).log10() / vmax[j].log10() * 2. * 256.) as i32;
|
||||
let y2 = ((histo[j][i + 1] + 1.).log10() / vmax[j].log10() * 2. * 256.) as i32;
|
||||
let pt1 = OcvPoint::new(x1, y1);
|
||||
let pt2 = OcvPoint::new(x2, y2);
|
||||
|
||||
//let val = (histo[j][i] + 1.).log10() / max[j].log10();
|
||||
let (color, thickness) = if i as f64 >= min[j] && i as f64 <= max[j] {
|
||||
(color1[j], 2)
|
||||
} else {
|
||||
(color2[j], 1)
|
||||
};
|
||||
line(&mut img, pt1, pt2, color, thickness, LINE_AA, 0)?;
|
||||
}
|
||||
}
|
||||
|
||||
highgui::imshow(window_name, &img)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// limit = 0.35 c'est bien
|
||||
pub fn is_same_frame(frame: &Mat, frame_prev: &Mat) -> Result<bool> {
|
||||
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
|
||||
|
||||
let d_bgr = image_diff(frame, frame_prev)?;
|
||||
let histo = histogram_1d(&d_bgr, nb_liss)?;
|
||||
let ((_id1, v1), (_id2, v2)) = first_invert(&histo);
|
||||
|
||||
if DEBUG {
|
||||
// on affiche l'image de la cam
|
||||
highgui::imshow("cam image", frame)?;
|
||||
// on affiche l'image de la cam
|
||||
highgui::imshow("prev image", frame_prev)?;
|
||||
// on affiche la difference
|
||||
highgui::imshow("diff image", &d_bgr)?;
|
||||
// on affiche l'histograme
|
||||
let ids = ((128 - _id2), (128 + _id1));
|
||||
draw_histograme_dbg("histograme", &histo, ids)?;
|
||||
// -- pour chaque image enregistrer on l'affiche ma ca se fait autre part
|
||||
}
|
||||
|
||||
if DEBUG {
|
||||
println!("v1[{_id1}]:{v1}\tv2[{_id1}:{v2}");
|
||||
}
|
||||
|
||||
if v1 >= limit || v2 >= limit {
|
||||
println!("\t XXX DIFFERENT XXX");
|
||||
Ok(false)
|
||||
} else {
|
||||
println!("\t :) Same (: ");
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
// On cherche des segment regourper par ilot de point. chaque illot a une plage de valeur en y qui
|
||||
// lui est propre, aucun autre ilot aura des point dans une plage de valeurs d'un autre illot.
|
||||
pub fn get_horizontal_segment(m: &Mat) -> Result<Vec<(((f32, f32), (f32, f32)), f32)>> {
|
||||
// on va faire un histogram des point selon leur position en y
|
||||
// ca permetera des les differencier
|
||||
// on fait cette histo gramme pour connaitre ces plage de valeur en y
|
||||
let mut seg_pt = HashSet::from([]);
|
||||
let (cols, rows) = (m.cols(), m.rows());
|
||||
let mut histo_x = vec![0.; cols.max(rows) as usize];
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &Point3_<u8> = m.at_2d(j, i)?;
|
||||
if v.x != 0 && v.y != 0 && v.z != 0 {
|
||||
seg_pt.insert((i, j));
|
||||
histo_x[i as usize] += 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// on determine le debut et la fin de ces plage de valeur en x
|
||||
let mut histo_limit = vec![];
|
||||
for i in (0..(histo_x.len() - 1)).rev() {
|
||||
if histo_x[i] != 0. && histo_x[i + 1] == 0. {
|
||||
histo_limit.push(Cnt::End(i));
|
||||
}
|
||||
if histo_x[i] == 0. && histo_x[i + 1] != 0. {
|
||||
histo_limit.push(Cnt::Beg(i + 1));
|
||||
}
|
||||
}
|
||||
let mut limits = vec![];
|
||||
for k in 0..(histo_limit.len() / 2) {
|
||||
if let (Cnt::Beg(a), Cnt::End(b)) = (histo_limit[2 * k + 1], histo_limit[2 * k]) {
|
||||
limits.push((a, b));
|
||||
}
|
||||
}
|
||||
|
||||
// on regroupe les point par illot.
|
||||
let mut segment_iland = vec![vec![]; limits.len()];
|
||||
for (x, y) in seg_pt {
|
||||
let id = get_id_groups(&limits, x as usize).unwrap();
|
||||
segment_iland[id].push((x, y));
|
||||
}
|
||||
|
||||
// on transforme chaque point en pt: (f32, f32) -> Pt
|
||||
// toujours avec la meme structure d'ilot.
|
||||
let segment_iland_pt: Vec<Vec<Pt>> = segment_iland
|
||||
.iter()
|
||||
.map(|iland| {
|
||||
iland
|
||||
.iter()
|
||||
.map(|(x, y)| Pt {
|
||||
x: *x as f64,
|
||||
y: *y as f64,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut segments = vec![];
|
||||
for (i, iland) in segment_iland_pt.iter().enumerate() {
|
||||
let mut center = Pt { x: 0., y: 0. };
|
||||
for p in iland {
|
||||
center += *p;
|
||||
}
|
||||
center /= iland.len() as f64;
|
||||
|
||||
let max_deg = 360;
|
||||
let (mut rad_min, mut y_min) = (0., f64::MAX);
|
||||
let mut iland_min = vec![];
|
||||
for deg in 0..max_deg {
|
||||
let rad = (deg as f64) / (max_deg as f64) * PI * 2.;
|
||||
let y_axis = Pt {
|
||||
x: rad.sin(),
|
||||
y: rad.cos(),
|
||||
};
|
||||
let x_axis = Pt {
|
||||
x: -y_axis.y,
|
||||
y: y_axis.x,
|
||||
};
|
||||
let mut tmp_iland = vec![];
|
||||
let mut y_abs_max = f64::MIN;
|
||||
for pt in iland {
|
||||
let mut p = *pt - center;
|
||||
p = Pt {
|
||||
x: p.cross(&x_axis),
|
||||
y: p.cross(&y_axis),
|
||||
};
|
||||
tmp_iland.push(p);
|
||||
if y_abs_max < p.y.abs() {
|
||||
y_abs_max = p.y.abs();
|
||||
}
|
||||
}
|
||||
if y_abs_max < y_min {
|
||||
y_min = y_abs_max;
|
||||
rad_min = rad;
|
||||
iland_min = tmp_iland;
|
||||
}
|
||||
}
|
||||
iland_min.sort_by(|pta, ptb| {
|
||||
if pta.y < ptb.y {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if pta.y == ptb.y {
|
||||
if pta.x.abs() < ptb.x.abs() {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if pta.x.abs() == ptb.x.abs() {
|
||||
std::cmp::Ordering::Equal
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
});
|
||||
let id1 = iland_min.len() / 2;
|
||||
let id2 = iland_min.len() - id1;
|
||||
let mean_r = Pt::mean(&iland_min[..id1]);
|
||||
let mean_l = Pt::mean(&iland_min[id2..]);
|
||||
//let mean_r = iland_min[0];
|
||||
//let mean_l = iland_min.last().unwrap();
|
||||
|
||||
let y_axis = Pt {
|
||||
x: rad_min.sin(),
|
||||
y: rad_min.cos(),
|
||||
};
|
||||
let x_axis = Pt {
|
||||
x: -y_axis.y,
|
||||
y: y_axis.x,
|
||||
};
|
||||
let pt_r = center + (y_axis * mean_r.y) + (x_axis * mean_r.x);
|
||||
let pt_l = center + (y_axis * mean_l.y) + (x_axis * mean_l.x);
|
||||
//segments.push(((pt_l.x as f32, pt_l.y as f32), (pt_r.x as f32, pt_r.y as f32)));
|
||||
let pt_r_2 = pt_l + (pt_r - pt_l) * 1.5;
|
||||
let pt_l_2 = pt_r + (pt_l - pt_r) * 1.5;
|
||||
segments.push((
|
||||
(
|
||||
((pt_l_2.x as f32, pt_l_2.y as f32)),
|
||||
((pt_r_2.x as f32, pt_r_2.y as f32)),
|
||||
),
|
||||
y_min as f32,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(segments)
|
||||
}
|
||||
|
||||
// On cherche des segment regourper par ilot de point. chaque illot a une plage de valeur en y qui
|
||||
// lui est propre, aucun autre ilot aura des point dans une plage de valeurs d'un autre illot.
|
||||
pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
|
||||
// on va faire un histogram des point selon leur position en y
|
||||
// ca permetera des les differencier
|
||||
// on fait cette histo gramme pour connaitre ces plage de valeur en y
|
||||
let mut seg_pt = HashSet::from([]);
|
||||
let (cols, rows) = (m.cols(), m.rows());
|
||||
let mut histo_y = vec![0.; cols.max(rows) as usize];
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &Point3_<u8> = m.at_2d(j, i)?;
|
||||
if v.x != 0 && v.y != 0 && v.z != 0 {
|
||||
seg_pt.insert((i, j));
|
||||
histo_y[j as usize] += 1.;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// on determine le debut et la fin de ces palge de l=valeur en y
|
||||
let mut histo_limit = vec![];
|
||||
for i in (0..(histo_y.len() - 1)).rev() {
|
||||
if histo_y[i] != 0. && histo_y[i + 1] == 0. {
|
||||
histo_limit.push(Cnt::End(i));
|
||||
}
|
||||
if histo_y[i] == 0. && histo_y[i + 1] != 0. {
|
||||
histo_limit.push(Cnt::Beg(i + 1));
|
||||
}
|
||||
}
|
||||
let mut limits = vec![];
|
||||
for k in 0..(histo_limit.len() / 2) {
|
||||
if let (Cnt::Beg(a), Cnt::End(b)) = (histo_limit[2 * k + 1], histo_limit[2 * k]) {
|
||||
limits.push((a, b));
|
||||
}
|
||||
}
|
||||
|
||||
// on regroupe les point par illot.
|
||||
let mut segment_iland = vec![vec![]; limits.len()];
|
||||
for (x, y) in seg_pt {
|
||||
let id = get_id_groups(&limits, y as usize).unwrap();
|
||||
segment_iland[id].push((x, y));
|
||||
}
|
||||
|
||||
// on transforme chaque point en pt: (f32, f32) -> Pt
|
||||
// toujours avec la meme structure d'ilot.
|
||||
let segment_iland_pt: Vec<Vec<Pt>> = segment_iland
|
||||
.iter()
|
||||
.map(|iland| {
|
||||
iland
|
||||
.iter()
|
||||
.map(|(x, y)| Pt {
|
||||
x: *x as f64,
|
||||
y: *y as f64,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Pour chaque ilot de pixel: on prend le centre, on cherche l'axe qui passe le plus au centre
|
||||
// de l'illot. Pour trouver cet axe, pour chaque pixel de l'ilot, on va calculer l'eccart au
|
||||
// carree avec cet axe. On selectionne l'axe qui a l'erreur la plus faible
|
||||
// TODO: peut etre un meileur algo de recheche de l'axe (dicotomie en partie)
|
||||
// En suite on tris ces pixel et on prend la moiter la plus haute et la moiter la plus basse
|
||||
// part raport a l'axe. On fait la mayenne des ces 2 groupe et on a les extremiter haute et
|
||||
// basse pour cet ilot de pixel. En suite on multiplie par 2 ce segement pour qui soit de la
|
||||
// taille de l'ilots.
|
||||
//
|
||||
// TODO: La selection de l'axe qui passe au centre de l'ilot pourrauiut aussi etre meilleur
|
||||
// au lieux d'utiliser l'arreur, on pourrait regarder la valeur absolue de la coordoner x la plus petit
|
||||
// DONE=> j'ai tester une autre methode mais il y a plus d'erreur... mais
|
||||
// l'orientation des segment est pas mal. En gros l'orientation de l'axe n'est pas
|
||||
// toujours la meme. C'est du a la fonction de tris. La fonction ne s'execute pas dans
|
||||
// le meme ordre sur les valeur, Et quand 2 valeurs sont identique, elle peuvent etre
|
||||
// inter changer.
|
||||
// TODO: La selection des pixel pour chaque illot pourrait etre ameliorer
|
||||
// En fait elle me va bien. C'est vrai que il ne sont pas ouf mais bon...
|
||||
let mut segments = vec![];
|
||||
for (i, iland) in segment_iland_pt.iter().enumerate() {
|
||||
let mut center = Pt { x: 0., y: 0. };
|
||||
for p in iland {
|
||||
center += *p;
|
||||
}
|
||||
center /= iland.len() as f64;
|
||||
|
||||
let max_deg = 360;
|
||||
let (mut err_min, mut rad_min, mut x_min) = (f64::MAX, 0., f64::MAX);
|
||||
let mut iland_min = vec![];
|
||||
for deg in 0..max_deg {
|
||||
let rad = (deg as f64) / (max_deg as f64) * PI * 2.;
|
||||
let y_axis = Pt {
|
||||
x: rad.sin(),
|
||||
y: rad.cos(),
|
||||
};
|
||||
let x_axis = Pt {
|
||||
x: -y_axis.y,
|
||||
y: y_axis.x,
|
||||
};
|
||||
let mut err = 0.;
|
||||
let mut tmp_iland = vec![];
|
||||
let mut x_abs_max = f64::MIN;
|
||||
for pt in iland {
|
||||
let mut p = *pt - center;
|
||||
p = Pt {
|
||||
x: p.cross(&x_axis),
|
||||
y: p.cross(&y_axis),
|
||||
};
|
||||
err += p.x * p.x;
|
||||
tmp_iland.push(p);
|
||||
if x_abs_max < p.x.abs() {
|
||||
x_abs_max = p.x.abs();
|
||||
}
|
||||
}
|
||||
if x_abs_max < x_min {
|
||||
x_min = x_abs_max;
|
||||
rad_min = rad;
|
||||
iland_min = tmp_iland;
|
||||
}
|
||||
//if err < err_min {
|
||||
// err_min = err;
|
||||
// rad_min = rad;
|
||||
// iland_min = tmp_iland;
|
||||
//}
|
||||
}
|
||||
iland_min.sort_by(|pta, ptb| {
|
||||
if pta.y < ptb.y {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if pta.y == ptb.y {
|
||||
if pta.x.abs() < ptb.x.abs() {
|
||||
std::cmp::Ordering::Greater
|
||||
} else if pta.x.abs() == ptb.x.abs() {
|
||||
std::cmp::Ordering::Equal
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
});
|
||||
let id1 = iland_min.len() / 2;
|
||||
let id2 = iland_min.len() - id1;
|
||||
let mean_up = Pt::mean(&iland_min[..id1]);
|
||||
let mean_down = Pt::mean(&iland_min[id2..]);
|
||||
//let mean_up = iland_min[0];
|
||||
//let mean_down = iland_min.last().unwrap();
|
||||
|
||||
let y_axis = Pt {
|
||||
x: rad_min.sin(),
|
||||
y: rad_min.cos(),
|
||||
};
|
||||
let x_axis = Pt {
|
||||
x: -y_axis.y,
|
||||
y: y_axis.x,
|
||||
};
|
||||
let pt_up = center + (y_axis * mean_up.y) + (x_axis * mean_up.x);
|
||||
let pt_down = center + (y_axis * mean_down.y) + (x_axis * mean_down.x);
|
||||
//segments.push(((pt_down.x as f32, pt_down.y as f32), (pt_up.x as f32, pt_up.y as f32)));
|
||||
let pt_up_2 = pt_down + (pt_up - pt_down) * 1.5;
|
||||
let pt_down_2 = pt_up + (pt_down - pt_up) * 1.5;
|
||||
segments.push((
|
||||
(pt_down_2.x as f32, pt_down_2.y as f32),
|
||||
(pt_up_2.x as f32, pt_up_2.y as f32),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(segments)
|
||||
}
|
||||
|
||||
fn average_pt_i32(vals: &[(i32, i32)]) -> (f32, f32) {
|
||||
let (mut mean_x, mut mean_y) = (0., 0.);
|
||||
let len = vals.len() as f32;
|
||||
|
||||
for (x, y) in vals {
|
||||
mean_x += *x as f32;
|
||||
mean_y += *y as f32;
|
||||
}
|
||||
(mean_x / len, mean_y / len)
|
||||
}
|
||||
|
||||
fn get_id_groups(limits: &Vec<(usize, usize)>, id: usize) -> Option<usize> {
|
||||
for (id_seg, (min, max)) in limits.iter().enumerate() {
|
||||
if id >= *min && id <= *max {
|
||||
return Some(id_seg);
|
||||
}
|
||||
}
|
||||
None
|
||||
//return usize::MAX; // im lazy to have Option return...
|
||||
}
|
||||
|
||||
pub fn annalyse_segment(m: &Mat) -> Result<Vec<Vec<(i32, i32)>>> {
|
||||
// on recupere les coordoner des point selectioner
|
||||
let mut seg_pt = HashSet::from([]);
|
||||
let (cols, rows) = (m.cols(), m.rows());
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &Point3_<u8> = m.at_2d(j, i)?;
|
||||
if v.x != 0 && v.y != 0 && v.z != 0 {
|
||||
seg_pt.insert((i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// on garde que ceux qui sont frontiere
|
||||
//let around_all = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)];
|
||||
let around_all = [(-1, 0), (0, 1), (1, 0), (0, -1)];
|
||||
let mut selected: HashSet<(i32, i32)> = seg_pt
|
||||
.iter()
|
||||
.filter_map(|(x, y)| {
|
||||
for (k, (i, j)) in around_all.iter().enumerate() {
|
||||
if seg_pt.get(&(*x + i, *y + j)).is_none() {
|
||||
return Some((*x, *y));
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect();
|
||||
|
||||
//let around = [(-1, 0), (0, -1), (1, 0), (0, 1), (-1, -1), (1, -1), (1, 1), (-1, 1)];
|
||||
let around = [
|
||||
(-1, 1),
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(1, 0),
|
||||
(1, -1),
|
||||
(0, -1),
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
];
|
||||
let mut lines = vec![];
|
||||
while selected.len() > 0 {
|
||||
let mut outed: HashSet<(i32, i32)> = HashSet::from([]);
|
||||
let (x, y) = selected.iter().next().unwrap();
|
||||
let mut line = vec![(*x, *y)];
|
||||
|
||||
outed.insert((*x, *y));
|
||||
let mut last = 0;
|
||||
'line: loop {
|
||||
let (x, y) = line[line.len() - 1];
|
||||
for k in 0..around.len() {
|
||||
let (i, j) = around[(k + last) % around.len()];
|
||||
if seg_pt.get(&(x + i, y + j)).is_some() && outed.get(&(x + i, y + j)).is_none() {
|
||||
line.push((x + i, y + j));
|
||||
outed.insert((x + i, y + j));
|
||||
last = k + last + around.len() - 2;
|
||||
// ici on pourrait cleaner le rest
|
||||
//for l in (k+1)..around.len() {
|
||||
// let (i, j) = around[(l+last)%around.len()];
|
||||
// outed.insert((x+i, y+j));
|
||||
// //
|
||||
//}
|
||||
continue 'line;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
lines.push(line);
|
||||
for (x, y) in outed {
|
||||
selected.remove(&(x, y));
|
||||
}
|
||||
}
|
||||
println!("\nseg: {}", lines.len());
|
||||
Ok(lines)
|
||||
}
|
||||
|
||||
pub fn image_mean(frames: &[Mat]) -> Result<Mat> {
|
||||
/*
|
||||
* Il faudrait pouvoir changer les matrice de type pour avoir des valeur plus grande
|
||||
* */
|
||||
let mut frames_big: Vec<Mat> = vec![];
|
||||
let len = frames.len() as i16;
|
||||
|
||||
for frame in frames {
|
||||
let mut tmp = Mat::default();
|
||||
frame.convert_to(&mut tmp, 19, 1., 0.)?; // 19 is for: CV_16SC3
|
||||
frames_big.push(tmp);
|
||||
}
|
||||
|
||||
let mut img_sum: Mat = frames_big[0].clone();
|
||||
let mask = Mat::default();
|
||||
for frame in frames_big[1..].iter() {
|
||||
let mut tmp = Mat::default();
|
||||
add(&img_sum, &frame, &mut tmp, &mask, -1)?;
|
||||
img_sum = tmp;
|
||||
}
|
||||
|
||||
let (cols, rows) = (img_sum.cols(), img_sum.rows());
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &mut Point3_<i16> = img_sum.at_2d_mut(j, i)?;
|
||||
v.x /= len;
|
||||
v.y /= len;
|
||||
v.z /= len;
|
||||
}
|
||||
}
|
||||
|
||||
let mut mean = Mat::default();
|
||||
img_sum.convert_to(&mut mean, 16, 1., 0.)?; // 16 is for: CV_8UC3
|
||||
|
||||
Ok(mean)
|
||||
}
|
||||
|
||||
pub fn image_diff(frame: &Mat, frame_prev: &Mat) -> Result<Mat> {
|
||||
let mut diff_bgr = Mat::default();
|
||||
let mut diff_bgr_2 = Mat::default();
|
||||
let mut d_bgr = Mat::default();
|
||||
let (row, col) = (frame.rows(), frame.cols());
|
||||
let mask = Mat::default();
|
||||
let v: VecN<f64, 4> = VecN::new(128., 128., 128., 128.);
|
||||
let mid: Mat = Mat::new_rows_cols_with_default(row, col, CV_8UC3, v)?;
|
||||
|
||||
// ca parait etonant d'enlever la difference dans l'autre sens mais paradoxalement, ca permet
|
||||
// d'avoir toutes les valeur, pck a chaque fois les valeur negative sont mise a 0 dans
|
||||
// l'operation de soustraction
|
||||
subtract(frame, frame_prev, &mut diff_bgr, &mask, -1)?;
|
||||
add(&diff_bgr, &mid, &mut diff_bgr_2, &mask, -1)?;
|
||||
subtract(frame_prev, frame, &mut diff_bgr, &mask, -1)?;
|
||||
subtract(&diff_bgr_2, &diff_bgr, &mut d_bgr, &mask, -1)?;
|
||||
|
||||
Ok(d_bgr)
|
||||
}
|
||||
|
||||
pub fn histogram_3d(m: &Mat, nb_liss: i32) -> Result<Vec<Vec<f64>>> {
|
||||
let (cols, rows) = (m.cols(), m.rows());
|
||||
let mut histo = vec![vec![0.; 256]; 3];
|
||||
|
||||
// on calcule l'histograme
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &Point3_<u8> = m.at_2d(j, i)?;
|
||||
let (b, g, r) = (v.x as usize, v.y as usize, v.z as usize);
|
||||
histo[2][r] += 1.;
|
||||
histo[1][g] += 1.;
|
||||
histo[0][b] += 1.;
|
||||
}
|
||||
}
|
||||
|
||||
// on lisse l'histograme
|
||||
for j in 0..3 {
|
||||
let mut tmp = histo[j].clone();
|
||||
for _ in 0..nb_liss {
|
||||
for i in 1..(tmp.len() - 1) {
|
||||
histo[j][i] = (tmp[i - 1] + 1. * tmp[i] + tmp[i + 1]) / 3.;
|
||||
}
|
||||
tmp = histo[j].clone();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(histo)
|
||||
}
|
||||
|
||||
pub fn histogram_1d(m: &Mat, nb_liss: i32) -> Result<Vec<f64>> {
|
||||
let (cols, rows) = (m.cols(), m.rows());
|
||||
let mut histo = vec![0; 256];
|
||||
let mut m_gray = Mat::default();
|
||||
|
||||
// on convertie en gris
|
||||
cvt_color(m, &mut m_gray, COLOR_BGR2GRAY, 0)?;
|
||||
// on calcule l'histograme
|
||||
for j in 0..rows {
|
||||
for i in 0..cols {
|
||||
let v: &u8 = m_gray.at_2d(j, i)?;
|
||||
let id = *v as usize;
|
||||
histo[id] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// on lisse l'histograme
|
||||
let mut histo: Vec<f64> = histo.iter().map(|x| *x as f64).collect();
|
||||
let mut tmp = histo.clone();
|
||||
for _ in 0..nb_liss {
|
||||
for i in 1..(histo.len() - 1) {
|
||||
histo[i] = (tmp[i - 1] + 2. * tmp[i] + tmp[i + 1]) / 4.;
|
||||
}
|
||||
tmp = histo.clone();
|
||||
}
|
||||
|
||||
Ok(histo)
|
||||
}
|
||||
|
||||
pub fn first_invert(histo: &Vec<f64>) -> ((usize, f64), (usize, f64)) {
|
||||
// on applique un log puis on normalise mar le log du max
|
||||
let mut normalised = vec![0.; histo.len()];
|
||||
let mut p1 = vec![0.; histo.len() / 2];
|
||||
let mut p2 = vec![0.; histo.len() / 2];
|
||||
let mut dp1 = vec![0.; histo.len() / 2];
|
||||
let mut dp2 = vec![0.; histo.len() / 2];
|
||||
let mid = (histo.len() + 1) / 2;
|
||||
let max = (histo[mid] as f64).log10(); // on par du principe que le max est au centre
|
||||
|
||||
for i in 0..histo.len() {
|
||||
normalised[i] = (histo[i] as f64 + 1.).log10() / max;
|
||||
}
|
||||
for i in (mid)..(histo.len() - 1) {
|
||||
p1[i - mid] = mid as f64 * ((normalised[mid] - normalised[i + 1]) / (i - mid + 2) as f64);
|
||||
}
|
||||
for i in (1..mid).rev() {
|
||||
p2[mid - i - 1] = mid as f64 * ((normalised[mid] - normalised[i]) / (mid - i) as f64);
|
||||
}
|
||||
for i in 0..(mid - 1) {
|
||||
dp1[i] = p1[i + 1] - p1[i];
|
||||
dp2[i] = p2[i + 1] - p2[i];
|
||||
}
|
||||
|
||||
let mut dist_1 = 0;
|
||||
for (i, v) in dp1.iter().enumerate() {
|
||||
if v < &0. {
|
||||
dist_1 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
let mut dist_2 = 0;
|
||||
for (i, v) in dp2.iter().enumerate() {
|
||||
if v < &0. {
|
||||
dist_2 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
(dist_1, normalised[mid + dist_1]),
|
||||
(dist_2, normalised[mid - dist_2]),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn trackbar_init_param(mem: &mut Param, winname: &str) -> Result<()> {
|
||||
named_window(winname, WINDOW_AUTOSIZE)?;
|
||||
highgui::move_window(winname, 20, 20)?;
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let m = Mat::new_rows_cols_with_default(1, 1024, 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 Param, winname: &str) -> Result<()> {
|
||||
//highgui
|
||||
let winname = format!("{}: {}", winname, 0); //"bord selected: 0";
|
||||
named_window(winname.as_str(), WINDOW_AUTOSIZE)?;
|
||||
highgui::move_window(winname.as_str(), 20, 520)?;
|
||||
//highgui::move_window(winname, 20, 20)?;
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let m = Mat::new_rows_cols_with_default(1, 1800, CV_8UC3, v)?;
|
||||
highgui::imshow(winname.as_str(), &m)?;
|
||||
//
|
||||
create_trackbar(
|
||||
"canny min",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.canny_v1),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"canny max",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.canny_v2),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
|
||||
create_trackbar(
|
||||
"rho : ",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.hough_param.rho),
|
||||
1000,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"theta : ",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.hough_param.theta),
|
||||
1000,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"treshold: ",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.hough_param.treshold),
|
||||
255,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"min_leng: ",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.hough_param.min_length),
|
||||
1000,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"max_gap : ",
|
||||
winname.as_str(),
|
||||
Some(&mut mem.hough_param.max_line_gap),
|
||||
50000,
|
||||
None,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn line_pos(mem: &mut Param, winname: &str) -> Result<()> {
|
||||
named_window(winname, WINDOW_AUTOSIZE)?;
|
||||
highgui::move_window(winname, 20, 20)?;
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
let m = Mat::new_rows_cols_with_default(1, 1024, CV_8UC3, v)?;
|
||||
highgui::imshow(winname, &m)?;
|
||||
|
||||
for i in 0..mem.line_pos.len() {
|
||||
create_trackbar(
|
||||
format!("pt[{i}]:\t").as_str(),
|
||||
winname,
|
||||
Some(&mut mem.line_pos[i]),
|
||||
4095,
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn adding_trackbar(mut mem: &mut Param, winname: &str) -> Result<()> {
|
||||
//println!("winname: {winname}");
|
||||
//line_pos(&mut mem, "Play Line")?;
|
||||
//trackbar_init_param(mem, "init_param")?;
|
||||
|
||||
named_window("histo bgr", WINDOW_AUTOSIZE)?;
|
||||
associate_trackbar("histo bgr", &mut mem.tresh)?;
|
||||
create_trackbar(
|
||||
"nb_liss",
|
||||
"histo bgr",
|
||||
Some(&mut mem.nb_liss),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
|
||||
//trackbar_line_segment(mem, "line detector")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn associate_trackbar(winname: &str, tresh: &mut Treshold) -> Result<()> {
|
||||
create_trackbar(
|
||||
"blue min: ",
|
||||
winname,
|
||||
Some(&mut tresh.min_0),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"blue max: ",
|
||||
winname,
|
||||
Some(&mut tresh.max_0),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
|
||||
create_trackbar(
|
||||
"green min: ",
|
||||
winname,
|
||||
Some(&mut tresh.min_1),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"green max: ",
|
||||
winname,
|
||||
Some(&mut tresh.max_1),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
|
||||
create_trackbar(
|
||||
"red min: ",
|
||||
winname,
|
||||
Some(&mut tresh.min_2),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
create_trackbar(
|
||||
"red max: ",
|
||||
winname,
|
||||
Some(&mut tresh.max_2),
|
||||
MAX_TRACKBAR,
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
use super::param::HoughLine;
|
||||
use crate::utils::{CartesianEquation, EqAffine, Pt};
|
||||
use opencv::core::{add, subtract, Mat, VecN, Vector, CV_8UC3};
|
||||
//use opencv::prelude::MatTraitConst;
|
||||
use opencv::imgproc::{cvt_color, hough_lines_p, COLOR_GRAY2BGR};
|
||||
use opencv::prelude::*; //MatTraitConst;
|
||||
use opencv::types::VectorOfVec4i;
|
||||
use opencv::Result;
|
||||
|
||||
pub fn mix_borders(background: &Mat, borders: Vec<Mat>) -> Result<Mat> {
|
||||
let (row, col) = (background.rows(), background.cols());
|
||||
//let mask = Mat::default();
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 0.);
|
||||
let mut sum_diff_0 = Mat::new_rows_cols_with_default(row, col, CV_8UC3, v)?;
|
||||
let mut sum_diff_1 = Mat::new_rows_cols_with_default(row, col, CV_8UC3, v)?;
|
||||
let mask = Mat::default();
|
||||
let mut tmp = Mat::default();
|
||||
|
||||
// on va faire la somme des difference
|
||||
// on va les ajouter a l'image du fond
|
||||
for bord in borders {
|
||||
//let diff = image_diff(&bord, background)?;
|
||||
//add(&diff, &mid, &mut diff_bgr_2, &mask, -1)?;
|
||||
let mut diff = Mat::default();
|
||||
subtract(&bord, background, &mut diff, &mask, -1)?;
|
||||
add(&diff, &sum_diff_0, &mut tmp, &mask, -1)?;
|
||||
sum_diff_0 = tmp.clone();
|
||||
|
||||
subtract(background, &bord, &mut diff, &mask, -1)?;
|
||||
add(&diff, &sum_diff_1, &mut tmp, &mask, -1)?;
|
||||
sum_diff_1 = tmp.clone();
|
||||
}
|
||||
//let v: VecN<f64, 4> = VecN::new(128., 128., 128., 128.);
|
||||
//let mid = Mat::new_rows_cols_with_default(row, col, CV_8UC3, v)?;
|
||||
let mut tmp = Mat::default();
|
||||
//let mut tmp2 = Mat::default();
|
||||
let mut mix = Mat::default();
|
||||
add(&sum_diff_0, &background, &mut tmp, &mask, -1)?;
|
||||
subtract(&tmp, &sum_diff_1, &mut mix, &mask, -1)?;
|
||||
|
||||
Ok(mix)
|
||||
}
|
||||
|
||||
//impl Add for (f64, f64) {
|
||||
//}
|
||||
pub fn bord_mult(pt: Vec<(f64, f64)>, factor: f64) -> Vec<(f64, f64)> {
|
||||
let pt: Vec<Pt> = pt.iter().map(|p| Pt::from(p)).collect();
|
||||
|
||||
let mut pa = vec![];
|
||||
let mut pb = vec![];
|
||||
for i in 0..pt.len() {
|
||||
let k = (i + pt.len() - 1) % pt.len();
|
||||
let j = (i + 1) % pt.len();
|
||||
pa.push((pt[i] - pt[j]) * factor + pt[j]);
|
||||
pb.push((pt[i] - pt[k]) * factor + pt[k]);
|
||||
}
|
||||
|
||||
let mut eq = vec![];
|
||||
for i in 0..pt.len() {
|
||||
let j = (i + 1) % pt.len();
|
||||
eq.push(CartesianEquation::new_from_pt(&pb[i], &pa[j]));
|
||||
}
|
||||
|
||||
let mut p_out = vec![];
|
||||
for i in 0..pt.len() {
|
||||
let k = (i + pt.len() - 1) % pt.len();
|
||||
p_out.push(eq[i].intersection(&eq[k]).unwrap()); // TODO: faire un truc pour le unwrap...
|
||||
// normalement c'est un gars sur ta
|
||||
// compris ;)... mais bon... un alignement
|
||||
// malencontreux ca arrive vite
|
||||
}
|
||||
|
||||
p_out.iter().map(|p| (p.x, p.y)).collect()
|
||||
}
|
||||
|
||||
// en fait ca marche pas dutout...next time
|
||||
pub fn bord_mult_v2(pt: Vec<(f64, f64)>, factor: f64) -> Vec<(f64, f64)> {
|
||||
let mut pt: Vec<Pt> = pt.iter().map(|p| Pt::from(p)).collect();
|
||||
|
||||
let mut pn = vec![];
|
||||
for i in 0..pt.len() {
|
||||
let j = (i + 2) % pt.len();
|
||||
pn.push((pt[i] - pt[j]) * factor + pt[j]);
|
||||
}
|
||||
|
||||
pn.iter().map(|p| (p.x, p.y)).collect()
|
||||
}
|
||||
|
||||
pub fn get_intersection(pts: &[((f64, f64), (f64, f64))]) -> Vec<(f64, f64)> {
|
||||
let mut eq_cart = vec![];
|
||||
for i in 0..pts.len() {
|
||||
eq_cart.push(CartesianEquation::new_from_tuple(pts[i]));
|
||||
}
|
||||
|
||||
let mut points = vec![];
|
||||
for i in 0..eq_cart.len() {
|
||||
let id_next = (i + 1) % eq_cart.len();
|
||||
let pt = eq_cart[i].intersection(&eq_cart[id_next]).unwrap(); // TODO verifier quand meme la sortie au lieu de unwrap salement... xD
|
||||
points.push((pt.x, pt.y));
|
||||
}
|
||||
|
||||
points
|
||||
}
|
||||
|
||||
pub fn get_extermities(lines: &Vector<VecN<i32, 4>>, id: usize) -> ((f64, f64), (f64, f64)) {
|
||||
let mut p0: (f64, f64) = (0., 0.);
|
||||
let mut p1: (f64, f64) = (0., 0.);
|
||||
let (mut min, mut max): (f64, f64) = (f64::MAX, f64::MIN);
|
||||
//let mut eq: (f64, f64, f64) = (0., 0., 0.);
|
||||
let mut dst_sum = 0.;
|
||||
let mut v_eq = vec![];
|
||||
|
||||
// on cherche les extremite
|
||||
for l in lines {
|
||||
// rename value and switch x and y if necessery
|
||||
let (mut a0, mut b0, mut a1, mut b1) = if id % 2 == 0 {
|
||||
(l[0] as f64, l[1] as f64, l[2] as f64, l[3] as f64)
|
||||
} else {
|
||||
(l[1] as f64, l[0] as f64, l[3] as f64, l[2] as f64) // switch x <-> y
|
||||
};
|
||||
|
||||
// reorder if not
|
||||
if a0 > a1 {
|
||||
(a0, b0, a1, b1) = (a1, b1, a0, b0);
|
||||
}
|
||||
|
||||
// update min/max
|
||||
min = min.min(a0).min(a1);
|
||||
max = max.max(a0).max(a1);
|
||||
|
||||
// cancel computation if devide by zero
|
||||
if a1 - a0 == 0. {
|
||||
continue;
|
||||
}
|
||||
|
||||
let eq = EqAffine::new(a0, b0, a1, b1);
|
||||
dst_sum += eq.dst;
|
||||
v_eq.push(eq);
|
||||
}
|
||||
|
||||
p0.0 = min;
|
||||
p1.0 = max;
|
||||
for eq in v_eq {
|
||||
p0.1 += eq.get_val_dst(min);
|
||||
p1.1 += eq.get_val_dst(max);
|
||||
}
|
||||
p0.1 /= dst_sum;
|
||||
p1.1 /= dst_sum;
|
||||
|
||||
// revert x-y if already reverted previously
|
||||
if id % 2 != 0 {
|
||||
p0 = (p0.1, p0.0);
|
||||
p1 = (p1.1, p1.0);
|
||||
}
|
||||
|
||||
(p0, p1)
|
||||
}
|
||||
|
||||
pub fn probabilistic_hough(
|
||||
edges: &Mat,
|
||||
hough_param: &HoughLine,
|
||||
id: usize,
|
||||
) -> Result<Vector<VecN<i32, 4>>> {
|
||||
let mut p_lines = VectorOfVec4i::new();
|
||||
let mut probabalistic_hough = Mat::default();
|
||||
|
||||
cvt_color(edges, &mut probabalistic_hough, COLOR_GRAY2BGR, 0)?;
|
||||
|
||||
// 2. Use Probabilistic Hough Transform
|
||||
let p = hough_param.get_param();
|
||||
hough_lines_p(
|
||||
edges,
|
||||
&mut p_lines,
|
||||
p.rho,
|
||||
p.theta,
|
||||
p.treshold,
|
||||
p.min_length,
|
||||
p.max_line_gap,
|
||||
)?;
|
||||
|
||||
Ok(p_lines)
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
use super::param::Treshold;
|
||||
use opencv::core::{self, bitwise_and, in_range, Mat, Scalar, Size_};
|
||||
use opencv::imgproc;
|
||||
use opencv::Result;
|
||||
|
||||
pub fn image_warp(img: &Mat, homography: &Mat, h_size: Size_<i32>) -> Result<Mat> {
|
||||
let mut warped_image = Mat::default();
|
||||
imgproc::warp_perspective(
|
||||
&img,
|
||||
&mut warped_image,
|
||||
homography,
|
||||
h_size,
|
||||
imgproc::INTER_CUBIC, // I dont see difference with INTER_CUBIC
|
||||
core::BORDER_CONSTANT,
|
||||
Scalar::default(),
|
||||
)?;
|
||||
|
||||
Ok(warped_image)
|
||||
}
|
||||
|
||||
pub fn image_treshold(img: &Mat, tresh: &Treshold) -> Result<Mat> {
|
||||
let (t1, s1, l1) = (tresh.min_0 as f64, tresh.min_1 as f64, tresh.min_2 as f64);
|
||||
let (t2, s2, l2) = (tresh.max_0 as f64, tresh.max_1 as f64, tresh.max_2 as f64);
|
||||
let min = Mat::from_slice(&[t1, s1, l1])?;
|
||||
let max = Mat::from_slice(&[t2, s2, l2])?;
|
||||
let mut color_selected = Mat::default();
|
||||
let _ = in_range(img, &min, &max, &mut color_selected);
|
||||
let mut bord_treshed = Mat::default();
|
||||
bitwise_and(&img, &img, &mut bord_treshed, &color_selected)?;
|
||||
|
||||
Ok(bord_treshed)
|
||||
}
|
||||
|
||||
pub fn image_warp_treshold(
|
||||
img: &Mat,
|
||||
homography: &Mat,
|
||||
h_size: Size_<i32>,
|
||||
tresh: &Treshold,
|
||||
) -> Result<Mat> {
|
||||
let warped = image_warp(img, homography, h_size)?;
|
||||
let treshed = image_treshold(&warped, tresh)?;
|
||||
Ok(treshed)
|
||||
}
|
@ -1,121 +1,44 @@
|
||||
//use opencv::Result;
|
||||
//use opencv::core::{self, Mat};
|
||||
|
||||
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::draw::{draw_line, draw_line_dotted};
|
||||
use crate::point::{Color, Point};
|
||||
use crate::point::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;
|
||||
|
||||
use opencv::{
|
||||
calib3d,
|
||||
core::{self, Size},
|
||||
imgproc,
|
||||
};
|
||||
mod param;
|
||||
use param::Param;
|
||||
|
||||
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),
|
||||
}
|
||||
mod sequence;
|
||||
pub use sequence::{InitBorder, LineDotted, LoadImage, SaveImage, Sequence, WaitSpace, InitIdcode};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Qualibration {
|
||||
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<Mat>,
|
||||
pub id: Option<Sequence>,
|
||||
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_<i32>,
|
||||
pub line_pos: Vec<i32>,
|
||||
pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence
|
||||
pub cnt: usize,
|
||||
seq: Vec<Box<dyn Sequence>>,
|
||||
cam: VideoCapture,
|
||||
|
||||
pub param: Param,
|
||||
}
|
||||
|
||||
impl Qualibration {
|
||||
pub fn new() -> Result<Self> {
|
||||
//let v: Vec<Box<dyn Sequence>> = 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;
|
||||
@ -130,816 +53,58 @@ 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<Box<dyn Sequence>> = vec![
|
||||
Box::new(LoadImage::new()),
|
||||
Box::new(WaitSpace::new()),
|
||||
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 {
|
||||
begin: std::time::Instant::now(),
|
||||
dst_size: 900,
|
||||
seq,
|
||||
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_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,
|
||||
param: Param::new(dir_name.to_owned())?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run_step(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<Vec<Point>, Box<dyn std::error::Error>> {
|
||||
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<Sequence> {
|
||||
let line_max = 4095;
|
||||
let line_add = 100;
|
||||
|
||||
if self.id.is_none() {
|
||||
pub fn draw_sequence(&mut self) -> Option<Vec<Point>> {
|
||||
if self.param.seq_id >= self.seq.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
//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))
|
||||
}
|
||||
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![]);
|
||||
}
|
||||
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 compute_sequence(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.id.is_none() {
|
||||
return Ok(());
|
||||
pub fn run_step(self: &mut Self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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());
|
||||
}
|
||||
}
|
||||
match self.id.unwrap() {
|
||||
Sequence::IdCode2 => {
|
||||
let mut id_code_1 = image_diff(&self.img[8], &self.img[1])?;
|
||||
|
||||
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<f64, 4> = 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<f64, 4> = 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<f64, 4> = VecN::new(blue, 128., 0., 255.);
|
||||
let pa = VecN::from_array([*x0 as i32, *y0 as i32]);
|
||||
let pb = VecN::from_array([*x1 as i32, *y1 as i32]);
|
||||
let a = OcvPoint::from_vec2(pa);
|
||||
let b = OcvPoint::from_vec2(pb);
|
||||
line(&mut bord_treshed, a, b, color, 1, LINE_8, 0)?;
|
||||
}
|
||||
highgui::imshow("segemnt detector", &bord_treshed)?;
|
||||
}
|
||||
Sequence::ComputeSelectNbAll => {
|
||||
let background: Mat;
|
||||
let steps: Vec<Mat>;
|
||||
|
||||
background = self.img[1].clone();
|
||||
steps = self.img[2..6].into();
|
||||
|
||||
let mut angles: Vec<f64> = 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<Mat>;
|
||||
|
||||
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<f64, 4> = 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<OcvPoint> = 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<OcvPoint> =
|
||||
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]))?;
|
||||
if frame.size()?.width > 0 || !self.param.capture_mode {
|
||||
self.seq[self.param.seq_id].compute_sequence(&mut self.param)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
//use std::cmp::Ordering;
|
||||
fn load_image(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<Self> {
|
||||
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<Vector<VecN<i32, 4>>> {
|
||||
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)
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::collections::HashSet;
|
||||
use std::f64::consts::PI;
|
||||
|
||||
use super::Qualibration;
|
||||
use super::Param;
|
||||
use super::DEBUG;
|
||||
use crate::utils::Pt;
|
||||
//use opencv::prelude::MatTraitConst;
|
||||
@ -25,7 +25,7 @@ opencv::not_opencv_branch_4! {
|
||||
use opencv::core::LINE_AA;
|
||||
}
|
||||
|
||||
use super::Treshold;
|
||||
use super::param::Treshold;
|
||||
const MAX_TRACKBAR: i32 = 255;
|
||||
|
||||
pub fn draw_histograme_dbg(
|
||||
@ -377,7 +377,7 @@ pub fn get_horizontal_segment(m: &Mat) -> Result<Vec<(((f32, f32), (f32, f32)),
|
||||
|
||||
// On cherche des segment regourper par ilot de point. chaque illot a une plage de valeur en y qui
|
||||
// lui est propre, aucun autre ilot aura des point dans une plage de valeurs d'un autre illot.
|
||||
pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
|
||||
pub fn get_vertical_segment(m: &Mat) -> Result<Vec<(((f32, f32), (f32, f32)), f32)>> {
|
||||
// on va faire un histogram des point selon leur position en y
|
||||
// ca permetera des les differencier
|
||||
// on fait cette histo gramme pour connaitre ces plage de valeur en y
|
||||
@ -534,8 +534,11 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
|
||||
let pt_up_2 = pt_down + (pt_up - pt_down) * 1.5;
|
||||
let pt_down_2 = pt_up + (pt_down - pt_up) * 1.5;
|
||||
segments.push((
|
||||
(pt_down_2.x as f32, pt_down_2.y as f32),
|
||||
(pt_up_2.x as f32, pt_up_2.y as f32),
|
||||
(
|
||||
(pt_down_2.x as f32, pt_down_2.y as f32),
|
||||
(pt_up_2.x as f32, pt_up_2.y as f32),
|
||||
),
|
||||
x_min as f32,
|
||||
));
|
||||
}
|
||||
|
||||
@ -799,7 +802,7 @@ pub fn first_invert(histo: &Vec<f64>) -> ((usize, f64), (usize, f64)) {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn trackbar_init_param(mem: &mut Qualibration, winname: &str) -> Result<()> {
|
||||
pub fn trackbar_init_param(mem: &mut Param, winname: &str) -> Result<()> {
|
||||
named_window(winname, WINDOW_AUTOSIZE)?;
|
||||
highgui::move_window(winname, 20, 20)?;
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
@ -815,7 +818,7 @@ pub fn trackbar_init_param(mem: &mut Qualibration, winname: &str) -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn trackbar_line_segment(mem: &mut Qualibration, winname: &str) -> Result<()> {
|
||||
pub fn trackbar_line_segment(mem: &mut Param, winname: &str) -> Result<()> {
|
||||
//highgui
|
||||
let winname = format!("{}: {}", winname, 0); //"bord selected: 0";
|
||||
named_window(winname.as_str(), WINDOW_AUTOSIZE)?;
|
||||
@ -878,7 +881,7 @@ pub fn trackbar_line_segment(mem: &mut Qualibration, winname: &str) -> Result<()
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn line_pos(mem: &mut Qualibration, winname: &str) -> Result<()> {
|
||||
pub fn line_pos(mem: &mut Param, winname: &str) -> Result<()> {
|
||||
named_window(winname, WINDOW_AUTOSIZE)?;
|
||||
highgui::move_window(winname, 20, 20)?;
|
||||
let v: VecN<f64, 4> = VecN::new(0., 0., 0., 255.);
|
||||
@ -898,7 +901,7 @@ pub fn line_pos(mem: &mut Qualibration, winname: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn adding_trackbar(mut mem: &mut Qualibration, winname: &str) -> Result<()> {
|
||||
pub fn adding_trackbar(mut mem: &mut Param, winname: &str) -> Result<()> {
|
||||
//println!("winname: {winname}");
|
||||
//line_pos(&mut mem, "Play Line")?;
|
||||
//trackbar_init_param(mem, "init_param")?;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::HoughLine;
|
||||
use super::param::HoughLine;
|
||||
use crate::utils::{CartesianEquation, EqAffine, Pt};
|
||||
use opencv::core::{add, subtract, Mat, VecN, Vector, CV_8UC3};
|
||||
//use opencv::prelude::MatTraitConst;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use super::Treshold;
|
||||
use super::param::Treshold;
|
||||
use opencv::core::{self, bitwise_and, in_range, Mat, Scalar, Size_};
|
||||
use opencv::imgproc;
|
||||
use opencv::Result;
|
||||
|
@ -1,8 +1,11 @@
|
||||
use opencv::{Result, core::{Mat, Size_, Size, Vector, find_file}};
|
||||
use opencv::imgcodecs::{imread, IMREAD_COLOR, imwrite};
|
||||
use std::time::Instant;
|
||||
use std::fs::{create_dir, read_dir};
|
||||
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 {
|
||||
@ -14,6 +17,7 @@ pub struct Param {
|
||||
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,
|
||||
@ -33,34 +37,35 @@ pub struct Param {
|
||||
impl Param {
|
||||
pub fn new(dir_name: String) -> Result<Self> {
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
@ -122,7 +127,6 @@ impl Param {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HoughLine {
|
||||
pub rho: i32,
|
27
src/qualibration/sequence.rs
Normal file
27
src/qualibration/sequence.rs
Normal file
@ -0,0 +1,27 @@
|
||||
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<Vec<Point>>;
|
||||
fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box<dyn std::error::Error>>;
|
||||
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:?}")
|
||||
}
|
||||
}
|
@ -1,16 +1,19 @@
|
||||
use crate::draw::draw_line;
|
||||
use crate::point::{Color, Point};
|
||||
use crate::qualib_refacto::{param::{Param, HoughLine}, Sequence};
|
||||
use crate::qualibration::{
|
||||
param::{HoughLine, Param},
|
||||
Sequence,
|
||||
};
|
||||
|
||||
use crate::qualib_refacto::annalyse::image_diff;
|
||||
use crate::qualib_refacto::borders::{
|
||||
bord_mult, get_extermities, get_intersection, mix_borders, probabilistic_hough,
|
||||
use crate::qualibration::annalyse::image_diff;
|
||||
use crate::qualibration::borders::{
|
||||
bord_mult, get_extermities, get_intersection, probabilistic_hough,
|
||||
};
|
||||
|
||||
use opencv::{
|
||||
calib3d,
|
||||
core::{self, Mat, Point as OcvPoint, Scalar, Size, VecN, Vector},
|
||||
imgproc::{self, canny, cvt_color, line, COLOR_BGR2GRAY},
|
||||
core::{Mat, Point as OcvPoint, Size, VecN, Vector},
|
||||
imgproc::{canny, cvt_color, COLOR_BGR2GRAY},
|
||||
Result,
|
||||
};
|
||||
|
||||
@ -23,6 +26,7 @@ opencv::not_opencv_branch_4! {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct InitBorder {
|
||||
finished: bool,
|
||||
borders: [Point; 4],
|
||||
cnt: usize,
|
||||
}
|
||||
@ -53,6 +57,7 @@ impl InitBorder {
|
||||
},
|
||||
],
|
||||
cnt: 0,
|
||||
finished: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,13 +97,14 @@ impl Sequence for InitBorder {
|
||||
|
||||
fn compute_sequence(&mut self, mem: &mut Param) -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<Mat> = imgs[..len].into();
|
||||
let background = imgs[len].clone();
|
||||
let borders: Vec<Mat> = imgs[..=len].into();
|
||||
|
||||
// on recupere chaqu'un des 4 bord
|
||||
let mut bords_pts = vec![];
|
||||
@ -167,6 +173,7 @@ impl Sequence for InitBorder {
|
||||
// Scalar::default(),
|
||||
//)?; // do perspective transformation
|
||||
//highgui::imshow("Warped Image", &warped_image)?;
|
||||
self.finished = true;
|
||||
Ok(())
|
||||
}
|
||||
|
105
src/qualibration/sequence/init_idcode.rs
Normal file
105
src/qualibration/sequence/init_idcode.rs
Normal file
@ -0,0 +1,105 @@
|
||||
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<Vec<Point>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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<f64, 4> = 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
|
||||
}
|
||||
}
|
167
src/qualibration/sequence/line_dotted.rs
Normal file
167
src/qualibration/sequence/line_dotted.rs
Normal file
@ -0,0 +1,167 @@
|
||||
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<Vec<Point>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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<f64, 4> = VecN::new(blue, 128., 0., 255.);
|
||||
let pa = VecN::from_array([*x0 as i32, *y0 as i32]);
|
||||
let pb = VecN::from_array([*x1 as i32, *y1 as i32]);
|
||||
let a = OcvPoint::from_vec2(pa);
|
||||
let b = OcvPoint::from_vec2(pb);
|
||||
line(&mut bord_treshed, a, b, color, 1, LINE_8, 0)?;
|
||||
}
|
||||
highgui::imshow("segemnt detector", &bord_treshed)?;
|
||||
self.finished = true;
|
||||
Ok(())
|
||||
}
|
||||
fn is_capture(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
use super::{Param, Sequence};
|
||||
use super::{super::Param, Sequence};
|
||||
use crate::point::Point;
|
||||
use opencv::{core::Mat, Result};
|
||||
use opencv::Result;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct LoadImage {
|
||||
@ -9,7 +9,7 @@ pub struct LoadImage {
|
||||
|
||||
impl LoadImage {
|
||||
pub fn new() -> LoadImage {
|
||||
LoadImage { finished: true }
|
||||
LoadImage { finished: false }
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{Param, Sequence};
|
||||
use super::{super::Param, Sequence};
|
||||
use crate::point::Point;
|
||||
use opencv::{core::Mat, Result};
|
||||
use opencv::Result;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SaveImage {
|
||||
@ -9,7 +9,7 @@ pub struct SaveImage {
|
||||
|
||||
impl SaveImage {
|
||||
pub fn new() -> SaveImage {
|
||||
SaveImage { finished: true }
|
||||
SaveImage { finished: false }
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{Param, Sequence};
|
||||
use super::{super::Param, Sequence};
|
||||
use crate::point::Point;
|
||||
use opencv::{core::Mat, Result};
|
||||
use opencv::Result;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct WaitSpace {}
|
||||
@ -13,7 +13,7 @@ impl WaitSpace {
|
||||
|
||||
impl Sequence for WaitSpace {
|
||||
fn draw(&self, mem: &Param) -> Option<Vec<Point>> {
|
||||
if mem.key == 32 {
|
||||
if mem.key == 32 || !mem.capture_mode {
|
||||
return None;
|
||||
}
|
||||
Some(vec![])
|
@ -1,13 +1,7 @@
|
||||
use crate::point::Point;
|
||||
static NEAR_ZERO: f64 = 0.000001;
|
||||
|
||||
use std::ops::Add;
|
||||
use std::ops::AddAssign;
|
||||
use std::ops::Div;
|
||||
use std::ops::DivAssign;
|
||||
use std::ops::Mul;
|
||||
use std::ops::MulAssign;
|
||||
use std::ops::Sub;
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub};
|
||||
//use std::ops::BitXor
|
||||
|
||||
impl Add for Pt {
|
||||
|
Loading…
Reference in New Issue
Block a user