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:
parent
6145b585f4
commit
910e340ec8
@ -11,10 +11,13 @@ pub fn draw_line_dotted(
|
|||||||
p2: &Point,
|
p2: &Point,
|
||||||
nb_all: usize,
|
nb_all: usize,
|
||||||
nb_visible: usize,
|
nb_visible: usize,
|
||||||
|
first_on: bool,
|
||||||
) -> Result<Vec<Point>, Box<dyn std::error::Error>> {
|
) -> Result<Vec<Point>, Box<dyn std::error::Error>> {
|
||||||
let mut pl = vec![];
|
let mut pl = vec![];
|
||||||
let black = Color { r: 0, g: 0, b: 0 };
|
let black = Color { r: 0, g: 0, b: 0 };
|
||||||
|
|
||||||
|
let cmp = if first_on { 0 } else { 1 };
|
||||||
|
|
||||||
for _ in 0..nb_all {
|
for _ in 0..nb_all {
|
||||||
pl.push(Point {
|
pl.push(Point {
|
||||||
color: black,
|
color: black,
|
||||||
@ -23,7 +26,7 @@ pub fn draw_line_dotted(
|
|||||||
}
|
}
|
||||||
for i in 0..nb_visible {
|
for i in 0..nb_visible {
|
||||||
pl.push(Point {
|
pl.push(Point {
|
||||||
color: if i % 2 == 0 { p2.color } else { black },
|
color: if i % 2 == cmp { p2.color } else { black },
|
||||||
..*p2
|
..*p2
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
pub mod annalyse;
|
pub mod annalyse;
|
||||||
pub mod borders;
|
pub mod borders;
|
||||||
|
pub mod compute_image;
|
||||||
|
|
||||||
use annalyse::{
|
use annalyse::{
|
||||||
annalyse_segment, draw_histograme_bgr_tresh, get_vertical_segment, histogram_3d, image_diff,
|
draw_histograme_bgr_tresh, get_horizontal_segment, get_vertical_segment, histogram_3d,
|
||||||
image_mean, is_same_frame,
|
image_diff, image_mean,
|
||||||
}; // mean dans le sans moyenne des image
|
}; // mean dans le sans moyenne des image
|
||||||
use borders::{bord_mult, get_extermities, get_intersection, mix_borders, probabilistic_hough};
|
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::env::args;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use crate::draw;
|
use crate::draw::{draw_line, draw_line_dotted};
|
||||||
use crate::point::{Color, Point};
|
use crate::point::{Color, Point};
|
||||||
|
|
||||||
use enum_iterator::{next, Sequence as Seq};
|
use enum_iterator::{next, Sequence as Seq};
|
||||||
@ -58,12 +60,14 @@ pub enum Sequence {
|
|||||||
RightBorder,
|
RightBorder,
|
||||||
ReadDir,
|
ReadDir,
|
||||||
ComputeArea,
|
ComputeArea,
|
||||||
PlayLineDotted,
|
IdCode1,
|
||||||
TakeMultiple(u16),
|
IdCode2,
|
||||||
TakeMultipleEmpty(u16),
|
|
||||||
ComputeLineDotted,
|
|
||||||
Finish,
|
Finish,
|
||||||
|
|
||||||
|
PlayLineDotted,
|
||||||
|
EmptyFrame,
|
||||||
|
ComputeLineDotted,
|
||||||
|
|
||||||
LinearConstSpeed, // [multiple test]
|
LinearConstSpeed, // [multiple test]
|
||||||
JumpFromTo,
|
JumpFromTo,
|
||||||
|
|
||||||
@ -76,6 +80,8 @@ pub enum Sequence {
|
|||||||
Horizontal(u16),
|
Horizontal(u16),
|
||||||
SelectNbAll(u16),
|
SelectNbAll(u16),
|
||||||
ComputeSelectNbAll,
|
ComputeSelectNbAll,
|
||||||
|
TakeMultiple(u16),
|
||||||
|
TakeMultipleEmpty(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -105,6 +111,7 @@ pub struct Qualibration {
|
|||||||
pub h_size: Size_<i32>,
|
pub h_size: Size_<i32>,
|
||||||
pub line_pos: Vec<i32>,
|
pub line_pos: Vec<i32>,
|
||||||
pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence
|
pub multiple: u16, // le nombre de fois qu'une photo est prise pour certaine sequence
|
||||||
|
pub cnt: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Qualibration {
|
impl Qualibration {
|
||||||
@ -142,7 +149,7 @@ impl Qualibration {
|
|||||||
tresh: Treshold::new("histogram: 0", 150, 255)?,
|
tresh: Treshold::new("histogram: 0", 150, 255)?,
|
||||||
dir_name: dir_name.clone(),
|
dir_name: dir_name.clone(),
|
||||||
key: 10,
|
key: 10,
|
||||||
canny_v1: 150,
|
canny_v1: 170,
|
||||||
canny_v2: 255,
|
canny_v2: 255,
|
||||||
hough_param: HoughLine {
|
hough_param: HoughLine {
|
||||||
rho: 100,
|
rho: 100,
|
||||||
@ -156,6 +163,7 @@ impl Qualibration {
|
|||||||
h_size: Size::default(),
|
h_size: Size::default(),
|
||||||
line_pos: vec![4095; 34],
|
line_pos: vec![4095; 34],
|
||||||
multiple: 20,
|
multiple: 20,
|
||||||
|
cnt: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,6 +194,7 @@ impl Qualibration {
|
|||||||
}
|
}
|
||||||
//println!("sequence: {:?}", self.id);
|
//println!("sequence: {:?}", self.id);
|
||||||
self.frame_prev = self.frame.clone();
|
self.frame_prev = self.frame.clone();
|
||||||
|
self.cnt += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,81 +211,8 @@ impl Qualibration {
|
|||||||
b: self.b as u8,
|
b: self.b as u8,
|
||||||
};
|
};
|
||||||
//let color = Color { r: 0, g: 0, b: 50 };
|
//let color = Color { r: 0, g: 0, b: 50 };
|
||||||
let p0 = Point {
|
let (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb) =
|
||||||
x: 0.,
|
get_point_to_draw(self.r as u8, self.g as u8, self.b as u8, color.clone());
|
||||||
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: self.r as u8,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let p5 = Point {
|
|
||||||
x: 4095.,
|
|
||||||
y: 1000.,
|
|
||||||
color: Color {
|
|
||||||
r: self.r as u8,
|
|
||||||
g: 0,
|
|
||||||
b: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let p6 = Point {
|
|
||||||
x: 0.,
|
|
||||||
y: 2000.,
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: self.g as u8,
|
|
||||||
b: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let p7 = Point {
|
|
||||||
x: 4095.,
|
|
||||||
y: 2000.,
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: self.g as u8,
|
|
||||||
b: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let p8 = Point {
|
|
||||||
x: 0.,
|
|
||||||
y: 3000.,
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: self.b as u8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let p9 = Point {
|
|
||||||
x: 4095.,
|
|
||||||
y: 3000.,
|
|
||||||
color: Color {
|
|
||||||
r: 0,
|
|
||||||
g: 0,
|
|
||||||
b: self.b as u8,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let nb_all = self.nb_all as usize;
|
let nb_all = self.nb_all as usize;
|
||||||
let nb_visible = self.nb_visible 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
|
let nb_wait = 30; // ca permet de prendre de la vitess en y. Et donc ca permet de
|
||||||
@ -284,11 +220,20 @@ impl Qualibration {
|
|||||||
|
|
||||||
if seq.is_some() {
|
if seq.is_some() {
|
||||||
match seq.unwrap() {
|
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::PlayLineDotted
|
||||||
| Sequence::TakeMultiple(_)
|
| Sequence::TakeMultiple(_)
|
||||||
| Sequence::ComputeLineDotted => {
|
| Sequence::ComputeLineDotted => {
|
||||||
// la on va faire une ligne qu'on peut observer
|
// la on va faire une ligne qu'on peut observer
|
||||||
pl = vec![];
|
|
||||||
let black = Color { r: 0, g: 0, b: 0 };
|
let black = Color { r: 0, g: 0, b: 0 };
|
||||||
for _ in 0..nb_all {
|
for _ in 0..nb_all {
|
||||||
pl.push(Point {
|
pl.push(Point {
|
||||||
@ -321,32 +266,32 @@ impl Qualibration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Sequence::WaitSpace => {
|
Sequence::WaitSpace => {
|
||||||
pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?;
|
pl = draw_line(&p0, &p1, nb_all, nb_visible)?;
|
||||||
pl.extend(draw::draw_line(&p1, &p2, nb_all, nb_visible)?);
|
pl.extend(draw_line(&p1, &p2, nb_all, nb_visible)?);
|
||||||
pl.extend(draw::draw_line(&p3, &p0, nb_all, nb_visible)?);
|
pl.extend(draw_line(&p3, &p0, nb_all, nb_visible)?);
|
||||||
pl.extend(draw::draw_line(&p2, &p3, nb_all, nb_visible)?);
|
pl.extend(draw_line(&p2, &p3, nb_all, nb_visible)?);
|
||||||
|
|
||||||
pl.extend(draw::draw_line_dotted(&p4, &p5, nb_all, nb_visible)?);
|
pl.extend(draw_line_dotted(&p4, &p5, nb_all, nb_visible, true)?);
|
||||||
pl.extend(draw::draw_line_dotted(&p6, &p7, nb_all, nb_visible)?);
|
pl.extend(draw_line_dotted(&p6, &p7, nb_all, nb_visible, true)?);
|
||||||
pl.extend(draw::draw_line_dotted(&p8, &p9, nb_all, nb_visible)?);
|
pl.extend(draw_line_dotted(&p8, &p9, nb_all, nb_visible, true)?);
|
||||||
}
|
}
|
||||||
Sequence::SelectNbAll(n) => {
|
Sequence::SelectNbAll(n) => {
|
||||||
pl = draw::draw_line(&p0, &p1, n as usize, n as usize)?;
|
pl = draw_line(&p0, &p1, n as usize, n as usize)?;
|
||||||
pl.extend(draw::draw_line(&p1, &p2, n as usize, n as usize)?);
|
pl.extend(draw_line(&p1, &p2, n as usize, n as usize)?);
|
||||||
pl.extend(draw::draw_line(&p3, &p0, n as usize, n as usize)?);
|
pl.extend(draw_line(&p3, &p0, n as usize, n as usize)?);
|
||||||
pl.extend(draw::draw_line(&p2, &p3, n as usize, n as usize)?);
|
pl.extend(draw_line(&p2, &p3, n as usize, n as usize)?);
|
||||||
}
|
}
|
||||||
Sequence::UpBorder => {
|
Sequence::UpBorder => {
|
||||||
pl = draw::draw_line(&p0, &p1, nb_all, nb_visible)?;
|
pl = draw_line(&p0, &p1, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
Sequence::RightBorder => {
|
Sequence::RightBorder => {
|
||||||
pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?;
|
pl = draw_line(&p1, &p2, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
Sequence::DownBorder => {
|
Sequence::DownBorder => {
|
||||||
pl = draw::draw_line(&p2, &p3, nb_all, nb_visible)?;
|
pl = draw_line(&p2, &p3, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
Sequence::LeftBorder => {
|
Sequence::LeftBorder => {
|
||||||
pl = draw::draw_line(&p3, &p0, nb_all, nb_visible)?;
|
pl = draw_line(&p3, &p0, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
Sequence::Vertical(n) => {
|
Sequence::Vertical(n) => {
|
||||||
let p1 = Point {
|
let p1 = Point {
|
||||||
@ -359,7 +304,7 @@ impl Qualibration {
|
|||||||
y: 4095.,
|
y: 4095.,
|
||||||
color,
|
color,
|
||||||
};
|
};
|
||||||
pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?;
|
pl = draw_line(&p1, &p2, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
Sequence::Horizontal(n) => {
|
Sequence::Horizontal(n) => {
|
||||||
let p1 = Point {
|
let p1 = Point {
|
||||||
@ -372,7 +317,7 @@ impl Qualibration {
|
|||||||
y: n as f32,
|
y: n as f32,
|
||||||
color,
|
color,
|
||||||
};
|
};
|
||||||
pl = draw::draw_line(&p1, &p2, nb_all, nb_visible)?;
|
pl = draw_line(&p1, &p2, nb_all, nb_visible)?;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -447,11 +392,100 @@ impl Qualibration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_sequence(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn compute_sequence(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if self.id.is_some() {
|
if self.id.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
match self.id.unwrap() {
|
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 => {
|
Sequence::ComputeLineDotted => {
|
||||||
let backgrounds = self.img[7..30].to_owned();
|
let id1 = 7 + (self.cnt % 22);
|
||||||
let lines_dots = self.img[30..52].to_owned();
|
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 background = image_mean(&backgrounds)?;
|
||||||
let line_dot = image_mean(&lines_dots)?;
|
let line_dot = image_mean(&lines_dots)?;
|
||||||
@ -463,7 +497,7 @@ impl Qualibration {
|
|||||||
&mut warped_image,
|
&mut warped_image,
|
||||||
&self.homography,
|
&self.homography,
|
||||||
self.h_size,
|
self.h_size,
|
||||||
imgproc::INTER_LINEAR, // I dont see difference with INTER_CUBIC
|
imgproc::INTER_CUBIC, // I dont see difference with INTER_CUBIC
|
||||||
core::BORDER_CONSTANT,
|
core::BORDER_CONSTANT,
|
||||||
Scalar::default(),
|
Scalar::default(),
|
||||||
)?;
|
)?;
|
||||||
@ -526,8 +560,7 @@ impl Qualibration {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
for l in lines {
|
for l in lines {
|
||||||
let (x0, y0, x1, y1) =
|
let (x0, y0, x1, y1) = (l[0] as f64, l[1] as f64, l[2] as f64, l[3] as f64);
|
||||||
(l[0] as f64, l[1] as f64, l[2] as f64, l[3] as f64);
|
|
||||||
|
|
||||||
let ang = (y1 - y0).atan2(x1 - x0);
|
let ang = (y1 - y0).atan2(x1 - x0);
|
||||||
angles.push(ang);
|
angles.push(ang);
|
||||||
@ -569,7 +602,7 @@ impl Qualibration {
|
|||||||
let b = OcvPoint::from_vec2(pb);
|
let b = OcvPoint::from_vec2(pb);
|
||||||
line(&mut mixed, a, b, color, 1, LINE_AA, 0)?;
|
line(&mut mixed, a, b, color, 1, LINE_AA, 0)?;
|
||||||
}
|
}
|
||||||
highgui::imshow("mixed bored", &mixed)?;
|
//highgui::imshow("mixed bored", &mixed)?;
|
||||||
|
|
||||||
let size = self.dst_size;
|
let size = self.dst_size;
|
||||||
// ici on va requadrer la partie de la projection laser de l'image
|
// ici on va requadrer la partie de la projection laser de l'image
|
||||||
@ -604,7 +637,7 @@ impl Qualibration {
|
|||||||
core::BORDER_CONSTANT,
|
core::BORDER_CONSTANT,
|
||||||
Scalar::default(),
|
Scalar::default(),
|
||||||
)?; // do perspective transformation
|
)?; // do perspective transformation
|
||||||
highgui::imshow("Warped Image", &warped_image)?;
|
//highgui::imshow("Warped Image", &warped_image)?;
|
||||||
}
|
}
|
||||||
Sequence::ReadDir => {
|
Sequence::ReadDir => {
|
||||||
if !self.capture_mode {
|
if !self.capture_mode {
|
||||||
@ -618,7 +651,6 @@ impl Qualibration {
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,6 +775,89 @@ impl Qualibration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// ca c'est les donner manipuler par les slider
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct HoughLine {
|
pub struct HoughLine {
|
||||||
|
@ -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
|
// 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.
|
// 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))>> {
|
||||||
@ -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
|
// on determine le debut et la fin de ces palge de l=valeur en y
|
||||||
let mut histo_limit = vec![];
|
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. {
|
if histo_y[i] != 0. && histo_y[i + 1] == 0. {
|
||||||
histo_limit.push(Cnt::End(i));
|
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.
|
// on regroupe les point par illot.
|
||||||
let mut segment_iland = vec![vec![]; limits.len()];
|
let mut segment_iland = vec![vec![]; limits.len()];
|
||||||
for (x, y) in seg_pt {
|
for (x, y) in seg_pt {
|
||||||
@ -309,7 +453,7 @@ 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...
|
// En fait elle me va bien. C'est vrai que il ne sont pas ouf mais bon...
|
||||||
let mut segments = vec![];
|
let mut segments = vec![];
|
||||||
for (i, iland) in segment_iland_pt.iter().enumerate() {
|
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 {
|
for p in iland {
|
||||||
center += *p;
|
center += *p;
|
||||||
}
|
}
|
||||||
@ -320,17 +464,26 @@ pub fn get_vertical_segment(m: &Mat) -> Result<Vec<((f32, f32), (f32, f32))>> {
|
|||||||
let mut iland_min = vec![];
|
let mut iland_min = vec![];
|
||||||
for deg in 0..max_deg {
|
for deg in 0..max_deg {
|
||||||
let rad = (deg as f64) / (max_deg as f64) * PI * 2.;
|
let rad = (deg as f64) / (max_deg as f64) * PI * 2.;
|
||||||
let y_axis = Pt{x: rad.sin(), y: rad.cos()};
|
let y_axis = Pt {
|
||||||
let x_axis = Pt{x: -y_axis.y, y: y_axis.x};
|
x: rad.sin(),
|
||||||
|
y: rad.cos(),
|
||||||
|
};
|
||||||
|
let x_axis = Pt {
|
||||||
|
x: -y_axis.y,
|
||||||
|
y: y_axis.x,
|
||||||
|
};
|
||||||
let mut err = 0.;
|
let mut err = 0.;
|
||||||
let mut tmp_iland = vec![];
|
let mut tmp_iland = vec![];
|
||||||
let mut x_abs_max = f64::MIN;
|
let mut x_abs_max = f64::MIN;
|
||||||
for pt in iland {
|
for pt in iland {
|
||||||
let mut p = *pt - center;
|
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;
|
err += p.x * p.x;
|
||||||
tmp_iland.push(p);
|
tmp_iland.push(p);
|
||||||
if x_abs_max < p.x.abs(){
|
if x_abs_max < p.x.abs() {
|
||||||
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 = tmp_iland;
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
iland_min.sort_by(|pta, ptb|{
|
iland_min.sort_by(|pta, ptb| {
|
||||||
if pta.y < ptb.y {
|
if pta.y < ptb.y {
|
||||||
std::cmp::Ordering::Greater
|
std::cmp::Ordering::Greater
|
||||||
} else if pta.y == ptb.y {
|
} 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_up = iland_min[0];
|
||||||
//let mean_down = iland_min.last().unwrap();
|
//let mean_down = iland_min.last().unwrap();
|
||||||
|
|
||||||
let y_axis = Pt{x: rad_min.sin(), y: rad_min.cos()};
|
let y_axis = Pt {
|
||||||
let x_axis = Pt{x: -y_axis.y, y: y_axis.x};
|
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_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);
|
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)));
|
//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_up_2 = pt_down + (pt_up - pt_down) * 1.5;
|
||||||
let pt_down_2 = pt_up + (pt_down - pt_up)*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)));
|
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)
|
Ok(segments)
|
||||||
|
43
src/qualibration/compute_image.rs
Normal file
43
src/qualibration/compute_image.rs
Normal 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)
|
||||||
|
}
|
@ -3,11 +3,11 @@ static NEAR_ZERO: f64 = 0.000001;
|
|||||||
|
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::ops::AddAssign;
|
use std::ops::AddAssign;
|
||||||
|
use std::ops::Div;
|
||||||
|
use std::ops::DivAssign;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use std::ops::MulAssign;
|
use std::ops::MulAssign;
|
||||||
use std::ops::Sub;
|
use std::ops::Sub;
|
||||||
use std::ops::Div;
|
|
||||||
use std::ops::DivAssign;
|
|
||||||
//use std::ops::BitXor
|
//use std::ops::BitXor
|
||||||
|
|
||||||
impl Add for Pt {
|
impl Add for Pt {
|
||||||
@ -28,7 +28,6 @@ impl AddAssign for Pt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Sub for Pt {
|
impl Sub for Pt {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
|
|
||||||
@ -110,7 +109,7 @@ impl Pt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mean(pts: &[Pt]) -> Pt {
|
pub fn mean(pts: &[Pt]) -> Pt {
|
||||||
let mut mean = Pt{x: 0., y: 0.};
|
let mut mean = Pt { x: 0., y: 0. };
|
||||||
for pt in pts {
|
for pt in pts {
|
||||||
mean += *pt;
|
mean += *pt;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user