diff --git a/.github/workflows/codespeed.yml b/.github/workflows/codespeed.yml index 1dd99f7..b5d069f 100644 --- a/.github/workflows/codespeed.yml +++ b/.github/workflows/codespeed.yml @@ -36,11 +36,12 @@ jobs: - name: Install project run: pip install bindings/. - - name: Build the benchmark target(s) - run: cd powerboxesrs && cargo codspeed build + # - name: Build the benchmark target(s) + # run: cd powerboxesrs && cargo codspeed build - name: Run benchmarks uses: CodSpeedHQ/action@v2 with: token: ${{ secrets.CODSPEED_TOKEN }} - run: pytest bindings/tests/ --codspeed && cd powerboxesrs && cargo codspeed run + # run: pytest bindings/tests/ --codspeed && cd powerboxesrs && cargo codspeed run + run: pytest bindings/tests/ --codspeed diff --git a/bindings/Cargo.lock b/bindings/Cargo.lock index 29c6538..ca1d0f2 100644 --- a/bindings/Cargo.lock +++ b/bindings/Cargo.lock @@ -4,9 +4,8 @@ version = 3 [[package]] name = "_powerboxes" -version = "0.2.1" +version = "0.2.3" dependencies = [ - "ndarray", "num-traits", "numpy", "powerboxesrs", @@ -14,25 +13,25 @@ dependencies = [ ] [[package]] -name = "atomic-polyfill" -version = "1.0.3" +name = "approx" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ - "critical-section", + "num-traits", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "bitflags" -version = "1.3.2" +name = "bytemuck" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" [[package]] name = "byteorder" @@ -46,90 +45,42 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - [[package]] name = "hash32" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ "byteorder", ] [[package]] name = "heapless" -version = "0.7.17" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "atomic-polyfill", "hash32", - "rustc_version", - "spin", "stable_deref_trait", ] [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indoc" -version = "2.0.4" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -138,72 +89,99 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] -name = "lock_api" -version = "0.4.11" +name = "matrixmultiply" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", - "scopeguard", + "rawpointer", ] [[package]] -name = "matrixmultiply" -version = "0.3.8" +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", - "rawpointer", ] [[package]] -name = "memoffset" -version = "0.9.0" +name = "nalgebra" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" dependencies = [ - "autocfg", + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "ndarray" -version = "0.15.6" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" dependencies = [ "matrixmultiply", "num-complex", "num-integer", "num-traits", + "portable-atomic", + "portable-atomic-util", "rawpointer", - "rayon", ] [[package]] name = "num-complex" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -211,11 +189,12 @@ dependencies = [ [[package]] name = "numpy" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef41cbb417ea83b30525259e30ccef6af39b31c240bda578889494c5392d331" +checksum = "cf314fca279e6e6ac2126a4ff98f26d88aa4ad06bc68fb6ae5cf4bd706758311" dependencies = [ "libc", + "nalgebra", "ndarray", "num-complex", "num-integer", @@ -226,63 +205,61 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "paste" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "parking_lot_core" -version = "0.9.9" +name = "portable-atomic" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" + +[[package]] +name = "portable-atomic-util" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "fcdd8420072e66d54a407b3316991fe946ce3ab1083a7f575b2463866624704d" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", + "portable-atomic", ] [[package]] name = "powerboxesrs" version = "0.2.3" dependencies = [ - "ndarray", + "nalgebra", "num-traits", - "rayon", "rstar", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.20.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b" +checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225" dependencies = [ "cfg-if", "indoc", "libc", "memoffset", - "parking_lot", + "once_cell", + "portable-atomic", "pyo3-build-config", "pyo3-ffi", "pyo3-macros", @@ -291,9 +268,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.20.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" +checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3" dependencies = [ "once_cell", "target-lexicon", @@ -301,9 +278,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.20.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b" +checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c" dependencies = [ "libc", "pyo3-build-config", @@ -311,9 +288,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.20.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b" +checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -323,21 +300,22 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.20.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424" +checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" dependencies = [ "heck", "proc-macro2", + "pyo3-build-config", "quote", "syn", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -348,40 +326,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" -[[package]] -name = "rayon" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags", -] - [[package]] name = "rstar" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73111312eb7a2287d229f06c00ff35b51ddee180f017ab6dec1f69d62ac098d6" +checksum = "133315eb94c7b1e8d0cb097e5a710d850263372fd028fff18969de708afc7008" dependencies = [ "heapless", "num-traits", @@ -395,40 +344,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "rustc_version" -version = "0.4.0" +name = "safe_arch" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" dependencies = [ - "semver", + "bytemuck", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "simba" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] [[package]] name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "spin" -version = "0.9.8" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" @@ -438,9 +379,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -449,15 +390,21 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.12" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "typenum" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unindent" @@ -466,58 +413,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] -name = "windows-targets" -version = "0.48.5" +name = "wide" +version = "0.7.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" 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", + "bytemuck", + "safe_arch", ] - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[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.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/bindings/Cargo.toml b/bindings/Cargo.toml index 84c0d17..402a01b 100644 --- a/bindings/Cargo.toml +++ b/bindings/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "_powerboxes" -version = "0.2.1" +version = "0.2.3" edition = "2021" license = "MIT" readme = "../README.md" @@ -15,11 +15,9 @@ name = "_powerboxes" crate-type = ["cdylib"] [dependencies] -num-traits = "0.2.17" -numpy = "0.20.0" -pyo3 = "0.20.0" -powerboxesrs = { path = "../powerboxesrs/" } -ndarray = { version = "0.15.6", features = ["rayon"] } +num-traits = "0.2.19" +numpy = { version = "0.22.0", features = ["nalgebra"] } +powerboxesrs = { version = "0.2.3", path = "../powerboxesrs" } +pyo3 = "0.22.3" + -[dev-dependencies] -pyo3 = { version = "0.20.0", features = ["auto-initialize"] } diff --git a/bindings/python/powerboxes/__init__.py b/bindings/python/powerboxes/__init__.py index 3b6f155..35d34b1 100644 --- a/bindings/python/powerboxes/__init__.py +++ b/bindings/python/powerboxes/__init__.py @@ -3,26 +3,25 @@ import numpy as np import numpy.typing as npt -from ._boxes import ( - _dtype_to_func_box_areas, - _dtype_to_func_box_convert, - _dtype_to_func_remove_small_boxes, -) -from ._diou import _dtype_to_func_diou_distance -from ._giou import ( - _dtype_to_func_giou_distance, - _dtype_to_func_parallel_giou_distance, -) -from ._iou import ( - _dtype_to_func_iou_distance, - _dtype_to_func_parallel_iou_distance, -) -from ._nms import _dtype_to_func_nms, _dtype_to_func_rtree_nms -from ._powerboxes import masks_to_boxes as _masks_to_boxes -from ._powerboxes import rotated_giou_distance as _rotated_giou_distance -from ._powerboxes import rotated_iou_distance as _rotated_iou_distance -from ._powerboxes import rotated_tiou_distance as _rotated_tiou_distance -from ._tiou import _dtype_to_func_tiou_distance +from ._boxes import _dtype_to_func_box_areas +# _dtype_to_func_box_convert, +# _dtype_to_func_remove_small_boxes, +# ) +# from ._diou import _dtype_to_func_diou_distance +# from ._giou import ( +# _dtype_to_func_giou_distance, +# _dtype_to_func_parallel_giou_distance, +# ) +# from ._iou import ( +# _dtype_to_func_iou_distance, +# _dtype_to_func_parallel_iou_distance, +# ) +# from ._nms import _dtype_to_func_nms, _dtype_to_func_rtree_nms +# from ._powerboxes import masks_to_boxes as _masks_to_boxes +# from ._powerboxes import rotated_giou_distance as _rotated_giou_distance +# from ._powerboxes import rotated_iou_distance as _rotated_iou_distance +# from ._powerboxes import rotated_tiou_distance as _rotated_tiou_distance +# from ._tiou import _dtype_to_func_tiou_distance _BOXES_NOT_SAME_TYPE = "boxes1 and boxes2 must have the same dtype" _BOXES_NOT_NP_ARRAY = "boxes must be numpy array" @@ -55,309 +54,309 @@ ) -def diou_distance( - boxes1: npt.NDArray[Union[np.float32, np.float64]], - boxes2: npt.NDArray[Union[np.float32, np.float64]], -) -> npt.NDArray[np.float64]: - """Compute pairwise box diou distances. - - DIoU distance is defined in https://arxiv.org/pdf/1911.08287.pdf - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_diou_distance[boxes1.dtype](boxes1, boxes2) - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes np.float32, np.float64" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def iou_distance( - boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] -) -> npt.NDArray[np.float64]: - """Compute pairwise box iou distances. - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_iou_distance[boxes1.dtype](boxes1, boxes2) - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def parallel_iou_distance( - boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] -) -> npt.NDArray[np.float64]: - """Compute pairwise box iou distances, in parallel. - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_parallel_iou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def parallel_giou_distance( - boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] -) -> npt.NDArray[np.float64]: - """Compute pairwise box giou distances, in parallel. - - see [here](https://giou.stanford.edu/) for giou distance definition - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_parallel_giou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def giou_distance( - boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] -) -> npt.NDArray[np.float64]: - """Compute pairwise box giou distances. - - see [here](https://giou.stanford.edu/) for giou distance definition - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_giou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def tiou_distance( - boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] -) -> npt.NDArray[np.float64]: - """Compute pairwise box tiou (tracking iou) distances. - - see [here](https://arxiv.org/pdf/2310.05171.pdf) for tiou definition - - Args: - boxes1: 2d array of boxes in xyxy format - boxes2: 2d array of boxes in xyxy format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype: - try: - return _dtype_to_func_tiou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" - ) - else: - raise ValueError(_BOXES_NOT_SAME_TYPE) - - -def rotated_iou_distance( - boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] -) -> npt.NDArray[np.float64]: - """Compute the pairwise iou distance between rotated boxes - - Boxes should be in (cx, cy, w, h, a) format - where cx and cy are center coordinates, w and h - width and height and a, the angle in degrees - - Args: - boxes1: 2d array of boxes in cxywha format - boxes2: 2d array of boxes in cxywha format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype == np.dtype("float64"): - return _rotated_iou_distance(boxes1, boxes2) - else: - raise TypeError( - f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" - ) - - -def rotated_giou_distance( - boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] -) -> npt.NDArray[np.float64]: - """Compute the pairwise giou distance between rotated boxes - - Boxes should be in (cx, cy, w, h, a) format - where cx and cy are center coordinates, w and h - width and height and a, the angle in degrees - - Args: - boxes1: 2d array of boxes in cxywha format - boxes2: 2d array of boxes in cxywha format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype == np.dtype("float64"): - return _rotated_giou_distance(boxes1, boxes2) - else: - raise TypeError( - f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" - ) - - -def rotated_tiou_distance( - boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] -) -> npt.NDArray[np.float64]: - """Compute pairwise box tiou (tracking iou) distances. - - see [here](https://arxiv.org/pdf/2310.05171.pdf) for tiou definition - - Boxes should be in (cx, cy, w, h, a) format - where cx and cy are center coordinates, w and h - width and height and a, the angle in degrees - - Args: - boxes1: 2d array of boxes in cxywha format - boxes2: 2d array of boxes in cxywha format - - Raises: - TypeError: if boxes1 or boxes2 are not numpy arrays - ValueError: if boxes1 and boxes2 have different dtypes - - Returns: - np.ndarray: 2d matrix of pairwise distances - """ - if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - if boxes1.dtype == boxes2.dtype == np.dtype("float64"): - return _rotated_tiou_distance(boxes1, boxes2) - else: - raise TypeError( - f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" - ) - - -def remove_small_boxes(boxes: npt.NDArray[T], min_size: float) -> npt.NDArray[T]: - """Remove boxes with area less than min_area. - - Args: - boxes: 2d array of boxes in xyxy format - min_size: minimum area of boxes to keep - - Raises: - TypeError: if boxes is not numpy array - - Returns: - np.ndarray: 2d array of boxes in xyxy format - """ - if not isinstance(boxes, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - try: - return _dtype_to_func_remove_small_boxes[boxes.dtype](boxes, min_size) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" - ) +# def diou_distance( +# boxes1: npt.NDArray[Union[np.float32, np.float64]], +# boxes2: npt.NDArray[Union[np.float32, np.float64]], +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box diou distances. + +# DIoU distance is defined in https://arxiv.org/pdf/1911.08287.pdf + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_diou_distance[boxes1.dtype](boxes1, boxes2) +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes np.float32, np.float64" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def iou_distance( +# boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box iou distances. + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_iou_distance[boxes1.dtype](boxes1, boxes2) +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def parallel_iou_distance( +# boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box iou distances, in parallel. + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_parallel_iou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def parallel_giou_distance( +# boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box giou distances, in parallel. + +# see [here](https://giou.stanford.edu/) for giou distance definition + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_parallel_giou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def giou_distance( +# boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box giou distances. + +# see [here](https://giou.stanford.edu/) for giou distance definition + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_giou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def tiou_distance( +# boxes1: npt.NDArray[T], boxes2: npt.NDArray[T] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box tiou (tracking iou) distances. + +# see [here](https://arxiv.org/pdf/2310.05171.pdf) for tiou definition + +# Args: +# boxes1: 2d array of boxes in xyxy format +# boxes2: 2d array of boxes in xyxy format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype: +# try: +# return _dtype_to_func_tiou_distance[boxes1.dtype](boxes1, boxes2) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes1.dtype} not in supported dtypes {supported_dtypes}" +# ) +# else: +# raise ValueError(_BOXES_NOT_SAME_TYPE) + + +# def rotated_iou_distance( +# boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] +# ) -> npt.NDArray[np.float64]: +# """Compute the pairwise iou distance between rotated boxes + +# Boxes should be in (cx, cy, w, h, a) format +# where cx and cy are center coordinates, w and h +# width and height and a, the angle in degrees + +# Args: +# boxes1: 2d array of boxes in cxywha format +# boxes2: 2d array of boxes in cxywha format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype == np.dtype("float64"): +# return _rotated_iou_distance(boxes1, boxes2) +# else: +# raise TypeError( +# f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" +# ) + + +# def rotated_giou_distance( +# boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] +# ) -> npt.NDArray[np.float64]: +# """Compute the pairwise giou distance between rotated boxes + +# Boxes should be in (cx, cy, w, h, a) format +# where cx and cy are center coordinates, w and h +# width and height and a, the angle in degrees + +# Args: +# boxes1: 2d array of boxes in cxywha format +# boxes2: 2d array of boxes in cxywha format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype == np.dtype("float64"): +# return _rotated_giou_distance(boxes1, boxes2) +# else: +# raise TypeError( +# f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" +# ) + + +# def rotated_tiou_distance( +# boxes1: npt.NDArray[np.float64], boxes2: npt.NDArray[np.float64] +# ) -> npt.NDArray[np.float64]: +# """Compute pairwise box tiou (tracking iou) distances. + +# see [here](https://arxiv.org/pdf/2310.05171.pdf) for tiou definition + +# Boxes should be in (cx, cy, w, h, a) format +# where cx and cy are center coordinates, w and h +# width and height and a, the angle in degrees + +# Args: +# boxes1: 2d array of boxes in cxywha format +# boxes2: 2d array of boxes in cxywha format + +# Raises: +# TypeError: if boxes1 or boxes2 are not numpy arrays +# ValueError: if boxes1 and boxes2 have different dtypes + +# Returns: +# np.ndarray: 2d matrix of pairwise distances +# """ +# if not isinstance(boxes1, np.ndarray) or not isinstance(boxes2, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# if boxes1.dtype == boxes2.dtype == np.dtype("float64"): +# return _rotated_tiou_distance(boxes1, boxes2) +# else: +# raise TypeError( +# f"Boxes dtype: {boxes1.dtype}, {boxes2.dtype} not in float64 dtype" +# ) + + +# def remove_small_boxes(boxes: npt.NDArray[T], min_size: float) -> npt.NDArray[T]: +# """Remove boxes with area less than min_area. + +# Args: +# boxes: 2d array of boxes in xyxy format +# min_size: minimum area of boxes to keep + +# Raises: +# TypeError: if boxes is not numpy array + +# Returns: +# np.ndarray: 2d array of boxes in xyxy format +# """ +# if not isinstance(boxes, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# try: +# return _dtype_to_func_remove_small_boxes[boxes.dtype](boxes, min_size) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" +# ) def boxes_areas(boxes: npt.NDArray[T]) -> npt.NDArray[np.float64]: """Compute areas of boxes. Args: - boxes: 2d array of boxes in xyxy format + boxes: 2d array of boxes in xyxy format and shape (N,4) Returns: np.ndarray: 1d array of areas @@ -372,114 +371,114 @@ def boxes_areas(boxes: npt.NDArray[T]) -> npt.NDArray[np.float64]: ) -def box_convert(boxes: npt.NDArray[T], in_fmt: str, out_fmt: str) -> npt.NDArray[T]: - """Convert boxes from one format to another. - - Available formats are: - - 'xyxy': (xmin, ymin, xmax, ymax) - - 'xywh': (xmin, ymin, width, height) - - 'cxcywh': (center_x, center_y, width, height) - - Args: - boxes: 2d array of boxes in in_fmt - in_fmt: format of input boxes - out_fmt: format of output boxes - - Returns: - np.ndarray: boxes in out_fmt - """ - if not isinstance(boxes, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - try: - return _dtype_to_func_box_convert[boxes.dtype](boxes, in_fmt, out_fmt) # type: ignore - except KeyError: - raise TypeError( - f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" - ) - - -def masks_to_boxes(masks: npt.NDArray[np.bool_]) -> npt.NDArray[np.uint64]: - """Convert masks to boxes in xyxy format. - - Args: - masks: 3d array of masks in (N, H, W) format - - Raises: - TypeError: if masks is not numpy array - - Returns: - npt.NDArray[np.uint64]: 2d array of boxes in xyxy format - """ - if not isinstance(masks, np.ndarray): - raise TypeError(_BOXES_NOT_NP_ARRAY) - return _masks_to_boxes(masks) - - -def nms( - boxes: npt.NDArray[T], - scores: npt.NDArray[np.float64], - iou_threshold: float, - score_threshold: float, -) -> npt.NDArray[np.uint64]: - """Apply non-maximum suppression to boxes. - - Args: - boxes: 2d array of boxes in xyxy format - scores: 1d array of scores - iou_threshold: threshold for iou - score_threshold: threshold for scores - - Raises: - TypeError: if boxes or scores are not numpy arrays - - Returns: - npt.NDArray[np.uint64]: 1d array of indices to keep - """ - if not isinstance(boxes, np.ndarray) or not isinstance(scores, np.ndarray): - raise TypeError("Boxes and scores must be numpy arrays") - try: - return _dtype_to_func_nms[boxes.dtype]( # type: ignore - boxes, scores, iou_threshold, score_threshold - ) - except KeyError: - raise TypeError( - f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" - ) - - -def rtree_nms( - boxes: npt.NDArray[Union[np.float64, np.float32, np.int64, np.int32, np.int16]], - scores: npt.NDArray[np.float64], - iou_threshold: float, - score_threshold: float, -) -> npt.NDArray[np.uint64]: - """Apply non-maximum suppression to boxes. - - Uses an rtree to speed up computation. This is only available for - signed integer dtypes and float32 and float64. - - Args: - boxes: 2d array of boxes in xyxy format - scores: 1d array of scores - iou_threshold: threshold for iou - score_threshold: threshold for scores - - Raises: - TypeError: if boxes or scores are not numpy arrays - - Returns: - npt.NDArray[np.uint64]: 1d array of indices to keep - """ - if not isinstance(boxes, np.ndarray) or not isinstance(scores, np.ndarray): - raise TypeError("Boxes and scores must be numpy arrays") - try: - return _dtype_to_func_rtree_nms[boxes.dtype]( # type: ignore - boxes, scores, iou_threshold, score_threshold - ) - except KeyError: - raise TypeError( - f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" - ) +# def box_convert(boxes: npt.NDArray[T], in_fmt: str, out_fmt: str) -> npt.NDArray[T]: +# """Convert boxes from one format to another. + +# Available formats are: +# - 'xyxy': (xmin, ymin, xmax, ymax) +# - 'xywh': (xmin, ymin, width, height) +# - 'cxcywh': (center_x, center_y, width, height) + +# Args: +# boxes: 2d array of boxes in in_fmt +# in_fmt: format of input boxes +# out_fmt: format of output boxes + +# Returns: +# np.ndarray: boxes in out_fmt +# """ +# if not isinstance(boxes, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# try: +# return _dtype_to_func_box_convert[boxes.dtype](boxes, in_fmt, out_fmt) # type: ignore +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" +# ) + + +# def masks_to_boxes(masks: npt.NDArray[np.bool_]) -> npt.NDArray[np.uint64]: +# """Convert masks to boxes in xyxy format. + +# Args: +# masks: 3d array of masks in (N, H, W) format + +# Raises: +# TypeError: if masks is not numpy array + +# Returns: +# npt.NDArray[np.uint64]: 2d array of boxes in xyxy format +# """ +# if not isinstance(masks, np.ndarray): +# raise TypeError(_BOXES_NOT_NP_ARRAY) +# return _masks_to_boxes(masks) + + +# def nms( +# boxes: npt.NDArray[T], +# scores: npt.NDArray[np.float64], +# iou_threshold: float, +# score_threshold: float, +# ) -> npt.NDArray[np.uint64]: +# """Apply non-maximum suppression to boxes. + +# Args: +# boxes: 2d array of boxes in xyxy format +# scores: 1d array of scores +# iou_threshold: threshold for iou +# score_threshold: threshold for scores + +# Raises: +# TypeError: if boxes or scores are not numpy arrays + +# Returns: +# npt.NDArray[np.uint64]: 1d array of indices to keep +# """ +# if not isinstance(boxes, np.ndarray) or not isinstance(scores, np.ndarray): +# raise TypeError("Boxes and scores must be numpy arrays") +# try: +# return _dtype_to_func_nms[boxes.dtype]( # type: ignore +# boxes, scores, iou_threshold, score_threshold +# ) +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" +# ) + + +# def rtree_nms( +# boxes: npt.NDArray[Union[np.float64, np.float32, np.int64, np.int32, np.int16]], +# scores: npt.NDArray[np.float64], +# iou_threshold: float, +# score_threshold: float, +# ) -> npt.NDArray[np.uint64]: +# """Apply non-maximum suppression to boxes. + +# Uses an rtree to speed up computation. This is only available for +# signed integer dtypes and float32 and float64. + +# Args: +# boxes: 2d array of boxes in xyxy format +# scores: 1d array of scores +# iou_threshold: threshold for iou +# score_threshold: threshold for scores + +# Raises: +# TypeError: if boxes or scores are not numpy arrays + +# Returns: +# npt.NDArray[np.uint64]: 1d array of indices to keep +# """ +# if not isinstance(boxes, np.ndarray) or not isinstance(scores, np.ndarray): +# raise TypeError("Boxes and scores must be numpy arrays") +# try: +# return _dtype_to_func_rtree_nms[boxes.dtype]( # type: ignore +# boxes, scores, iou_threshold, score_threshold +# ) +# except KeyError: +# raise TypeError( +# f"Box dtype: {boxes.dtype} not in supported dtypes {supported_dtypes}" +# ) __all__ = [ diff --git a/bindings/python/powerboxes/_boxes.py b/bindings/python/powerboxes/_boxes.py index 10718a5..06252ec 100644 --- a/bindings/python/powerboxes/_boxes.py +++ b/bindings/python/powerboxes/_boxes.py @@ -10,24 +10,24 @@ box_areas_u16, box_areas_u32, box_areas_u64, - box_convert_f32, - box_convert_f64, - box_convert_i16, - box_convert_i32, - box_convert_i64, - box_convert_u8, - box_convert_u16, - box_convert_u32, - box_convert_u64, - remove_small_boxes_f32, - remove_small_boxes_f64, - remove_small_boxes_i16, - remove_small_boxes_i32, - remove_small_boxes_i64, - remove_small_boxes_u8, - remove_small_boxes_u16, - remove_small_boxes_u32, - remove_small_boxes_u64, + # box_convert_f32, + # box_convert_f64, + # box_convert_i16, + # box_convert_i32, + # box_convert_i64, + # box_convert_u8, + # box_convert_u16, + # box_convert_u32, + # box_convert_u64, + # remove_small_boxes_f32, + # remove_small_boxes_f64, + # remove_small_boxes_i16, + # remove_small_boxes_i32, + # remove_small_boxes_i64, + # remove_small_boxes_u8, + # remove_small_boxes_u16, + # remove_small_boxes_u32, + # remove_small_boxes_u64, ) _dtype_to_func_box_areas = { @@ -42,26 +42,26 @@ np.dtype("uint8"): box_areas_u8, } -_dtype_to_func_box_convert = { - np.dtype("float64"): box_convert_f64, - np.dtype("float32"): box_convert_f32, - np.dtype("int64"): box_convert_i64, - np.dtype("int32"): box_convert_i32, - np.dtype("int16"): box_convert_i16, - np.dtype("uint64"): box_convert_u64, - np.dtype("uint32"): box_convert_u32, - np.dtype("uint16"): box_convert_u16, - np.dtype("uint8"): box_convert_u8, -} +# _dtype_to_func_box_convert = { +# np.dtype("float64"): box_convert_f64, +# np.dtype("float32"): box_convert_f32, +# np.dtype("int64"): box_convert_i64, +# np.dtype("int32"): box_convert_i32, +# np.dtype("int16"): box_convert_i16, +# np.dtype("uint64"): box_convert_u64, +# np.dtype("uint32"): box_convert_u32, +# np.dtype("uint16"): box_convert_u16, +# np.dtype("uint8"): box_convert_u8, +# } -_dtype_to_func_remove_small_boxes = { - np.dtype("float64"): remove_small_boxes_f64, - np.dtype("float32"): remove_small_boxes_f32, - np.dtype("int64"): remove_small_boxes_i64, - np.dtype("int32"): remove_small_boxes_i32, - np.dtype("int16"): remove_small_boxes_i16, - np.dtype("uint64"): remove_small_boxes_u64, - np.dtype("uint32"): remove_small_boxes_u32, - np.dtype("uint16"): remove_small_boxes_u16, - np.dtype("uint8"): remove_small_boxes_u8, -} +# _dtype_to_func_remove_small_boxes = { +# np.dtype("float64"): remove_small_boxes_f64, +# np.dtype("float32"): remove_small_boxes_f32, +# np.dtype("int64"): remove_small_boxes_i64, +# np.dtype("int32"): remove_small_boxes_i32, +# np.dtype("int16"): remove_small_boxes_i16, +# np.dtype("uint64"): remove_small_boxes_u64, +# np.dtype("uint32"): remove_small_boxes_u32, +# np.dtype("uint16"): remove_small_boxes_u16, +# np.dtype("uint8"): remove_small_boxes_u8, +# } diff --git a/bindings/python/powerboxes/_diou.py b/bindings/python/powerboxes/_diou.py index dd46265..6a21a59 100644 --- a/bindings/python/powerboxes/_diou.py +++ b/bindings/python/powerboxes/_diou.py @@ -1,11 +1,11 @@ -import numpy as np +# import numpy as np -from ._powerboxes import ( - diou_distance_f32, - diou_distance_f64, -) +# from ._powerboxes import ( +# diou_distance_f32, +# diou_distance_f64, +# ) -_dtype_to_func_diou_distance = { - np.dtype("float64"): diou_distance_f64, - np.dtype("float32"): diou_distance_f32, -} +# _dtype_to_func_diou_distance = { +# np.dtype("float64"): diou_distance_f64, +# np.dtype("float32"): diou_distance_f32, +# } diff --git a/bindings/python/powerboxes/_giou.py b/bindings/python/powerboxes/_giou.py index 843b045..2bf9461 100644 --- a/bindings/python/powerboxes/_giou.py +++ b/bindings/python/powerboxes/_giou.py @@ -1,45 +1,45 @@ -import numpy as np +# import numpy as np -from ._powerboxes import ( - giou_distance_f32, - giou_distance_f64, - giou_distance_i16, - giou_distance_i32, - giou_distance_i64, - giou_distance_u8, - giou_distance_u16, - giou_distance_u32, - giou_distance_u64, - parallel_giou_distance_f32, - parallel_giou_distance_f64, - parallel_giou_distance_i16, - parallel_giou_distance_i32, - parallel_giou_distance_i64, - parallel_giou_distance_u8, - parallel_giou_distance_u16, - parallel_giou_distance_u32, - parallel_giou_distance_u64, -) +# from ._powerboxes import ( +# giou_distance_f32, +# giou_distance_f64, +# giou_distance_i16, +# giou_distance_i32, +# giou_distance_i64, +# giou_distance_u8, +# giou_distance_u16, +# giou_distance_u32, +# giou_distance_u64, +# parallel_giou_distance_f32, +# parallel_giou_distance_f64, +# parallel_giou_distance_i16, +# parallel_giou_distance_i32, +# parallel_giou_distance_i64, +# parallel_giou_distance_u8, +# parallel_giou_distance_u16, +# parallel_giou_distance_u32, +# parallel_giou_distance_u64, +# ) -_dtype_to_func_giou_distance = { - np.dtype("float64"): giou_distance_f64, - np.dtype("float32"): giou_distance_f32, - np.dtype("int64"): giou_distance_i64, - np.dtype("int32"): giou_distance_i32, - np.dtype("int16"): giou_distance_i16, - np.dtype("uint64"): giou_distance_u64, - np.dtype("uint32"): giou_distance_u32, - np.dtype("uint16"): giou_distance_u16, - np.dtype("uint8"): giou_distance_u8, -} -_dtype_to_func_parallel_giou_distance = { - np.dtype("float64"): parallel_giou_distance_f64, - np.dtype("float32"): parallel_giou_distance_f32, - np.dtype("int64"): parallel_giou_distance_i64, - np.dtype("int32"): parallel_giou_distance_i32, - np.dtype("int16"): parallel_giou_distance_i16, - np.dtype("uint64"): parallel_giou_distance_u64, - np.dtype("uint32"): parallel_giou_distance_u32, - np.dtype("uint16"): parallel_giou_distance_u16, - np.dtype("uint8"): parallel_giou_distance_u8, -} +# _dtype_to_func_giou_distance = { +# np.dtype("float64"): giou_distance_f64, +# np.dtype("float32"): giou_distance_f32, +# np.dtype("int64"): giou_distance_i64, +# np.dtype("int32"): giou_distance_i32, +# np.dtype("int16"): giou_distance_i16, +# np.dtype("uint64"): giou_distance_u64, +# np.dtype("uint32"): giou_distance_u32, +# np.dtype("uint16"): giou_distance_u16, +# np.dtype("uint8"): giou_distance_u8, +# } +# _dtype_to_func_parallel_giou_distance = { +# np.dtype("float64"): parallel_giou_distance_f64, +# np.dtype("float32"): parallel_giou_distance_f32, +# np.dtype("int64"): parallel_giou_distance_i64, +# np.dtype("int32"): parallel_giou_distance_i32, +# np.dtype("int16"): parallel_giou_distance_i16, +# np.dtype("uint64"): parallel_giou_distance_u64, +# np.dtype("uint32"): parallel_giou_distance_u32, +# np.dtype("uint16"): parallel_giou_distance_u16, +# np.dtype("uint8"): parallel_giou_distance_u8, +# } diff --git a/bindings/python/powerboxes/_iou.py b/bindings/python/powerboxes/_iou.py index 87e0017..bf2f5cf 100644 --- a/bindings/python/powerboxes/_iou.py +++ b/bindings/python/powerboxes/_iou.py @@ -1,45 +1,45 @@ -import numpy as np +# import numpy as np -from ._powerboxes import ( - iou_distance_f32, - iou_distance_f64, - iou_distance_i16, - iou_distance_i32, - iou_distance_i64, - iou_distance_u8, - iou_distance_u16, - iou_distance_u32, - iou_distance_u64, - parallel_iou_distance_f32, - parallel_iou_distance_f64, - parallel_iou_distance_i16, - parallel_iou_distance_i32, - parallel_iou_distance_i64, - parallel_iou_distance_u8, - parallel_iou_distance_u16, - parallel_iou_distance_u32, - parallel_iou_distance_u64, -) +# from ._powerboxes import ( +# iou_distance_f32, +# iou_distance_f64, +# iou_distance_i16, +# iou_distance_i32, +# iou_distance_i64, +# iou_distance_u8, +# iou_distance_u16, +# iou_distance_u32, +# iou_distance_u64, +# parallel_iou_distance_f32, +# parallel_iou_distance_f64, +# parallel_iou_distance_i16, +# parallel_iou_distance_i32, +# parallel_iou_distance_i64, +# parallel_iou_distance_u8, +# parallel_iou_distance_u16, +# parallel_iou_distance_u32, +# parallel_iou_distance_u64, +# ) -_dtype_to_func_parallel_iou_distance = { - np.dtype("float64"): parallel_iou_distance_f64, - np.dtype("float32"): parallel_iou_distance_f32, - np.dtype("int64"): parallel_iou_distance_i64, - np.dtype("int32"): parallel_iou_distance_i32, - np.dtype("int16"): parallel_iou_distance_i16, - np.dtype("uint64"): parallel_iou_distance_u64, - np.dtype("uint32"): parallel_iou_distance_u32, - np.dtype("uint16"): parallel_iou_distance_u16, - np.dtype("uint8"): parallel_iou_distance_u8, -} -_dtype_to_func_iou_distance = { - np.dtype("float64"): iou_distance_f64, - np.dtype("float32"): iou_distance_f32, - np.dtype("int64"): iou_distance_i64, - np.dtype("int32"): iou_distance_i32, - np.dtype("int16"): iou_distance_i16, - np.dtype("uint64"): iou_distance_u64, - np.dtype("uint32"): iou_distance_u32, - np.dtype("uint16"): iou_distance_u16, - np.dtype("uint8"): iou_distance_u8, -} +# _dtype_to_func_parallel_iou_distance = { +# np.dtype("float64"): parallel_iou_distance_f64, +# np.dtype("float32"): parallel_iou_distance_f32, +# np.dtype("int64"): parallel_iou_distance_i64, +# np.dtype("int32"): parallel_iou_distance_i32, +# np.dtype("int16"): parallel_iou_distance_i16, +# np.dtype("uint64"): parallel_iou_distance_u64, +# np.dtype("uint32"): parallel_iou_distance_u32, +# np.dtype("uint16"): parallel_iou_distance_u16, +# np.dtype("uint8"): parallel_iou_distance_u8, +# } +# _dtype_to_func_iou_distance = { +# np.dtype("float64"): iou_distance_f64, +# np.dtype("float32"): iou_distance_f32, +# np.dtype("int64"): iou_distance_i64, +# np.dtype("int32"): iou_distance_i32, +# np.dtype("int16"): iou_distance_i16, +# np.dtype("uint64"): iou_distance_u64, +# np.dtype("uint32"): iou_distance_u32, +# np.dtype("uint16"): iou_distance_u16, +# np.dtype("uint8"): iou_distance_u8, +# } diff --git a/bindings/python/powerboxes/_nms.py b/bindings/python/powerboxes/_nms.py index 2d1efac..5fced5f 100644 --- a/bindings/python/powerboxes/_nms.py +++ b/bindings/python/powerboxes/_nms.py @@ -1,38 +1,38 @@ -import numpy as np +# import numpy as np -from ._powerboxes import ( - nms_f32, - nms_f64, - nms_i16, - nms_i32, - nms_i64, - nms_u8, - nms_u16, - nms_u32, - nms_u64, - rtree_nms_f32, - rtree_nms_f64, - rtree_nms_i16, - rtree_nms_i32, - rtree_nms_i64, -) +# from ._powerboxes import ( +# nms_f32, +# nms_f64, +# nms_i16, +# nms_i32, +# nms_i64, +# nms_u8, +# nms_u16, +# nms_u32, +# nms_u64, +# rtree_nms_f32, +# rtree_nms_f64, +# rtree_nms_i16, +# rtree_nms_i32, +# rtree_nms_i64, +# ) -_dtype_to_func_nms = { - np.dtype("float64"): nms_f64, - np.dtype("float32"): nms_f32, - np.dtype("int64"): nms_i64, - np.dtype("int32"): nms_i32, - np.dtype("int16"): nms_i16, - np.dtype("uint64"): nms_u64, - np.dtype("uint32"): nms_u32, - np.dtype("uint16"): nms_u16, - np.dtype("uint8"): nms_u8, -} +# _dtype_to_func_nms = { +# np.dtype("float64"): nms_f64, +# np.dtype("float32"): nms_f32, +# np.dtype("int64"): nms_i64, +# np.dtype("int32"): nms_i32, +# np.dtype("int16"): nms_i16, +# np.dtype("uint64"): nms_u64, +# np.dtype("uint32"): nms_u32, +# np.dtype("uint16"): nms_u16, +# np.dtype("uint8"): nms_u8, +# } -_dtype_to_func_rtree_nms = { - np.dtype("float64"): rtree_nms_f64, - np.dtype("float32"): rtree_nms_f32, - np.dtype("int64"): rtree_nms_i64, - np.dtype("int32"): rtree_nms_i32, - np.dtype("int16"): rtree_nms_i16, -} +# _dtype_to_func_rtree_nms = { +# np.dtype("float64"): rtree_nms_f64, +# np.dtype("float32"): rtree_nms_f32, +# np.dtype("int64"): rtree_nms_i64, +# np.dtype("int32"): rtree_nms_i32, +# np.dtype("int16"): rtree_nms_i16, +# } diff --git a/bindings/src/lib.rs b/bindings/src/lib.rs index c54b234..d5a5918 100644 --- a/bindings/src/lib.rs +++ b/bindings/src/lib.rs @@ -1,79 +1,18 @@ mod utils; -use std::fmt::Debug; +// use std::fmt::Debug; -use ndarray::Array1; -use num_traits::{Bounded, Float, Num, Signed, ToPrimitive}; -use numpy::{PyArray1, PyArray2, PyArray3}; -use powerboxesrs::{boxes, diou, giou, iou, nms, tiou}; +use std::ops::SubAssign; + +use num_traits::Num; +// use num_traits::{Bounded, Float, Num, Signed, ToPrimitive}; +use numpy::{nalgebra::{ClosedMul, Scalar}, PyArray2}; +use powerboxesrs::boxes; use pyo3::prelude::*; -use utils::{preprocess_array1, preprocess_array3, preprocess_boxes, preprocess_rotated_boxes}; +use utils::preprocess_boxes; #[pymodule] -fn _powerboxes(_py: Python, m: &PyModule) -> PyResult<()> { - // TIoU - m.add_function(wrap_pyfunction!(tiou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_f32, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_i64, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_i32, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_i16, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_u64, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_u32, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_u16, m)?)?; - m.add_function(wrap_pyfunction!(tiou_distance_u8, m)?)?; - // IoU - m.add_function(wrap_pyfunction!(iou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_f32, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_i64, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_i32, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_i16, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_u64, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_u32, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_u16, m)?)?; - m.add_function(wrap_pyfunction!(iou_distance_u8, m)?)?; - // Parallel IoU - m.add_function(wrap_pyfunction!(parallel_iou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_f32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_i64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_i32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_i16, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_u64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_u32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_u16, m)?)?; - m.add_function(wrap_pyfunction!(parallel_iou_distance_u8, m)?)?; - // DIoU - m.add_function(wrap_pyfunction!(diou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(diou_distance_f32, m)?)?; - // GIoU - m.add_function(wrap_pyfunction!(giou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_f32, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_i64, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_i32, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_i16, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_u64, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_u32, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_u16, m)?)?; - m.add_function(wrap_pyfunction!(giou_distance_u8, m)?)?; - // Parallel GIoU - m.add_function(wrap_pyfunction!(parallel_giou_distance_f64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_f32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_i64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_i32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_i16, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_u64, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_u32, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_u16, m)?)?; - m.add_function(wrap_pyfunction!(parallel_giou_distance_u8, m)?)?; - // Remove small boxes - m.add_function(wrap_pyfunction!(remove_small_boxes_f64, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_f32, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_i64, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_i32, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_i16, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_u64, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_u32, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_u16, m)?)?; - m.add_function(wrap_pyfunction!(remove_small_boxes_u8, m)?)?; +fn _powerboxes(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { // Boxes areas m.add_function(wrap_pyfunction!(box_areas_f64, m)?)?; m.add_function(wrap_pyfunction!(box_areas_f32, m)?)?; @@ -84,1084 +23,1145 @@ fn _powerboxes(_py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(box_areas_u32, m)?)?; m.add_function(wrap_pyfunction!(box_areas_u16, m)?)?; m.add_function(wrap_pyfunction!(box_areas_u8, m)?)?; - // Box convert - m.add_function(wrap_pyfunction!(box_convert_f64, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_f32, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_i64, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_i32, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_i16, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_u64, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_u32, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_u16, m)?)?; - m.add_function(wrap_pyfunction!(box_convert_u8, m)?)?; - // nms - m.add_function(wrap_pyfunction!(nms_f64, m)?)?; - m.add_function(wrap_pyfunction!(nms_f32, m)?)?; - m.add_function(wrap_pyfunction!(nms_i64, m)?)?; - m.add_function(wrap_pyfunction!(nms_i32, m)?)?; - m.add_function(wrap_pyfunction!(nms_i16, m)?)?; - m.add_function(wrap_pyfunction!(nms_u64, m)?)?; - m.add_function(wrap_pyfunction!(nms_u32, m)?)?; - m.add_function(wrap_pyfunction!(nms_u16, m)?)?; - m.add_function(wrap_pyfunction!(nms_u8, m)?)?; - // rtree nms - m.add_function(wrap_pyfunction!(rtree_nms_f64, m)?)?; - m.add_function(wrap_pyfunction!(rtree_nms_f32, m)?)?; - m.add_function(wrap_pyfunction!(rtree_nms_i64, m)?)?; - m.add_function(wrap_pyfunction!(rtree_nms_i32, m)?)?; - m.add_function(wrap_pyfunction!(rtree_nms_i16, m)?)?; - // Masks to boxes - m.add_function(wrap_pyfunction!(masks_to_boxes, m)?)?; - // Rotated IoU - m.add_function(wrap_pyfunction!(rotated_iou_distance, m)?)?; - // Rotated GIoU - m.add_function(wrap_pyfunction!(rotated_giou_distance, m)?)?; - // Rotated TIoU - m.add_function(wrap_pyfunction!(rotated_tiou_distance, m)?)?; Ok(()) } -// Masks to boxes -#[pyfunction] -fn masks_to_boxes(_py: Python, masks: &PyArray3) -> PyResult>> { - let masks = preprocess_array3(masks); - let boxes = boxes::masks_to_boxes(masks); - let boxes_as_numpy = utils::array_to_numpy(_py, boxes).unwrap(); - return Ok(boxes_as_numpy.to_owned()); -} +// // TIoU +// m.add_function(wrap_pyfunction!(tiou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_f32, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_i64, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_i32, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_i16, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_u64, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_u32, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_u16, m)?)?; +// m.add_function(wrap_pyfunction!(tiou_distance_u8, m)?)?; +// // IoU +// m.add_function(wrap_pyfunction!(iou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_f32, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_i64, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_i32, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_i16, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_u64, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_u32, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_u16, m)?)?; +// m.add_function(wrap_pyfunction!(iou_distance_u8, m)?)?; +// // Parallel IoU +// m.add_function(wrap_pyfunction!(parallel_iou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_f32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_i64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_i32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_i16, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_u64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_u32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_u16, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_iou_distance_u8, m)?)?; +// // DIoU +// m.add_function(wrap_pyfunction!(diou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(diou_distance_f32, m)?)?; +// // GIoU +// m.add_function(wrap_pyfunction!(giou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_f32, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_i64, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_i32, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_i16, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_u64, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_u32, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_u16, m)?)?; +// m.add_function(wrap_pyfunction!(giou_distance_u8, m)?)?; +// // Parallel GIoU +// m.add_function(wrap_pyfunction!(parallel_giou_distance_f64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_f32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_i64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_i32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_i16, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_u64, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_u32, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_u16, m)?)?; +// m.add_function(wrap_pyfunction!(parallel_giou_distance_u8, m)?)?; + // Remove small boxes + // m.add_function(wrap_pyfunction!(remove_small_boxes_f64, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_f32, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_i64, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_i32, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_i16, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_u64, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_u32, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_u16, m)?)?; + // m.add_function(wrap_pyfunction!(remove_small_boxes_u8, m)?)?; +// // Box convert +// m.add_function(wrap_pyfunction!(box_convert_f64, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_f32, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_i64, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_i32, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_i16, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_u64, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_u32, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_u16, m)?)?; +// m.add_function(wrap_pyfunction!(box_convert_u8, m)?)?; +// // nms +// m.add_function(wrap_pyfunction!(nms_f64, m)?)?; +// m.add_function(wrap_pyfunction!(nms_f32, m)?)?; +// m.add_function(wrap_pyfunction!(nms_i64, m)?)?; +// m.add_function(wrap_pyfunction!(nms_i32, m)?)?; +// m.add_function(wrap_pyfunction!(nms_i16, m)?)?; +// m.add_function(wrap_pyfunction!(nms_u64, m)?)?; +// m.add_function(wrap_pyfunction!(nms_u32, m)?)?; +// m.add_function(wrap_pyfunction!(nms_u16, m)?)?; +// m.add_function(wrap_pyfunction!(nms_u8, m)?)?; +// // rtree nms +// m.add_function(wrap_pyfunction!(rtree_nms_f64, m)?)?; +// m.add_function(wrap_pyfunction!(rtree_nms_f32, m)?)?; +// m.add_function(wrap_pyfunction!(rtree_nms_i64, m)?)?; +// m.add_function(wrap_pyfunction!(rtree_nms_i32, m)?)?; +// m.add_function(wrap_pyfunction!(rtree_nms_i16, m)?)?; +// // Masks to boxes +// m.add_function(wrap_pyfunction!(masks_to_boxes, m)?)?; +// // Rotated IoU +// m.add_function(wrap_pyfunction!(rotated_iou_distance, m)?)?; +// // Rotated GIoU +// m.add_function(wrap_pyfunction!(rotated_giou_distance, m)?)?; +// // Rotated TIoU +// m.add_function(wrap_pyfunction!(rotated_tiou_distance, m)?)?; -// Rotated box IoU +// // Masks to boxes +// #[pyfunction] +// fn masks_to_boxes(_py: Python, masks: &PyArray3) -> PyResult>> { +// let masks = preprocess_array3(masks); +// let boxes = boxes::masks_to_boxes(&masks); +// let boxes_as_numpy = utils::array_to_numpy(_py, boxes).unwrap(); +// return Ok(boxes_as_numpy.to_owned()); +// } -#[pyfunction] -fn rotated_iou_distance( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); - let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); - let iou = iou::rotated_iou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} +// // Rotated box IoU -// Rotated box GIoU +// #[pyfunction] +// fn rotated_iou_distance( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); +// let iou = iou::rotated_iou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } -#[pyfunction] -fn rotated_giou_distance( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); - let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); - let iou = giou::rotated_giou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} +// // Rotated box GIoU -// Rotated box TIoU +// #[pyfunction] +// fn rotated_giou_distance( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); +// let iou = giou::rotated_giou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } -#[pyfunction] -fn rotated_tiou_distance( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); - let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); - let iou = tiou::rotated_tiou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} -// DIoU -fn diou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + Float + numpy::Element, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let iou = diou::diou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} +// // Rotated box TIoU -#[pyfunction] -fn diou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(diou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn diou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(diou_distance_generic(_py, boxes1, boxes2)?); -} +// #[pyfunction] +// fn rotated_tiou_distance( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// let boxes1 = preprocess_rotated_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_rotated_boxes(boxes2).unwrap(); +// let iou = tiou::rotated_tiou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } +// // DIoU +// fn diou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Float + numpy::Element, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let iou = diou::diou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } -// IoU -fn iou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let iou = iou::iou_distance(boxes1, boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} +// #[pyfunction] +// fn diou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(diou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn diou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(diou_distance_generic(_py, boxes1, boxes2)?); +// } -#[pyfunction] -fn iou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_i64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_i32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_i16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_u64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_u32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_u16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn iou_distance_u8( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(iou_distance_generic(_py, boxes1, boxes2)?); -} -// Parallel IoU -fn parallel_iou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy + Sync + Send, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let iou = iou::parallel_iou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} -#[pyfunction] -fn parallel_iou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_i64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_i32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_i16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_u64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_u32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_u16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_iou_distance_u8( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); -} -// TIoU -fn tiou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let tiou = tiou::tiou_distance(&boxes1, &boxes2); - let tiou_as_numpy = utils::array_to_numpy(_py, tiou).unwrap(); - return Ok(tiou_as_numpy.to_owned()); -} +// // IoU +// fn iou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let iou = iou::iou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } -#[pyfunction] -fn tiou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_i64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_i32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_i16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_u64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_u32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_u16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn tiou_distance_u8( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); -} -// GIoU -fn giou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let iou = giou::giou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} -#[pyfunction] -fn giou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_i64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_i32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_i16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_u64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_u32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_u16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn giou_distance_u8( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(giou_distance_generic(_py, boxes1, boxes2)?); -} -// Parallel GIoU -fn parallel_giou_distance_generic( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, -{ - let boxes1 = preprocess_boxes(boxes1).unwrap(); - let boxes2 = preprocess_boxes(boxes2).unwrap(); - let iou = giou::giou_distance(&boxes1, &boxes2); - let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); - return Ok(iou_as_numpy.to_owned()); -} -#[pyfunction] -fn parallel_giou_distance_f64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_f32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_i64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_i32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_i16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_u64( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_u32( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_u16( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -#[pyfunction] -fn parallel_giou_distance_u8( - _py: Python, - boxes1: &PyArray2, - boxes2: &PyArray2, -) -> PyResult>> { - return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); -} -// Remove small boxes -fn remove_small_boxes_generic( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> -where - T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, -{ - let boxes = preprocess_boxes(boxes).unwrap(); - let filtered_boxes = boxes::remove_small_boxes(&boxes, min_size); - let filtered_boxes_as_numpy = utils::array_to_numpy(_py, filtered_boxes).unwrap(); - return Ok(filtered_boxes_as_numpy.to_owned()); -} -#[pyfunction] -fn remove_small_boxes_f64( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_f32( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_i64( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_i32( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_i16( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_u64( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_u32( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_u16( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} -#[pyfunction] -fn remove_small_boxes_u8( - _py: Python, - boxes: &PyArray2, - min_size: f64, -) -> PyResult>> { - return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); -} +// #[pyfunction] +// fn iou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_i64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_i32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_i16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_u64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_u32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_u16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn iou_distance_u8( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(iou_distance_generic(_py, boxes1, boxes2)?); +// } +// // Parallel IoU +// fn parallel_iou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy + Sync + Send, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let iou = iou::parallel_iou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn parallel_iou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_i64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_i32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_i16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_u64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_u32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_u16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_iou_distance_u8( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_iou_distance_generic(_py, boxes1, boxes2)?); +// } +// // TIoU +// fn tiou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let tiou = tiou::tiou_distance(&boxes1, &boxes2); +// let tiou_as_numpy = utils::array_to_numpy(_py, tiou).unwrap(); +// return Ok(tiou_as_numpy.to_owned()); +// } + +// #[pyfunction] +// fn tiou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_i64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_i32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_i16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_u64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_u32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_u16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn tiou_distance_u8( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(tiou_distance_generic(_py, boxes1, boxes2)?); +// } +// // GIoU +// fn giou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let iou = giou::giou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn giou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_i64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_i32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_i16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_u64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_u32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_u16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn giou_distance_u8( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(giou_distance_generic(_py, boxes1, boxes2)?); +// } +// // Parallel GIoU +// fn parallel_giou_distance_generic( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, +// { +// let boxes1 = preprocess_boxes(boxes1).unwrap(); +// let boxes2 = preprocess_boxes(boxes2).unwrap(); +// let iou = giou::giou_distance(&boxes1, &boxes2); +// let iou_as_numpy = utils::array_to_numpy(_py, iou).unwrap(); +// return Ok(iou_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn parallel_giou_distance_f64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_f32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_i64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_i32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_i16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_u64( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_u32( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_u16( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// #[pyfunction] +// fn parallel_giou_distance_u8( +// _py: Python, +// boxes1: &PyArray2, +// boxes2: &PyArray2, +// ) -> PyResult>> { +// return Ok(parallel_giou_distance_generic(_py, boxes1, boxes2)?); +// } +// // Remove small boxes +// fn remove_small_boxes_generic( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> +// where +// T: Num + ToPrimitive + PartialOrd + numpy::Element + Copy, +// { +// let boxes = preprocess_boxes(boxes).unwrap(); +// let filtered_boxes = boxes::remove_small_boxes(&boxes, min_size); +// let filtered_boxes_as_numpy = utils::array_to_numpy(_py, filtered_boxes).unwrap(); +// return Ok(filtered_boxes_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn remove_small_boxes_f64( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_f32( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_i64( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_i32( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_i16( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_u64( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_u32( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_u16( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } +// #[pyfunction] +// fn remove_small_boxes_u8( +// _py: Python, +// boxes: &PyArray2, +// min_size: f64, +// ) -> PyResult>> { +// return Ok(remove_small_boxes_generic(_py, boxes, min_size)?); +// } // Boxes areas -fn generic_box_areas(_py: Python, boxes: &PyArray2) -> PyResult>> +fn generic_box_areas<'py, T>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> where - T: Num + numpy::Element + PartialOrd + ToPrimitive + Sync + Send + Copy, + T: Num + numpy::Element + Scalar + SubAssign + ClosedMul, { - let boxes = preprocess_boxes(boxes).unwrap(); + let boxes = preprocess_boxes(&boxes); let areas = boxes::box_areas(&boxes); - let areas_as_numpy = utils::array_to_numpy(_py, areas).unwrap(); - return Ok(areas_as_numpy.to_owned()); + let areas_as_numpy = utils::matrixXx1_to_numpy(_py, areas); + return Ok(areas_as_numpy); } #[pyfunction] -fn box_areas_f64(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_f64<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_f32(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_f32<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_i64(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_i64<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_i32(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_i32<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_i16(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_i16<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_u64(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_u64<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_u32(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_u32<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_u16(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_u16<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } #[pyfunction] -fn box_areas_u8(_py: Python, boxes: &PyArray2) -> PyResult>> { +fn box_areas_u8<'py>(_py: Python<'py>, boxes: Bound<'py, PyArray2>) -> PyResult>> { return Ok(generic_box_areas(_py, boxes)?); } -fn box_convert_generic( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> -where - T: Num + numpy::Element + PartialOrd + ToPrimitive + Sync + Send + Copy, -{ - let boxes = preprocess_boxes(boxes).unwrap(); - let in_fmt = match in_fmt { - "xyxy" => boxes::BoxFormat::XYXY, - "xywh" => boxes::BoxFormat::XYWH, - "cxcywh" => boxes::BoxFormat::CXCYWH, - _ => { - return Err(pyo3::exceptions::PyValueError::new_err( - "Invalid input format", - )) - } - }; - let out_fmt = match out_fmt { - "xyxy" => boxes::BoxFormat::XYXY, - "xywh" => boxes::BoxFormat::XYWH, - "cxcywh" => boxes::BoxFormat::CXCYWH, - _ => { - return Err(pyo3::exceptions::PyValueError::new_err( - "Invalid output format", - )) - } - }; - let converted_boxes = boxes::box_convert(&boxes, in_fmt, out_fmt); - let converted_boxes_as_numpy = utils::array_to_numpy(_py, converted_boxes).unwrap(); - return Ok(converted_boxes_as_numpy.to_owned()); -} +// fn box_convert_generic( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> +// where +// T: Num + numpy::Element + PartialOrd + ToPrimitive + Sync + Send + Copy, +// { +// let boxes = preprocess_boxes(boxes).unwrap(); +// let in_fmt = match in_fmt { +// "xyxy" => boxes::BoxFormat::XYXY, +// "xywh" => boxes::BoxFormat::XYWH, +// "cxcywh" => boxes::BoxFormat::CXCYWH, +// _ => { +// return Err(pyo3::exceptions::PyValueError::new_err( +// "Invalid input format", +// )) +// } +// }; +// let out_fmt = match out_fmt { +// "xyxy" => boxes::BoxFormat::XYXY, +// "xywh" => boxes::BoxFormat::XYWH, +// "cxcywh" => boxes::BoxFormat::CXCYWH, +// _ => { +// return Err(pyo3::exceptions::PyValueError::new_err( +// "Invalid output format", +// )) +// } +// }; +// let converted_boxes = boxes::box_convert(&boxes, &in_fmt, &out_fmt); +// let converted_boxes_as_numpy = utils::array_to_numpy(_py, converted_boxes).unwrap(); +// return Ok(converted_boxes_as_numpy.to_owned()); +// } -#[pyfunction] -fn box_convert_f64( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_f32( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_i64( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_i32( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_i16( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_u64( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_u32( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_u16( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} -#[pyfunction] -fn box_convert_u8( - _py: Python, - boxes: &PyArray2, - in_fmt: &str, - out_fmt: &str, -) -> PyResult>> { - return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); -} +// #[pyfunction] +// fn box_convert_f64( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_f32( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_i64( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_i32( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_i16( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_u64( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_u32( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_u16( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } +// #[pyfunction] +// fn box_convert_u8( +// _py: Python, +// boxes: &PyArray2, +// in_fmt: &str, +// out_fmt: &str, +// ) -> PyResult>> { +// return Ok(box_convert_generic(_py, boxes, in_fmt, out_fmt).unwrap()); +// } -// nms -fn nms_generic( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> -where - T: numpy::Element + Num + PartialEq + PartialOrd + ToPrimitive + Copy, -{ - let boxes = preprocess_boxes(boxes).unwrap(); - let scores = preprocess_array1(scores); - let keep = nms::nms(&boxes, &scores, iou_threshold, score_threshold); - let keep_as_ndarray = Array1::from(keep); - let keep_as_numpy = utils::array_to_numpy(_py, keep_as_ndarray).unwrap(); - return Ok(keep_as_numpy.to_owned()); -} -#[pyfunction] -fn nms_f64( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_f32( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_i64( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_i32( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_i16( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_u64( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_u32( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_u16( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn nms_u8( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} +// // nms +// fn nms_generic( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> +// where +// T: Num + numpy::Element + PartialOrd + ToPrimitive + Copy, +// { +// let boxes = preprocess_boxes(boxes).unwrap(); +// let scores = preprocess_array1(scores); +// let keep = nms::nms(&boxes, &scores, iou_threshold, score_threshold); +// let keep_as_numpy = utils::array_to_numpy(_py, keep).unwrap(); +// return Ok(keep_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn nms_f64( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_f32( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_i64( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_i32( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_i16( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_u64( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_u32( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_u16( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn nms_u8( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } -// rtree nms -fn rtree_nms_generic( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> -where - T: numpy::Element - + Num - + Signed - + Bounded - + Debug - + PartialEq - + PartialOrd - + ToPrimitive - + Copy - + Sync - + Send, -{ - let boxes = preprocess_boxes(boxes).unwrap(); - let scores = preprocess_array1(scores); - let keep = nms::rtree_nms(&boxes, &scores, iou_threshold, score_threshold); - let keep_as_ndarray = Array1::from(keep); - let keep_as_numpy = utils::array_to_numpy(_py, keep_as_ndarray).unwrap(); - return Ok(keep_as_numpy.to_owned()); -} -#[pyfunction] -fn rtree_nms_f64( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(rtree_nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn rtree_nms_f32( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(rtree_nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn rtree_nms_i64( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(rtree_nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn rtree_nms_i32( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(rtree_nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} -#[pyfunction] -fn rtree_nms_i16( - _py: Python, - boxes: &PyArray2, - scores: &PyArray1, - iou_threshold: f64, - score_threshold: f64, -) -> PyResult>> { - return Ok(rtree_nms_generic( - _py, - boxes, - scores, - iou_threshold, - score_threshold, - )?); -} +// // rtree nms +// fn rtree_nms_generic( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> +// where +// T: Num +// + numpy::Element +// + PartialOrd +// + ToPrimitive +// + Copy +// + Signed +// + Bounded +// + Debug +// + Sync +// + Send, +// { +// let boxes = preprocess_boxes(boxes).unwrap(); +// let scores = preprocess_array1(scores); +// let keep = nms::rtree_nms(&boxes, &scores, iou_threshold, score_threshold); +// let keep_as_numpy = utils::array_to_numpy(_py, keep).unwrap(); +// return Ok(keep_as_numpy.to_owned()); +// } +// #[pyfunction] +// fn rtree_nms_f64( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(rtree_nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn rtree_nms_f32( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(rtree_nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn rtree_nms_i64( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(rtree_nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn rtree_nms_i32( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(rtree_nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } +// #[pyfunction] +// fn rtree_nms_i16( +// _py: Python, +// boxes: &PyArray2, +// scores: &PyArray1, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> PyResult>> { +// return Ok(rtree_nms_generic( +// _py, +// boxes, +// scores, +// iou_threshold, +// score_threshold, +// )?); +// } diff --git a/bindings/src/utils.rs b/bindings/src/utils.rs index ae3c5a3..e2bb75d 100644 --- a/bindings/src/utils.rs +++ b/bindings/src/utils.rs @@ -1,147 +1,130 @@ -use ndarray::{ArrayBase, Dim, OwnedRepr, ViewRepr}; use num_traits::Num; -use numpy::{IntoPyArray, PyArray, PyArray1, PyArray2, PyArray3}; +// use ndarray::{Array1, Array2, Array3, ArrayBase, OwnedRepr}; +// use num_traits::Num; +use numpy::{nalgebra::{ArrayStorage, Dim, Dyn, Matrix, MatrixView, MatrixXx1, MatrixXx4, Scalar, U1, U4}, Element, PyArray1, PyArray2, PyArrayMethods, PyReadonlyArray2, ToPyArray}; use pyo3::prelude::*; -/// Converts a 2-dimensional Rust ndarray to a NumPy array. -/// -/// # Arguments -/// -/// * `py` - The Python interpreter context. -/// * `array` - The 2-dimensional Rust ndarray to convert. -/// -/// # Returns -/// -/// A reference to the converted NumPy array. -/// -/// # Example -/// -/// ```rust -/// let py = Python::acquire_gil().python(); -/// let array_2d: Array2 = Array2::ones((3, 3)); -/// let numpy_array_2d = array2_to_numpy(py, array_2d).unwrap(); -/// ``` -pub fn array_to_numpy( - py: Python, - array: ArrayBase, D>, -) -> PyResult<&PyArray> -where - T: numpy::Element, - D: ndarray::Dimension, -{ - let numpy_array = array.into_pyarray(py); - - return Ok(numpy_array); -} - -pub fn preprocess_boxes( - array: &PyArray2, -) -> Result, Dim<[usize; 2]>>, PyErr> -where - N: numpy::Element, -{ - let array = unsafe { array.as_array() }; - let array_shape = array.shape(); - - if array_shape[1] != 4 { - return Err(pyo3::exceptions::PyValueError::new_err( - "Arrays must have at least shape (N, 4)", - )); - } else { - let num_boxes = array_shape[0]; +// pub fn array_to_numpy( +// py: Python, +// array: ArrayBase, D>, +// ) -> PyResult<&PyArray> { +// let numpy_array: &PyArray = array.into_pyarray(py); +// return Ok(numpy_array); +// } - if num_boxes == 0 { - return Err(pyo3::exceptions::PyValueError::new_err( - "Arrays must have shape (N, 4) with N > 0", - )); - } - } - - return Ok(array); -} +// Converts a numpy array to a nalgabra matrix 4xN -pub fn preprocess_rotated_boxes<'a, N>( - array: &PyArray2, -) -> Result, Dim<[usize; 2]>>, PyErr> +pub fn preprocess_boxes<'py, N>(array: &Bound<'py, PyArray2>) -> MatrixXx4 where - N: Num + numpy::Element + Send + 'a, + N: Num + Scalar + Element, { - let array = unsafe { array.as_array() }; - let array_shape = array.shape(); - - if array_shape[1] != 5 { - return Err(pyo3::exceptions::PyValueError::new_err( - "Arrays must have at least shape (N, 5)", - )); - } else { - let num_boxes = array_shape[0]; - - if num_boxes == 0 { - return Err(pyo3::exceptions::PyValueError::new_err( - "Arrays must have shape (N, 5) with N > 0", - )); - } - } - - return Ok(array); + let boxes = unsafe { array.as_array() }; + let mat = MatrixXx4::from_iterator(boxes.nrows(), boxes.iter().cloned()); + return mat } -pub fn preprocess_array3<'a, N>(array: &PyArray3) -> ArrayBase, Dim<[usize; 3]>> -where - N: numpy::Element + 'a, +#[allow(non_snake_case)] +pub fn matrixXx4_to_numpy<'py, N>(py: Python<'py>, mat: MatrixXx4) -> Bound<'py, PyArray2> +where N: Num + Scalar + Element, { - let array = unsafe { array.as_array() }; + let array: Bound<'py, PyArray2> = mat.to_pyarray_bound(py); return array; } - -pub fn preprocess_array1<'a, N>(array: &PyArray1) -> ArrayBase, Dim<[usize; 1]>> -where - N: numpy::Element + 'a, +#[allow(non_snake_case)] +pub fn matrixXx1_to_numpy<'py, N>(py: Python<'py>, mat: MatrixXx1) -> Bound<'py, PyArray2> +where N: Num + Scalar + Element, { - let array: ArrayBase, ndarray::prelude::Dim<[usize; 1]>> = - unsafe { array.as_array() }; + let array: Bound<'py, PyArray2> = mat.to_pyarray_bound(py); return array; } -#[cfg(test)] -mod tests { - use super::*; - use ndarray::Array1; - - #[test] - fn test_array_to_numpy() { - let array = Array1::from(vec![1., 2., 3., 4.]); - Python::with_gil(|py| { - let result = array_to_numpy(py, array).unwrap(); - assert_eq!(result.readonly().shape(), &[4]); - }); - } - - #[test] - fn test_preprocess_boxes() { - Python::with_gil(|python| { - let array = PyArray2::::zeros(python, [2, 4], false); - let result = preprocess_boxes::(array); - assert!(result.is_ok()); - let unwrapped_result = result.unwrap(); - assert_eq!(unwrapped_result.shape(), &[2, 4]); - }); - } - #[test] - fn test_preprocess_boxes_bad_shape() { - Python::with_gil(|python| { - let array = PyArray2::::zeros(python, [2, 16], false); - let result = preprocess_boxes::(array); - assert!(result.is_err()); - }); - } - - #[test] - fn test_preprocess_array1() { - Python::with_gil(|python| { - let array = PyArray1::::zeros(python, [2], false); - let result = preprocess_array1::(array); - assert_eq!(result.shape(), &[2]); - }); - } -} +// pub fn preprocess_rotated_boxes<'a, N>( +// array: &PyArray2, +// ) -> Result, Dim<[usize; 2]>>, PyErr> +// where +// N: Num + numpy::Element + Send, +// { +// let array = unsafe { array.as_array() }; +// let array_shape = array.shape(); + +// if array_shape[1] != 5 { +// return Err(pyo3::exceptions::PyValueError::new_err( +// "Arrays must have at least shape (N, 5)", +// )); +// } else { +// let num_boxes = array_shape[0]; + +// if num_boxes == 0 { +// return Err(pyo3::exceptions::PyValueError::new_err( +// "Arrays must have shape (N, 5) with N > 0", +// )); +// } +// } + +// let array = array +// .to_owned() +// .into_shape((array_shape[0], array_shape[1])) +// .unwrap(); +// return Ok(array); +// } + +// pub fn preprocess_array3(array: &PyArray3) -> Array3 +// where +// N: numpy::Element, +// { +// let array = unsafe { array.as_array().to_owned() }; +// return array; +// } + +// pub fn preprocess_array1(array: &PyArray1) -> Array1 +// where +// N: numpy::Element, +// { +// let array = unsafe { array.as_array().to_owned() }; +// return array; +// } + +// #[cfg(test)] +// mod tests { +// use super::*; +// use ndarray::ArrayBase; + +// #[test] +// fn test_array_to_numpy() { +// let data = vec![1., 2., 3., 4.]; +// let array = ArrayBase::from_shape_vec((1, 4), data).unwrap(); +// Python::with_gil(|py| { +// let result = array_to_numpy(py, array).unwrap(); +// assert_eq!(result.readonly().shape(), &[1, 4]); +// assert_eq!(result.readonly().shape(), &[1, 4]); +// }); +// } + +// #[test] +// fn test_preprocess_boxes() { +// Python::with_gil(|python| { +// let array = PyArray2::::zeros(python, [2, 4], false); +// let result = preprocess_boxes::(array); +// assert!(result.is_ok()); +// let unwrapped_result = result.unwrap(); +// assert_eq!(unwrapped_result.shape(), &[2, 4]); +// }); +// } +// #[test] +// fn test_preprocess_boxes_bad_shape() { +// Python::with_gil(|python| { +// let array = PyArray2::::zeros(python, [2, 16], false); +// let result = preprocess_boxes::(array); +// assert!(result.is_err()); +// }); +// } + +// #[test] +// fn test_preprocess_array1() { +// Python::with_gil(|python| { +// let array = PyArray1::::zeros(python, [2], false); +// let result = preprocess_array1::(array); +// assert_eq!(result.shape(), &[2]); +// }); +// } +// } diff --git a/bindings/tests/test_boxes.py b/bindings/tests/test_boxes.py index fe5b27f..6f57044 100644 --- a/bindings/tests/test_boxes.py +++ b/bindings/tests/test_boxes.py @@ -1,31 +1,31 @@ -import os +# import os -import numpy as np -from PIL import Image -from powerboxes import masks_to_boxes +# import numpy as np +# from PIL import Image +# from powerboxes import masks_to_boxes -def test_masks_box(): - expected = np.array( - [ - [127, 2, 165, 40], - [2, 50, 44, 92], - [56, 63, 98, 100], - [139, 68, 175, 104], - [160, 112, 198, 145], - [49, 138, 99, 182], - [108, 148, 152, 213], - ], - ) - assets_directory = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "assets" - ) - mask_path = os.path.join(assets_directory, "masks.tiff") - image = Image.open(mask_path) - masks = np.zeros((image.n_frames, image.height, image.width)) - for index in range(image.n_frames): - image.seek(index) - masks[index] = np.array(image) - out = masks_to_boxes(masks.astype(np.bool_)) - assert out.dtype == np.dtype("uint64") - np.testing.assert_allclose(out, expected, atol=1e-4) +# def test_masks_box(): +# expected = np.array( +# [ +# [127, 2, 165, 40], +# [2, 50, 44, 92], +# [56, 63, 98, 100], +# [139, 68, 175, 104], +# [160, 112, 198, 145], +# [49, 138, 99, 182], +# [108, 148, 152, 213], +# ], +# ) +# assets_directory = os.path.join( +# os.path.dirname(os.path.abspath(__file__)), "assets" +# ) +# mask_path = os.path.join(assets_directory, "masks.tiff") +# image = Image.open(mask_path) +# masks = np.zeros((image.n_frames, image.height, image.width)) +# for index in range(image.n_frames): +# image.seek(index) +# masks[index] = np.array(image) +# out = masks_to_boxes(masks.astype(np.bool_)) +# assert out.dtype == np.dtype("uint64") +# np.testing.assert_allclose(out, expected, atol=1e-4) diff --git a/bindings/tests/test_dtypes.py b/bindings/tests/test_dtypes.py index ac68c5c..9a28403 100644 --- a/bindings/tests/test_dtypes.py +++ b/bindings/tests/test_dtypes.py @@ -1,415 +1,415 @@ -import numpy as np -import pytest -from powerboxes import ( - _BOXES_NOT_NP_ARRAY, - _BOXES_NOT_SAME_TYPE, - box_convert, - boxes_areas, - diou_distance, - giou_distance, - iou_distance, - masks_to_boxes, - nms, - parallel_giou_distance, - parallel_iou_distance, - remove_small_boxes, - rotated_giou_distance, - rotated_iou_distance, - rotated_tiou_distance, - rtree_nms, - supported_dtypes, - tiou_distance, -) +# import numpy as np +# import pytest +# from powerboxes import ( +# _BOXES_NOT_NP_ARRAY, +# _BOXES_NOT_SAME_TYPE, +# box_convert, +# boxes_areas, +# diou_distance, +# giou_distance, +# iou_distance, +# masks_to_boxes, +# nms, +# parallel_giou_distance, +# parallel_iou_distance, +# remove_small_boxes, +# rotated_giou_distance, +# rotated_iou_distance, +# rotated_tiou_distance, +# rtree_nms, +# supported_dtypes, +# tiou_distance, +# ) -np.random.seed(42) - -unsuported_dtype_example = np.float16 - - -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_giou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - giou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) +# np.random.seed(42) + +# unsuported_dtype_example = np.float16 + + +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_giou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# giou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) -def test_giou_distance_different_dtypes(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): - giou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) - - -def test_giou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - giou_distance("bonjour", "how are you?") +# def test_giou_distance_different_dtypes(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): +# giou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) + + +# def test_giou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# giou_distance("bonjour", "how are you?") -def test_giou_distance_bad_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - giou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) - +# def test_giou_distance_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# giou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) + -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_parallel_giou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - parallel_giou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_parallel_giou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# parallel_giou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) -def test_parallel_giou_distance_different_dtypes(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): - parallel_giou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) +# def test_parallel_giou_distance_different_dtypes(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): +# parallel_giou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) -def test_parallel_giou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - parallel_giou_distance("bonjour", "how are you?") +# def test_parallel_giou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# parallel_giou_distance("bonjour", "how are you?") -def test_parallel_giou_distance_bad_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - parallel_giou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) +# def test_parallel_giou_distance_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# parallel_giou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_parallel_iou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - parallel_iou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_parallel_iou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# parallel_iou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) -def test_parallel_iou_distance_different_dtypes(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): - parallel_iou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) +# def test_parallel_iou_distance_different_dtypes(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): +# parallel_iou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) -def test_parallel_iou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - parallel_iou_distance("bonjour", "how are you?") +# def test_parallel_iou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# parallel_iou_distance("bonjour", "how are you?") -def test_parallel_iou_distance_bad_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - parallel_iou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) +# def test_parallel_iou_distance_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# parallel_iou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_iou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - iou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_iou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# iou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) -def test_iou_distance_different_dtypes(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): - iou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) +# def test_iou_distance_different_dtypes(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): +# iou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) -def test_iou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - iou_distance("bonjour", "how are you?") +# def test_iou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# iou_distance("bonjour", "how are you?") -def test_iou_distance_bad_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - iou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) +# def test_iou_distance_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# iou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_tiou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - tiou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_tiou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# tiou_distance(boxes1.astype(dtype), boxes2.astype(dtype)) -def test_tiou_distance_different_dtypes(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): - tiou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) +# def test_tiou_distance_different_dtypes(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(ValueError, match=_BOXES_NOT_SAME_TYPE): +# tiou_distance(boxes1.astype(np.float64), boxes2.astype(np.uint8)) -def test_tiou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - tiou_distance("bonjour", "how are you?") +# def test_tiou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# tiou_distance("bonjour", "how are you?") -def test_tiou_distance_bad_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - tiou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) +# def test_tiou_distance_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# tiou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_remove_small_boxes(dtype): - boxes = np.random.random((100, 4)) - remove_small_boxes(boxes.astype(dtype), 0.4) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_remove_small_boxes(dtype): +# boxes = np.random.random((100, 4)) +# remove_small_boxes(boxes.astype(dtype), 0.4) -def test_remove_small_boxes_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - remove_small_boxes("bonjour", "how are you?") +# def test_remove_small_boxes_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# remove_small_boxes("bonjour", "how are you?") -def test_remove_small_boxes_bad_dtype(): - boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) - with pytest.raises(TypeError): - remove_small_boxes( - boxes1.astype(unsuported_dtype_example), - ) +# def test_remove_small_boxes_bad_dtype(): +# boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) +# with pytest.raises(TypeError): +# remove_small_boxes( +# boxes1.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_boxes_areas(dtype): - boxes = np.random.random((100, 4)) - boxes_areas(boxes.astype(dtype)) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_boxes_areas(dtype): +# boxes = np.random.random((100, 4)) +# boxes_areas(boxes.astype(dtype)) -def test_boxes_areas_bad_inpus(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - boxes_areas("hey") +# def test_boxes_areas_bad_inpus(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# boxes_areas("hey") -def test_boxes_areas_bad_dtype(): - boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) - with pytest.raises(TypeError): - boxes_areas( - boxes1.astype(unsuported_dtype_example), - ) +# def test_boxes_areas_bad_dtype(): +# boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) +# with pytest.raises(TypeError): +# boxes_areas( +# boxes1.astype(unsuported_dtype_example), +# ) -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert(dtype): - boxes = np.random.random((100, 4)) - box_convert(boxes.astype(dtype), "xyxy", "xywh") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert(dtype): +# boxes = np.random.random((100, 4)) +# box_convert(boxes.astype(dtype), "xyxy", "xywh") -def test_box_convert_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - box_convert("foo", "xyxy", "xywh") +# def test_box_convert_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# box_convert("foo", "xyxy", "xywh") -def test_box_convert_bad_dtype(): - boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) - with pytest.raises(TypeError): - box_convert( - boxes1.astype(unsuported_dtype_example), - ) +# def test_box_convert_bad_dtype(): +# boxes1 = np.random.random((100, 4)).astype(unsuported_dtype_example) +# with pytest.raises(TypeError): +# box_convert( +# boxes1.astype(unsuported_dtype_example), +# ) -def test_masks_to_boxes_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - masks_to_boxes("foo") +# def test_masks_to_boxes_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# masks_to_boxes("foo") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_nms(dtype): - boxes1 = np.random.random((100, 4)) - scores = np.random.random((100,)) - nms(boxes1.astype(dtype), scores, 0.5, 0.5) +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_nms(dtype): +# boxes1 = np.random.random((100, 4)) +# scores = np.random.random((100,)) +# nms(boxes1.astype(dtype), scores, 0.5, 0.5) -def test_nms_bad_inputs(): - with pytest.raises(TypeError, match="Boxes and scores must be numpy arrays"): - nms("foo", "bar", 0.5, 0.5) +# def test_nms_bad_inputs(): +# with pytest.raises(TypeError, match="Boxes and scores must be numpy arrays"): +# nms("foo", "bar", 0.5, 0.5) -def test_nms_bad_dtype(): - boxes1 = np.random.random((100, 4)) - scores = np.random.random((100,)) - with pytest.raises(TypeError): - nms(boxes1.astype(unsuported_dtype_example), scores, 0.5, 0.5) +# def test_nms_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# scores = np.random.random((100,)) +# with pytest.raises(TypeError): +# nms(boxes1.astype(unsuported_dtype_example), scores, 0.5, 0.5) -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "int16"]) -def test_rtree_nms(dtype): - boxes1 = np.random.random((100, 4)) - scores = np.random.random((100,)) - rtree_nms(boxes1.astype(dtype), scores, 0.5, 0.5) +# @pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "int16"]) +# def test_rtree_nms(dtype): +# boxes1 = np.random.random((100, 4)) +# scores = np.random.random((100,)) +# rtree_nms(boxes1.astype(dtype), scores, 0.5, 0.5) -def test_rtree_nms_bad_inputs(): - with pytest.raises(TypeError, match="Boxes and scores must be numpy arrays"): - rtree_nms("foo", "bar", 0.5, 0.5) - - -def test_rtree_nms_bad_dtype(): - boxes1 = np.random.random((100, 4)) - scores = np.random.random((100,)) - with pytest.raises(TypeError): - rtree_nms(boxes1.astype(unsuported_dtype_example), scores, 0.5, 0.5) +# def test_rtree_nms_bad_inputs(): +# with pytest.raises(TypeError, match="Boxes and scores must be numpy arrays"): +# rtree_nms("foo", "bar", 0.5, 0.5) + + +# def test_rtree_nms_bad_dtype(): +# boxes1 = np.random.random((100, 4)) +# scores = np.random.random((100,)) +# with pytest.raises(TypeError): +# rtree_nms(boxes1.astype(unsuported_dtype_example), scores, 0.5, 0.5) - -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_iou_distance(dtype): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - rotated_iou_distance( - boxes1.astype(dtype), - boxes2.astype(dtype), - ) - - -def test_rotated_iou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - rotated_iou_distance("foo", "bar") - with pytest.raises(Exception): - try: - rotated_iou_distance(np.random.random((100, 4)), np.random.random((100, 4))) - except: # noqa: E722 - raise RuntimeError() - with pytest.raises(RuntimeError): - try: - rotated_iou_distance(np.random.random((0, 4)), np.random.random((100, 4))) - except: # noqa: E722 - raise RuntimeError() - - -def test_rotated_iou_distance_dtype(): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - with pytest.raises(TypeError): - rotated_iou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) - - -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_giou_distance(dtype): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - rotated_giou_distance( - boxes1.astype(dtype), - boxes2.astype(dtype), - ) - - -def test_rotated_giou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - rotated_giou_distance("foo", "bar") - with pytest.raises(Exception): - try: - rotated_giou_distance( - np.random.random((100, 4)), np.random.random((100, 4)) - ) - except: # noqa: E722 - raise RuntimeError() - with pytest.raises(RuntimeError): - try: - rotated_giou_distance(np.random.random((0, 4)), np.random.random((100, 4))) - except: # noqa: E722 - raise RuntimeError() - - -def test_rotated_giou_distance_dtype(): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - with pytest.raises(TypeError): - rotated_giou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) - - -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_tiou_distance(dtype): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - rotated_tiou_distance( - boxes1.astype(dtype), - boxes2.astype(dtype), - ) - - -def test_rotated_tiou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - rotated_tiou_distance("foo", "bar") - with pytest.raises(Exception): - try: - rotated_tiou_distance( - np.random.random((100, 4)), np.random.random((100, 4)) - ) - except: # noqa: E722 - raise RuntimeError() - with pytest.raises(RuntimeError): - try: - rotated_tiou_distance(np.random.random((0, 4)), np.random.random((100, 4))) - except: # noqa: E722 - raise RuntimeError() - - -def test_rotated_tiou_distance_dtype(): - boxes1 = np.random.random((100, 5)) - boxes2 = np.random.random((100, 5)) - with pytest.raises(TypeError): - rotated_tiou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) - - -@pytest.mark.parametrize("dtype", ["float64", "float32"]) -def test_diou_distance(dtype): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - diou_distance( - boxes1.astype(dtype), - boxes2.astype(dtype), - ) - - -def test_diou_distance_bad_inputs(): - with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): - diou_distance("foo", "bar") - with pytest.raises(Exception): - try: - diou_distance(np.random.random((100, 23)), np.random.random((100, 23))) - except: # noqa: E722 - raise RuntimeError() - with pytest.raises(RuntimeError): - try: - diou_distance(np.random.random((0, 23)), np.random.random((100, 23))) - except: # noqa: E722 - raise RuntimeError() - - -def test_diou_distance_dtype(): - boxes1 = np.random.random((100, 4)) - boxes2 = np.random.random((100, 4)) - with pytest.raises(TypeError): - diou_distance( - boxes1.astype(unsuported_dtype_example), - boxes2.astype(unsuported_dtype_example), - ) + +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_iou_distance(dtype): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# rotated_iou_distance( +# boxes1.astype(dtype), +# boxes2.astype(dtype), +# ) + + +# def test_rotated_iou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# rotated_iou_distance("foo", "bar") +# with pytest.raises(Exception): +# try: +# rotated_iou_distance(np.random.random((100, 4)), np.random.random((100, 4))) +# except: # noqa: E722 +# raise RuntimeError() +# with pytest.raises(RuntimeError): +# try: +# rotated_iou_distance(np.random.random((0, 4)), np.random.random((100, 4))) +# except: # noqa: E722 +# raise RuntimeError() + + +# def test_rotated_iou_distance_dtype(): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# with pytest.raises(TypeError): +# rotated_iou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) + + +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_giou_distance(dtype): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# rotated_giou_distance( +# boxes1.astype(dtype), +# boxes2.astype(dtype), +# ) + + +# def test_rotated_giou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# rotated_giou_distance("foo", "bar") +# with pytest.raises(Exception): +# try: +# rotated_giou_distance( +# np.random.random((100, 4)), np.random.random((100, 4)) +# ) +# except: # noqa: E722 +# raise RuntimeError() +# with pytest.raises(RuntimeError): +# try: +# rotated_giou_distance(np.random.random((0, 4)), np.random.random((100, 4))) +# except: # noqa: E722 +# raise RuntimeError() + + +# def test_rotated_giou_distance_dtype(): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# with pytest.raises(TypeError): +# rotated_giou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) + + +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_tiou_distance(dtype): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# rotated_tiou_distance( +# boxes1.astype(dtype), +# boxes2.astype(dtype), +# ) + + +# def test_rotated_tiou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# rotated_tiou_distance("foo", "bar") +# with pytest.raises(Exception): +# try: +# rotated_tiou_distance( +# np.random.random((100, 4)), np.random.random((100, 4)) +# ) +# except: # noqa: E722 +# raise RuntimeError() +# with pytest.raises(RuntimeError): +# try: +# rotated_tiou_distance(np.random.random((0, 4)), np.random.random((100, 4))) +# except: # noqa: E722 +# raise RuntimeError() + + +# def test_rotated_tiou_distance_dtype(): +# boxes1 = np.random.random((100, 5)) +# boxes2 = np.random.random((100, 5)) +# with pytest.raises(TypeError): +# rotated_tiou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) + + +# @pytest.mark.parametrize("dtype", ["float64", "float32"]) +# def test_diou_distance(dtype): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# diou_distance( +# boxes1.astype(dtype), +# boxes2.astype(dtype), +# ) + + +# def test_diou_distance_bad_inputs(): +# with pytest.raises(TypeError, match=_BOXES_NOT_NP_ARRAY): +# diou_distance("foo", "bar") +# with pytest.raises(Exception): +# try: +# diou_distance(np.random.random((100, 23)), np.random.random((100, 23))) +# except: # noqa: E722 +# raise RuntimeError() +# with pytest.raises(RuntimeError): +# try: +# diou_distance(np.random.random((0, 23)), np.random.random((100, 23))) +# except: # noqa: E722 +# raise RuntimeError() + + +# def test_diou_distance_dtype(): +# boxes1 = np.random.random((100, 4)) +# boxes2 = np.random.random((100, 4)) +# with pytest.raises(TypeError): +# diou_distance( +# boxes1.astype(unsuported_dtype_example), +# boxes2.astype(unsuported_dtype_example), +# ) diff --git a/bindings/tests/test_speed.py b/bindings/tests/test_speed.py index 68b7ebe..ab5d152 100644 --- a/bindings/tests/test_speed.py +++ b/bindings/tests/test_speed.py @@ -1,22 +1,22 @@ import numpy as np import pytest from powerboxes import ( - box_convert, + # box_convert, boxes_areas, - diou_distance, - giou_distance, - iou_distance, - masks_to_boxes, - nms, - parallel_giou_distance, - parallel_iou_distance, - remove_small_boxes, - rotated_giou_distance, - rotated_iou_distance, - rotated_tiou_distance, - rtree_nms, + # diou_distance, + # giou_distance, + # iou_distance, + # masks_to_boxes, + # nms, + # parallel_giou_distance, + # parallel_iou_distance, + # remove_small_boxes, + # rotated_giou_distance, + # rotated_iou_distance, + # rotated_tiou_distance, + # rtree_nms, supported_dtypes, - tiou_distance, + # tiou_distance, ) np.random.seed(42) @@ -33,83 +33,83 @@ def generate_boxes(request): return np.concatenate([topleft, topleft + wh], axis=1).astype(np.float64) -@pytest.mark.benchmark(group="rotated_tiou_distance") -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_tiou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 5)).astype(dtype) - boxes2 = np.random.random((100, 5)).astype(dtype) - benchmark(rotated_tiou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="rotated_tiou_distance") +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_tiou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 5)).astype(dtype) +# boxes2 = np.random.random((100, 5)).astype(dtype) +# benchmark(rotated_tiou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="rotated_iou_distance") -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_iou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 5)).astype(dtype) - boxes2 = np.random.random((100, 5)).astype(dtype) - benchmark(rotated_iou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="rotated_iou_distance") +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_iou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 5)).astype(dtype) +# boxes2 = np.random.random((100, 5)).astype(dtype) +# benchmark(rotated_iou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="rotated_giou_distance") -@pytest.mark.parametrize("dtype", ["float64"]) -def test_rotated_giou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 5)).astype(dtype) - boxes2 = np.random.random((100, 5)).astype(dtype) - benchmark(rotated_giou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="rotated_giou_distance") +# @pytest.mark.parametrize("dtype", ["float64"]) +# def test_rotated_giou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 5)).astype(dtype) +# boxes2 = np.random.random((100, 5)).astype(dtype) +# benchmark(rotated_giou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="tiou_distance") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_tiou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(tiou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="tiou_distance") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_tiou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(tiou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="giou_distance") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_giou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(giou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="giou_distance") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_giou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(giou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="parallel_giou_distance") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_parallel_giou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(parallel_giou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="parallel_giou_distance") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_parallel_giou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(parallel_giou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="diou_distance") -@pytest.mark.parametrize("dtype", [np.float32, np.float64]) -def test_diou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(diou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="diou_distance") +# @pytest.mark.parametrize("dtype", [np.float32, np.float64]) +# def test_diou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(diou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="iou_distance") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_iou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(iou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="iou_distance") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_iou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(iou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="parallel_iou_distance") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_parallel_iou_distance(benchmark, dtype): - boxes1 = np.random.random((100, 4)).astype(dtype) - boxes2 = np.random.random((100, 4)).astype(dtype) - benchmark(parallel_iou_distance, boxes1, boxes2) +# @pytest.mark.benchmark(group="parallel_iou_distance") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_parallel_iou_distance(benchmark, dtype): +# boxes1 = np.random.random((100, 4)).astype(dtype) +# boxes2 = np.random.random((100, 4)).astype(dtype) +# benchmark(parallel_iou_distance, boxes1, boxes2) -@pytest.mark.benchmark(group="remove_small_boxes") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_remove_small_boxes(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(remove_small_boxes, boxes, 0.4) +# @pytest.mark.benchmark(group="remove_small_boxes") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_remove_small_boxes(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(remove_small_boxes, boxes, 0.4) @pytest.mark.benchmark(group="remove_small_boxes") @@ -119,81 +119,81 @@ def test_boxes_areas(benchmark, dtype): benchmark(boxes_areas, boxes) -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_xyxy_xywh(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "xyxy", "xywh") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_xyxy_xywh(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "xyxy", "xywh") -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_xyxy_cxcywh(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "xyxy", "cxcywh") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_xyxy_cxcywh(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "xyxy", "cxcywh") -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_cxcywh_xywh(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "cxcywh", "xywh") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_cxcywh_xywh(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "cxcywh", "xywh") -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_cxcywh_xyxy(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "cxcywh", "xywh") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_cxcywh_xyxy(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "cxcywh", "xywh") -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_xywh_cxcywh(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "xywh", "cxcywh") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_xywh_cxcywh(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "xywh", "cxcywh") -@pytest.mark.benchmark(group="box_convert") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_box_convert_xywh_xyxy(benchmark, dtype): - boxes = np.random.random((100, 4)).astype(dtype) - benchmark(box_convert, boxes, "xywh", "xyxy") +# @pytest.mark.benchmark(group="box_convert") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_box_convert_xywh_xyxy(benchmark, dtype): +# boxes = np.random.random((100, 4)).astype(dtype) +# benchmark(box_convert, boxes, "xywh", "xyxy") -@pytest.mark.benchmark(group="masks_to_boxes") -def test_masks_to_boxes(benchmark): - masks = np.array([True] * (100 * 100 * 100)).reshape((100, 100, 100)) - benchmark(masks_to_boxes, masks) +# @pytest.mark.benchmark(group="masks_to_boxes") +# def test_masks_to_boxes(benchmark): +# masks = np.array([True] * (100 * 100 * 100)).reshape((100, 100, 100)) +# benchmark(masks_to_boxes, masks) -@pytest.mark.benchmark(group="nms") -@pytest.mark.parametrize("dtype", supported_dtypes) -def test_nms(benchmark, dtype, generate_boxes): - boxes = generate_boxes - boxes = boxes.astype(dtype) - benchmark(nms, boxes, SCORES, 0.5, 0.5) - - -@pytest.mark.benchmark(group="nms") -@pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "int16"]) -def test_rtree_nms(benchmark, dtype, generate_boxes): - boxes = generate_boxes - boxes = boxes.astype(dtype) - benchmark(rtree_nms, boxes, SCORES, 0.5, 0.5) - - -@pytest.mark.benchmark(group="nms_many_boxes") -@pytest.mark.parametrize("generate_boxes", [1000, 5000, 10000, 20000], indirect=True) -def test_nms_many_boxes(benchmark, generate_boxes): - boxes = generate_boxes - scores = np.random.random(len(boxes)) - benchmark(nms, boxes, scores, 0.5, 0.5) - - -@pytest.mark.benchmark(group="nms_many_boxes") -@pytest.mark.parametrize("generate_boxes", [1000, 5000, 10000, 20000], indirect=True) -def test_rtree_nms_many_boxes(benchmark, generate_boxes): - boxes = generate_boxes - scores = np.random.random(len(boxes)) - benchmark(rtree_nms, boxes, scores, 0.5, 0.5) +# @pytest.mark.benchmark(group="nms") +# @pytest.mark.parametrize("dtype", supported_dtypes) +# def test_nms(benchmark, dtype, generate_boxes): +# boxes = generate_boxes +# boxes = boxes.astype(dtype) +# benchmark(nms, boxes, SCORES, 0.5, 0.5) + + +# @pytest.mark.benchmark(group="nms") +# @pytest.mark.parametrize("dtype", ["float64", "float32", "int64", "int32", "int16"]) +# def test_rtree_nms(benchmark, dtype, generate_boxes): +# boxes = generate_boxes +# boxes = boxes.astype(dtype) +# benchmark(rtree_nms, boxes, SCORES, 0.5, 0.5) + + +# @pytest.mark.benchmark(group="nms_many_boxes") +# @pytest.mark.parametrize("generate_boxes", [1000, 5000, 10000, 20000], indirect=True) +# def test_nms_many_boxes(benchmark, generate_boxes): +# boxes = generate_boxes +# scores = np.random.random(len(boxes)) +# benchmark(nms, boxes, scores, 0.5, 0.5) + + +# @pytest.mark.benchmark(group="nms_many_boxes") +# @pytest.mark.parametrize("generate_boxes", [1000, 5000, 10000, 20000], indirect=True) +# def test_rtree_nms_many_boxes(benchmark, generate_boxes): +# boxes = generate_boxes +# scores = np.random.random(len(boxes)) +# benchmark(rtree_nms, boxes, scores, 0.5, 0.5) diff --git a/powerboxesrs/Cargo.lock b/powerboxesrs/Cargo.lock index 6184f24..fb883da 100644 --- a/powerboxesrs/Cargo.lock +++ b/powerboxesrs/Cargo.lock @@ -24,12 +24,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] -name = "atomic-polyfill" -version = "1.0.3" +name = "approx" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" dependencies = [ - "critical-section", + "num-traits", ] [[package]] @@ -50,6 +50,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "bytemuck" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" + [[package]] name = "byteorder" version = "1.5.0" @@ -189,12 +195,6 @@ dependencies = [ "itertools", ] -[[package]] -name = "critical-section" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -252,23 +252,20 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "hash32" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ "byteorder", ] [[package]] name = "heapless" -version = "0.7.17" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ - "atomic-polyfill", "hash32", - "rustc_version", - "spin", "stable_deref_trait", ] @@ -337,16 +334,6 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.20" @@ -379,17 +366,30 @@ dependencies = [ ] [[package]] -name = "ndarray" -version = "0.15.6" +name = "nalgebra" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" dependencies = [ + "approx", "matrixmultiply", + "nalgebra-macros", "num-complex", - "num-integer", + "num-rational", "num-traits", - "rawpointer", - "rayon", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -411,11 +411,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", @@ -433,6 +444,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "plotters" version = "0.3.5" @@ -467,26 +484,25 @@ version = "0.2.3" dependencies = [ "codspeed-criterion-compat", "criterion", - "ndarray", + "nalgebra", "num-traits", - "rayon", "rstar", ] [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -548,24 +564,15 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rstar" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73111312eb7a2287d229f06c00ff35b51ddee180f017ab6dec1f69d62ac098d6" +checksum = "133315eb94c7b1e8d0cb097e5a710d850263372fd028fff18969de708afc7008" dependencies = [ "heapless", "num-traits", "smallvec", ] -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.25" @@ -585,6 +592,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "safe_arch" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +dependencies = [ + "bytemuck", +] + [[package]] name = "same-file" version = "1.0.6" @@ -600,12 +616,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" - [[package]] name = "serde" version = "1.0.193" @@ -638,19 +648,23 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.11.2" +name = "simba" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] [[package]] -name = "spin" -version = "0.9.8" +name = "smallvec" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "stable_deref_trait" @@ -660,9 +674,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -679,6 +693,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -759,6 +779,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "wide" +version = "0.7.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/powerboxesrs/Cargo.toml b/powerboxesrs/Cargo.toml index 818eb2f..fc3c2b3 100644 --- a/powerboxesrs/Cargo.toml +++ b/powerboxesrs/Cargo.toml @@ -15,10 +15,9 @@ name = "powerboxesrs" crate-type = ["lib"] [dependencies] -ndarray = { version = "0.15.6", features = ["rayon"] } -num-traits = "0.2.17" -rayon = "1.8.0" -rstar = "0.11.0" +nalgebra = "0.32.6" +num-traits = "0.2.19" +rstar = "0.12.0" [dev-dependencies] codspeed-criterion-compat = "2.3.1" diff --git a/powerboxesrs/benches/bench_iou.rs b/powerboxesrs/benches/bench_iou.rs index 0e50b05..9699aa1 100644 --- a/powerboxesrs/benches/bench_iou.rs +++ b/powerboxesrs/benches/bench_iou.rs @@ -1,85 +1,85 @@ -use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Criterion}; -use ndarray::Array2; -use powerboxesrs::giou::{giou_distance, parallel_giou_distance}; -use powerboxesrs::iou::{iou_distance, parallel_iou_distance}; +// use codspeed_criterion_compat::{black_box, criterion_group, criterion_main, Criterion}; +// use ndarray::Array2; +// use powerboxesrs::giou::{giou_distance, parallel_giou_distance}; +// use powerboxesrs::iou::{iou_distance, parallel_iou_distance}; -pub fn iou_distance_benchmark(c: &mut Criterion) { - let mut boxes1 = Array2::::zeros((100, 4)); - for i in 0..100 { - for j in 0..4 { - if j < 2 { - boxes1[[i, j]] = 0.0; - } else { - boxes1[[i, j]] = 10.0; - } - } - } - let boxes2 = boxes1.clone(); +// pub fn iou_distance_benchmark(c: &mut Criterion) { +// let mut boxes1 = Array2::::zeros((100, 4)); +// for i in 0..100 { +// for j in 0..4 { +// if j < 2 { +// boxes1[[i, j]] = 0.0; +// } else { +// boxes1[[i, j]] = 10.0; +// } +// } +// } +// let boxes2 = boxes1.clone(); - c.bench_function("iou distance benchmark", |b| { - b.iter(|| iou_distance(black_box(&boxes1), black_box(&boxes2))) - }); -} +// c.bench_function("iou distance benchmark", |b| { +// b.iter(|| iou_distance(black_box(&boxes1), black_box(&boxes2))) +// }); +// } -pub fn parallel_iou_distance_benchmark(c: &mut Criterion) { - let mut boxes1 = Array2::::zeros((100, 4)); - for i in 0..100 { - for j in 0..4 { - if j < 2 { - boxes1[[i, j]] = 0.0; - } else { - boxes1[[i, j]] = 10.0; - } - } - } - let boxes2 = boxes1.clone(); +// pub fn parallel_iou_distance_benchmark(c: &mut Criterion) { +// let mut boxes1 = Array2::::zeros((100, 4)); +// for i in 0..100 { +// for j in 0..4 { +// if j < 2 { +// boxes1[[i, j]] = 0.0; +// } else { +// boxes1[[i, j]] = 10.0; +// } +// } +// } +// let boxes2 = boxes1.clone(); - c.bench_function("parallel iou distance benchmark", |b| { - b.iter(|| parallel_iou_distance(black_box(&boxes1), black_box(&boxes2))) - }); -} +// c.bench_function("parallel iou distance benchmark", |b| { +// b.iter(|| parallel_iou_distance(black_box(&boxes1), black_box(&boxes2))) +// }); +// } -pub fn giou_distance_benchmark(c: &mut Criterion) { - let mut boxes1 = Array2::::zeros((100, 4)); - for i in 0..100 { - for j in 0..4 { - if j < 2 { - boxes1[[i, j]] = 0.0; - } else { - boxes1[[i, j]] = 10.0; - } - } - } - let boxes2 = boxes1.clone(); +// pub fn giou_distance_benchmark(c: &mut Criterion) { +// let mut boxes1 = Array2::::zeros((100, 4)); +// for i in 0..100 { +// for j in 0..4 { +// if j < 2 { +// boxes1[[i, j]] = 0.0; +// } else { +// boxes1[[i, j]] = 10.0; +// } +// } +// } +// let boxes2 = boxes1.clone(); - c.bench_function("giou distance benchmark", |b| { - b.iter(|| giou_distance(black_box(&boxes1), black_box(&boxes2))) - }); -} +// c.bench_function("giou distance benchmark", |b| { +// b.iter(|| giou_distance(black_box(&boxes1), black_box(&boxes2))) +// }); +// } -pub fn parallel_giou_distance_benchmark(c: &mut Criterion) { - let mut boxes1 = Array2::::zeros((100, 4)); - for i in 0..100 { - for j in 0..4 { - if j < 2 { - boxes1[[i, j]] = 0.0; - } else { - boxes1[[i, j]] = 10.0; - } - } - } - let boxes2 = boxes1.clone(); +// pub fn parallel_giou_distance_benchmark(c: &mut Criterion) { +// let mut boxes1 = Array2::::zeros((100, 4)); +// for i in 0..100 { +// for j in 0..4 { +// if j < 2 { +// boxes1[[i, j]] = 0.0; +// } else { +// boxes1[[i, j]] = 10.0; +// } +// } +// } +// let boxes2 = boxes1.clone(); - c.bench_function("parallel giou distance benchmark", |b| { - b.iter(|| parallel_giou_distance(black_box(&boxes1), black_box(&boxes2))) - }); -} +// c.bench_function("parallel giou distance benchmark", |b| { +// b.iter(|| parallel_giou_distance(black_box(&boxes1), black_box(&boxes2))) +// }); +// } -criterion_group!( - benches, - iou_distance_benchmark, - parallel_iou_distance_benchmark, - giou_distance_benchmark, - parallel_giou_distance_benchmark -); -criterion_main!(benches); +// criterion_group!( +// benches, +// iou_distance_benchmark, +// parallel_iou_distance_benchmark, +// giou_distance_benchmark, +// parallel_giou_distance_benchmark +// ); +// criterion_main!(benches); diff --git a/powerboxesrs/src/boxes.rs b/powerboxesrs/src/boxes.rs index bf5bcfe..8812715 100644 --- a/powerboxesrs/src/boxes.rs +++ b/powerboxesrs/src/boxes.rs @@ -1,6 +1,7 @@ -use ndarray::{Array1, Array2, ArrayView2, ArrayView3, ArrayViewMut2, Axis, Zip}; -use num_traits::{real::Real, Num, ToPrimitive}; +use num_traits::{Num, ToPrimitive}; +use std::ops::SubAssign; +use nalgebra::{MatrixXx1, MatrixXx4, Scalar, ClosedMul}; #[derive(Copy, Clone)] pub enum BoxFormat { XYXY, @@ -8,89 +9,25 @@ pub enum BoxFormat { CXCYWH, } -/// Calculates the areas of a 2D array of boxes. -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of boxes represented as an `ArrayView2` in xyxy format. -/// -/// # Returns -/// -/// An `Array1` containing the areas of each box in the same order as the input array. -/// /// # Examples -/// /// ``` -/// use ndarray::array; -/// use powerboxesrs::boxes::box_areas; -/// -/// let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; -/// -/// let areas = box_areas(&boxes); +/// use nalgebra::{MatrixXx4, MatrixXx1}; +/// use powerboxesrs::boxes::box_areas_nalgebra; +/// let boxes = MatrixXx4::from_vec(vec![1., 0., 2., 0., 3., 10., 4., 10.]); /// -/// assert_eq!(areas, array![4., 100.]); +/// let areas = box_areas_nalgebra(boxes); +/// assert_eq!(areas, MatrixXx1::from_vec(vec![4., 100.])); /// ``` -pub fn box_areas<'a, N, BA>(boxes: BA) -> Array1 +pub fn box_areas(boxes: &MatrixXx4) -> MatrixXx1 where - N: Num + PartialEq + ToPrimitive + Copy + 'a, - BA: Into>, + N: Scalar + Num + SubAssign + ClosedMul, { - let boxes = boxes.into(); - let num_boxes = boxes.nrows(); - let mut areas = Array1::::zeros(num_boxes); - Zip::indexed(&mut areas).for_each(|i, area| { - let box1 = boxes.row(i); - let area_ = (box1[2] - box1[0]) * (box1[3] - box1[1]); - *area = area_.to_f64().unwrap(); - }); - + let widths = boxes.column(2) - boxes.column(0); + let heights = boxes.column(3) - boxes.column(1); + let areas = widths.component_mul(&heights); return areas; } -/// Calculates the areas of a 2D array of boxes in parallel. -/// This function is only faster than `box_areas` for large arrays -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of boxes represented as an `Array2` in xyxy format. -/// -/// # Returns -/// -/// An `Array1` containing the areas of each box in the same order as the input array. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::boxes::parallel_box_areas; -/// -/// let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; -/// -/// let areas = parallel_box_areas(&boxes); -/// -/// assert_eq!(areas, array![4., 100.]); -/// ``` -pub fn parallel_box_areas<'a, N, BA>(boxes: BA) -> Array1 -where - N: Real + Send + Sync + 'a, - BA: Into>, -{ - let boxes = boxes.into(); - let num_boxes = boxes.nrows(); - let mut areas = Array1::::zeros(num_boxes); - - Zip::indexed(&mut areas).par_for_each(|i, area| { - let box1 = boxes.row(i); - let x1: N = box1[0]; - let y1: N = box1[1]; - let x2: N = box1[2]; - let y2: N = box1[3]; - let _area = (x2 - x1) * (y2 - y1); - *area = _area.to_f64().unwrap(); - }); - - return areas; -} /// Removes all boxes from the input array that have a size smaller than `min_size`. /// @@ -115,550 +52,434 @@ where /// /// assert_eq!(result, array![[0., 0., 10., 10.]]); /// ``` -pub fn remove_small_boxes<'a, N, BA>(boxes: BA, min_size: f64) -> Array2 +// pub fn remove_small_boxes(boxes: &MatrixXx4, min_size: f64) -> MatrixXx4 +// where +// N: Scalar + Num + SubAssign + ClosedMul + ToPrimitive, +// { +// let areas = box_areas(boxes); +// let keep = areas.map(|x| x.to_f64().unwrap() > min_size); +// let indices: Vec = keep.iter().enumerate().filter_map(|(i, x)| if *x { Some(i) } else { None }).collect(); +// return boxes.select_rows(&indices); +// } +pub fn remove_small_boxes(boxes: &MatrixXx4, min_size: f64) -> MatrixXx4 where - N: Num + PartialEq + Clone + PartialOrd + ToPrimitive + Copy + 'a, - BA: Into>, + N: Scalar + Num + SubAssign + ClosedMul + ToPrimitive + Copy, { - let boxes = boxes.into(); + // Get the areas of the boxes let areas = box_areas(boxes); - let keep: Vec = areas - .indexed_iter() - .filter(|(_, &area)| area >= min_size) - .map(|(index, _)| index) + + // Collect indices of boxes whose areas are larger than the min_size + let indices: Vec = areas.iter() + .enumerate() + .filter_map(|(i, &area)| { + // Convert to f64 safely + area.to_f64().and_then(|a| if a > min_size { Some(i) } else { None }) + }) .collect(); - return boxes.select(Axis(0), &keep); -} -/// Converts a 2D array of boxes from one format to another, in-place. -/// This works because all box formats use 4 values in their representations. -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of boxes in the input format. -/// * `in_fmt` - The input format of the boxes. -/// * `out_fmt` - The desired output format of the boxes. -/// -/// # Example -/// -/// ``` -/// use ndarray::arr2; -/// use powerboxesrs::boxes::{BoxFormat, box_convert_inplace}; -/// -/// let mut boxes = arr2(&[ -/// [10.0, 20.0, 30.0, 40.0], -/// [75.0, 25.0, 100.0, 200.0], -/// [100.0, 100.0, 101.0, 101.0], -/// ]); -/// let expected_output = arr2(&[ -/// [20.0, 30.0, 20.0, 20.0], -/// [87.5, 112.5, 25.0, 175.0], -/// [100.5, 100.5, 1.0, 1.0], -/// ]); -/// box_convert_inplace(&mut boxes, BoxFormat::XYXY, BoxFormat::CXCYWH); -/// assert_eq!(boxes, expected_output); -/// ``` -pub fn box_convert_inplace<'a, N, BA>(boxes: BA, in_fmt: BoxFormat, out_fmt: BoxFormat) -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Clone + Copy + 'a, - BA: Into>, -{ - boxes - .into() - .rows_mut() - .into_iter() - .for_each(|mut bx| match (in_fmt, out_fmt) { - (BoxFormat::XYXY, BoxFormat::XYWH) => { - bx[2] = bx[2] - bx[0]; - bx[3] = bx[3] - bx[1]; - } - (BoxFormat::XYXY, BoxFormat::CXCYWH) => { - let x1 = bx[0]; - let y1 = bx[1]; - let x2 = bx[2]; - let y2 = bx[3]; - bx[0] = (x1 + x2) / (N::one() + N::one()); - bx[1] = (y1 + y2) / (N::one() + N::one()); - bx[2] = x2 - x1; - bx[3] = y2 - y1; - } - (BoxFormat::XYWH, BoxFormat::XYXY) => { - bx[2] = bx[0] + bx[2]; - bx[3] = bx[1] + bx[3]; - } - (BoxFormat::XYWH, BoxFormat::CXCYWH) => { - let w = bx[2]; - let h = bx[3]; - bx[0] = bx[0] + w / (N::one() + N::one()); - bx[1] = bx[1] + h / (N::one() + N::one()); - bx[2] = w; - bx[3] = h; - } - (BoxFormat::CXCYWH, BoxFormat::XYXY) => { - let cx = bx[0]; - let cy = bx[1]; - let wd2 = bx[2] / (N::one() + N::one()); - let hd2 = bx[3] / (N::one() + N::one()); - bx[0] = cx - wd2; - bx[1] = cy - hd2; - bx[2] = cx + wd2; - bx[3] = cy + hd2; - } - (BoxFormat::CXCYWH, BoxFormat::XYWH) => { - let w = bx[2]; - let h = bx[3]; - bx[0] = bx[0] - w / (N::one() + N::one()); - bx[1] = bx[1] - h / (N::one() + N::one()); - bx[2] = w; - bx[3] = h; - } - (BoxFormat::XYXY, BoxFormat::XYXY) => (), - (BoxFormat::XYWH, BoxFormat::XYWH) => (), - (BoxFormat::CXCYWH, BoxFormat::CXCYWH) => (), - }); + // Select rows (boxes) that pass the filter + boxes.select_rows(&indices) } -/// Converts a 2D array of boxes from one format to another. -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of boxes in the input format. -/// * `in_fmt` - The input format of the boxes. -/// * `out_fmt` - The desired output format of the boxes. -/// -/// # Returns -/// -/// A 2D array of boxes in the output format. -/// -/// # Example -/// -/// ``` -/// use ndarray::arr2; -/// use powerboxesrs::boxes::{BoxFormat, box_convert}; -/// -/// let boxes = arr2(&[ -/// [10.0, 20.0, 30.0, 40.0], -/// [75.0, 25.0, 100.0, 200.0], -/// [100.0, 100.0, 101.0, 101.0], -/// ]); -/// let expected_output = arr2(&[ -/// [20.0, 30.0, 20.0, 20.0], -/// [87.5, 112.5, 25.0, 175.0], -/// [100.5, 100.5, 1.0, 1.0], -/// ]); -/// let output = box_convert(&boxes, BoxFormat::XYXY, BoxFormat::CXCYWH); -/// assert_eq!(output, expected_output); -/// ``` -pub fn box_convert<'a, N, BA>(boxes: BA, in_fmt: BoxFormat, out_fmt: BoxFormat) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Clone + Copy + 'a, - BA: Into>, -{ - let mut converted_boxes = boxes.into().to_owned(); - box_convert_inplace(&mut converted_boxes, in_fmt, out_fmt); - converted_boxes -} +// /// Converts a 2D array of boxes from one format to another. +// /// +// /// # Arguments +// /// +// /// * `boxes` - A 2D array of boxes in the input format. +// /// * `in_fmt` - The input format of the boxes. +// /// * `out_fmt` - The desired output format of the boxes. +// /// +// /// # Returns +// /// +// /// A 2D array of boxes in the output format. +// /// +// /// # Example +// /// +// /// ``` +// /// use ndarray::arr2; +// /// use powerboxesrs::boxes::{BoxFormat, box_convert}; +// /// +// /// let boxes = arr2(&[ +// /// [10.0, 20.0, 30.0, 40.0], +// /// [75.0, 25.0, 100.0, 200.0], +// /// [100.0, 100.0, 101.0, 101.0], +// /// ]); +// /// let in_fmt = BoxFormat::XYXY; +// /// let out_fmt = BoxFormat::CXCYWH; +// /// let expected_output = arr2(&[ +// /// [20.0, 30.0, 20.0, 20.0], +// /// [87.5, 112.5, 25.0, 175.0], +// /// [100.5, 100.5, 1.0, 1.0], +// /// ]); +// /// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// /// assert_eq!(output, expected_output); +// /// ``` +// pub fn box_convert(boxes: &Array2, in_fmt: &BoxFormat, out_fmt: &BoxFormat) -> Array2 +// where +// N: Num + PartialEq + ToPrimitive + Clone + Copy, +// { +// let num_boxes: usize = boxes.nrows(); +// let mut converted_boxes = Array2::::zeros((num_boxes, 4)); -/// Converts a 2D array of boxes from one format to another, in parallel. -/// This function is only faster than `box_convert` for large arrays -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of boxes in the input format. -/// * `in_fmt` - The input format of the boxes. -/// * `out_fmt` - The desired output format of the boxes. -/// -/// # Returns -/// -/// A 2D array of boxes in the output format. -/// -/// # Example -/// -/// ``` -/// use ndarray::arr2; -/// use powerboxesrs::boxes::{BoxFormat, parallel_box_convert}; -/// -/// let boxes = arr2(&[ -/// [10.0, 20.0, 30.0, 40.0], -/// [75.0, 25.0, 100.0, 200.0], -/// [100.0, 100.0, 101.0, 101.0], -/// ]); -/// let expected_output = arr2(&[ -/// [20.0, 30.0, 20.0, 20.0], -/// [87.5, 112.5, 25.0, 175.0], -/// [100.5, 100.5, 1.0, 1.0], -/// ]); -/// let output = parallel_box_convert(&boxes, BoxFormat::XYXY, BoxFormat::CXCYWH); -/// assert_eq!(expected_output, output); -/// ``` -pub fn parallel_box_convert( - boxes: &Array2, - in_fmt: BoxFormat, - out_fmt: BoxFormat, -) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Clone + Sync + Send + Copy, -{ - let mut converted_boxes = boxes.clone(); +// Zip::indexed(converted_boxes.rows_mut()).for_each(|i, mut box1| { +// let box2 = boxes.row(i); +// match (in_fmt, out_fmt) { +// (BoxFormat::XYXY, BoxFormat::XYWH) => { +// let x1 = box2[0]; +// let y1 = box2[1]; +// let x2 = box2[2]; +// let y2 = box2[3]; +// box1[0] = x1; +// box1[1] = y1; +// box1[2] = x2 - x1; +// box1[3] = y2 - y1; +// } +// (BoxFormat::XYXY, BoxFormat::CXCYWH) => { +// let x1 = box2[0]; +// let y1 = box2[1]; +// let x2 = box2[2]; +// let y2 = box2[3]; +// box1[0] = (x1 + x2) / (N::one() + N::one()); +// box1[1] = (y1 + y2) / (N::one() + N::one()); +// box1[2] = x2 - x1; +// box1[3] = y2 - y1; +// } +// (BoxFormat::XYWH, BoxFormat::XYXY) => { +// let x1 = box2[0]; +// let y1 = box2[1]; +// let w = box2[2]; +// let h = box2[3]; +// box1[0] = x1; +// box1[1] = y1; +// box1[2] = x1 + w; +// box1[3] = y1 + h; +// } +// (BoxFormat::XYWH, BoxFormat::CXCYWH) => { +// let x1 = box2[0]; +// let y1 = box2[1]; +// let w = box2[2]; +// let h = box2[3]; +// box1[0] = x1 + w / (N::one() + N::one()); +// box1[1] = y1 + h / (N::one() + N::one()); +// box1[2] = w; +// box1[3] = h; +// } +// (BoxFormat::CXCYWH, BoxFormat::XYXY) => { +// let cx = box2[0]; +// let cy = box2[1]; +// let w = box2[2]; +// let h = box2[3]; +// box1[0] = cx - w / (N::one() + N::one()); +// box1[1] = cy - h / (N::one() + N::one()); +// box1[2] = cx + w / (N::one() + N::one()); +// box1[3] = cy + h / (N::one() + N::one()); +// } +// (BoxFormat::CXCYWH, BoxFormat::XYWH) => { +// let cx = box2[0]; +// let cy = box2[1]; +// let w = box2[2]; +// let h = box2[3]; +// box1[0] = cx - w / (N::one() + N::one()); +// box1[1] = cy - h / (N::one() + N::one()); +// box1[2] = w; +// box1[3] = h; +// } +// (BoxFormat::XYXY, BoxFormat::XYXY) => (), +// (BoxFormat::XYWH, BoxFormat::XYWH) => (), +// (BoxFormat::CXCYWH, BoxFormat::CXCYWH) => (), +// } +// }); +// return converted_boxes; +// } - Zip::indexed(converted_boxes.rows_mut()).par_for_each(|i, mut box1| { - let box2 = boxes.row(i); - match (in_fmt, out_fmt) { - (BoxFormat::XYXY, BoxFormat::XYWH) => { - let x1 = box2[0]; - let y1 = box2[1]; - let x2 = box2[2]; - let y2 = box2[3]; - box1[2] = x2 - x1; - box1[3] = y2 - y1; - } - (BoxFormat::XYXY, BoxFormat::CXCYWH) => { - let x1 = box2[0]; - let y1 = box2[1]; - let x2 = box2[2]; - let y2 = box2[3]; - box1[0] = (x1 + x2) / (N::one() + N::one()); - box1[1] = (y1 + y2) / (N::one() + N::one()); - box1[2] = x2 - x1; - box1[3] = y2 - y1; - } - (BoxFormat::XYWH, BoxFormat::XYXY) => { - let x1 = box2[0]; - let y1 = box2[1]; - let w = box2[2]; - let h = box2[3]; - box1[2] = x1 + w; - box1[3] = y1 + h; - } - (BoxFormat::XYWH, BoxFormat::CXCYWH) => { - let x1 = box2[0]; - let y1 = box2[1]; - let w = box2[2]; - let h = box2[3]; - box1[0] = x1 + w / (N::one() + N::one()); - box1[1] = y1 + h / (N::one() + N::one()); - } - (BoxFormat::CXCYWH, BoxFormat::XYXY) => { - let cx = box2[0]; - let cy = box2[1]; - let w = box2[2]; - let h = box2[3]; - box1[0] = cx - w / (N::one() + N::one()); - box1[1] = cy - h / (N::one() + N::one()); - box1[2] = cx + w / (N::one() + N::one()); - box1[3] = cy + h / (N::one() + N::one()); - } - (BoxFormat::CXCYWH, BoxFormat::XYWH) => { - let cx = box2[0]; - let cy = box2[1]; - let w = box2[2]; - let h = box2[3]; - box1[0] = cx - w / (N::one() + N::one()); - box1[1] = cy - h / (N::one() + N::one()); - } - (BoxFormat::XYXY, BoxFormat::XYXY) => (), - (BoxFormat::XYWH, BoxFormat::XYWH) => (), - (BoxFormat::CXCYWH, BoxFormat::CXCYWH) => (), - } - }); - return converted_boxes; -} -/// Compute the bounding boxes around the provided masks. -/// Returns a [N, 4] array containing bounding boxes. The boxes are in xyxy format -/// -/// # Arguments -/// -/// * `masks` - A [N, H, W] array of masks to transform where N is the number of masks and (H, W) are the spatial dimensions of the image. -/// -/// # Returns -/// -/// A [N, 4] array of boxes in xyxy format. -/// # Example -/// ``` -/// use ndarray::{arr3, array}; -/// use powerboxesrs::boxes::masks_to_boxes; -/// let masks = arr3(&[ -/// [[true, true, true], [false, false, false]], -/// [[false, false, false], [true, true, true]], -/// [[false, false, false], [false, false, true]], -/// ]); -/// let boxes = masks_to_boxes(&masks); -/// assert_eq!(boxes, array![[0, 0, 2, 0], [0, 1, 2, 1], [2, 1, 2, 1]]); -pub fn masks_to_boxes<'a, MA>(masks: MA) -> Array2 -where - MA: Into>, -{ - let masks = masks.into(); - let num_masks = masks.shape()[0]; - let height = masks.shape()[1]; - let width = masks.shape()[2]; - let mut boxes = Array2::::zeros((num_masks, 4)); +// /// Compute the bounding boxes around the provided masks. +// /// Returns a [N, 4] array containing bounding boxes. The boxes are in xyxy format +// /// +// /// # Arguments +// /// +// /// * `masks` - A [N, H, W] array of masks to transform where N is the number of masks and (H, W) are the spatial dimensions of the image. +// /// +// /// # Returns +// /// +// /// A [N, 4] array of boxes in xyxy format. +// /// # Example +// /// ``` +// /// use ndarray::{arr3, array}; +// /// use powerboxesrs::boxes::masks_to_boxes; +// /// let masks = arr3(&[ +// /// [[true, true, true], [false, false, false]], +// /// [[false, false, false], [true, true, true]], +// /// [[false, false, false], [false, false, true]], +// /// ]); +// /// let boxes = masks_to_boxes(&masks); +// /// assert_eq!(boxes, array![[0, 0, 2, 0], [0, 1, 2, 1], [2, 1, 2, 1]]); +// pub fn masks_to_boxes(masks: &Array3) -> Array2 { +// let num_masks = masks.shape()[0]; +// let height = masks.shape()[1]; +// let width = masks.shape()[2]; +// let mut boxes = Array2::::zeros((num_masks, 4)); - for (i, mask) in masks.outer_iter().enumerate() { - let mut x1 = width; - let mut y1 = height; - let mut x2 = 0; - let mut y2 = 0; +// for (i, mask) in masks.outer_iter().enumerate() { +// let mut x1 = width; +// let mut y1 = height; +// let mut x2 = 0; +// let mut y2 = 0; - // get the indices where the mask is true - mask.indexed_iter().for_each(|(index, &value)| { - if value { - let (y, x) = index; - if x < x1 { - x1 = x; - } - if x > x2 { - x2 = x; - } - if y < y1 { - y1 = y; - } - if y > y2 { - y2 = y; - } - } - }); - boxes[[i, 0]] = x1; - boxes[[i, 1]] = y1; - boxes[[i, 2]] = x2; - boxes[[i, 3]] = y2; - } +// // get the indices where the mask is true +// mask.indexed_iter().for_each(|(index, &value)| { +// if value { +// let (y, x) = index; +// if x < x1 { +// x1 = x; +// } +// if x > x2 { +// x2 = x; +// } +// if y < y1 { +// y1 = y; +// } +// if y > y2 { +// y2 = y; +// } +// } +// }); +// boxes[[i, 0]] = x1; +// boxes[[i, 1]] = y1; +// boxes[[i, 2]] = x2; +// boxes[[i, 3]] = y2; +// } - return boxes; -} +// return boxes; +// } -/// Calculates the areas of rotated boxes in the cxcywha format. -/// -/// Given an array of rotated boxes represented in the cxcywha format, where each row -/// corresponds to a box and the columns represent center-x, center-y, width, height, -/// and orientation angle, this function computes the area of each box and returns -/// an array containing the computed areas. -/// -/// # Arguments -/// -/// * `boxes` - A 2D array representing rotated boxes in the cxcywha format. -/// -/// # Returns -/// -/// A 1D array containing the computed areas of each rotated box. -/// -pub fn rotated_box_areas<'a, BA>(boxes: BA) -> Array1 -where - BA: Into>, -{ - let boxes = boxes.into(); - let n_boxes = boxes.nrows(); +// /// Calculates the areas of rotated boxes in the cxcywha format. +// /// +// /// Given an array of rotated boxes represented in the cxcywha format, where each row +// /// corresponds to a box and the columns represent center-x, center-y, width, height, +// /// and orientation angle, this function computes the area of each box and returns +// /// an array containing the computed areas. +// /// +// /// # Arguments +// /// +// /// * `boxes` - A 2D array representing rotated boxes in the cxcywha format. +// /// +// /// # Returns +// /// +// /// A 1D array containing the computed areas of each rotated box. +// /// +// pub fn rotated_box_areas(boxes: &Array2) -> Array1 { +// let n_boxes = boxes.nrows(); - let mut areas = Array1::zeros(n_boxes); +// let mut areas = Array1::zeros(n_boxes); - for i in 0..n_boxes { - areas[i] = boxes[[i, 2]] * boxes[[i, 3]] - } +// for i in 0..n_boxes { +// areas[i] = boxes[[i, 2]] * boxes[[i, 3]] +// } - areas -} +// areas +// } -#[cfg(test)] -mod tests { - use super::*; - use ndarray::{arr2, arr3, array, Array3}; - #[test] - fn test_box_convert_xyxy_to_xywh() { - let boxes = arr2(&[ - [10., 20., 30., 40.], - [75., 25., 100., 200.], - [100., 100., 101., 101.], - ]); - let in_fmt = BoxFormat::XYXY; - let out_fmt = BoxFormat::XYWH; - let expected_output = arr2(&[ - [10.0, 20.0, 20.0, 20.0], - [75.0, 25.0, 25.0, 175.0], - [100.0, 100.0, 1.0, 1.0], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[cfg(test)] +// mod tests { +// use super::*; +// use ndarray::{arr2, arr3, array}; +// #[test] +// fn test_box_convert_xyxy_to_xywh() { +// let boxes = arr2(&[ +// [10., 20., 30., 40.], +// [75., 25., 100., 200.], +// [100., 100., 101., 101.], +// ]); +// let in_fmt = BoxFormat::XYXY; +// let out_fmt = BoxFormat::XYWH; +// let expected_output = arr2(&[ +// [10.0, 20.0, 20.0, 20.0], +// [75.0, 25.0, 25.0, 175.0], +// [100.0, 100.0, 1.0, 1.0], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_box_convert_xyxy_to_cxcywh() { - let boxes = arr2(&[ - [10.0, 20.0, 30.0, 40.0], - [75.0, 25.0, 100.0, 200.0], - [100.0, 100.0, 101.0, 101.0], - ]); - let in_fmt = BoxFormat::XYXY; - let out_fmt = BoxFormat::CXCYWH; - let expected_output = arr2(&[ - [20.0, 30.0, 20.0, 20.0], - [87.5, 112.5, 25.0, 175.0], - [100.5, 100.5, 1.0, 1.0], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[test] +// fn test_box_convert_xyxy_to_cxcywh() { +// let boxes = arr2(&[ +// [10.0, 20.0, 30.0, 40.0], +// [75.0, 25.0, 100.0, 200.0], +// [100.0, 100.0, 101.0, 101.0], +// ]); +// let in_fmt = BoxFormat::XYXY; +// let out_fmt = BoxFormat::CXCYWH; +// let expected_output = arr2(&[ +// [20.0, 30.0, 20.0, 20.0], +// [87.5, 112.5, 25.0, 175.0], +// [100.5, 100.5, 1.0, 1.0], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_box_convert_xywh_to_xyxy() { - let boxes = arr2(&[ - [10.0, 20.0, 20.0, 20.0], - [75.0, 25.0, 25.0, 175.0], - [100.0, 100.0, 1.0, 1.0], - ]); - let in_fmt = BoxFormat::XYWH; - let out_fmt = BoxFormat::XYXY; - let expected_output = arr2(&[ - [10.0, 20.0, 30.0, 40.0], - [75.0, 25.0, 100.0, 200.0], - [100.0, 100.0, 101.0, 101.0], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[test] +// fn test_box_convert_xywh_to_xyxy() { +// let boxes = arr2(&[ +// [10.0, 20.0, 20.0, 20.0], +// [75.0, 25.0, 25.0, 175.0], +// [100.0, 100.0, 1.0, 1.0], +// ]); +// let in_fmt = BoxFormat::XYWH; +// let out_fmt = BoxFormat::XYXY; +// let expected_output = arr2(&[ +// [10.0, 20.0, 30.0, 40.0], +// [75.0, 25.0, 100.0, 200.0], +// [100.0, 100.0, 101.0, 101.0], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_box_convert_xywh_to_cxcywh() { - let boxes = arr2(&[ - [10.0, 20.0, 20.0, 20.0], - [75.0, 25.0, 25.0, 175.0], - [100.0, 100.0, 1.0, 1.0], - ]); - let in_fmt = BoxFormat::XYWH; - let out_fmt = BoxFormat::CXCYWH; - let expected_output = arr2(&[ - [20.0, 30.0, 20.0, 20.0], - [87.5, 112.5, 25.0, 175.0], - [100.5, 100.5, 1.0, 1.0], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[test] +// fn test_box_convert_xywh_to_cxcywh() { +// let boxes = arr2(&[ +// [10.0, 20.0, 20.0, 20.0], +// [75.0, 25.0, 25.0, 175.0], +// [100.0, 100.0, 1.0, 1.0], +// ]); +// let in_fmt = BoxFormat::XYWH; +// let out_fmt = BoxFormat::CXCYWH; +// let expected_output = arr2(&[ +// [20.0, 30.0, 20.0, 20.0], +// [87.5, 112.5, 25.0, 175.0], +// [100.5, 100.5, 1.0, 1.0], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_box_convert_cxcywh_to_xyxy() { - let boxes = arr2(&[ - [20.0, 30.0, 20.0, 20.0], - [87.5, 112.5, 25.0, 175.0], - [100.5, 100.5, 1.0, 1.0], - ]); - let in_fmt = BoxFormat::CXCYWH; - let out_fmt = BoxFormat::XYXY; - let expected_output = arr2(&[ - [10., 20., 30., 40.], - [75., 25., 100., 200.], - [100., 100., 101., 101.], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[test] +// fn test_box_convert_cxcywh_to_xyxy() { +// let boxes = arr2(&[ +// [20.0, 30.0, 20.0, 20.0], +// [87.5, 112.5, 25.0, 175.0], +// [100.5, 100.5, 1.0, 1.0], +// ]); +// let in_fmt = BoxFormat::CXCYWH; +// let out_fmt = BoxFormat::XYXY; +// let expected_output = arr2(&[ +// [10., 20., 30., 40.], +// [75., 25., 100., 200.], +// [100., 100., 101., 101.], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_box_convert_cxcywh_to_xywh() { - let boxes = arr2(&[ - [20.0, 30.0, 20.0, 20.0], - [87.5, 112.5, 25.0, 175.0], - [100.5, 100.5, 1.0, 1.0], - ]); - let in_fmt = BoxFormat::CXCYWH; - let out_fmt = BoxFormat::XYWH; - let expected_output = arr2(&[ - [10.0, 20.0, 20.0, 20.0], - [75.0, 25.0, 25.0, 175.0], - [100.0, 100.0, 1.0, 1.0], - ]); - let output = box_convert(&boxes, in_fmt, out_fmt); - let parallel_output = parallel_box_convert(&boxes, in_fmt, out_fmt); - assert_eq!(output, expected_output); - assert_eq!(output, parallel_output); - } +// #[test] +// fn test_box_convert_cxcywh_to_xywh() { +// let boxes = arr2(&[ +// [20.0, 30.0, 20.0, 20.0], +// [87.5, 112.5, 25.0, 175.0], +// [100.5, 100.5, 1.0, 1.0], +// ]); +// let in_fmt = BoxFormat::CXCYWH; +// let out_fmt = BoxFormat::XYWH; +// let expected_output = arr2(&[ +// [10.0, 20.0, 20.0, 20.0], +// [75.0, 25.0, 25.0, 175.0], +// [100.0, 100.0, 1.0, 1.0], +// ]); +// let output = box_convert(&boxes, &in_fmt, &out_fmt); +// let parallel_output = parallel_box_convert(&boxes, &in_fmt, &out_fmt); +// assert_eq!(output, expected_output); +// assert_eq!(output, parallel_output); +// } - #[test] - fn test_coherence() { - let boxes = arr2(&[ - [10., 20., 30., 40.], - [75., 25., 100., 200.], - [100., 100., 101., 101.], - ]); - let xywh = parallel_box_convert(&boxes, BoxFormat::XYXY, BoxFormat::XYWH); - let cxcywh = parallel_box_convert(&xywh, BoxFormat::XYWH, BoxFormat::CXCYWH); - assert_eq!( - parallel_box_convert(&cxcywh, BoxFormat::CXCYWH, BoxFormat::XYXY), - boxes - ); - assert_eq!( - parallel_box_convert(&xywh, BoxFormat::XYWH, BoxFormat::XYXY), - boxes - ); - } - #[test] - fn test_box_areas_single_box() { - let boxes = array![[1., 2., 3., 4.]]; - let areas = box_areas(&boxes); - let parallel_areas = parallel_box_areas(&boxes); - assert_eq!(areas, array![4.]); - assert_eq!(parallel_areas, areas); - } +// #[test] +// fn test_coherence() { +// let boxes = arr2(&[ +// [10., 20., 30., 40.], +// [75., 25., 100., 200.], +// [100., 100., 101., 101.], +// ]); +// let xywh = parallel_box_convert(&boxes, &BoxFormat::XYXY, &BoxFormat::XYWH); +// let cxcywh = parallel_box_convert(&xywh, &BoxFormat::XYWH, &BoxFormat::CXCYWH); +// assert_eq!( +// parallel_box_convert(&cxcywh, &BoxFormat::CXCYWH, &BoxFormat::XYXY), +// boxes +// ); +// assert_eq!( +// parallel_box_convert(&xywh, &BoxFormat::XYWH, &BoxFormat::XYXY), +// boxes +// ); +// } +// #[test] +// fn test_box_areas_single_box() { +// let boxes = array![[1., 2., 3., 4.]]; +// let areas = box_areas(&boxes); +// let parallel_areas = parallel_box_areas(&boxes); +// assert_eq!(areas, array![4.]); +// assert_eq!(parallel_areas, areas); +// } - #[test] - fn test_box_areas_multiple_boxes() { - let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; - let areas = box_areas(&boxes); - let parallel_areas = parallel_box_areas(&boxes); - assert_eq!(areas, array![4., 100.]); - assert_eq!(parallel_areas, areas); - } +// #[test] +// fn test_box_areas_multiple_boxes() { +// let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; +// let areas = box_areas(&boxes); +// let parallel_areas = parallel_box_areas(&boxes); +// assert_eq!(areas, array![4., 100.]); +// assert_eq!(parallel_areas, areas); +// } - #[test] - fn test_box_areas_zero_area() { - let boxes = array![[1., 2., 1., 2.]]; - let areas = box_areas(&boxes); - let parallel_areas = parallel_box_areas(&boxes); - assert_eq!(areas, array![0.]); - assert_eq!(parallel_areas, areas); - } +// #[test] +// fn test_box_areas_zero_area() { +// let boxes = array![[1., 2., 1., 2.]]; +// let areas = box_areas(&boxes); +// let parallel_areas = parallel_box_areas(&boxes); +// assert_eq!(areas, array![0.]); +// assert_eq!(parallel_areas, areas); +// } - #[test] - fn test_box_areas_negative_coordinates() { - let boxes = array![[-1., -1., 1., 1.]]; - let areas = box_areas(&boxes); - let parallel_areas = parallel_box_areas(&boxes); - assert_eq!(areas, array![4.]); - assert_eq!(parallel_areas, areas); - } +// #[test] +// fn test_box_areas_negative_coordinates() { +// let boxes = array![[-1., -1., 1., 1.]]; +// let areas = box_areas(&boxes); +// let parallel_areas = parallel_box_areas(&boxes); +// assert_eq!(areas, array![4.]); +// assert_eq!(parallel_areas, areas); +// } - #[test] - fn test_remove_small_boxes() { - let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; - let min_size = 10.; - let filtered_boxes = remove_small_boxes(&boxes, min_size); - assert_eq!(filtered_boxes, array![[0., 0., 10., 10.]]); - } +// #[test] +// fn test_remove_small_boxes() { +// let boxes = array![[1., 2., 3., 4.], [0., 0., 10., 10.]]; +// let min_size = 10.; +// let filtered_boxes = remove_small_boxes(&boxes, min_size); +// assert_eq!(filtered_boxes, array![[0., 0., 10., 10.]]); +// } - #[test] - fn test_masks_to_boxes() { - let masks: Array3 = arr3(&[ - [[true, true, true], [false, false, false]], - [[false, false, false], [true, true, true]], - [[false, false, false], [false, false, true]], - ]); - let boxes = masks_to_boxes(&masks); - assert_eq!(boxes, array![[0, 0, 2, 0], [0, 1, 2, 1], [2, 1, 2, 1]]); - } - #[test] - fn test_rotated_box_areas_single_box() { - let boxes = array![[1., 2., 3., 4., 100.]]; - let areas = rotated_box_areas(&boxes); - assert_eq!(areas, array![12.]); - } -} +// #[test] +// fn test_masks_to_boxes() { +// let masks: Array3 = arr3(&[ +// [[true, true, true], [false, false, false]], +// [[false, false, false], [true, true, true]], +// [[false, false, false], [false, false, true]], +// ]); +// let boxes = masks_to_boxes(&masks); +// assert_eq!(boxes, array![[0, 0, 2, 0], [0, 1, 2, 1], [2, 1, 2, 1]]); +// } +// #[test] +// fn test_rotated_box_areas_single_box() { +// let boxes = array![[1., 2., 3., 4., 100.]]; +// let areas = rotated_box_areas(&boxes); +// assert_eq!(areas, array![12.]); +// } +// } diff --git a/powerboxesrs/src/diou.rs b/powerboxesrs/src/diou.rs index a2f0418..644b1b4 100644 --- a/powerboxesrs/src/diou.rs +++ b/powerboxesrs/src/diou.rs @@ -1,119 +1,116 @@ -use crate::{boxes, utils}; -use ndarray::{Array2, ArrayView2}; -use num_traits::{Float, Num, ToPrimitive}; +// use crate::{boxes, utils}; +// use ndarray::Array2; +// use num_traits::{real::Real, Float, Num, ToPrimitive}; -/// Calculates the intersection over union (DIoU) distance between two sets of bounding boxes. -/// https://arxiv.org/pdf/1911.08287.pdf -/// -/// -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. -/// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. -/// -/// # Returns -/// -/// A 2D array of shape (N, M) representing the DIoU distance between each pair of bounding boxes -/// ``` -pub fn diou_distance<'a, BA, N>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Num + PartialOrd + ToPrimitive + Float + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); - let two = N::one() + N::one(); - let mut diou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::box_areas(&boxes1); - let areas_boxes2 = boxes::box_areas(&boxes2); - for (i, a1) in boxes1.outer_iter().enumerate() { - let a1_x1 = a1[0]; - let a1_y1 = a1[1]; - let a1_x2 = a1[2]; - let a1_y2 = a1[3]; - let area1 = areas_boxes1[i]; +// /// Calculates the intersection over union (DIoU) distance between two sets of bounding boxes. +// /// https://arxiv.org/pdf/1911.08287.pdf +// /// +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. +// /// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. +// /// +// /// # Returns +// /// +// /// A 2D array of shape (N, M) representing the DIoU distance between each pair of bounding boxes +// /// ``` +// pub fn diou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy + Float + Real, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); +// let two = N::from(2).unwrap(); +// let mut diou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::box_areas(&boxes1); +// let areas_boxes2 = boxes::box_areas(&boxes2); +// for (i, a1) in boxes1.outer_iter().enumerate() { +// let a1_x1 = a1[0]; +// let a1_y1 = a1[1]; +// let a1_x2 = a1[2]; +// let a1_y2 = a1[3]; +// let area1 = areas_boxes1[i]; - for (j, a2) in boxes2.outer_iter().enumerate() { - let a2_x1 = a2[0]; - let a2_y1 = a2[1]; - let a2_x2 = a2[2]; - let a2_y2 = a2[3]; - let area2 = areas_boxes2[j]; - let x1 = utils::max(a1_x1, a2_x1); - let y1 = utils::max(a1_y1, a2_y1); - let x2 = utils::min(a1_x2, a2_x2); - let y2 = utils::min(a1_y2, a2_y2); - if x2 < x1 || y2 < y1 { - diou_matrix[[i, j]] = utils::ONE; - continue; - } - let intersection = (x2 - x1) * (y2 - y1); - let intersection = intersection.to_f64().unwrap(); - let intersection = utils::min(intersection, utils::min(area1, area2)); - let iou = intersection / (area1 + area2 - intersection); +// for (j, a2) in boxes2.outer_iter().enumerate() { +// let a2_x1 = a2[0]; +// let a2_y1 = a2[1]; +// let a2_x2 = a2[2]; +// let a2_y2 = a2[3]; +// let area2 = areas_boxes2[j]; +// let x1 = utils::max(a1_x1, a2_x1); +// let y1 = utils::max(a1_y1, a2_y1); +// let x2 = utils::min(a1_x2, a2_x2); +// let y2 = utils::min(a1_y2, a2_y2); +// if x2 < x1 || y2 < y1 { +// diou_matrix[[i, j]] = utils::ONE; +// continue; +// } +// let intersection = (x2 - x1) * (y2 - y1); +// let intersection = intersection.to_f64().unwrap(); +// let intersection = utils::min(intersection, utils::min(area1, area2)); +// let iou = intersection / (area1 + area2 - intersection + utils::EPS); - let center_box1 = [(a1_x1 + a1_x2) / two, (a1_y1 + a1_y2) / two]; - let center_box2 = [(a2_x1 + a2_x2) / two, (a2_y1 + a2_y2) / two]; +// let center_box1 = [(a1_x1 + a1_x2) / two, (a1_y1 + a1_y2) / two]; +// let center_box2 = [(a2_x1 + a2_x2) / two, (a2_y1 + a2_y2) / two]; - let d = Float::sqrt( - Float::powf(center_box1[0] - center_box2[0], two) - + Float::powf(center_box1[1] - center_box2[1], two), - ); - let c = Float::sqrt(Float::powf(x2 - x1, two) + Float::powf(y2 - y1, two)); - let diou_penalty = Float::powf(d, two) / Float::powf(c, two); - diou_matrix[[i, j]] = utils::ONE - (iou - diou_penalty.to_f64().unwrap()); - } - } +// let d = Float::sqrt( +// Float::powf(center_box1[0] - center_box2[0], two) +// + Float::powf(center_box1[1] - center_box2[1], two), +// ); +// let c = Float::sqrt(Float::powf(x2 - x1, two) + Float::powf(y2 - y1, two)); +// let diou_penalty = Float::powf(d, two) / Float::powf(c, two); +// diou_matrix[[i, j]] = utils::ONE - (iou - diou_penalty.to_f64().unwrap()); +// } +// } - diou_matrix -} +// diou_matrix +// } -#[cfg(test)] -mod tests { - use ndarray::arr2; +// #[cfg(test)] +// mod tests { +// use ndarray::arr2; - use super::*; +// use super::*; - #[test] - fn test_diou_distance() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); - let diou_distance_result = diou_distance(&boxes1, &boxes2); +// #[test] +// fn test_diou_distance() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); +// let diou_distance_result = diou_distance(&boxes1, &boxes2); - assert_eq!(diou_distance_result, arr2(&[[1.8571428571428572]])); - } +// assert_eq!(diou_distance_result, arr2(&[[1.8571428571428572]])); +// } - #[test] - fn test_diou_distance_distance2() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); - let diou_distance_result = diou_distance(&boxes1, &boxes2); - assert_eq!(diou_distance_result, arr2(&[[1.0]])); - } +// #[test] +// fn test_diou_distance_distance2() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); +// let diou_distance_result = diou_distance(&boxes1, &boxes2); +// assert_eq!(diou_distance_result, arr2(&[[1.0]])); +// } - #[test] - fn test_diou_distance_distance3() { - let boxes1 = arr2(&[[2.5, 2.5, 3.0, 3.0]]); - let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); - let diou_distance_result = diou_distance(&boxes1, &boxes2); - assert_eq!(diou_distance_result, arr2(&[[3.187499999999999]])); - } +// #[test] +// fn test_diou_distance_distance3() { +// let boxes1 = arr2(&[[2.5, 2.5, 3.0, 3.0]]); +// let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); +// let diou_distance_result = diou_distance(&boxes1, &boxes2); +// assert_eq!(diou_distance_result, arr2(&[[3.187499999999999]])); +// } - #[test] - fn test_diou_distance_distance4() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let diou_distance_result = diou_distance(&boxes1, &boxes2); - assert_eq!(diou_distance_result, arr2(&[[0.0]])); - } +// #[test] +// fn test_diou_distance_distance4() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let diou_distance_result = diou_distance(&boxes1, &boxes2); +// assert_eq!(diou_distance_result, arr2(&[[0.0]])); +// } - #[test] - fn test_diou_distance_distance5() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); - let diou_distance_result = diou_distance(&boxes1, &boxes2); - assert_eq!(diou_distance_result, arr2(&[[1.0]])); - } -} +// #[test] +// fn test_diou_distance_distance5() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); +// let diou_distance_result = diou_distance(&boxes1, &boxes2); +// assert_eq!(diou_distance_result, arr2(&[[1.0]])); +// } +// } diff --git a/powerboxesrs/src/giou.rs b/powerboxesrs/src/giou.rs index 449207b..3decaac 100644 --- a/powerboxesrs/src/giou.rs +++ b/powerboxesrs/src/giou.rs @@ -1,298 +1,287 @@ -use ndarray::{Array2, ArrayView2, Zip}; -use num_traits::{real::Real, Num, ToPrimitive}; -use rstar::RTree; +// use ndarray::{Array2, Zip}; +// use num_traits::{Num, ToPrimitive}; +// use rstar::RTree; -use crate::{ - boxes::{self, rotated_box_areas}, - rotation::{intersection_area, minimal_bounding_rect, Rect}, - utils, -}; -/// Computes the Generalized Intersection over Union (GIOU) distance between two sets of bounding boxes. -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates in xyxy format of the first set of bounding boxes. -/// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates in xyxy format of the second set of bounding boxes. -/// -/// # Returns -/// -/// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::giou::giou_distance; -/// -/// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; -/// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; -/// -/// let giou = giou_distance(&boxes1, &boxes2); -/// -/// assert_eq!(giou.shape(), &[2, 3]); -/// assert_eq!(giou, array![[0., 1.6800000000000002, 1.7777777777777777], [1.7777777777777777, 1.0793650793650793, 0.]]); -/// ``` -pub fn giou_distance<'a, N, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Copy + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// use crate::{ +// boxes::{self, rotated_box_areas}, +// rotation::{intersection_area, minimal_bounding_rect, Rect}, +// utils, +// }; +// /// Computes the Generalized Intersection over Union (GIOU) distance between two sets of bounding boxes. +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates in xyxy format of the first set of bounding boxes. +// /// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates in xyxy format of the second set of bounding boxes. +// /// +// /// # Returns +// /// +// /// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::array; +// /// use powerboxesrs::giou::giou_distance; +// /// +// /// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; +// /// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; +// /// +// /// let giou = giou_distance(&boxes1, &boxes2); +// /// +// /// assert_eq!(giou.shape(), &[2, 3]); +// /// assert_eq!(giou, array![[0., 1.6800000000000002, 1.7777777777777777], [1.7777777777777777, 1.0793650793650793, 0.]]); +// /// ``` +// pub fn giou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let mut giou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::box_areas(&boxes1); - let areas_boxes2 = boxes::box_areas(&boxes2); - for (i, a1) in boxes1.outer_iter().enumerate() { - let a1_x1 = a1[0]; - let a1_y1 = a1[1]; - let a1_x2 = a1[2]; - let a1_y2 = a1[3]; +// let mut giou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::box_areas(&boxes1); +// let areas_boxes2 = boxes::box_areas(&boxes2); +// for (i, a1) in boxes1.outer_iter().enumerate() { +// let a1_x1 = a1[0]; +// let a1_y1 = a1[1]; +// let a1_x2 = a1[2]; +// let a1_y2 = a1[3]; - let area1 = areas_boxes1[i]; +// let area1 = areas_boxes1[i]; - for (j, a2) in boxes2.outer_iter().enumerate() { - let a2_x1 = a2[0]; - let a2_y1 = a2[1]; - let a2_x2 = a2[2]; - let a2_y2 = a2[3]; - let area2 = areas_boxes2[j]; +// for (j, a2) in boxes2.outer_iter().enumerate() { +// let a2_x1 = a2[0]; +// let a2_y1 = a2[1]; +// let a2_x2 = a2[2]; +// let a2_y2 = a2[3]; +// let area2 = areas_boxes2[j]; - let x1 = utils::max(a1_x1, a2_x1); - let y1 = utils::max(a1_y1, a2_y1); - let x2 = utils::min(a1_x2, a2_x2); - let y2 = utils::min(a1_y2, a2_y2); - let (iou, union) = if x2 < x1 || y2 < y1 { - (utils::ZERO, area1 + area2) - } else { - let intersection = (x2 - x1) * (y2 - y1); - let intersection = intersection.to_f64().unwrap(); - let intersection = utils::min(intersection, utils::min(area1, area2)); - let union = area1 + area2 - intersection; - (intersection / union, union) - }; - // Calculate the enclosing box (C) coordinates - let c_x1 = utils::min(a1_x1, a2_x1); - let c_y1 = utils::min(a1_y1, a2_y1); - let c_x2 = utils::max(a1_x2, a2_x2); - let c_y2 = utils::max(a1_y2, a2_y2); - // Calculate the area of the enclosing box (C) - let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); - let c_area = c_area.to_f64().unwrap(); - let giou = iou - ((c_area - union) / c_area); - giou_matrix[[i, j]] = utils::ONE - giou; - } - } +// let x1 = utils::max(a1_x1, a2_x1); +// let y1 = utils::max(a1_y1, a2_y1); +// let x2 = utils::min(a1_x2, a2_x2); +// let y2 = utils::min(a1_y2, a2_y2); +// let (iou, union) = if x2 < x1 || y2 < y1 { +// (utils::ZERO, area1 + area2) +// } else { +// let intersection = (x2 - x1) * (y2 - y1); +// let intersection = intersection.to_f64().unwrap(); +// let intersection = utils::min(intersection, utils::min(area1, area2)); +// let union = area1 + area2 - intersection + utils::EPS; +// (intersection / union, union) +// }; +// // Calculate the enclosing box (C) coordinates +// let c_x1 = utils::min(a1_x1, a2_x1); +// let c_y1 = utils::min(a1_y1, a2_y1); +// let c_x2 = utils::max(a1_x2, a2_x2); +// let c_y2 = utils::max(a1_y2, a2_y2); +// // Calculate the area of the enclosing box (C) +// let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); +// let c_area = c_area.to_f64().unwrap(); +// let giou = iou - ((c_area - union) / c_area); +// giou_matrix[[i, j]] = utils::ONE - giou; +// } +// } - giou_matrix -} -/// Computes the parallelized version of the Generalized Intersection over Union (GIOU) distance between two sets of bounding boxes. -/// Usually better when a high number of bounding boxes is used. -/// -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates of the first set of bounding boxes. -/// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates of the second set of bounding boxes. -/// -/// # Returns -/// -/// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::giou::parallel_giou_distance; -/// -/// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; -/// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; -/// -/// let giou = parallel_giou_distance(&boxes1, &boxes2); -/// -/// assert_eq!(giou.shape(), &[2, 3]); -/// assert_eq!(giou, array![[0., 1.6800000000000002, 1.7777777777777777], [1.7777777777777777, 1.0793650793650793, 0.]]); -/// ``` -pub fn parallel_giou_distance<'a, N, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Real + Sync + Send + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// giou_matrix +// } +// /// Computes the parallelized version of the Generalized Intersection over Union (GIOU) distance between two sets of bounding boxes. +// /// Usually better when a high number of bounding boxes is used. +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates of the first set of bounding boxes. +// /// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates of the second set of bounding boxes. +// /// +// /// # Returns +// /// +// /// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::array; +// /// use powerboxesrs::giou::parallel_giou_distance; +// /// +// /// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; +// /// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; +// /// +// /// let giou = parallel_giou_distance(&boxes1, &boxes2); +// /// +// /// assert_eq!(giou.shape(), &[2, 3]); +// /// assert_eq!(giou, array![[0., 1.6800000000000002, 1.7777777777777777], [1.7777777777777777, 1.0793650793650793, 0.]]); +// /// ``` +// pub fn parallel_giou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy + Sync + Send, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let mut giou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::parallel_box_areas(boxes1); - let areas_boxes2 = boxes::parallel_box_areas(boxes2); - Zip::indexed(giou_matrix.rows_mut()).par_for_each(|i, mut row| { - let a1 = boxes1.row(i); - let a1_x1 = a1[0]; - let a1_y1 = a1[1]; - let a1_x2 = a1[2]; - let a1_y2 = a1[3]; - let area1 = areas_boxes1[i]; - row.indexed_iter_mut() - .zip(boxes2.rows()) - .for_each(|((j, d), box2)| { - let a2_x1 = box2[0]; - let a2_y1 = box2[1]; - let a2_x2 = box2[2]; - let a2_y2 = box2[3]; - let area2 = areas_boxes2[j]; +// let mut giou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::parallel_box_areas(&boxes1); +// let areas_boxes2 = boxes::parallel_box_areas(&boxes2); +// Zip::indexed(giou_matrix.rows_mut()).par_for_each(|i, mut row| { +// let a1 = boxes1.row(i); +// let a1_x1 = a1[0]; +// let a1_y1 = a1[1]; +// let a1_x2 = a1[2]; +// let a1_y2 = a1[3]; +// let area1 = areas_boxes1[i]; +// row.indexed_iter_mut() +// .zip(boxes2.rows()) +// .for_each(|((j, d), box2)| { +// let a2_x1 = box2[0]; +// let a2_y1 = box2[1]; +// let a2_x2 = box2[2]; +// let a2_y2 = box2[3]; +// let area2 = areas_boxes2[j]; - let x1 = utils::max(a1_x1, a2_x1); - let y1 = utils::max(a1_y1, a2_y1); - let x2 = utils::min(a1_x2, a2_x2); - let y2 = utils::min(a1_y2, a2_y2); - let (iou, union) = if x2 < x1 || y2 < y1 { - (utils::ZERO, area1 + area2) - } else { - let intersection = (x2 - x1) * (y2 - y1); - let intersection = intersection.to_f64().unwrap(); - let intersection = utils::min(intersection, utils::min(area1, area2)); - let union = area1 + area2 - intersection; - (intersection / union, union) - }; - // Calculate the enclosing box (C) coordinates - let c_x1 = utils::min(a1_x1, a2_x1); - let c_y1 = utils::min(a1_y1, a2_y1); - let c_x2 = utils::max(a1_x2, a2_x2); - let c_y2 = utils::max(a1_y2, a2_y2); - // Calculate the area of the enclosing box (C) - let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); - let c_area = c_area.to_f64().unwrap(); - let giou = iou - ((c_area - union) / c_area); +// let x1 = utils::max(a1_x1, a2_x1); +// let y1 = utils::max(a1_y1, a2_y1); +// let x2 = utils::min(a1_x2, a2_x2); +// let y2 = utils::min(a1_y2, a2_y2); +// let (iou, union) = if x2 < x1 || y2 < y1 { +// (utils::ZERO, area1 + area2) +// } else { +// let intersection = (x2 - x1) * (y2 - y1); +// let intersection = intersection.to_f64().unwrap(); +// let intersection = utils::min(intersection, utils::min(area1, area2)); +// let union = area1 + area2 - intersection + utils::EPS; +// (intersection / union, union) +// }; +// // Calculate the enclosing box (C) coordinates +// let c_x1 = utils::min(a1_x1, a2_x1); +// let c_y1 = utils::min(a1_y1, a2_y1); +// let c_x2 = utils::max(a1_x2, a2_x2); +// let c_y2 = utils::max(a1_y2, a2_y2); +// // Calculate the area of the enclosing box (C) +// let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); +// let c_area = c_area.to_f64().unwrap(); +// let giou = iou - ((c_area - union) / c_area); - *d = utils::ONE - giou; - }); - }); +// *d = utils::ONE - giou; +// }); +// }); - giou_matrix -} +// giou_matrix +// } -/// Calculates the rotated Generalized IoU (Giou) distance between two sets of rotated bounding boxes. -/// -/// Given two sets of rotated bounding boxes represented by `boxes1` and `boxes2`, this function -/// computes the rotated Giou distance matrix between them. The rotated Giou distance is a measure -/// of dissimilarity between two rotated bounding boxes, taking into account both their overlap -/// and the encompassing area. -/// -/// # Arguments -/// -/// * `boxes1` - A reference to a 2D array (Array2) containing the parameters of the first set of rotated bounding boxes. -/// Each row of `boxes1` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle]. -/// -/// * `boxes2` - A reference to a 2D array (Array2) containing the parameters of the second set of rotated bounding boxes. -/// Each row of `boxes2` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle]. -/// -/// # Returns -/// -/// A 2D array (Array2) representing the rotated Giou distance matrix between the input sets of rotated bounding boxes. -/// The element at position (i, j) in the matrix represents the rotated Giou distance between the i-th box in `boxes1` and -/// the j-th box in `boxes2`. -/// -pub fn rotated_giou_distance<'a, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// /// Calculates the rotated Generalized IoU (Giou) distance between two sets of rotated bounding boxes. +// /// +// /// Given two sets of rotated bounding boxes represented by `boxes1` and `boxes2`, this function +// /// computes the rotated Giou distance matrix between them. The rotated Giou distance is a measure +// /// of dissimilarity between two rotated bounding boxes, taking into account both their overlap +// /// and the encompassing area. +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A reference to a 2D array (Array2) containing the parameters of the first set of rotated bounding boxes. +// /// Each row of `boxes1` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle]. +// /// +// /// * `boxes2` - A reference to a 2D array (Array2) containing the parameters of the second set of rotated bounding boxes. +// /// Each row of `boxes2` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle]. +// /// +// /// # Returns +// /// +// /// A 2D array (Array2) representing the rotated Giou distance matrix between the input sets of rotated bounding boxes. +// /// The element at position (i, j) in the matrix represents the rotated Giou distance between the i-th box in `boxes1` and +// /// the j-th box in `boxes2`. +// /// +// pub fn rotated_giou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); - let areas1 = rotated_box_areas(&boxes1); - let areas2 = rotated_box_areas(&boxes2); +// let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); +// let areas1 = rotated_box_areas(&boxes1); +// let areas2 = rotated_box_areas(&boxes2); - let boxes1_rects: Vec = boxes1 - .rows() - .into_iter() - .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) - .collect(); - let boxes2_rects: Vec = boxes2 - .rows() - .into_iter() - .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) - .collect(); - let boxes1_bounding_rects: Vec> = boxes1_rects - .iter() - .enumerate() - .map(|(idx, rect)| { - let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); - utils::Bbox { - index: idx, - x1: min_x, - y1: min_y, - x2: max_x, - y2: max_y, - } - }) - .collect(); - let boxes2_bounding_rects: Vec> = boxes2_rects - .iter() - .enumerate() - .map(|(idx, rect)| { - let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); - utils::Bbox { - index: idx, - x1: min_x, - y1: min_y, - x2: max_x, - y2: max_y, - } - }) - .collect(); +// let boxes1_rects: Vec = boxes1 +// .rows() +// .into_iter() +// .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) +// .collect(); +// let boxes2_rects: Vec = boxes2 +// .rows() +// .into_iter() +// .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) +// .collect(); +// let boxes1_bounding_rects: Vec> = boxes1_rects +// .iter() +// .enumerate() +// .map(|(idx, rect)| { +// let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); +// utils::Bbox { +// index: idx, +// x1: min_x, +// y1: min_y, +// x2: max_x, +// y2: max_y, +// } +// }) +// .collect(); +// let boxes2_bounding_rects: Vec> = boxes2_rects +// .iter() +// .enumerate() +// .map(|(idx, rect)| { +// let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); +// utils::Bbox { +// index: idx, +// x1: min_x, +// y1: min_y, +// x2: max_x, +// y2: max_y, +// } +// }) +// .collect(); - let box1_rtree: RTree> = RTree::bulk_load(boxes1_bounding_rects); - let box2_rtree: RTree> = RTree::bulk_load(boxes2_bounding_rects); +// let box1_rtree: RTree> = RTree::bulk_load(boxes1_bounding_rects); +// let box2_rtree: RTree> = RTree::bulk_load(boxes2_bounding_rects); - for (box1, box2) in box1_rtree.intersection_candidates_with_other_tree(&box2_rtree) { - let area1 = areas1[box1.index]; - let area2 = areas2[box2.index]; - let rect1 = boxes1_rects[box1.index]; - let rect2 = boxes2_rects[box2.index]; - let intersection = intersection_area(&rect1, &rect2); - let union = area1 + area2 - intersection; - // Calculate the enclosing box (C) coordinates - let c_x1 = utils::min(box1.x1, box2.x1); - let c_y1 = utils::min(box1.y1, box2.y1); - let c_x2 = utils::max(box1.x2, box2.x2); - let c_y2 = utils::max(box1.y2, box2.y2); - let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); - let c_area = c_area.to_f64().unwrap(); - iou_matrix[[box1.index, box2.index]] = intersection / union - ((c_area - union) / c_area); - } +// for (box1, box2) in box1_rtree.intersection_candidates_with_other_tree(&box2_rtree) { +// let area1 = areas1[box1.index]; +// let area2 = areas2[box2.index]; +// let rect1 = boxes1_rects[box1.index]; +// let rect2 = boxes2_rects[box2.index]; +// let intersection = intersection_area(&rect1, &rect2); +// let union = area1 + area2 - intersection + utils::EPS; +// // Calculate the enclosing box (C) coordinates +// let c_x1 = utils::min(box1.x1, box2.x1); +// let c_y1 = utils::min(box1.y1, box2.y1); +// let c_x2 = utils::max(box1.x2, box2.x2); +// let c_y2 = utils::max(box1.y2, box2.y2); +// let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); +// let c_area = c_area.to_f64().unwrap(); +// iou_matrix[[box1.index, box2.index]] = intersection / union - ((c_area - union) / c_area); +// } - return iou_matrix; -} +// return iou_matrix; +// } -#[cfg(test)] -mod tests { - use ndarray::arr2; +// #[cfg(test)] +// mod tests { +// use ndarray::arr2; - use super::*; +// use super::*; - #[test] - fn test_giou() { - let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0], [1.0, 1.0, 4.0, 4.0]]); - let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0], [3.0, 3.0, 6.0, 6.0]]); +// #[test] +// fn test_giou() { +// let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0], [1.0, 1.0, 4.0, 4.0]]); +// let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0], [3.0, 3.0, 6.0, 6.0]]); - let giou_matrix = giou_distance(&boxes1, &boxes2); - let parallel_giou_matrix = parallel_giou_distance(&boxes1, &boxes2); - assert_eq!(giou_matrix[[0, 0]], 1.2611764705882353); - assert_eq!(giou_matrix[[0, 1]], 1.5); - assert_eq!(giou_matrix[[1, 0]], 0.8392857142857143); - assert_eq!(giou_matrix[[1, 1]], 1.2611764705882353); - assert_eq!(giou_matrix, parallel_giou_matrix); - } +// let giou_matrix = giou_distance(&boxes1, &boxes2); +// let parallel_giou_matrix = parallel_giou_distance(&boxes1, &boxes2); +// assert_eq!(giou_matrix[[0, 0]], 1.2611764705882353); +// assert_eq!(giou_matrix[[0, 1]], 1.5); +// assert_eq!(giou_matrix[[1, 0]], 0.8392857142857143); +// assert_eq!(giou_matrix[[1, 1]], 1.2611764705882353); +// assert_eq!(giou_matrix, parallel_giou_matrix); +// } - #[test] - fn test_rotated_giou() { - let boxes1 = arr2(&[[5.0, 5.0, 2.0, 2.0, 0.0]]); - let boxes2 = arr2(&[[4.0, 4.0, 2.0, 2.0, 0.0]]); - let rotated_iou_distance_result = rotated_giou_distance(&boxes1, &boxes2); - assert_eq!(rotated_iou_distance_result, arr2(&[[-0.07936507936507936]])); - } -} +// #[test] +// fn test_rotated_giou() { +// let boxes1 = arr2(&[[5.0, 5.0, 2.0, 2.0, 0.0]]); +// let boxes2 = arr2(&[[4.0, 4.0, 2.0, 2.0, 0.0]]); +// let rotated_iou_distance_result = rotated_giou_distance(&boxes1, &boxes2); +// assert_eq!(rotated_iou_distance_result, arr2(&[[-0.07936507936507936]])); +// } +// } diff --git a/powerboxesrs/src/iou.rs b/powerboxesrs/src/iou.rs index 2547ae8..8cd0d6f 100644 --- a/powerboxesrs/src/iou.rs +++ b/powerboxesrs/src/iou.rs @@ -1,290 +1,279 @@ -use crate::{ - boxes::{self, rotated_box_areas}, - rotation::{intersection_area, minimal_bounding_rect, Rect}, - utils, -}; -use ndarray::{Array2, ArrayView2, Zip}; -use num_traits::{Num, ToPrimitive}; -use rstar::RTree; +// use crate::{ +// boxes::{self, rotated_box_areas}, +// rotation::{intersection_area, minimal_bounding_rect, Rect}, +// utils, +// }; +// use ndarray::{Array2, Zip}; +// use num_traits::{Num, ToPrimitive}; +// use rstar::RTree; -/// Calculates the intersection over union (IoU) distance between two sets of bounding boxes. -/// -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. -/// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. -/// -/// # Returns -/// -/// A 2D array of shape (N, M) representing the IoU distance between each pair of bounding boxes. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::iou::iou_distance; -/// -/// let boxes1 = array![[0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0]]; -/// let boxes2 = array![[0.5, 0.5, 1.5, 1.5], [2.5, 2.5, 3.5, 3.5]]; -/// let iou = iou_distance(&boxes1, &boxes2); -/// assert_eq!(iou, array![[0.8571428571428572, 1.],[1., 0.8571428571428572]]); -/// ``` -pub fn iou_distance<'a, N, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Copy + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// /// Calculates the intersection over union (IoU) distance between two sets of bounding boxes. +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. +// /// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. +// /// +// /// # Returns +// /// +// /// A 2D array of shape (N, M) representing the IoU distance between each pair of bounding boxes. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::array; +// /// use powerboxesrs::iou::iou_distance; +// /// +// /// let boxes1 = array![[0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0]]; +// /// let boxes2 = array![[0.5, 0.5, 1.5, 1.5], [2.5, 2.5, 3.5, 3.5]]; +// /// let iou = iou_distance(&boxes1, &boxes2); +// /// assert_eq!(iou, array![[0.8571428571428572, 1.],[1., 0.8571428571428572]]); +// /// ``` +// pub fn iou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let mut iou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::box_areas(&boxes1); - let areas_boxes2 = boxes::box_areas(&boxes2); - for (i, a1) in boxes1.outer_iter().enumerate() { - let a1_x1 = a1[0]; - let a1_y1 = a1[1]; - let a1_x2 = a1[2]; - let a1_y2 = a1[3]; - let area1 = areas_boxes1[i]; +// let mut iou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::box_areas(&boxes1); +// let areas_boxes2 = boxes::box_areas(&boxes2); +// for (i, a1) in boxes1.outer_iter().enumerate() { +// let a1_x1 = a1[0]; +// let a1_y1 = a1[1]; +// let a1_x2 = a1[2]; +// let a1_y2 = a1[3]; +// let area1 = areas_boxes1[i]; - for (j, a2) in boxes2.outer_iter().enumerate() { - let a2_x1 = a2[0]; - let a2_y1 = a2[1]; - let a2_x2 = a2[2]; - let a2_y2 = a2[3]; - let area2 = areas_boxes2[j]; - let x1 = utils::max(a1_x1, a2_x1); - let y1 = utils::max(a1_y1, a2_y1); - let x2 = utils::min(a1_x2, a2_x2); - let y2 = utils::min(a1_y2, a2_y2); - if x2 < x1 || y2 < y1 { - iou_matrix[[i, j]] = utils::ONE; - continue; - } - let intersection = (x2 - x1) * (y2 - y1); - let intersection = intersection.to_f64().unwrap(); - let intersection = utils::min(intersection, utils::min(area1, area2)); - iou_matrix[[i, j]] = utils::ONE - (intersection / (area1 + area2 - intersection)); - } - } +// for (j, a2) in boxes2.outer_iter().enumerate() { +// let a2_x1 = a2[0]; +// let a2_y1 = a2[1]; +// let a2_x2 = a2[2]; +// let a2_y2 = a2[3]; +// let area2 = areas_boxes2[j]; +// let x1 = utils::max(a1_x1, a2_x1); +// let y1 = utils::max(a1_y1, a2_y1); +// let x2 = utils::min(a1_x2, a2_x2); +// let y2 = utils::min(a1_y2, a2_y2); +// if x2 < x1 || y2 < y1 { +// iou_matrix[[i, j]] = utils::ONE; +// continue; +// } +// let intersection = (x2 - x1) * (y2 - y1); +// let intersection = intersection.to_f64().unwrap(); +// let intersection = utils::min(intersection, utils::min(area1, area2)); +// iou_matrix[[i, j]] = +// utils::ONE - (intersection / (area1 + area2 - intersection + utils::EPS)); +// } +// } - iou_matrix -} +// iou_matrix +// } -/// Calculates the intersection over union (IoU) distance between two sets of bounding boxes. -/// This function uses rayon to parallelize the computation, which can be faster than the -/// non-parallelized version for large numbers of boxes. -/// -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. -/// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. -/// -/// # Returns -/// -/// A 2D array of shape (N, M) representing the IoU distance between each pair of bounding boxes. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::iou::parallel_iou_distance; -/// -/// let boxes1 = array![[0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0]]; -/// let boxes2 = array![[0.5, 0.5, 1.5, 1.5], [2.5, 2.5, 3.5, 3.5]]; -/// let iou = parallel_iou_distance(&boxes1, &boxes2); -/// assert_eq!(iou, array![[0.8571428571428572, 1.],[1., 0.8571428571428572]]); -/// ``` -pub fn parallel_iou_distance<'a, N, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Send + Sync + Copy + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// /// Calculates the intersection over union (IoU) distance between two sets of bounding boxes. +// /// This function uses rayon to parallelize the computation, which can be faster than the +// /// non-parallelized version for large numbers of boxes. +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape (N, 4) representing N bounding boxes in xyxy format. +// /// * `boxes2` - A 2D array of shape (M, 4) representing M bounding boxes in xyxy format. +// /// +// /// # Returns +// /// +// /// A 2D array of shape (N, M) representing the IoU distance between each pair of bounding boxes. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::array; +// /// use powerboxesrs::iou::parallel_iou_distance; +// /// +// /// let boxes1 = array![[0.0, 0.0, 1.0, 1.0], [2.0, 2.0, 3.0, 3.0]]; +// /// let boxes2 = array![[0.5, 0.5, 1.5, 1.5], [2.5, 2.5, 3.5, 3.5]]; +// /// let iou = parallel_iou_distance(&boxes1, &boxes2); +// /// assert_eq!(iou, array![[0.8571428571428572, 1.],[1., 0.8571428571428572]]); +// /// ``` +// pub fn parallel_iou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy + Clone + Sync + Send, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let mut iou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::box_areas(&boxes1); - let areas_boxes2 = boxes::box_areas(&boxes2); - Zip::indexed(iou_matrix.rows_mut()).par_for_each(|i, mut row| { - let a1 = boxes1.row(i); - let a1_x1 = a1[0]; - let a1_y1 = a1[1]; - let a1_x2 = a1[2]; - let a1_y2 = a1[3]; - let area1 = areas_boxes1[i]; - row.indexed_iter_mut() - .zip(boxes2.rows()) - .for_each(|((j, d), box2)| { - let a2_x1 = box2[0]; - let a2_y1 = box2[1]; - let a2_x2 = box2[2]; - let a2_y2 = box2[3]; - let area2 = areas_boxes2[j]; +// let mut iou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::box_areas(&boxes1); +// let areas_boxes2 = boxes::box_areas(&boxes2); +// Zip::indexed(iou_matrix.rows_mut()).par_for_each(|i, mut row| { +// let a1 = boxes1.row(i); +// let a1_x1 = a1[0]; +// let a1_y1 = a1[1]; +// let a1_x2 = a1[2]; +// let a1_y2 = a1[3]; +// let area1 = areas_boxes1[i]; +// row.indexed_iter_mut() +// .zip(boxes2.rows()) +// .for_each(|((j, d), box2)| { +// let a2_x1 = box2[0]; +// let a2_y1 = box2[1]; +// let a2_x2 = box2[2]; +// let a2_y2 = box2[3]; +// let area2 = areas_boxes2[j]; - let x1 = utils::max(a1_x1, a2_x1); - let y1 = utils::max(a1_y1, a2_y1); - let x2 = utils::min(a1_x2, a2_x2); - let y2 = utils::min(a1_y2, a2_y2); - if x2 < x1 || y2 < y1 { - *d = utils::ONE; - } else { - let intersection = (x2 - x1) * (y2 - y1); - let intersection = intersection.to_f64().unwrap(); - let intersection = utils::min(intersection, utils::min(area1, area2)); - *d = 1. - (intersection / (area1 + area2 - intersection)); - } - }); - }); +// let x1 = utils::max(a1_x1, a2_x1); +// let y1 = utils::max(a1_y1, a2_y1); +// let x2 = utils::min(a1_x2, a2_x2); +// let y2 = utils::min(a1_y2, a2_y2); +// if x2 < x1 || y2 < y1 { +// *d = utils::ONE; +// } else { +// let intersection = (x2 - x1) * (y2 - y1); +// let intersection = intersection.to_f64().unwrap(); +// let intersection = utils::min(intersection, utils::min(area1, area2)); +// *d = 1. - (intersection / (area1 + area2 - intersection + utils::EPS)); +// } +// }); +// }); - return iou_matrix; -} +// return iou_matrix; +// } -/// Calculates the Rotated Intersection over Union (IoU) distance matrix between two sets of rotated bounding boxes. -/// -/// -/// # Arguments -/// * `boxes1` - A 2D array representing the first set of rotated bounding boxes. Each row contains -/// the parameters (center_x, center_y, width, height, angle) of a rotated box. -/// * `boxes2` - A 2D array representing the second set of rotated bounding boxes. Each row contains -/// the parameters (center_x, center_y, width, height, angle) of a rotated box. -/// -/// # Returns -/// A 2D array containing the Rotated IoU distance matrix. The element at position (i, j) represents -/// the Rotated IoU distance between the i-th box in `boxes1` and the j-th box in `boxes2`. -pub fn rotated_iou_distance<'a, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); +// /// Calculates the Rotated Intersection over Union (IoU) distance matrix between two sets of rotated bounding boxes. +// /// +// /// +// /// # Arguments +// /// * `boxes1` - A 2D array representing the first set of rotated bounding boxes. Each row contains +// /// the parameters (center_x, center_y, width, height, angle) of a rotated box. +// /// * `boxes2` - A 2D array representing the second set of rotated bounding boxes. Each row contains +// /// the parameters (center_x, center_y, width, height, angle) of a rotated box. +// /// +// /// # Returns +// /// A 2D array containing the Rotated IoU distance matrix. The element at position (i, j) represents +// /// the Rotated IoU distance between the i-th box in `boxes1` and the j-th box in `boxes2`. +// pub fn rotated_iou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); +// let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); +// let areas1 = rotated_box_areas(&boxes1); +// let areas2 = rotated_box_areas(&boxes2); - let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); - let areas1 = rotated_box_areas(&boxes1); - let areas2 = rotated_box_areas(&boxes2); +// let boxes1_rects: Vec = boxes1 +// .rows() +// .into_iter() +// .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) +// .collect(); +// let boxes2_rects: Vec = boxes2 +// .rows() +// .into_iter() +// .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) +// .collect(); +// let boxes1_bounding_rects: Vec> = boxes1_rects +// .iter() +// .enumerate() +// .map(|(idx, rect)| { +// let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); +// utils::Bbox { +// index: idx, +// x1: min_x, +// y1: min_y, +// x2: max_x, +// y2: max_y, +// } +// }) +// .collect(); +// let boxes2_bounding_rects: Vec> = boxes2_rects +// .iter() +// .enumerate() +// .map(|(idx, rect)| { +// let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); +// utils::Bbox { +// index: idx, +// x1: min_x, +// y1: min_y, +// x2: max_x, +// y2: max_y, +// } +// }) +// .collect(); - let boxes1_rects: Vec = boxes1 - .rows() - .into_iter() - .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) - .collect(); - let boxes2_rects: Vec = boxes2 - .rows() - .into_iter() - .map(|row| Rect::new(row[0], row[1], row[2], row[3], row[4])) - .collect(); - let boxes1_bounding_rects: Vec> = boxes1_rects - .iter() - .enumerate() - .map(|(idx, rect)| { - let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); - utils::Bbox { - index: idx, - x1: min_x, - y1: min_y, - x2: max_x, - y2: max_y, - } - }) - .collect(); - let boxes2_bounding_rects: Vec> = boxes2_rects - .iter() - .enumerate() - .map(|(idx, rect)| { - let (min_x, min_y, max_x, max_y) = minimal_bounding_rect(&rect.points()); - utils::Bbox { - index: idx, - x1: min_x, - y1: min_y, - x2: max_x, - y2: max_y, - } - }) - .collect(); +// let box1_rtree: RTree> = RTree::bulk_load(boxes1_bounding_rects); +// let box2_rtree: RTree> = RTree::bulk_load(boxes2_bounding_rects); - let box1_rtree: RTree> = RTree::bulk_load(boxes1_bounding_rects); - let box2_rtree: RTree> = RTree::bulk_load(boxes2_bounding_rects); +// for (box1, box2) in box1_rtree.intersection_candidates_with_other_tree(&box2_rtree) { +// let area1 = areas1[box1.index]; +// let area2 = areas2[box2.index]; +// let intersection = intersection_area(&boxes1_rects[box1.index], &boxes2_rects[box2.index]); +// let union = area1 + area2 - intersection + utils::EPS; +// iou_matrix[[box1.index, box2.index]] = utils::ONE - intersection / union; +// } - for (box1, box2) in box1_rtree.intersection_candidates_with_other_tree(&box2_rtree) { - let area1 = areas1[box1.index]; - let area2 = areas2[box2.index]; - let intersection = intersection_area(&boxes1_rects[box1.index], &boxes2_rects[box2.index]); - let union = area1 + area2 - intersection; - iou_matrix[[box1.index, box2.index]] = utils::ONE - intersection / union; - } +// return iou_matrix; +// } - return iou_matrix; -} +// #[cfg(test)] +// mod tests { +// use ndarray::arr2; -#[cfg(test)] -mod tests { - use ndarray::arr2; +// use super::*; - use super::*; +// #[test] +// fn test_iou_distance() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); +// let iou_distance_result = iou_distance(&boxes1, &boxes2); +// let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); - #[test] - fn test_iou_distance() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); - let iou_distance_result = iou_distance(&boxes1, &boxes2); - let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); +// assert_eq!(iou_distance_result, arr2(&[[0.8571428571428572]])); +// assert_eq!(parallel_iou_distance_result, arr2(&[[0.8571428571428572]])); +// } - assert_eq!(iou_distance_result, arr2(&[[0.8571428571428572]])); - assert_eq!(parallel_iou_distance_result, arr2(&[[0.8571428571428572]])); - } +// #[test] +// fn test_iou_distance2() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); +// let iou_distance_result = iou_distance(&boxes1, &boxes2); +// let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); +// assert_eq!(iou_distance_result, arr2(&[[1.0]])); +// assert_eq!(parallel_iou_distance_result, arr2(&[[1.0]])); +// } - #[test] - fn test_iou_distance2() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); - let iou_distance_result = iou_distance(&boxes1, &boxes2); - let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); - assert_eq!(iou_distance_result, arr2(&[[1.0]])); - assert_eq!(parallel_iou_distance_result, arr2(&[[1.0]])); - } +// #[test] +// fn test_iou_distance3() { +// let boxes1 = arr2(&[[2.5, 2.5, 3.0, 3.0]]); +// let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); +// let iou_distance_result = iou_distance(&boxes1, &boxes2); +// let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); +// assert_eq!(iou_distance_result, arr2(&[[0.9375]])); +// assert_eq!(parallel_iou_distance_result, arr2(&[[0.9375]])); +// } - #[test] - fn test_iou_distance3() { - let boxes1 = arr2(&[[2.5, 2.5, 3.0, 3.0]]); - let boxes2 = arr2(&[[1.0, 1.0, 3.0, 3.0]]); - let iou_distance_result = iou_distance(&boxes1, &boxes2); - let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); - assert_eq!(iou_distance_result, arr2(&[[0.9375]])); - assert_eq!(parallel_iou_distance_result, arr2(&[[0.9375]])); - } +// #[test] +// fn test_iou_distance4() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let iou_distance_result = iou_distance(&boxes1, &boxes2); +// let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); +// assert_eq!(iou_distance_result, arr2(&[[0.0]])); +// assert_eq!(parallel_iou_distance_result, arr2(&[[0.0]])); +// } - #[test] - fn test_iou_distance4() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let iou_distance_result = iou_distance(&boxes1, &boxes2); - let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); - assert_eq!(iou_distance_result, arr2(&[[0.0]])); - assert_eq!(parallel_iou_distance_result, arr2(&[[0.0]])); - } +// #[test] +// fn test_iou_distance5() { +// let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); +// let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); +// let iou_distance_result = iou_distance(&boxes1, &boxes2); +// let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); +// assert_eq!(iou_distance_result, arr2(&[[1.0]])); +// assert_eq!(parallel_iou_distance_result, arr2(&[[1.0]])); +// } - #[test] - fn test_iou_distance5() { - let boxes1 = arr2(&[[0.0, 0.0, 2.0, 2.0]]); - let boxes2 = arr2(&[[3.0, 3.0, 4.0, 4.0]]); - let iou_distance_result = iou_distance(&boxes1, &boxes2); - let parallel_iou_distance_result = parallel_iou_distance(&boxes1, &boxes2); - assert_eq!(iou_distance_result, arr2(&[[1.0]])); - assert_eq!(parallel_iou_distance_result, arr2(&[[1.0]])); - } - - #[test] - fn test_rotated_iou_distance() { - let boxes1 = arr2(&[[5.0, 5.0, 2.0, 2.0, 0.0]]); - let boxes2 = arr2(&[[4.0, 4.0, 2.0, 2.0, 0.0]]); - let rotated_iou_distance_result = rotated_iou_distance(&boxes1, &boxes2); - assert_eq!(rotated_iou_distance_result, arr2(&[[0.8571428571428572]])); - } -} +// #[test] +// fn test_rotated_iou_distance() { +// let boxes1 = arr2(&[[5.0, 5.0, 2.0, 2.0, 0.0]]); +// let boxes2 = arr2(&[[4.0, 4.0, 2.0, 2.0, 0.0]]); +// let rotated_iou_distance_result = rotated_iou_distance(&boxes1, &boxes2); +// assert_eq!(rotated_iou_distance_result, arr2(&[[0.8571428571428572]])); +// } +// } diff --git a/powerboxesrs/src/nms.rs b/powerboxesrs/src/nms.rs index 1506be7..0d9a08a 100644 --- a/powerboxesrs/src/nms.rs +++ b/powerboxesrs/src/nms.rs @@ -1,302 +1,302 @@ -// Largely inspired by lsnms: https://github.com/remydubois/lsnms -use std::cmp::Ordering; +// // Largely inspired by lsnms: https://github.com/remydubois/lsnms +// use std::cmp::Ordering; -use crate::utils; -use ndarray::{Array1, ArrayView1, ArrayView2, Axis}; -use num_traits::{Num, ToPrimitive}; -use rstar::{RTree, RTreeNum, AABB}; +// use crate::utils; +// use ndarray::{Array1, ArrayView1, ArrayView2, Axis}; +// use num_traits::{Num, ToPrimitive}; +// use rstar::{RTree, RTreeNum, AABB}; -#[inline(always)] -pub fn area(bx: N, by: N, bxx: N, byy: N) -> N -where - N: Num + PartialEq + PartialOrd + ToPrimitive, -{ - (bxx - bx) * (byy - by) -} +// #[inline(always)] +// pub fn area(bx: N, by: N, bxx: N, byy: N) -> N +// where +// N: Num + PartialEq + PartialOrd + ToPrimitive, +// { +// (bxx - bx) * (byy - by) +// } -/// Performs non-maximum suppression (NMS) on a set of bounding boxes using their scores and IoU. -/// # Arguments -/// -/// * `boxes` - A 2D array of shape `(num_boxes, 4)` representing the coordinates in xyxy format of the bounding boxes. -/// * `scores` - A 1D array of shape `(num_boxes,)` representing the scores of the bounding boxes. -/// * `iou_threshold` - A float representing the IoU threshold to use for filtering. -/// * `score_threshold` - A float representing the score threshold to use for filtering. -/// -/// # Returns -/// -/// A 1D array of shape `(num_boxes,)` representing the indices of the bounding boxes to keep. -/// -/// # Examples -/// -/// ``` -/// use ndarray::{arr2, Array1}; -/// use powerboxesrs::nms::nms; -/// -/// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); -/// let scores = Array1::from(vec![1.0, 1.0]); -/// let keep = nms(&boxes, &scores, 0.8, 0.0); -/// assert_eq!(keep, vec![0, 1]); -/// ``` -pub fn nms<'a, N, BA, SA>( - boxes: BA, - scores: SA, - iou_threshold: f64, - score_threshold: f64, -) -> Vec -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Copy + PartialEq + 'a, - BA: Into>, - SA: Into>, -{ - let boxes = boxes.into(); - let scores = scores.into(); - assert_eq!(boxes.nrows(), scores.len_of(Axis(0))); +// /// Performs non-maximum suppression (NMS) on a set of bounding boxes using their scores and IoU. +// /// # Arguments +// /// +// /// * `boxes` - A 2D array of shape `(num_boxes, 4)` representing the coordinates in xyxy format of the bounding boxes. +// /// * `scores` - A 1D array of shape `(num_boxes,)` representing the scores of the bounding boxes. +// /// * `iou_threshold` - A float representing the IoU threshold to use for filtering. +// /// * `score_threshold` - A float representing the score threshold to use for filtering. +// /// +// /// # Returns +// /// +// /// A 1D array of shape `(num_boxes,)` representing the indices of the bounding boxes to keep. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::{arr2, Array1}; +// /// use powerboxesrs::nms::nms; +// /// +// /// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); +// /// let scores = Array1::from(vec![1.0, 1.0]); +// /// let keep = nms(&boxes, &scores, 0.8, 0.0); +// /// assert_eq!(keep, vec![0, 1]); +// /// ``` +// pub fn nms<'a, N, BA, SA>( +// boxes: BA, +// scores: SA, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> Vec +// where +// N: Num + PartialEq + PartialOrd + ToPrimitive + Copy + PartialEq + 'a, +// BA: Into>, +// SA: Into>, +// { +// let boxes = boxes.into(); +// let scores = scores.into(); +// assert_eq!(boxes.nrows(), scores.len_of(Axis(0))); - let order: Vec = { - let mut indices: Vec<_> = if score_threshold > utils::ZERO { - // filter out boxes lower than score threshold - scores - .iter() - .enumerate() - .filter(|(_, &score)| score >= score_threshold) - .map(|(idx, _)| idx) - .collect() - } else { - (0..scores.len()).collect() - }; - // sort box indices by scores - indices.sort_unstable_by(|&a, &b| { - scores[b].partial_cmp(&scores[a]).unwrap_or(Ordering::Equal) - }); - indices - }; +// let order: Vec = { +// let mut indices: Vec<_> = if score_threshold > utils::ZERO { +// // filter out boxes lower than score threshold +// scores +// .iter() +// .enumerate() +// .filter(|(_, &score)| score >= score_threshold) +// .map(|(idx, _)| idx) +// .collect() +// } else { +// (0..scores.len()).collect() +// }; +// // sort box indices by scores +// indices.sort_unstable_by(|&a, &b| { +// scores[b].partial_cmp(&scores[a]).unwrap_or(Ordering::Equal) +// }); +// indices +// }; - let mut keep: Vec = Vec::new(); - let mut suppress = vec![false; order.len()]; +// let mut keep: Vec = Vec::new(); +// let mut suppress = vec![false; order.len()]; - for (i, &idx) in order.iter().enumerate() { - if suppress[i] { - continue; - } - keep.push(idx); - let box1 = boxes.row(idx); - let b1x = box1[0]; - let b1y = box1[1]; - let b1xx = box1[2]; - let b1yy = box1[3]; - let area1 = area(b1x, b1y, b1xx, b1yy); - for j in (i + 1)..order.len() { - if suppress[j] { - continue; - } - let box2 = boxes.row(order[j]); - let b2x = box2[0]; - let b2y = box2[1]; - let b2xx = box2[2]; - let b2yy = box2[3]; +// for (i, &idx) in order.iter().enumerate() { +// if suppress[i] { +// continue; +// } +// keep.push(idx); +// let box1 = boxes.row(idx); +// let b1x = box1[0]; +// let b1y = box1[1]; +// let b1xx = box1[2]; +// let b1yy = box1[3]; +// let area1 = area(b1x, b1y, b1xx, b1yy); +// for j in (i + 1)..order.len() { +// if suppress[j] { +// continue; +// } +// let box2 = boxes.row(order[j]); +// let b2x = box2[0]; +// let b2y = box2[1]; +// let b2xx = box2[2]; +// let b2yy = box2[3]; - // Intersection-over-union - let x = utils::max(b1x, b2x); - let y = utils::max(b1y, b2y); - let xx = utils::min(b1xx, b2xx); - let yy = utils::min(b1yy, b2yy); - if x > xx || y > yy { - // Boxes are not intersecting at all - continue; - }; - // Boxes are intersecting - let intersection: N = area(x, y, xx, yy); - let area2: N = area(b2x, b2y, b2xx, b2yy); - let union: N = area1 + area2 - intersection; - let iou: f64 = intersection.to_f64().unwrap() / union.to_f64().unwrap(); - if iou > iou_threshold { - suppress[j] = true; - } - } - } - keep -} +// // Intersection-over-union +// let x = utils::max(b1x, b2x); +// let y = utils::max(b1y, b2y); +// let xx = utils::min(b1xx, b2xx); +// let yy = utils::min(b1yy, b2yy); +// if x > xx || y > yy { +// // Boxes are not intersecting at all +// continue; +// }; +// // Boxes are intersecting +// let intersection: N = area(x, y, xx, yy); +// let area2: N = area(b2x, b2y, b2xx, b2yy); +// let union: N = area1 + area2 - intersection; +// let iou: f64 = intersection.to_f64().unwrap() / union.to_f64().unwrap(); +// if iou > iou_threshold { +// suppress[j] = true; +// } +// } +// } +// keep +// } -/// Performs non-maximum suppression (NMS) on a set of bounding using their score and IoU. -/// This function internally uses an RTree to speed up the computation. It is recommended to use this function -/// when the number of boxes is large. -/// The RTree implementation is based on the rstar crate. It allows to perform queries in O(log n) time. -/// -/// # Arguments -/// -/// * `boxes` - A 2D array of shape `(num_boxes, 4)` representing the coordinates in xyxy format of the bounding boxes. -/// * `scores` - A 1D array of shape `(num_boxes,)` representing the scores of the bounding boxes. -/// * `iou_threshold` - A float representing the IoU threshold to use for filtering. -/// * `score_threshold` - A float representing the score threshold to use for filtering. -/// -/// # Returns -/// -/// A 1D array of shape `(num_boxes,)` representing the indices of the bounding boxes to keep. -/// -/// # Examples -/// -/// ``` -/// use ndarray::{arr2, Array1}; -/// use powerboxesrs::nms::rtree_nms; -/// -/// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); -/// let scores = Array1::from(vec![1.0, 1.0]); -/// let keep = rtree_nms(&boxes, &scores, 0.8, 0.0); -/// assert_eq!(keep, vec![0, 1]); -/// ``` -pub fn rtree_nms<'a, N, BA, SA>( - boxes: BA, - scores: SA, - iou_threshold: f64, - score_threshold: f64, -) -> Vec -where - N: RTreeNum + PartialEq + PartialOrd + ToPrimitive + Copy + PartialEq + Send + Sync + 'a, - BA: Into>, - SA: Into>, -{ - let scores = scores.into(); - let boxes = boxes.into(); - let order: Vec = { - let mut indices: Vec<_> = if score_threshold > utils::ZERO { - // filter out boxes lower than score threshold - scores - .iter() - .enumerate() - .filter(|(_, &score)| score >= score_threshold) - .map(|(idx, _)| idx) - .collect() - } else { - (0..scores.len()).collect() - }; - // sort box indices by scores - indices.sort_unstable_by(|&a, &b| { - scores[b].partial_cmp(&scores[a]).unwrap_or(Ordering::Equal) - }); - indices - }; +// /// Performs non-maximum suppression (NMS) on a set of bounding using their score and IoU. +// /// This function internally uses an RTree to speed up the computation. It is recommended to use this function +// /// when the number of boxes is large. +// /// The RTree implementation is based on the rstar crate. It allows to perform queries in O(log n) time. +// /// +// /// # Arguments +// /// +// /// * `boxes` - A 2D array of shape `(num_boxes, 4)` representing the coordinates in xyxy format of the bounding boxes. +// /// * `scores` - A 1D array of shape `(num_boxes,)` representing the scores of the bounding boxes. +// /// * `iou_threshold` - A float representing the IoU threshold to use for filtering. +// /// * `score_threshold` - A float representing the score threshold to use for filtering. +// /// +// /// # Returns +// /// +// /// A 1D array of shape `(num_boxes,)` representing the indices of the bounding boxes to keep. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::{arr2, Array1}; +// /// use powerboxesrs::nms::rtree_nms; +// /// +// /// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); +// /// let scores = Array1::from(vec![1.0, 1.0]); +// /// let keep = rtree_nms(&boxes, &scores, 0.8, 0.0); +// /// assert_eq!(keep, vec![0, 1]); +// /// ``` +// pub fn rtree_nms<'a, N, BA, SA>( +// boxes: BA, +// scores: SA, +// iou_threshold: f64, +// score_threshold: f64, +// ) -> Vec +// where +// N: RTreeNum + PartialEq + PartialOrd + ToPrimitive + Copy + PartialEq + Send + Sync + 'a, +// BA: Into>, +// SA: Into>, +// { +// let scores = scores.into(); +// let boxes = boxes.into(); +// let order: Vec = { +// let mut indices: Vec<_> = if score_threshold > utils::ZERO { +// // filter out boxes lower than score threshold +// scores +// .iter() +// .enumerate() +// .filter(|(_, &score)| score >= score_threshold) +// .map(|(idx, _)| idx) +// .collect() +// } else { +// (0..scores.len()).collect() +// }; +// // sort box indices by scores +// indices.sort_unstable_by(|&a, &b| { +// scores[b].partial_cmp(&scores[a]).unwrap_or(Ordering::Equal) +// }); +// indices +// }; - let mut keep: Vec = Vec::new(); - let mut suppress = Array1::from_elem(scores.len(), false); +// let mut keep: Vec = Vec::new(); +// let mut suppress = Array1::from_elem(scores.len(), false); - // build rtree - let rtree: RTree> = RTree::bulk_load( - order - .iter() - .map(|&idx| { - let box_ = boxes.row(idx); - utils::Bbox { - x1: box_[0], - y1: box_[1], - x2: box_[2], - y2: box_[3], - index: idx, - } - }) - .collect(), - ); - for i in 0..order.len() { - let idx = order[i]; - if suppress[i] { - continue; - } - keep.push(idx); - let box1 = boxes.row(idx); - let b1x = box1[0]; - let b1y = box1[1]; - let b1xx = box1[2]; - let b1yy = box1[3]; - let area1 = area(b1x, b1y, b1xx, b1yy); - for bbox in - rtree.locate_in_envelope_intersecting(&AABB::from_corners([b1x, b1y], [b1xx, b1yy])) - { - let idx_j = bbox.index; - if suppress[idx_j] { - continue; - } - let box2 = boxes.row(idx_j); - let b2x = box2[0]; - let b2y = box2[1]; - let b2xx = box2[2]; - let b2yy = box2[3]; +// // build rtree +// let rtree: RTree> = RTree::bulk_lo´ad( +// order +// .iter() +// .map(|&idx| { +// let box_ = boxes.row(idx); +// utils::Bbox { +// x1: box_[0], +// y1: box_[1], +// x2: box_[2], +// y2: box_[3], +// index: idx, +// } +// }) +// .collect(), +// ); +// for i in 0..order.len() { +// let idx = order[i]; +// if suppress[i] { +// continue; +// } +// keep.push(idx); +// let box1 = boxes.row(idx); +// let b1x = box1[0]; +// let b1y = box1[1]; +// let b1xx = box1[2]; +// let b1yy = box1[3]; +// let area1 = area(b1x, b1y, b1xx, b1yy); +// for bbox in +// rtree.locate_in_envelope_intersecting(&AABB::from_corners([b1x, b1y], [b1xx, b1yy])) +// { +// let idx_j = bbox.index; +// if suppress[idx_j] { +// continue; +// } +// let box2 = boxes.row(idx_j); +// let b2x = box2[0]; +// let b2y = box2[1]; +// let b2xx = box2[2]; +// let b2yy = box2[3]; - // Intersection-over-union - let x = utils::max(b1x, b2x); - let y = utils::max(b1y, b2y); - let xx = utils::min(b1xx, b2xx); - let yy = utils::min(b1yy, b2yy); - if x > xx || y > yy { - // Boxes are not intersecting at all - continue; - }; - // Boxes are intersecting - let intersection: N = area(x, y, xx, yy); - let area2: N = area(b2x, b2y, b2xx, b2yy); - let union: N = area1 + area2 - intersection; - let iou: f64 = intersection.to_f64().unwrap() / union.to_f64().unwrap(); - if iou > iou_threshold { - suppress[idx_j] = true; - } - } - } - keep -} +// // Intersection-over-union +// let x = utils::max(b1x, b2x); +// let y = utils::max(b1y, b2y); +// let xx = utils::min(b1xx, b2xx); +// let yy = utils::min(b1yy, b2yy); +// if x > xx || y > yy { +// // Boxes are not intersecting at all +// continue; +// }; +// // Boxes are intersecting +// let intersection: N = area(x, y, xx, yy); +// let area2: N = area(b2x, b2y, b2xx, b2yy); +// let union: N = area1 + area2 - intersection; +// let iou: f64 = intersection.to_f64().unwrap() / union.to_f64().unwrap(); +// if iou > iou_threshold { +// suppress[idx_j] = true; +// } +// } +// } +// keep +// } -#[cfg(test)] -mod tests { - use ndarray::{arr2, Array1}; +// #[cfg(test)] +// mod tests { +// use ndarray::{arr2, Array1}; - use super::*; +// use super::*; - #[test] - fn test_nms_normal_case() { - let boxes = arr2(&[ - [184.68927598, 850.65932762, 201.47437531, 866.02327337], - [185.68927598, 851.65932762, 200.47437531, 865.02327337], - [875.33814954, 706.46958933, 902.14487263, 737.14697788], - [874.33814954, 703.46958933, 901.14487263, 732.14697788], - [277.71729109, 744.81869575, 308.13768447, 777.11413807], - [275.71729109, 740.81869575, 310.13768447, 765.11413807], - ]); - let scores = Array1::from(vec![0.9, 0.8, 0.7, 0.6, 0.5, 0.4]); - let keep = nms(&boxes, &scores, 0.5, 0.0); - let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 0.0); +// #[test] +// fn test_nms_normal_case() { +// let boxes = arr2(&[ +// [184.68927598, 850.65932762, 201.47437531, 866.02327337], +// [185.68927598, 851.65932762, 200.47437531, 865.02327337], +// [875.33814954, 706.46958933, 902.14487263, 737.14697788], +// [874.33814954, 703.46958933, 901.14487263, 732.14697788], +// [277.71729109, 744.81869575, 308.13768447, 777.11413807], +// [275.71729109, 740.81869575, 310.13768447, 765.11413807], +// ]); +// let scores = Array1::from(vec![0.9, 0.8, 0.7, 0.6, 0.5, 0.4]); +// let keep = nms(&boxes, &scores, 0.5, 0.0); +// let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 0.0); - assert_eq!(keep, vec![0, 2, 4]); - assert_eq!(keep_rtree, keep); - } +// assert_eq!(keep, vec![0, 2, 4]); +// assert_eq!(keep_rtree, keep); +// } - #[test] - fn test_nms_empty_case() { - // empty case - let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); - let scores = Array1::from(vec![0.0, 0.0]); - let keep = nms(&boxes, &scores, 0.5, 1.0); - let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 1.0); +// #[test] +// fn test_nms_empty_case() { +// // empty case +// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); +// let scores = Array1::from(vec![0.0, 0.0]); +// let keep = nms(&boxes, &scores, 0.5, 1.0); +// let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 1.0); - assert_eq!(keep, vec![]); - assert_eq!(keep, keep_rtree) - } +// assert_eq!(keep, vec![]); +// assert_eq!(keep, keep_rtree) +// } - #[test] - fn test_nms_score_threshold() { - // score threshold - let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); - let scores = Array1::from(vec![0.0, 1.0]); - let keep = nms(&boxes, &scores, 0.5, 0.5); - let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 0.5); - assert_eq!(keep, vec![1]); - assert_eq!(keep, keep_rtree) - } +// #[test] +// fn test_nms_score_threshold() { +// // score threshold +// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); +// let scores = Array1::from(vec![0.0, 1.0]); +// let keep = nms(&boxes, &scores, 0.5, 0.5); +// let keep_rtree = rtree_nms(&boxes, &scores, 0.5, 0.5); +// assert_eq!(keep, vec![1]); +// assert_eq!(keep, keep_rtree) +// } - #[test] - fn test_nms_iou_threshold() { - // iou threshold - let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); - let scores = Array1::from(vec![1.0, 1.0]); - let keep = nms(&boxes, &scores, 0.8, 0.0); - let keep_rtree = rtree_nms(&boxes, &scores, 0.8, 0.0); - assert_eq!(keep, vec![0, 1]); - assert_eq!(keep, keep_rtree) - } -} +// #[test] +// fn test_nms_iou_threshold() { +// // iou threshold +// let boxes = arr2(&[[0.0, 0.0, 2.0, 2.0], [1.0, 1.0, 3.0, 3.0]]); +// let scores = Array1::from(vec![1.0, 1.0]); +// let keep = nms(&boxes, &scores, 0.8, 0.0); +// let keep_rtree = rtree_nms(&boxes, &scores, 0.8, 0.0); +// assert_eq!(keep, vec![0, 1]); +// assert_eq!(keep, keep_rtree) +// } +// } diff --git a/powerboxesrs/src/tiou.rs b/powerboxesrs/src/tiou.rs index 929a6f2..790d380 100644 --- a/powerboxesrs/src/tiou.rs +++ b/powerboxesrs/src/tiou.rs @@ -1,179 +1,171 @@ -use ndarray::{Array2, ArrayView2}; -use num_traits::{Num, ToPrimitive}; - -use crate::{ - boxes::{self, rotated_box_areas}, - rotation::{minimal_bounding_rect, Rect}, - utils, -}; -/// Computes the Tracking Intersection over Union (TIOU) distance between two sets of bounding boxes. -/// see https://arxiv.org/pdf/2310.05171.pdf -/// # Arguments -/// -/// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates in xyxy format of the first set of bounding boxes. -/// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates in xyxy format of the second set of bounding boxes. -/// -/// # Returns -/// -/// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. -/// -/// # Examples -/// -/// ``` -/// use ndarray::array; -/// use powerboxesrs::tiou::tiou_distance; -/// -/// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; -/// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; -/// -/// let tiou = tiou_distance(&boxes1, &boxes2); -/// -/// assert_eq!(tiou.shape(), &[2, 3]); -/// assert_eq!(tiou, array![[0., 0.84, 0.8888888888888888], [0.8888888888888888, 0.5555555555555556, 0.]]); -/// ``` -pub fn tiou_distance<'a, N, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - N: Num + PartialEq + PartialOrd + ToPrimitive + Copy + 'a, - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); - - let mut tiou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); - let areas_boxes1 = boxes::box_areas(boxes1); - let areas_boxes2 = boxes::box_areas(boxes2); - let boxes1_vecs: Vec<(N, N, N, N)> = boxes1 - .rows() - .into_iter() - .map(|r| (r[0], r[1], r[2], r[3])) - .collect(); - let boxes2_vecs: Vec<(N, N, N, N)> = boxes2 - .rows() - .into_iter() - .map(|r| (r[0], r[1], r[2], r[3])) - .collect(); - for (i, a1) in boxes1_vecs.iter().enumerate() { - let (a1_x1, a1_y1, a1_x2, a1_y2) = a1; - - let area1 = areas_boxes1[i]; - - for (j, a2) in boxes2_vecs.iter().enumerate() { - let (a2_x1, a2_y1, a2_x2, a2_y2) = a2; - let area2 = areas_boxes2[j]; - // Calculate the enclosing box (C) coordinates - let c_x1 = utils::min(*a1_x1, *a2_x1); - let c_y1 = utils::min(*a1_y1, *a2_y1); - let c_x2 = utils::max(*a1_x2, *a2_x2); - let c_y2 = utils::max(*a1_y2, *a2_y2); - // Calculate the area of the enclosing box (C) - let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); - let c_area = c_area.to_f64().unwrap(); - tiou_matrix[[i, j]] = utils::ONE - utils::min(area1 / c_area, area2 / c_area) - } - } - - tiou_matrix -} - -/// Calculates the rotated tracking IoU (Tiou) distance between two sets of rotated bounding boxes. -/// -/// Given two sets of rotated bounding boxes represented by `boxes1` and `boxes2`, this function -/// computes the rotated Tiou distance matrix between them. The rotated Tiou distance is a measure -/// of dissimilarity between two rotated bounding boxes, taking into account both their overlap -/// and the encompassing area. -/// -/// # Arguments -/// -/// * `boxes1` - A reference to a 2D array (Array2) containing the parameters of the first set of rotated bounding boxes. -/// Each row of `boxes1` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle in degrees]. -/// -/// * `boxes2` - A reference to a 2D array (Array2) containing the parameters of the second set of rotated bounding boxes. -/// Each row of `boxes2` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle in degrees]. -/// -/// # Returns -/// -/// A 2D array (Array2) representing the rotated Tiou distance matrix between the input sets of rotated bounding boxes. -/// The element at position (i, j) in the matrix represents the rotated Giou distance between the i-th box in `boxes1` and -/// the j-th box in `boxes2`. -/// -pub fn rotated_tiou_distance<'a, BA>(boxes1: BA, boxes2: BA) -> Array2 -where - BA: Into>, -{ - let boxes1 = boxes1.into(); - let boxes2 = boxes2.into(); - let num_boxes1 = boxes1.nrows(); - let num_boxes2 = boxes2.nrows(); - - let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); - let areas1 = rotated_box_areas(boxes1); - let areas2 = rotated_box_areas(boxes2); - - let boxes1_rects: Vec<(f64, f64, f64, f64)> = boxes1 - .rows() - .into_iter() - .map(|row| { - minimal_bounding_rect(&Rect::new(row[0], row[1], row[2], row[3], row[4]).points()) - }) - .collect(); - let boxes2_rects: Vec<(f64, f64, f64, f64)> = boxes2 - .rows() - .into_iter() - .map(|row| { - minimal_bounding_rect(&Rect::new(row[0], row[1], row[2], row[3], row[4]).points()) - }) - .collect(); - - for (i, r1) in boxes1_rects.iter().enumerate() { - let area1 = areas1[i]; - let (x1_r1, y1_r1, x2_r1, y2_r1) = r1; - - for (j, r2) in boxes2_rects.iter().enumerate() { - let area2 = areas2[j]; - let (x1_r2, y1_r2, x2_r2, y2_r2) = r2; - - // Calculate the enclosing box (C) coordinates - let c_x1 = utils::min(*x1_r1, *x1_r2); - let c_y1 = utils::min(*y1_r1, *y1_r2); - let c_x2 = utils::max(*x2_r1, *x2_r2); - let c_y2 = utils::max(*y2_r1, *y2_r2); - // Calculate the area of the enclosing box (C) - let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); - let c_area = c_area.to_f64().unwrap(); - iou_matrix[[i, j]] = utils::ONE - utils::min(area1 / c_area, area2 / c_area) - } - } - return iou_matrix; -} - -#[cfg(test)] -mod tests { - use ndarray::arr2; - - use super::*; - - #[test] - fn test_tiou() { - let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0], [1.0, 1.0, 4.0, 4.0]]); - let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0], [3.0, 3.0, 6.0, 6.0]]); - - let tiou_matrix = tiou_distance(&boxes1, &boxes2); - assert_eq!(tiou_matrix, arr2(&[[0.64, 0.75], [0.4375, 0.64]])); - } - #[test] - fn test_rotated_tiou() { - let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0, 20.0], [1.0, 1.0, 4.0, 4.0, 19.0]]); - let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0, 0.0], [3.0, 3.0, 6.0, 6.0, 20.0]]); - - let tiou_matrix = rotated_tiou_distance(&boxes1, &boxes2); - assert_eq!( - tiou_matrix, - arr2(&[ - [0.7818149787949012, 0.8829233169330242], - [0.561738213456193, 0.7725560385451797] - ]) - ); - } -} +// use ndarray::Array2; +// use num_traits::{Num, ToPrimitive}; + +// use crate::{ +// boxes::{self, rotated_box_areas}, +// rotation::{minimal_bounding_rect, Rect}, +// utils, +// }; +// /// Computes the Tracking Intersection over Union (TIOU) distance between two sets of bounding boxes. +// /// see https://arxiv.org/pdf/2310.05171.pdf +// /// # Arguments +// /// +// /// * `boxes1` - A 2D array of shape `(num_boxes1, 4)` representing the coordinates in xyxy format of the first set of bounding boxes. +// /// * `boxes2` - A 2D array of shape `(num_boxes2, 4)` representing the coordinates in xyxy format of the second set of bounding boxes. +// /// +// /// # Returns +// /// +// /// A 2D array of shape `(num_boxes1, num_boxes2)` representing the GIOU distance between each pair of bounding boxes. +// /// +// /// # Examples +// /// +// /// ``` +// /// use ndarray::array; +// /// use powerboxesrs::tiou::tiou_distance; +// /// +// /// let boxes1 = array![[0., 0., 10., 10.], [20., 20., 30., 30.]]; +// /// let boxes2 = array![[0., 0., 10., 10.], [15., 15., 25., 25.], [20., 20., 30., 30.]]; +// /// +// /// let tiou = tiou_distance(&boxes1, &boxes2); +// /// +// /// assert_eq!(tiou.shape(), &[2, 3]); +// /// assert_eq!(tiou, array![[0., 0.84, 0.8888888888888888], [0.8888888888888888, 0.5555555555555556, 0.]]); +// /// ``` +// pub fn tiou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 +// where +// N: Num + PartialOrd + ToPrimitive + Copy, +// { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); + +// let mut tiou_matrix = Array2::::zeros((num_boxes1, num_boxes2)); +// let areas_boxes1 = boxes::box_areas(&boxes1); +// let areas_boxes2 = boxes::box_areas(&boxes2); +// let boxes1_vecs: Vec<(N, N, N, N)> = boxes1 +// .rows() +// .into_iter() +// .map(|r| (r[0], r[1], r[2], r[3])) +// .collect(); +// let boxes2_vecs: Vec<(N, N, N, N)> = boxes2 +// .rows() +// .into_iter() +// .map(|r| (r[0], r[1], r[2], r[3])) +// .collect(); +// for (i, a1) in boxes1_vecs.iter().enumerate() { +// let (a1_x1, a1_y1, a1_x2, a1_y2) = a1; + +// let area1 = areas_boxes1[i]; + +// for (j, a2) in boxes2_vecs.iter().enumerate() { +// let (a2_x1, a2_y1, a2_x2, a2_y2) = a2; +// let area2 = areas_boxes2[j]; +// // Calculate the enclosing box (C) coordinates +// let c_x1 = utils::min(*a1_x1, *a2_x1); +// let c_y1 = utils::min(*a1_y1, *a2_y1); +// let c_x2 = utils::max(*a1_x2, *a2_x2); +// let c_y2 = utils::max(*a1_y2, *a2_y2); +// // Calculate the area of the enclosing box (C) +// let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); +// let c_area = c_area.to_f64().unwrap(); +// tiou_matrix[[i, j]] = utils::ONE - utils::min(area1 / c_area, area2 / c_area) +// } +// } + +// tiou_matrix +// } + +// /// Calculates the rotated tracking IoU (Tiou) distance between two sets of rotated bounding boxes. +// /// +// /// Given two sets of rotated bounding boxes represented by `boxes1` and `boxes2`, this function +// /// computes the rotated Tiou distance matrix between them. The rotated Tiou distance is a measure +// /// of dissimilarity between two rotated bounding boxes, taking into account both their overlap +// /// and the encompassing area. +// /// +// /// # Arguments +// /// +// /// * `boxes1` - A reference to a 2D array (Array2) containing the parameters of the first set of rotated bounding boxes. +// /// Each row of `boxes1` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle in degrees]. +// /// +// /// * `boxes2` - A reference to a 2D array (Array2) containing the parameters of the second set of rotated bounding boxes. +// /// Each row of `boxes2` represents a rotated bounding box with parameters [center_x, center_y, width, height, angle in degrees]. +// /// +// /// # Returns +// /// +// /// A 2D array (Array2) representing the rotated Tiou distance matrix between the input sets of rotated bounding boxes. +// /// The element at position (i, j) in the matrix represents the rotated Giou distance between the i-th box in `boxes1` and +// /// the j-th box in `boxes2`. +// /// +// pub fn rotated_tiou_distance(boxes1: &Array2, boxes2: &Array2) -> Array2 { +// let num_boxes1 = boxes1.nrows(); +// let num_boxes2 = boxes2.nrows(); + +// let mut iou_matrix = Array2::::ones((num_boxes1, num_boxes2)); +// let areas1 = rotated_box_areas(&boxes1); +// let areas2 = rotated_box_areas(&boxes2); + +// let boxes1_rects: Vec<(f64, f64, f64, f64)> = boxes1 +// .rows() +// .into_iter() +// .map(|row| { +// minimal_bounding_rect(&Rect::new(row[0], row[1], row[2], row[3], row[4]).points()) +// }) +// .collect(); +// let boxes2_rects: Vec<(f64, f64, f64, f64)> = boxes2 +// .rows() +// .into_iter() +// .map(|row| { +// minimal_bounding_rect(&Rect::new(row[0], row[1], row[2], row[3], row[4]).points()) +// }) +// .collect(); + +// for (i, r1) in boxes1_rects.iter().enumerate() { +// let area1 = areas1[i]; +// let (x1_r1, y1_r1, x2_r1, y2_r1) = r1; + +// for (j, r2) in boxes2_rects.iter().enumerate() { +// let area2 = areas2[j]; +// let (x1_r2, y1_r2, x2_r2, y2_r2) = r2; + +// // Calculate the enclosing box (C) coordinates +// let c_x1 = utils::min(*x1_r1, *x1_r2); +// let c_y1 = utils::min(*y1_r1, *y1_r2); +// let c_x2 = utils::max(*x2_r1, *x2_r2); +// let c_y2 = utils::max(*y2_r1, *y2_r2); +// // Calculate the area of the enclosing box (C) +// let c_area = (c_x2 - c_x1) * (c_y2 - c_y1); +// let c_area = c_area.to_f64().unwrap(); +// iou_matrix[[i, j]] = utils::ONE - utils::min(area1 / c_area, area2 / c_area) +// } +// } +// return iou_matrix; +// } + +// #[cfg(test)] +// mod tests { +// use ndarray::arr2; + +// use super::*; + +// #[test] +// fn test_tiou() { +// let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0], [1.0, 1.0, 4.0, 4.0]]); +// let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0], [3.0, 3.0, 6.0, 6.0]]); + +// let tiou_matrix = tiou_distance(&boxes1, &boxes2); +// assert_eq!(tiou_matrix, arr2(&[[0.64, 0.75], [0.4375, 0.64]])); +// } +// #[test] +// fn test_rotated_tiou() { +// let boxes1 = arr2(&[[0.0, 0.0, 3.0, 3.0, 20.0], [1.0, 1.0, 4.0, 4.0, 19.0]]); +// let boxes2 = arr2(&[[2.0, 2.0, 5.0, 5.0, 0.0], [3.0, 3.0, 6.0, 6.0, 20.0]]); + +// let tiou_matrix = rotated_tiou_distance(&boxes1, &boxes2); +// assert_eq!( +// tiou_matrix, +// arr2(&[ +// [0.7818149787949012, 0.8829233169330242], +// [0.561738213456193, 0.7725560385451797] +// ]) +// ); +// } +// }