From 3fe8109102083ef32da9e11eef5dc45dba530333 Mon Sep 17 00:00:00 2001 From: Lia Lenckowski Date: Tue, 5 Sep 2023 21:41:17 +0200 Subject: actually use 'Hue' in the HueEmbedder, add ColorEmbedder, parallelize image embedding --- Cargo.lock | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++---- Cargo.toml | 2 + src/embedders.rs | 59 +++++++++++++++++---- src/main.rs | 2 + 4 files changed, 195 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f493b6f..339e4f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -150,6 +150,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.45.0", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -220,10 +233,18 @@ version = "0.1.0" dependencies = [ "clap", "image", + "indicatif", "priority-queue", + "rayon", "xdg", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "exr" version = "1.7.0" @@ -363,6 +384,28 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "jpeg-decoder" version = "0.3.0" @@ -381,6 +424,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "lebe" version = "0.5.2" @@ -477,6 +526,12 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" version = "1.18.0" @@ -516,6 +571,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "portable-atomic" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" + [[package]] name = "priority-queue" version = "1.3.2" @@ -636,6 +697,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "utf8parse" version = "0.2.1" @@ -708,13 +775,37 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -723,51 +814,93 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index 88a19a4..3e3ce75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,5 @@ image = "0" xdg = "2" clap = {version = "4", features = ["derive"]} priority-queue = "1" +rayon = "1" +indicatif = "0" diff --git a/src/embedders.rs b/src/embedders.rs index 7310a58..94fc122 100644 --- a/src/embedders.rs +++ b/src/embedders.rs @@ -1,3 +1,4 @@ +use rayon::prelude::*; use std::path::PathBuf; pub trait MetricElem { @@ -22,7 +23,7 @@ impl EmbedderT for BrightnessEmbedder { fn embed(&mut self, paths: &[PathBuf]) -> Result, String> { paths - .iter() + .par_iter() .map(|p| { let im = image::open(p).map_err(|e| e.to_string())?; let num_bytes = 3 * (im.height() * im.width()); @@ -36,11 +37,14 @@ impl EmbedderT for BrightnessEmbedder { .map(|e| *e as u64) .sum::() as f64 / num_bytes as f64) }) + .collect::>() + .into_iter() .try_collect() } } -struct Hue (f64); +#[repr(transparent)] +pub struct Hue (f64); impl MetricElem for Hue { fn dist(&self, b: &Hue) -> f64 { let d = self.0.dist(&b.0); @@ -50,11 +54,11 @@ impl MetricElem for Hue { pub struct HueEmbedder; impl EmbedderT for HueEmbedder { - type Embedding = f64; // TODO anderes Ding was Winkel vergleicht + type Embedding = Hue; - fn embed(&mut self, paths: &[PathBuf]) -> Result, String> { + fn embed(&mut self, paths: &[PathBuf]) -> Result, String> { paths - .iter() + .par_iter() .map(|p| { let im = image::open(p).map_err(|e| e.to_string())?; let num_pixels = im.height() * im.width(); @@ -67,7 +71,7 @@ impl EmbedderT for HueEmbedder { }) .map(|e| e as f64 / 255. / num_pixels as f64); - let mut hue = + let hue = if sr >= sg && sr >= sb { (sg - sb) / (sr - sg.min(sb)) } @@ -78,16 +82,49 @@ impl EmbedderT for HueEmbedder { 4. + (sr - sg) / (sb - sr.min(sg)) }; - if hue < 0. { - hue += 6.; - } - if hue.is_nan() { Err("Encountered NaN hue, possibly because of a colorless or empty image")?; } - Ok(hue) + Ok(Hue(hue)) + }) + .collect::>() + .into_iter() + .try_collect() + } +} + +impl MetricElem for (f64, f64, f64) { + fn dist(&self, o: &(f64, f64, f64)) -> f64 { + let (dr, dg, db) = + ((self.0 - o.0), (self.1 - o.1), (self.2 - o.2)); + (dr*dr + dg*dg + db*db).sqrt() + } +} + +pub struct ColorEmbedder; +impl EmbedderT for ColorEmbedder { + type Embedding = (f64, f64, f64); + + fn embed(&mut self, paths: &[PathBuf]) -> Result, String> { + paths + .par_iter() + .map(|p| { + let im = image::open(p).map_err(|e| e.to_string())?; + let num_pixels = im.height() * im.width(); + let [sr, sg, sb] = im + .to_rgb8() + .pixels() + .fold([0, 0, 0], |[or, og, ob], n| { + let [nr, ng, nb] = n.0; + [or + nr as u64, og + ng as u64, ob + nb as u64] + }) + .map(|e| e as f64 / num_pixels as f64); + + Ok((sr, sg, sb)) }) + .collect::>() + .into_iter() .try_collect() } } diff --git a/src/main.rs b/src/main.rs index f34413a..a28885d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,7 @@ mod embedders; enum Embedder { Brightness, Hue, + Color, } #[derive(Debug, Parser)] @@ -124,6 +125,7 @@ fn main() -> Result<(), String> { let tsp_path = match args.embedder { Embedder::Brightness => process_embedder(BrightnessEmbedder, args), Embedder::Hue => process_embedder(HueEmbedder, args), + Embedder::Color => process_embedder(ColorEmbedder, args), }?; for p in tsp_path { -- cgit v1.2.3-70-g09d2