feat: during IdCode implementation

The purpose is to include a en coded number in the image to be sure it's
the right image.
This commit is contained in:
Lapin Raving 2023-09-19 16:05:50 +02:00
parent 6145b585f4
commit 910e340ec8
5 changed files with 607 additions and 285 deletions

View file

@ -230,6 +230,151 @@ pub fn is_same_frame(frame: &Mat, frame_prev: &Mat) -> Result<bool> {
}
}
// 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))>> {
@ -251,7 +396,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
// on determine le debut et la fin de ces palge de l=valeur en y
let mut histo_limit = vec![];
for i in (0..(histo_y.len()-1)).rev() {
for i in (0..(histo_y.len() - 1)).rev() {
if histo_y[i] != 0. && histo_y[i + 1] == 0. {
histo_limit.push(Cnt::End(i));
}
@ -266,7 +411,6 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
}
}
// on regroupe les point par illot.
let mut segment_iland = vec![vec![]; limits.len()];
for (x, y) in seg_pt {
@ -296,7 +440,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
// En suite on tris ces pixel et on prend la moiter la plus haute et la moiter la plus basse
// part raport a l'axe. On fait la mayenne des ces 2 groupe et on a les extremiter haute et
// basse pour cet ilot de pixel. En suite on multiplie par 2 ce segement pour qui soit de la
// taille de l'ilots.
// taille de l'ilots.
//
// TODO: La selection de l'axe qui passe au centre de l'ilot pourrauiut aussi etre meilleur
// au lieux d'utiliser l'arreur, on pourrait regarder la valeur absolue de la coordoner x la plus petit
@ -309,28 +453,37 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
// En fait elle me va bien. C'est vrai que il ne sont pas ouf mais bon...
let mut segments = vec![];
for (i, iland) in segment_iland_pt.iter().enumerate() {
let mut center = Pt{x: 0., y: 0.};
let mut center = Pt { x: 0., y: 0. };
for p in iland {
center += *p;
}
center /= iland.len() as f64;
let max_deg = 360;
let (mut err_min, mut rad_min, mut x_min) = (f64::MAX, 0., f64::MAX);
let mut iland_min = vec![];
for deg in 0..max_deg {
let rad = (deg as f64) / (max_deg as f64) * PI * 2.;
let y_axis = Pt{x: rad.sin(), y: rad.cos()};
let x_axis = Pt{x: -y_axis.y, y: y_axis.x};
let y_axis = Pt {
x: rad.sin(),
y: rad.cos(),
};
let x_axis = Pt {
x: -y_axis.y,
y: y_axis.x,
};
let mut err = 0.;
let mut tmp_iland = vec![];
let mut x_abs_max = f64::MIN;
for pt in iland {
let mut p = *pt - center;
p = Pt{x: p.cross(&x_axis), y: p.cross(&y_axis)};
p = Pt {
x: p.cross(&x_axis),
y: p.cross(&y_axis),
};
err += p.x * p.x;
tmp_iland.push(p);
if x_abs_max < p.x.abs(){
if x_abs_max < p.x.abs() {
x_abs_max = p.x.abs();
}
}
@ -345,7 +498,7 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
// iland_min = tmp_iland;
//}
}
iland_min.sort_by(|pta, ptb|{
iland_min.sort_by(|pta, ptb| {
if pta.y < ptb.y {
std::cmp::Ordering::Greater
} else if pta.y == ptb.y {
@ -367,14 +520,23 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
//let mean_up = iland_min[0];
//let mean_down = iland_min.last().unwrap();
let y_axis = Pt{x: rad_min.sin(), y: rad_min.cos()};
let x_axis = Pt{x: -y_axis.y, y: y_axis.x};
let y_axis = Pt {
x: rad_min.sin(),
y: rad_min.cos(),
};
let x_axis = Pt {
x: -y_axis.y,
y: y_axis.x,
};
let pt_up = center + (y_axis * mean_up.y) + (x_axis * mean_up.x);
let pt_down = center + (y_axis * mean_down.y) + (x_axis * mean_down.x);
//segments.push(((pt_down.x as f32, pt_down.y as f32), (pt_up.x as f32, pt_up.y as f32)));
let pt_up_2 = pt_down + (pt_up - pt_down)*1.5;
let pt_down_2 = pt_up + (pt_down - pt_up)*1.5;
segments.push(((pt_down_2.x as f32, pt_down_2.y as f32), (pt_up_2.x as f32, pt_up_2.y as f32)));
let pt_up_2 = pt_down + (pt_up - pt_down) * 1.5;
let pt_down_2 = pt_up + (pt_down - pt_up) * 1.5;
segments.push((
(pt_down_2.x as f32, pt_down_2.y as f32),
(pt_up_2.x as f32, pt_up_2.y as f32),
));
}
Ok(segments)

View file

@ -0,0 +1,43 @@
use super::Treshold;
use opencv::core::{self, bitwise_and, in_range, Mat, Scalar, Size_};
use opencv::imgproc;
use opencv::Result;
pub fn image_warp(img: &Mat, homography: &Mat, h_size: Size_<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)
}