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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
extern crate ndarray; use ndarray::*; use std::f32; pub struct Character { pub rho: f32, pub theta: f32, pub string: String } fn new_char(theta: f32, rho: f32, string: &'static str) -> Character { Character { rho: rho, theta: theta, string: string.to_string() } } impl Character { pub fn score(&self, theta: f32, rho: f32) -> f32 { (self.theta - theta).abs() * 50. + (self.rho - rho).abs() } } pub struct AsciiArtFilter { pub character_list: Vec<Character> } pub fn default() -> AsciiArtFilter { let character_list = vec![ new_char(0., 0.25, "| "), new_char(0., 0.5, "|"), new_char(0., 0.75, " |"), new_char(f32::asin(1./f32::sqrt(5.)), 1./f32::sqrt(5.), "/ "), new_char(f32::asin(1./f32::sqrt(5.)), 2./f32::sqrt(5.), " /"), new_char(f32::asin(1./f32::sqrt(5.)), 1.5/f32::sqrt(5.), "/"), new_char(1./4.*f32::consts::PI, 1./f32::sqrt(32.), "\" "), new_char(1./4.*f32::consts::PI, 1./f32::sqrt(2.), "/"), new_char(1./4.*f32::consts::PI, 7./f32::sqrt(32.), " ."), new_char(1./2.*f32::consts::PI, 0.25, " ̄"), new_char(1./2.*f32::consts::PI, 0.5, "ー"), new_char(1./2.*f32::consts::PI, 0.75, "_"), new_char(3./4.*f32::consts::PI, 3./f32::sqrt(32.), ". "), new_char(3./4.*f32::consts::PI, 0., "\"), new_char(3./4.*f32::consts::PI, -3./f32::sqrt(32.), " \""), new_char( f32::consts::PI - f32::asin(1./f32::sqrt(5.)), 0., "\\ "), new_char( f32::consts::PI - f32::asin(1./f32::sqrt(5.)), - 0.5/f32::sqrt(5.), "\"), new_char( f32::consts::PI - f32::asin(1./f32::sqrt(5.)), - 1./f32::sqrt(5.), " \\"), ]; let aaf: AsciiArtFilter = AsciiArtFilter { character_list: character_list }; return aaf; } impl AsciiArtFilter { pub fn run(&self, img: Array3<f32>) -> String { let mut result = String::from(""); for yi in 0..img.shape()[0] { for xi in 0..img.shape()[1] { let slope = img[[yi, xi, 0]]; let rho = img[[yi, xi, 1]]; let character = self.nearest_character(slope, rho); result += &character; } result += "\n"; } return result; } fn nearest_character(&self, theta: f32, rho: f32) -> String { if theta.is_nan() || rho.is_nan() { return String::from(" "); } let minimum_character_by_theta_opt = self.character_list.iter() .min_by(|left, right| left.score(theta, rho) .partial_cmp(&right.score(theta, rho)) .unwrap()); let minimum_character_by_theta = minimum_character_by_theta_opt.unwrap(); return minimum_character_by_theta.string.clone(); } }