diff --git a/.gitignore b/.gitignore index 8e5d337..b943344 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,8 @@ ipcli/target/debug/* *.cargo-lock ipcli/target/debug/.* ipcli/target/x* + +*Cargo.lock +*.iml +/target +.idea/ diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 443c83b..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,377 +0,0 @@ -[root] -name = "ipcli" -version = "0.1.0" -dependencies = [ - "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "adler32" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ansi_term" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "atty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "byteorder" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clap" -version = "2.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "coco" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "color_quant" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "deflate" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "adler32 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "enum_primitive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "futures" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "gif" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "image" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jpeg-decoder 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "png 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "inflate" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "jpeg-decoder" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lzw" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magenta" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magenta-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-integer" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-iter" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-rational" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "num_cpus" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "png" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "deflate 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)", - "inflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "scoped_threadpool" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "term_size" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-segmentation" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "vec_map" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum adler32 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce93f29e3642662cac79d45e9c27ead906b91ac9921c1cf6f4801d01b4e19a8b" -"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" -"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2267a8fdd4dce6956ba6649e130f62fb279026e5e84b92aa939ac8f85ce3f9f0" -"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" -"checksum color_quant 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a475fc4af42d83d28adf72968d9bcfaf035a1a9381642d8e85d8a04957767b0d" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum deflate 0.7.15 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5853b87cd72596b2702f9cb8a4502de33334e85b4d7f4cc594d7b12fa60427" -"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" -"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" -"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" -"checksum gif 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e41945ba23db3bf51b24756d73d81acb4f28d85c3dccc32c6fae904438c25f" -"checksum image 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "634700d4a51fa91ceaa798001d46bf862c7b712bd691085d7ba6afd5521e21f7" -"checksum inflate 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1238524675af3938a7c74980899535854b88ba07907bb1c944abe5b8fc437e5" -"checksum jpeg-decoder 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2805ccb10ffe4d10e06ef68a158ff94c255211ecbae848fbde2146b098f93ce7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" -"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" -"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" -"checksum png 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f256476eee4447f55909d52d22a16cfa6e5e55e5cb77fa182c7fcc8c4456ee3c" -"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" -"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" -"checksum scoped_threadpool 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef399c8893e8cb7aa9696e895427fab3a6bf265977bb96e126f24ddd2cda85a" -"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" -"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" -"checksum textwrap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f728584ea33b0ad19318e20557cb0a39097751dbb07171419673502f848c7af6" -"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/README.md b/README.md index c52fc1c..521e572 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Generated histograms are also stored this way. * ***contrast:*** -o contrast -v 20.0 * ***grayscale***: -o grayscale * ***invert*** -o invert +* ***Canny Edge Detection*** -o canny -v 0.5 50 100 ## Examples diff --git a/src/canny.rs b/src/canny.rs new file mode 100644 index 0000000..a65e0bf --- /dev/null +++ b/src/canny.rs @@ -0,0 +1,133 @@ +use image::{FilterType, GenericImage, Pixel, ImageBuffer, Rgba, Primitive}; +use image::DynamicImage; +use image::imageops; +use std::collections::HashSet; + +use saveFile; +use std::hash::Hash; + +fn gradient_magnitude(x_gradient: &ImageBuffer, Vec>, y_gradient: &ImageBuffer, Vec>, x_pos: u32, y_pos: u32) -> f64 +{ + let x_grad_val = x_gradient.get_pixel(x_pos, y_pos).data[0] as f64; + let y_grad_val = y_gradient.get_pixel(x_pos, y_pos).data[0] as f64; + + (x_grad_val*x_grad_val + y_grad_val*y_grad_val).sqrt() +} + +// Implementation based on: https://docs.opencv.org/trunk/da/d22/tutorial_py_canny.html and +// https://en.wikipedia.org/wiki/Canny_edge_detector +// +// sigma is a parameter for the Gaussian filter +// min_val and max_val are parameters for the Canny Edge Detector +pub fn edge_detect(image_path: &str, sigma: f32, min_val: f64, max_val: f64) { + // Get image and process it for edge detection + let img = image::open(image_path).expect("Opening image failed"); + println!("Processing image..."); + let processed_img = img.grayscale().blur(sigma); + + // Calculate gradients using Sobel's Edge Detection Operator + println!("Calculating gradients..."); + let x_gradient = imageops::filter3x3(&processed_img, &[-1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0]); + let y_gradient = imageops::filter3x3(&processed_img, &[-1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0]); + + // Make resulting image based on the Sobel image ... x_gradient.dimensions() == y_gradient.dimensions() + let (width,height) = x_gradient.dimensions(); + let mut result_img = DynamicImage::new_rgba8(width, height); + + // Perform Non-Maximum Suppression + println!("Non-Maximum Supression..."); + for x in 0..width { + for y in 0..height { + // Because gradients are grayscaled, each color chanel has the same value + let x_grad_val = x_gradient.get_pixel(x, y).data[0]; + let y_grad_val = y_gradient.get_pixel(x, y).data[0]; + + let magnitude = gradient_magnitude(&x_gradient, &y_gradient, x, y); + let angle = (y_grad_val as f64).atan2(x_grad_val as f64); + + // Move along gradient to see if current pixel is non-maximal + let mut is_maximal = true; + let step_size = 2.0; + + let forward_x = x as f64 + step_size*angle.cos(); + let forward_y = y as f64 + step_size*angle.sin(); + + // Do bound check and check if pixel in forward direction of gradient is bigger than the current pixel + if forward_x >= 0.0 && forward_y >= 0.0 && forward_x < width as f64 && forward_y < height as f64 { + let forward_x = forward_x as u32; + let forward_y = forward_y as u32; + if gradient_magnitude(&x_gradient, &y_gradient, forward_x, forward_y) >= magnitude { + is_maximal = false; + } + } + + let backward_x = x as f64 - step_size*angle.cos(); + let backward_y = y as f64 - step_size*angle.sin(); + // Do bound check and check if pixel in backward direction of gradient is bigger than the current pixel + if backward_x >= 0.0 && backward_y >= 0.0 && backward_x < width as f64 && backward_y < height as f64 { + let backward_x = backward_x as u32; + let backward_y = backward_y as u32; + if gradient_magnitude(&x_gradient, &y_gradient, backward_x, backward_y) >= magnitude { + is_maximal = false; + } + } + + if !is_maximal { + // Zero out non-maximal pixels + result_img.put_pixel(x, y, Rgba([0, 0, 0, 0])) + } else { + let magnitude_int = magnitude as u8; + // Edge pixels with magnitude under the given minimum value are disregarded as edge pixels + if magnitude <= min_val { + result_img.put_pixel(x, y, Rgba([0, 0, 0, 0])) + } else { + result_img.put_pixel(x, y, Rgba([magnitude_int, magnitude_int, magnitude_int, 0])) + } + } + + } + } + + // Perform Hysteresis Thresholding + println!("Hysteresis Thresholding..."); + let mut sure_edge_set: HashSet<(u32, u32)> = HashSet::new(); + // Find all edge pixels that are definitely edge pixels + for x in 0..width { + for y in 0..height { + let edge_val = result_img.get_pixel(x, y).data[0]; + if edge_val as f64 >= max_val || sure_edge_set.contains(&(x, y)) { + // Remember the pixel + sure_edge_set.insert((x, y)); + + let x = x as i64; + let y = y as i64; + // Make neighboring non-zero pixels also sure edges + let neighbors = [(x + 1, y), (x + 1, y + 1), (x, y + 1), (x - 1, y + 1), (x - 1, y), (x - 1, y - 1), (x, y - 1), (x + 1, y - 1)]; + // Iterate through each neighbor + for (neighbor_x, neighbor_y) in &neighbors { + // Do bound checks and use floats to prevent subtraction overflow + if *neighbor_x >= 0 && *neighbor_y >= 0 && result_img.in_bounds(*neighbor_x as u32, *neighbor_y as u32) { + let neighbor_pixel_val = result_img.get_pixel(*neighbor_x as u32, *neighbor_y as u32).data[0]; + if neighbor_pixel_val > 0 { + sure_edge_set.insert((*neighbor_x as u32, *neighbor_y as u32)); + } + } + } + } + } + } + // Discard non-edge pixels + for x in 0..width { + for y in 0..height { + if !sure_edge_set.contains(&(x, y)) { + result_img.put_pixel(x, y, Rgba([0, 0, 0, 0])); + } else { + result_img.put_pixel(x, y, Rgba([255, 255, 255, 0])); + } + } + } + + + println!("Saving images..."); + saveFile(&result_img, format!("{}.jpg", image_path).as_str(), "Canny"); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index fe32ea4..97b09c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ extern crate clap; extern crate image; +mod canny; + use clap::{Arg,App,SubCommand}; use std::fs::File; use image::{FilterType, GenericImage, Pixel,ImageBuffer,Rgb}; @@ -73,6 +75,15 @@ fn main() { let v: u8 = value.parse().unwrap(); binary_treshold(imagePath,v); } + "canny" => { + // Perform input checking + let values: Vec<&str> = value.split_whitespace().collect(); + if let (Ok(sigma), Ok(min_val), Ok(max_val)) = (values[0].parse::(), values[1].parse::(), values[2].parse::()) { + canny::edge_detect(imagePath, sigma, min_val, max_val); + } else { + println!("Canny Edge Detection Requires 3 Parameters: sigma min_val max_val") + } + } _ => {println!("Not implemented yet!")} } } diff --git a/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120 b/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120 deleted file mode 100644 index 1e895fe..0000000 --- a/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120 +++ /dev/null @@ -1 +0,0 @@ -1b3a320ece0dab22 \ No newline at end of file diff --git a/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120.json b/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120.json deleted file mode 100644 index 089e680..0000000 --- a/target/debug/.fingerprint/ipcli-e4ae739736d65120/bin-ipcli-e4ae739736d65120.json +++ /dev/null @@ -1 +0,0 @@ -{"rustc":4149359360477813300,"features":"[]","target":11363022221500507186,"profile":731176819336294830,"deps":[["clap v2.26.0",17862266554049713463],["image v0.15.0",5255379680165291198]],"local":{"MtimeBased":[[1502968439,163188600],"C:\\Users\\spejss\\Documents\\GitHub\\Image-Processing-CLI-in-Rust\\target\\debug\\.fingerprint\\ipcli-e4ae739736d65120\\dep-bin-ipcli-e4ae739736d65120"]},"rustflags":[]} \ No newline at end of file diff --git a/target/debug/.fingerprint/ipcli-e4ae739736d65120/dep-bin-ipcli-e4ae739736d65120 b/target/debug/.fingerprint/ipcli-e4ae739736d65120/dep-bin-ipcli-e4ae739736d65120 deleted file mode 100644 index 872aed6..0000000 Binary files a/target/debug/.fingerprint/ipcli-e4ae739736d65120/dep-bin-ipcli-e4ae739736d65120 and /dev/null differ diff --git a/target/debug/deps/ipcli-e4ae739736d65120.exe b/target/debug/deps/ipcli-e4ae739736d65120.exe deleted file mode 100644 index 149f4a6..0000000 Binary files a/target/debug/deps/ipcli-e4ae739736d65120.exe and /dev/null differ diff --git a/target/debug/deps/ipcli-e4ae739736d65120.pdb b/target/debug/deps/ipcli-e4ae739736d65120.pdb deleted file mode 100644 index f181a9d..0000000 Binary files a/target/debug/deps/ipcli-e4ae739736d65120.pdb and /dev/null differ