1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
//! Frontier that targets an image.
use super::{Frontier, Pixel};
use crate::color::{ColorSpace, Rgb8};
use crate::metric::soft::SoftKdTree;
use crate::metric::NearestNeighbors;
use image::RgbImage;
/// A [Frontier] that places colors on the closest pixel of a target image.
#[derive(Debug)]
pub struct ImageFrontier<C: ColorSpace> {
nodes: SoftKdTree<Pixel<C>>,
width: u32,
height: u32,
len: usize,
deleted: usize,
}
impl<C: ColorSpace> ImageFrontier<C> {
/// Create an ImageFrontier from an image.
pub fn new(img: &RgbImage) -> Self {
let width = img.width();
let height = img.height();
let len = (width as usize) * (height as usize);
Self {
nodes: img
.enumerate_pixels()
.map(|(x, y, p)| Pixel::new(x, y, C::from(*p)))
.collect(),
width,
height,
len,
deleted: 0,
}
}
}
impl<C: ColorSpace> Frontier for ImageFrontier<C> {
fn width(&self) -> u32 {
self.width
}
fn height(&self) -> u32 {
self.height
}
fn len(&self) -> usize {
self.len - self.deleted
}
fn place(&mut self, rgb8: Rgb8) -> Option<(u32, u32)> {
let color = C::from(rgb8);
if let Some(node) = self.nodes.nearest(&color).map(|n| n.item) {
let pos = node.pos;
node.delete();
self.deleted += 1;
if 32 * self.deleted >= self.len {
self.nodes.rebuild();
self.len -= self.deleted;
self.deleted = 0;
}
Some(pos)
} else {
None
}
}
}
|