use crate::{
helper::{
file::{get_current_dir, save_image, save_to_file},
mat_plot_lib::pyplot,
rendering::RenderableTextBuilder,
},
plots::array_plot::array_plot,
};
use rayon::prelude::*;
fn hsv_to_rgb(hsv: (u8, u8, u8)) -> (u8, u8, u8) {
let (h, s, v) = hsv;
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());
let m = v - c;
let (r1, g1, b1) = match h as u16 {
0..=59 => (c, x, 0.0),
60..=119 => (x, c, 0.0),
120..=179 => (0.0, c, x),
180..=239 => (0.0, x, c),
240..=299 => (x, 0.0, c),
300..=359 => (c, 0.0, x),
_ => (0.0, 0.0, 0.0), };
let r = ((r1 + m) * 255.0).round() as u8;
let g = ((g1 + m) * 255.0).round() as u8;
let b = ((b1 + m) * 255.0).round() as u8;
(r, g, b)
}
#[derive(Clone)]
pub struct ImagePlotBuilder<'a> {
img: &'a Vec<Vec<(u8, u8, u8)>>,
path: Option<String>,
}
struct ImagePlot<'a> {
img: &'a Vec<Vec<(u8, u8, u8)>>,
path: String,
}
impl<'a> ImagePlotBuilder<'a> {
fn from<'b: 'a>(img: &'b Vec<Vec<(u8, u8, u8)>>) -> Self {
ImagePlotBuilder {
img,
path: None,
}
}
pub fn set_rel_path(&mut self, path: &str) -> &mut Self {
if path.contains(".") {
self.path = Some(get_current_dir() + path);
} else {
self.path = Some(get_current_dir() + path + ".png");
}
self
}
pub fn set_abs_path(&mut self, path: &str) -> &mut Self {
if path.contains(".") {
self.path = Some(path.to_string());
} else {
self.path = Some(path.to_string() + ".png");
}
self
}
fn build(&self) -> ImagePlot {
ImagePlot {
img: self.img,
path: self.path.clone().unwrap_or_else(|| get_current_dir() + &"output.png"),
}
}
pub fn as_string(&self) -> String {
self.build().as_string()
}
pub fn print(&self) {
self.build().print();
}
pub fn save_as_text(&self, path: &str) {
save_to_file(&self.build().as_string(), path);
}
pub fn save(&self) {
self.build().save();
}
pub fn as_image(&self) -> RenderableTextBuilder {
RenderableTextBuilder::from(self.build().as_string())
}
pub fn pyplot(&self) {
self.build().pyplot(None);
}
pub fn save_pyplot(&self, path: &str) {
self.build().pyplot(Some(path));
}
#[allow(dead_code)]
pub(crate) fn plot(&self) -> String {
self.build().plot()
}
}
impl<'a> ImagePlot<'a> {
fn plot(&self) -> String {
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();
array_plot(&brightnesses)
.set_axes(false)
.set_title(&self.path)
.as_string()
}
fn as_string(&self) -> String {
self.plot()
}
fn print(&self) {
println!("{}", self.as_string());
}
fn pyplot(&self, path: Option<&str>) {
let command = format!("imshow(np.array({:?}))", self.img);
pyplot(&command, None, None, None, path);
}
fn save(&self) {
save_image(&self.img, &self.path);
}
}
pub fn image_plot<'a>(img: &'a Vec<Vec<(u8, u8, u8)>>) -> ImagePlotBuilder<'a> {
ImagePlotBuilder::from(img)
}
pub fn convert_from_hsv(hsv: &Vec<Vec<(u8, u8, u8)>>) -> Vec<Vec<(u8, u8, u8)>> {
hsv.par_iter().map(|row| row.into_iter().map(|pixel| hsv_to_rgb(*pixel)).collect()).collect()
}
pub fn downsample(img: &Vec<Vec<(u8, u8, u8)>>, scale_factor: f64) -> Vec<Vec<(u8, u8, u8)>> {
let img_h = img.len();
let img_w = if img.len() != 0 {img[0].len()} else {0};
let o_h = (scale_factor * img_h as f64) as usize;
let o_w = (scale_factor * img_w as f64) as usize;
let mut o: Vec<Vec<(u8, u8, u8)>> = Vec::with_capacity(o_w * o_h);
for y in 0..o_h {
for x in 0..o_w {
let mut sum_r = 0;
let mut sum_g = 0;
let mut sum_b = 0;
let mut count = 0;
for r in ((y as f64 * scale_factor).floor() as usize)..(((y + 1) as f64 * scale_factor).ceil() as usize) {
for c in ((x as f64 * scale_factor).floor() as usize)..(((x + 1) as f64 * scale_factor).ceil() as usize) {
let (r, g, b) = img[r][c];
sum_r += r as u32;
sum_g += g as u32;
sum_b += b as u32;
count += 1;
}
}
let process = |sum| (sum as f64 / count as f64).clamp(0., 255.) as u8;
o[y][x] = (process(sum_r), process(sum_g), process(sum_b));
}
}
o
}