symcode/acute32/
library.rs1use std::collections::HashMap;
2
3use bit_vec::BitVec;
4use visioncortex::{BinaryImage, Sampler};
5
6use super::{Acute32SymcodeConfig, GlyphLabel, GlyphTrace, Symbol, Trace, image_diff_area};
7
8#[derive(Debug)]
9pub struct Acute32Library {
10 templates: Vec<Symbol>,
11}
12
13impl Default for Acute32Library {
14 fn default() -> Self {
15 Self { templates: vec![] }
16 }
17}
18
19impl Acute32Library {
20 pub fn is_empty(&self) -> bool {
21 self.templates.is_empty()
22 }
23
24 pub fn len(&self) -> usize {
25 self.templates.len()
26 }
27
28 pub fn get_glyph_at(&self, i: usize) -> Option<&Symbol> {
29 if i >= self.templates.len() {
30 None
31 } else {
32 Some(&self.templates[i])
33 }
34 }
35
36 pub fn get_glyph_with_label(&self, label: GlyphLabel) -> Option<&Symbol> {
37 for glyph in self.templates.iter() {
38 if glyph.label == label {
39 return Some(glyph);
40 }
41 }
42 None
43 }
44
45 pub fn print_label_and_trace(&self) -> String {
46 let list: Vec<String> = self.templates.iter().map(|glyph| {
47 format!("{:?}: {:?}\n", glyph.label, glyph.encoding.bits)
48 }).collect();
49 list.join("")
50 }
51
52 pub fn get_labels_grouped_by_trace(&self) -> String {
53 let mut map: HashMap<BitVec, Vec<GlyphLabel>> = HashMap::new();
54
55 self.templates.iter().for_each(|glyph| {
56 match map.get_mut(&glyph.encoding.bits) {
57 Some(labels) => {
58 labels.push(glyph.label);
59 },
60 None => {
61 map.insert(glyph.encoding.bits.clone(), vec![glyph.label]);
62 }
63 }
64 });
65
66 let list: Vec<String> = map.iter().map(|(bits, labels)| {
67 format!("{:?}: {}\n", bits, labels.len())
68 }).collect();
69
70 list.join("")
71 }
72
73 pub fn add_template(&mut self, image: BinaryImage, symcode_config: &Acute32SymcodeConfig) {
75 let label = GlyphLabel::from_usize_representation(self.templates.len());
77 self.templates.push(Symbol::from_image_label(image, label, symcode_config.stat_tolerance));
79 }
80
81 pub fn find_most_similar_glyph(&self, image: BinaryImage, symcode_config: &Acute32SymcodeConfig) -> GlyphLabel {
82 let image = &Sampler::resample_image(&image, symcode_config.symbol_width, symcode_config.symbol_height);
83 let input_encoding = &GlyphTrace::from_image(image, symcode_config.stat_tolerance);
84 self.templates.iter()
87 .fold( (std::u64::MAX, GlyphLabel::Invalid),
88 |(min_error, min_label), template| {
89 if template.encoding.diff(input_encoding) > symcode_config.max_encoding_difference {
90 return (min_error, min_label);
91 }
92 let error = image_diff_area(&template.image, image);
93 if error < min_error {
94 (error, template.label)
95 } else {
96 (min_error, min_label)
97 }
98 }
99 ).1
100 }
101}