diff --git a/Cargo.lock b/Cargo.lock index 14bcde2..50a704d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,15 +555,16 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] @@ -1649,11 +1650,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", + "libc", + "once_cell", ] [[package]] @@ -1720,9 +1723,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.11" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -1730,23 +1733,23 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim", + "strsim 0.11.1", ] [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.61", @@ -1754,9 +1757,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cloudabi" @@ -2116,7 +2119,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 2.0.61", ] @@ -2934,6 +2937,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -3083,7 +3092,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core", + "windows-core 0.51.1", ] [[package]] @@ -3196,6 +3205,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.10.5" @@ -3265,9 +3280,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -4053,9 +4068,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opencv" -version = "0.88.4" +version = "0.91.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82171a36b8642ad249ab90a34dfa00148b0a5a77d4486b4821fe19ae6587a93a" +checksum = "e64b5a733be752a917aa27981c1100fbc7836cf2cfe3fb06f5cac691339837b7" dependencies = [ "cc", "dunce", @@ -4068,13 +4083,14 @@ dependencies = [ "semver", "shlex", "vcpkg", + "windows 0.56.0", ] [[package]] name = "opencv-binding-generator" -version = "0.81.0" +version = "0.89.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1941efeef14b642f70c7d8294d12d340a60f03499961e24d4c0be5ca66c7bb" +checksum = "81af1298c489597ffdbadc7710673ec26f8a2440228992681ffa3b8f00233bd9" dependencies = [ "clang", "clang-sys", @@ -4831,6 +4847,7 @@ dependencies = [ "rustmas-light-client", "serde", "statistical", + "thiserror", "tokio", ] @@ -5332,7 +5349,7 @@ dependencies = [ "atomic-write-file", "dotenvy", "either", - "heck", + "heck 0.4.1", "hex", "once_cell", "proc-macro2", @@ -5492,6 +5509,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.5.0" @@ -6382,11 +6405,21 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-implement", - "windows-interface", + "windows-implement 0.48.0", + "windows-interface 0.48.0", "windows-targets 0.48.5", ] +[[package]] +name = "windows" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +dependencies = [ + "windows-core 0.56.0", + "windows-targets 0.52.5", +] + [[package]] name = "windows-core" version = "0.51.1" @@ -6396,6 +6429,18 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-core" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +dependencies = [ + "windows-implement 0.56.0", + "windows-interface 0.56.0", + "windows-result", + "windows-targets 0.52.5", +] + [[package]] name = "windows-implement" version = "0.48.0" @@ -6407,6 +6452,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "windows-implement" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "windows-interface" version = "0.48.0" @@ -6418,6 +6474,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "windows-interface" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "windows-result" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749f0da9cc72d82e600d8d2e44cadd0b9eedb9038f71a1c58556ac1c5791813b" +dependencies = [ + "windows-targets 0.52.5", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -6442,7 +6518,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.5", ] [[package]] @@ -6477,17 +6553,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -6504,9 +6581,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -6522,9 +6599,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -6540,9 +6617,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -6558,9 +6641,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -6576,9 +6659,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -6594,9 +6677,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -6612,9 +6695,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" diff --git a/configurator/Cargo.toml b/configurator/Cargo.toml index eb52208..b381e13 100644 --- a/configurator/Cargo.toml +++ b/configurator/Cargo.toml @@ -8,11 +8,11 @@ rustmas-light-client = { path = "../light-client", default-features = false } lightfx = { path = "../lightfx" } chrono = "0.4.30" -clap = { version = "4.0.8", features = ["derive"] } +clap = { version = "4.0.8", features = ["derive", "string"] } csv = "1.1.6" indicatif = "0.17.1" itertools = "0.10.5" -opencv = { version = "0.88", features = ["clang-runtime"] } +opencv = { version = "0.91", features = ["clang-runtime"] } serde = { version = "1.0", features = ["derive"] } nalgebra = "0.31.4" statistical = "1.0.0" @@ -20,3 +20,4 @@ tokio = { version = "1", features = ["full"] } log = "0.4.17" env_logger = "0.10.0" +thiserror = "1.0.60" diff --git a/configurator/src/capture.rs b/configurator/src/capture.rs index 04a8142..c94729e 100644 --- a/configurator/src/capture.rs +++ b/configurator/src/capture.rs @@ -2,7 +2,7 @@ use std::{ error::Error, fmt::Write, io::{self, Read, Write as IoWrite}, - path::Path, + path::{Path, PathBuf}, thread, time::Duration, }; @@ -167,11 +167,17 @@ impl Capturer { ) -> Result>, Box> { let mut coords = Vec::new(); let timestamp = chrono::offset::Local::now().format("%FT%X"); - let dir = format!("captures/{}", timestamp); - std::fs::create_dir_all(dir.as_str().to_owned() + "/img")?; - std::fs::create_dir_all(dir.as_str().to_owned() + "/img/on")?; - std::fs::create_dir_all(dir.as_str().to_owned() + "/img/off")?; - std::fs::create_dir_all(dir.as_str().to_owned() + "/img/marked")?; + let base_dir = PathBuf::from(format!("captures/{}", timestamp)); + let on_dir = base_dir.join("img/on"); + let off_dir = base_dir.join("img/off"); + let marked_dir = base_dir.join("img/marked"); + + std::fs::create_dir_all(&base_dir)?; + if save_pictures { + std::fs::create_dir_all(&on_dir)?; + std::fs::create_dir_all(&off_dir)?; + std::fs::create_dir_all(&marked_dir)?; + } let pb = ProgressBar::new(self.number_of_lights as u64) .with_style( @@ -194,7 +200,7 @@ impl Capturer { thread::sleep(Duration::from_millis(100)); let base_picture = self.camera.capture()?; if save_pictures { - base_picture.save_to_file((format!("{}/img/off/{:03}.jpg", dir, i)).as_str())?; + base_picture.save_to_file(off_dir.with_file_name(format!("{:03}.jpg", i)))?; } let frame = self.single_light_on(i); @@ -208,13 +214,9 @@ impl Capturer { let found_coords = cv::find_light_from_diff(&base_picture, &led_picture)?; if save_pictures { - led_picture.save_to_file((format!("{}/img/on/{:03}.jpg", dir, i)).as_str())?; - led_picture.mark( - found_coords.inner.0, - found_coords.inner.1, - found_coords.confident(), - )?; - led_picture.save_to_file((format!("{}/img/marked/{:03}.jpg", dir, i)).as_str())?; + led_picture.save_to_file(on_dir.with_file_name(format!("{:03}.jpg", i)))?; + led_picture.mark(&found_coords)?; + led_picture.save_to_file(marked_dir.with_file_name(format!("{:03}.jpg", i)))?; } coords.push(found_coords); } @@ -225,10 +227,13 @@ impl Capturer { thread::sleep(Duration::from_millis(100)); let mut all_lights_picture = self.capture_with_retry(); for point in &coords { - all_lights_picture.mark(point.inner.0, point.inner.1, point.confident())?; + all_lights_picture.mark(point)?; } - all_lights_picture.save_to_file(format!("{}/reference.jpg", dir).as_str())?; - Self::save_2d_coordinates(format!("{dir}/{perspective_name}.csv").as_str(), &coords)?; + all_lights_picture.save_to_file(base_dir.with_file_name("reference.jpg"))?; + Self::save_2d_coordinates( + base_dir.with_file_name(format!("{perspective_name}.csv")), + &coords, + )?; Ok(Self::normalize(Self::mark_outliers_by_distance( coords, diff --git a/configurator/src/cv.rs b/configurator/src/cv.rs index 6cc44c0..afd1051 100644 --- a/configurator/src/cv.rs +++ b/configurator/src/cv.rs @@ -1,8 +1,10 @@ use std::fmt; +use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; use std::{error::Error, time::Duration}; use log::debug; +use opencv::imgproc::COLOR_GRAY2RGB; use opencv::{ core, highgui, imgproc, prelude::{Mat, MatTraitConst}, @@ -32,15 +34,15 @@ pub struct Picture { } impl Picture { - pub fn mark(&mut self, x: usize, y: usize, confident: bool) -> Result<(), Box> { - let color = if confident { + pub fn mark(&mut self, coords: &WithConfidence<(usize, usize)>) -> Result<(), Box> { + let color = if coords.confident() { core::VecN::new(0.0, 255.0, 0.0, 255.0) // green } else { core::VecN::new(0.0, 0.0, 255.0, 255.0) // red }; imgproc::circle( &mut self.inner, - core::Point::new(x as i32, y as i32), + core::Point::new(coords.inner.0 as i32, coords.inner.1 as i32), 20, color, 2, @@ -50,11 +52,19 @@ impl Picture { Ok(()) } - pub fn save_to_file(&self, filename: &str) -> Result<(), Box> { - debug!("Writing file: {}", filename); - opencv::imgcodecs::imwrite(filename, &self.inner, &opencv::core::Vector::default())?; + pub fn save_to_file>(&self, path: P) -> Result<(), Box> { + let path = path.as_ref().to_str().ok_or("Bad path provided")?; + debug!("Writing file: {}", path); + opencv::imgcodecs::imwrite(path, &self.inner, &opencv::core::Vector::default())?; Ok(()) } + + pub fn from_file(path: &Path) -> Result> { + Ok(Self::from(opencv::imgcodecs::imread( + path.to_str().ok_or("Image path isn't valid unicode")?, + 1, + )?)) + } } impl From for Picture { @@ -159,6 +169,14 @@ impl Drop for Display { pub fn find_light_from_diff( base_picture: &Picture, led_picture: &Picture, +) -> Result, Box> { + find_light_from_diff_with_output(base_picture, led_picture, None) +} + +pub fn find_light_from_diff_with_output( + base_picture: &Picture, + led_picture: &Picture, + output_dir: Option, ) -> Result, Box> { let mut base_gray = Mat::default(); imgproc::cvt_color( @@ -167,6 +185,10 @@ pub fn find_light_from_diff( imgproc::COLOR_BGR2GRAY, 0, )?; + if let Some(output_dir) = &output_dir { + Picture::from(base_gray.clone()) + .save_to_file(output_dir.with_file_name("1_base_grayscale.jpg"))?; + } let mut led_gray = Mat::default(); imgproc::cvt_color( &led_picture.inner, @@ -174,8 +196,15 @@ pub fn find_light_from_diff( imgproc::COLOR_BGR2GRAY, 0, )?; + if let Some(output_dir) = &output_dir { + Picture::from(led_gray.clone()) + .save_to_file(output_dir.with_file_name("2_led_grayscale.jpg"))?; + } let mut diff = Mat::default(); core::absdiff(&base_gray, &led_gray, &mut diff)?; + if let Some(output_dir) = &output_dir { + Picture::from(diff.clone()).save_to_file(output_dir.with_file_name("3_diff.jpg"))?; + } // erode to remove the noise let mut eroded = Mat::default(); @@ -191,6 +220,9 @@ pub fn find_light_from_diff( core::BORDER_CONSTANT, border_value, )?; + if let Some(output_dir) = &output_dir { + Picture::from(eroded.clone()).save_to_file(output_dir.with_file_name("4_eroded.jpg"))?; + } let mut max_loc = core::Point::default(); let mut max_val: f64 = 0.0; @@ -209,9 +241,18 @@ pub fn find_light_from_diff( confidence: f64::NEG_INFINITY, }); } - - Ok(WithConfidence::<(usize, usize)> { + let result = WithConfidence::<(usize, usize)> { inner: (max_loc.x as usize, max_loc.y as usize), confidence: max_val / 255.0, - }) + }; + if let Some(output_dir) = &output_dir { + // eroded image is in grayscale but we want to mark it in color, so we convert it + let mut eroded_color = Mat::default(); + imgproc::cvt_color(&eroded, &mut eroded_color, COLOR_GRAY2RGB, 0)?; + let mut pic = Picture::from(eroded_color); + pic.mark(&result)?; + pic.save_to_file(output_dir.with_file_name("5_eroded_marked.jpg"))?; + } + + Ok(result) } diff --git a/configurator/src/main.rs b/configurator/src/main.rs index 569cda5..09a44fd 100644 --- a/configurator/src/main.rs +++ b/configurator/src/main.rs @@ -1,7 +1,7 @@ mod capture; mod cv; -use std::error::Error; +use std::{error::Error, path::PathBuf}; use capture::{Capturer, WithConfidence}; use clap::{arg, Parser, Subcommand}; @@ -11,6 +11,12 @@ use log::{debug, info}; use nalgebra::Vector3; use rustmas_light_client as light_client; +#[derive(Debug, thiserror::Error)] +#[error("Configurator error: {message}")] +pub struct ConfiguratorError { + pub message: String, +} + #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Cli { @@ -20,6 +26,14 @@ struct Cli { #[derive(Subcommand, Debug)] enum Commands { + /// Get the difference of two pictures (mostly for demo purposes) + Difference { + #[arg(short, long, num_args = 2, value_name = "JPG_PATH")] + pictures: Vec, + #[arg(short, long, default_value = std::env::current_dir().unwrap_or(".".into()).into_os_string())] + output_dir: PathBuf, + }, + /// Capture 3D coordinates of lights by measuring from 4 sides Capture { #[arg(short, long, default_value = "lights.csv")] @@ -163,6 +177,31 @@ async fn main() -> Result<(), Box> { let cli = Cli::parse(); match cli.command { + Commands::Difference { + pictures, + output_dir, + } => { + // since num_args is set to 2, clap will make sure there are two paths provided + let before = cv::Picture::from_file(&pictures[0])?; + let after = cv::Picture::from_file(&pictures[1])?; + + if !output_dir.exists() { + std::fs::create_dir_all(&output_dir)?; + } + if !output_dir.is_dir() { + Err(ConfiguratorError { + message: "Wrong output dir!".to_owned(), + })?; + } + + let coords = cv::find_light_from_diff_with_output(&before, &after, Some(output_dir))?; + println!( + "Found coords: x:{},y:{}, confidence: {}", + coords.inner.0, coords.inner.1, coords.confidence + ); + + Ok(()) + } Commands::Capture { output, number_of_lights,