pico_detect/localize/
mod.rs1mod localizer;
2pub mod perturbate;
3
4use image::Luma;
5pub use localizer::Localizer;
6
7use nalgebra::Point2;
8use perturbate::Perturbator;
9use pixelutil_image::ExtendedImageView;
10use rand::RngCore;
11
12use crate::Target;
13
14#[derive(Debug, Clone, Copy)]
16pub struct LocalizePerturbate {
17 pub perturbator: Perturbator,
19 pub runs: usize,
21}
22
23impl Default for LocalizePerturbate {
24 #[inline]
26 fn default() -> Self {
27 Self {
28 perturbator: Default::default(),
29 runs: 15,
30 }
31 }
32}
33
34impl LocalizePerturbate {
35 #[inline]
38 pub fn new(runs: usize) -> Self {
39 Self {
40 perturbator: Default::default(),
41 runs,
42 }
43 }
44
45 #[inline]
47 pub fn run<R, I>(
48 &self,
49 localizer: &Localizer,
50 rng: &mut R,
51 image: &I,
52 target: Target,
53 ) -> Point2<f32>
54 where
55 R: RngCore,
56 I: ExtendedImageView<Pixel = Luma<u8>>,
57 {
58 let mut xs: Vec<f32> = Vec::with_capacity(self.runs);
59 let mut ys: Vec<f32> = Vec::with_capacity(self.runs);
60
61 self.perturbator.run(rng, self.runs, target, |t| {
62 let p = localizer.localize(image, t);
63
64 xs.push(p.x);
65 ys.push(p.y);
66 });
67
68 xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
69 ys.sort_by(|a, b| a.partial_cmp(b).unwrap());
70
71 let index = (self.runs - 1) / 2;
72
73 Point2::new(xs[index], ys[index])
74 }
75}