cgrustplot/plots/
image_plot.rs1use crate::{
11 helper::{
12 file::{get_current_dir, save_image, save_to_file},
13 mat_plot_lib::pyplot,
14 rendering::RenderableTextBuilder,
15 },
16 plots::array_plot::array_plot,
17};
18use rayon::prelude::*;
19
20fn hsv_to_rgb(hsv: (u8, u8, u8)) -> (u8, u8, u8) {
21 let (h, s, v) = hsv;
22
23 let h = h as f64 * 360.0 / 255.0; let s = s as f64 / 255.0; let v = v as f64 / 255.0; let c = v * s; let x = c * (1.0 - ((h / 60.0) % 2.0 - 1.0).abs());
29 let m = v - c;
30
31 let (r1, g1, b1) = match h as u16 {
32 0..=59 => (c, x, 0.0),
33 60..=119 => (x, c, 0.0),
34 120..=179 => (0.0, c, x),
35 180..=239 => (0.0, x, c),
36 240..=299 => (x, 0.0, c),
37 300..=359 => (c, 0.0, x),
38 _ => (0.0, 0.0, 0.0), };
40
41 let r = ((r1 + m) * 255.0).round() as u8;
42 let g = ((g1 + m) * 255.0).round() as u8;
43 let b = ((b1 + m) * 255.0).round() as u8;
44 (r, g, b)
45}
46
47#[derive(Clone)]
56pub struct ImagePlotBuilder<'a> {
57 img: &'a Vec<Vec<(u8, u8, u8)>>,
58 path: Option<String>,
59}
60
61struct ImagePlot<'a> {
63 img: &'a Vec<Vec<(u8, u8, u8)>>,
64 path: String,
65}
66
67impl<'a> ImagePlotBuilder<'a> {
68 fn from<'b: 'a>(img: &'b Vec<Vec<(u8, u8, u8)>>) -> Self {
70 ImagePlotBuilder {
71 img,
72 path: None,
73 }
74 }
75
76 pub fn set_rel_path(&mut self, path: &str) -> &mut Self {
77 if path.contains(".") {
78 self.path = Some(get_current_dir() + path);
79 } else {
80 self.path = Some(get_current_dir() + path + ".png");
81 }
82 self
83 }
84
85 pub fn set_abs_path(&mut self, path: &str) -> &mut Self {
86 if path.contains(".") {
87 self.path = Some(path.to_string());
88 } else {
89 self.path = Some(path.to_string() + ".png");
90 }
91 self
92 }
93
94 fn build(&self) -> ImagePlot {
95 ImagePlot {
96 img: self.img,
97 path: self.path.clone().unwrap_or_else(|| get_current_dir() + &"output.png"),
98 }
99 }
100
101 pub fn as_string(&self) -> String {
103 self.build().as_string()
104 }
105
106 pub fn print(&self) {
108 self.build().print();
109 }
110
111 pub fn save_as_text(&self, path: &str) {
113 save_to_file(&self.build().as_string(), path);
114 }
115
116 pub fn save(&self) {
118 self.build().save();
119 }
120
121 pub fn as_image(&self) -> RenderableTextBuilder {
123 RenderableTextBuilder::from(self.build().as_string())
124 }
125
126 pub fn pyplot(&self) {
128 self.build().pyplot(None);
129 }
130
131 pub fn save_pyplot(&self, path: &str) {
133 self.build().pyplot(Some(path));
134 }
135
136 #[allow(dead_code)]
138 pub(crate) fn plot(&self) -> String {
139 self.build().plot()
140 }
141}
142
143impl<'a> ImagePlot<'a> {
144 fn plot(&self) -> String {
145 let brightnesses: Vec<Vec<u32>> = self.img.par_iter().map(|row| row.iter().map(|p| p.0 as u32 + p.1 as u32 + p.2 as u32).collect()).collect();
146 array_plot(&brightnesses)
147 .set_axes(false)
148 .set_title(&self.path)
149 .as_string()
150 }
151
152 fn as_string(&self) -> String {
153 self.plot()
154 }
155
156 fn print(&self) {
157 println!("{}", self.as_string());
158 }
159
160 fn pyplot(&self, path: Option<&str>) {
161 let command = format!("imshow(np.array({:?}))", self.img);
162 pyplot(&command, None, None, None, path);
163 }
164
165 fn save(&self) {
166 save_image(&self.img, &self.path);
167 }
168}
169
170pub fn image_plot<'a>(img: &'a Vec<Vec<(u8, u8, u8)>>) -> ImagePlotBuilder<'a> {
188 ImagePlotBuilder::from(img)
189}
190
191pub fn convert_from_hsv(hsv: &Vec<Vec<(u8, u8, u8)>>) -> Vec<Vec<(u8, u8, u8)>> {
193 hsv.par_iter().map(|row| row.into_iter().map(|pixel| hsv_to_rgb(*pixel)).collect()).collect()
194}
195
196pub fn downsample(img: &Vec<Vec<(u8, u8, u8)>>, scale_factor: f64) -> Vec<Vec<(u8, u8, u8)>> {
199 let img_h = img.len();
200 let img_w = if img.len() != 0 {img[0].len()} else {0};
201
202 let o_h = (scale_factor * img_h as f64) as usize;
203 let o_w = (scale_factor * img_w as f64) as usize;
204
205 let mut o: Vec<Vec<(u8, u8, u8)>> = Vec::with_capacity(o_w * o_h);
206
207 for y in 0..o_h {
208 for x in 0..o_w {
209 let mut sum_r = 0;
210 let mut sum_g = 0;
211 let mut sum_b = 0;
212 let mut count = 0;
213
214 for r in ((y as f64 * scale_factor).floor() as usize)..(((y + 1) as f64 * scale_factor).ceil() as usize) {
215 for c in ((x as f64 * scale_factor).floor() as usize)..(((x + 1) as f64 * scale_factor).ceil() as usize) {
216 let (r, g, b) = img[r][c];
217 sum_r += r as u32;
218 sum_g += g as u32;
219 sum_b += b as u32;
220 count += 1;
221 }
222 }
223
224 let process = |sum| (sum as f64 / count as f64).clamp(0., 255.) as u8;
225
226 o[y][x] = (process(sum_r), process(sum_g), process(sum_b));
227 }
228 }
229
230 o
231}