Compare commits

...

20 Commits

Author SHA1 Message Date
1de21e93e1 basic firebrand recognition
Co-authored-by: Alex <AlexanderMcDowell@users.noreply.github.com>
2022-11-14 22:47:43 -08:00
59e0f2d861 firebrand edge detection demo
Co-authored-by: Alex <AlexanderMcDowell@users.noreply.github.com>
2022-11-13 17:57:41 -08:00
cc2820da90 start firebrand detection 2022-11-11 19:39:19 -08:00
f8d4f85858 fully working csv download 2022-11-04 18:58:35 -07:00
76e178176d save csv + paper dims
Co-authored-by: Alex <AlexanderMcDowell@users.noreply.github.com>
2022-11-04 18:42:22 -07:00
fa1e988344 use static js 2022-11-04 17:55:25 -07:00
dcf78bb88d fix mm^2 issue 2022-11-03 17:36:22 -07:00
481de4dfb1 update content 2022-10-31 21:01:37 -07:00
8a364b81e6 interface improvements
Co-authored-by: Alex <AlexanderMcDowell@users.noreply.github.com>
2022-10-28 20:49:54 -07:00
97ab6a1ed1 size projections in web interface
Co-authored-by: Alex <AlexanderMcDowell@users.noreply.github.com>
2022-10-28 20:11:50 -07:00
405b9f7f91 restructure 2022-10-28 17:52:47 -07:00
52fe136f3f Merge branch 'master' of https://git.turtlebasket.ml/datadonkey-com/berkeley-firelab-general 2022-10-28 15:19:02 -07:00
e4516e12d9 update templates 2022-10-28 15:18:51 -07:00
Your Name
55110d6736 Added projected area code for images 2022-10-28 04:16:34 +00:00
407a103913 start projected area 2022-10-27 14:12:25 -07:00
6635404cf9 restructure 2022-10-27 14:11:06 -07:00
81e8195fb7 update readme 2022-10-27 12:11:39 -07:00
6f69f508b6 tweak formatting 2022-10-27 12:05:52 -07:00
f83a98ffe0 temp probability density plot 2022-10-27 12:01:35 -07:00
d10665fd67 cleanups 2022-10-27 10:31:42 -07:00
60 changed files with 1346 additions and 195 deletions

5
.gitignore vendored
View File

@@ -1,5 +1,10 @@
# CUSTOM # CUSTOM
images-input/*
!images-input/.gitkeep
images-output/*
!images-output/.gitkeep
config.yaml
.vscode/ .vscode/
*.swp *.swp

View File

@@ -10,3 +10,7 @@ dev:
clean: clean:
rm -rf static/* rm -rf static/*
touch static/.gitkeep touch static/.gitkeep
batch:
pipenv run python3 batch-process.py

View File

@@ -10,6 +10,11 @@ flask = "*"
gunicorn = "*" gunicorn = "*"
werkzeug = "*" werkzeug = "*"
pyyaml = "*" pyyaml = "*"
matplotlib = "*"
plotly = "*"
pandas = "*"
scipy = "==1.8.1"
scikit-image = "*"
[dev-packages] [dev-packages]

482
Pipfile.lock generated
View File

@@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "0cfa12a983973f0699999da1f8adcf4662998d4d37158ae1eed984cb7b773fc3" "sha256": "4ce52e44137325bfa984f7d78467dce4463d471bfc344ecd116c2beb2af52d60"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@@ -24,6 +24,89 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==8.1.3" "version": "==8.1.3"
}, },
"contourpy": {
"hashes": [
"sha256:0389349875424aa8c5e61f757e894687916bc4e9616cc6afcbd8051aa2428952",
"sha256:0395ae71164bfeb2dedd136e03c71a2718a5aa9873a46f518f4133be0d63e1d2",
"sha256:057114f698ffb9e54657e8fda6802e2f5c8fad609845cf6afaf31590ef6a33c0",
"sha256:061e1f066c419ffe25b615a1df031b4832ea1d7f2676937e69e8e00e24512005",
"sha256:06c4d1dde5ee4f909a8a95ba1eb04040c6c26946b4f3b5beaf10d45f14e940ee",
"sha256:09ed9b63f4df8a7591b7a4a26c1ad066dcaafda1f846250fdcb534074a411692",
"sha256:0f7672148f8fca48e4efc16aba24a7455b40c22d4f8abe42475dec6a12b0bb9a",
"sha256:0f89f0608a5aa8142ed0e53957916623791a88c7f5e5f07ae530c328beeb888f",
"sha256:128bd7acf569f8443ad5b2227f30ac909e4f5399ed221727eeacf0c6476187e6",
"sha256:19ea64fa0cf389d2ebc10974616acfa1fdecbd73d1fd9c72215b782f3c40f561",
"sha256:1fb782982c42cee667b892a0b0c52a9f6c7ecf1da5c5f4345845f04eaa862f93",
"sha256:218722a29c5c26677d37c44f5f8a372daf6f07870aad793a97d47eb6ad6b3290",
"sha256:2b5e334330d82866923015b455260173cb3b9e3b4e297052d758abd262031289",
"sha256:2bf5c846c257578b03d498b20f54f53551616a507d8e5463511c58bb58e9a9cf",
"sha256:2d0ad9a85f208473b1f3613c45756c7aa6fcc288266a8c7b873f896aaf741b6b",
"sha256:2f54dcc9bb9390fd0636301ead134d46d5229fe86da0db4d974c0fda349f560e",
"sha256:3109fa601d2a448cec4643abd3a31f972bf05b7c2f2e83df9d3429878f8c10ae",
"sha256:3210d93ad2af742b6a96cf39792f7181822edbb8fe11c3ef29d1583fe637a8d8",
"sha256:3b3082ade8849130203d461b98c2a061b382c46074b43b4edd5cefd81af92b8a",
"sha256:3c3f2f6b898a40207843ae01970e57e33d22a26b22f23c6a5e07b4716751085f",
"sha256:3ca40d7844b391d90b864c6a6d1bb6b88b09035fb4d866d64d43c4d26fb0ab64",
"sha256:3cfc067ddde78b76dcbc9684d82688b7d3c5158fa2254a085f9bcb9586c1e2d8",
"sha256:434942fa2f9019b9ae525fb752dc523800c49a1a28fbd6d9240b0fa959573dcc",
"sha256:46b8e24813e2fb5a3e598c1f8b9ae403e1438cb846a80cc2b33cddf19dddd7f2",
"sha256:59c827e536bb5e3ef58e06da0faba61fd89a14f30b68bcfeca41f43ca83a1942",
"sha256:60f37acd4e4227c5a29f737d9a85ca3145c529a8dd4bf70af7f0637c61b49222",
"sha256:689d7d2a840619915d0abd1ecc6e399fee202f8ad315acda2807f4ca420d0802",
"sha256:6c02e22cf09996194bcb3a4784099975cf527d5c29caf759abadf29ebdb2fe27",
"sha256:79908b9d02b1d6c1c71ff3b7ad127f3f82e14a8e091ab44b3c7e34b649fea733",
"sha256:7c9e99aac7b430f6a9f15eebf058c742097cea3369f23a2bfc5e64d374b67e3a",
"sha256:813c2944e940ef8dccea71305bacc942d4b193a021140874b3e58933ec44f5b6",
"sha256:87121b9428ac568fb84fae4af5e7852fc34f02eadc4e3e91f6c8989327692186",
"sha256:896631cd40222aef3697e4e51177d14c3709fda49d30983269d584f034acc8a4",
"sha256:970a4be7ec84ccda7c27cb4ae74930bbbd477bc8d849ed55ea798084dd5fca8c",
"sha256:9939796abcadb2810a63dfb26ff8ca4595fe7dd70a3ceae7f607a2639b714307",
"sha256:99a8071e351b50827ad976b92ed91845fb614ac67a3c41109b24f3d8bd3afada",
"sha256:9c16fa267740d67883899e054cccb4279e002f3f4872873b752c1ba15045ff49",
"sha256:a30e95274f5c0e007ccc759ec258aa5708c534ec058f153ee25ac700a2f1438b",
"sha256:a74afd8d560eaafe0d9e3e1db8c06081282a05ca4de00ee416195085a79d7d3d",
"sha256:b46a04588ceb7cf132568e0e564a854627ef87a1ed3bf536234540a79ced44b0",
"sha256:b4963cf08f4320d98ae72ec7694291b8ab85cb7da3b0cd824bc32701bc992edf",
"sha256:b50e481a4317a8efcfffcfddcd4c9b36eacba440440e70cbe0256aeb6fd6abae",
"sha256:b85553699862c09937a7a5ea14ee6229087971a7d51ae97d5f4b407f571a2c17",
"sha256:bcc98d397c3dea45d5b262029564b29cb8e945f2607a38bee6163694c0a8b4ef",
"sha256:bed3a2a823a041e8d249b1a7ec132933e1505299329b5cfe1b2b5ec689ec7675",
"sha256:bf6b4c0c723664f65c2a47c8cb6ebbf660b0b2e2d936adf2e8503d4e93359465",
"sha256:bfd634cb9685161b2a51f73a7fc4736fd0d67a56632d52319317afaa27f08243",
"sha256:c0d5ee865b5fd16bf62d72122aadcc90aab296c30c1adb0a32b4b66bd843163e",
"sha256:c2b4eab7c12f9cb460509bc34a3b086f9802f0dba27c89a63df4123819ad64af",
"sha256:c51568e94f7f232296de30002f2a50f77a7bd346673da3e4f2aaf9d2b833f2e5",
"sha256:c5158616ab39d34b76c50f40c81552ee180598f7825dc7a66fd187d29958820f",
"sha256:cdacddb18d55ffec42d1907079cdc04ec4fa8a990cdf5b9d9fe67d281fc0d12e",
"sha256:ce763369e646e59e4ca2c09735cd1bdd3048d909ad5f2bc116e83166a9352f3c",
"sha256:d45822b0a2a452327ab4f95efe368d234d5294bbf89a99968be27c7938a21108",
"sha256:d8150579bf30cdf896906baf256aa200cd50dbe6e565c17d6fd3d678e21ff5de",
"sha256:d88814befbd1433152c5f6dd536905149ba028d795a22555b149ae0a36024d9e",
"sha256:dca5be83a6dfaf933a46e3bc2b9f2685e5ec61b22f6a38ad740aac9c16e9a0ff",
"sha256:dd084459ecdb224e617e4ab3f1d5ebe4d1c48facb41f24952b76aa6ba9712bb0",
"sha256:def9a01b73c9e27d70ea03b381fb3e7aadfac1f398dbd63751313c3a46747ef5",
"sha256:df65f4b2b4e74977f0336bef12a88051ab24e6a16873cd9249f34d67cb3e345d",
"sha256:dfe924e5a63861c82332a12adeeab955dc8c8009ddbbd80cc2fcca049ff89a49",
"sha256:e67dcaa34dcd908fcccbf49194211d847c731b6ebaac661c1c889f1bf6af1e44",
"sha256:eba62b7c21a33e72dd8adab2b92dd5610d8527f0b2ac28a8e0770e71b21a13f9",
"sha256:ed9c91bf4ce614efed5388c3f989a7cfe08728ab871d995a486ea74ff88993db",
"sha256:f05d311c937da03b0cd26ac3e14cb991f6ff8fc94f98b3df9713537817539795",
"sha256:f1cc623fd6855b25da52b3275e0c9e51711b86a9dccc75f8c9ab4432fd8e42c7",
"sha256:f670686d99c867d0f24b28ce8c6f02429c6eef5e2674aab287850d0ee2d20437",
"sha256:f856652f9b533c6cd2b9ad6836a7fc0e43917d7ff15be46c5baf1350f8cdc5d9",
"sha256:fb0458d74726937ead9e2effc91144aea5a58ecee9754242f8539a782bed685a"
],
"markers": "python_version >= '3.7'",
"version": "==1.0.5"
},
"cycler": {
"hashes": [
"sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3",
"sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"
],
"markers": "python_version >= '3.6'",
"version": "==0.11.0"
},
"flask": { "flask": {
"hashes": [ "hashes": [
"sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b", "sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b",
@@ -32,6 +115,14 @@
"index": "pypi", "index": "pypi",
"version": "==2.2.2" "version": "==2.2.2"
}, },
"fonttools": {
"hashes": [
"sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1",
"sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"
],
"markers": "python_version >= '3.7'",
"version": "==4.38.0"
},
"gunicorn": { "gunicorn": {
"hashes": [ "hashes": [
"sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
@@ -40,6 +131,14 @@
"index": "pypi", "index": "pypi",
"version": "==20.1.0" "version": "==20.1.0"
}, },
"imageio": {
"hashes": [
"sha256:9bdafe9c5a3d336a187f3f554f3e30bcdbf8a1d7d46f0e4d94e4a535adfb64c7",
"sha256:db7010cd10712518819a4187baf61b05988361ea20c23e829918727b27acb977"
],
"markers": "python_version >= '3.7'",
"version": "==2.22.2"
},
"itsdangerous": { "itsdangerous": {
"hashes": [ "hashes": [
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44", "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
@@ -56,6 +155,80 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==3.1.2" "version": "==3.1.2"
}, },
"kiwisolver": {
"hashes": [
"sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b",
"sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166",
"sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c",
"sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c",
"sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0",
"sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4",
"sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9",
"sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286",
"sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767",
"sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c",
"sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6",
"sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b",
"sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004",
"sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf",
"sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494",
"sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac",
"sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626",
"sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766",
"sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514",
"sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6",
"sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f",
"sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d",
"sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191",
"sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d",
"sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51",
"sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f",
"sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8",
"sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454",
"sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb",
"sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da",
"sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8",
"sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de",
"sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a",
"sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9",
"sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008",
"sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3",
"sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32",
"sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938",
"sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1",
"sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9",
"sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d",
"sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824",
"sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b",
"sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd",
"sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2",
"sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5",
"sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69",
"sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3",
"sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae",
"sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597",
"sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e",
"sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955",
"sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca",
"sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a",
"sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea",
"sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede",
"sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4",
"sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6",
"sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686",
"sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408",
"sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871",
"sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29",
"sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750",
"sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897",
"sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0",
"sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2",
"sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09",
"sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"
],
"markers": "python_version >= '3.7'",
"version": "==1.4.4"
},
"llvmlite": { "llvmlite": {
"hashes": [ "hashes": [
"sha256:03aee0ccd81735696474dc4f8b6be60774892a2929d6c05d093d17392c237f32", "sha256:03aee0ccd81735696474dc4f8b6be60774892a2929d6c05d093d17392c237f32",
@@ -136,6 +309,61 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==2.1.1" "version": "==2.1.1"
}, },
"matplotlib": {
"hashes": [
"sha256:02561141c434154f7bae8e5449909d152367cb40aa57bfb2a27f2748b9c5f95f",
"sha256:05e86446562063d6186ff6d700118c0dbd5dccc403a6187351ee526c48878f10",
"sha256:0bab7564aafd5902128d54b68dca04f5755413fb6b502100bb0235a545882c48",
"sha256:12ab21d0cad122f5b23688d453a0280676e7c42f634f0dbd093d15d42d142b1f",
"sha256:183bf3ac6a6023ee590aa4b677f391ceed65ec0d6b930901a8483c267bd12995",
"sha256:1e2c75d5d1ff6b7ef9870360bfa23bea076b8dc0945a60d19453d7619ed9ea8f",
"sha256:220314c2d6b9ca11570d7cd4b841c9f3137546f188336003b9fb8def4dcb804d",
"sha256:2469f57e4c5cc0e85eddc7b30995ea9c404a78c0b1856da75d1a5887156ca350",
"sha256:27337bcb38d5db7430c14f350924542d75416ec1546d5d9d9f39b362b71db3fb",
"sha256:2cc5d726d4d42865f909c5208a7841109d76584950dd0587b01a77cc279d4ab7",
"sha256:3c53486278a0629fd892783271dc994b962fba8dfe207445d039e14f1928ea46",
"sha256:4648f0d79a87bf50ee740058305c91091ee5e1fbb71a7d2f5fe6707bfe328d1c",
"sha256:47cb088bbce82ae9fc2edf3c25e56a5c6142ce2553fea2b781679f960a70c207",
"sha256:4a3d903588b519b38ed085d0ae762a1dcd4b70164617292175cfd91b90d6c415",
"sha256:4d3b0e0a4611bd22065bbf47e9b2f689ac9e575bcb850a9f0ae2bbed75cab956",
"sha256:52935b7d4ccbf0dbc9cf454dbb10ca99c11cbe8da9467596b96e5e21fd4dfc5c",
"sha256:563896ba269324872ace436a57775dcc8322678a9496b28a8c25cdafa5ec2b92",
"sha256:565f514dec81a41cbed10eb6011501879695087fc2787fb89423a466508abbbd",
"sha256:5f97141e05baf160c3ec125f06ceb2a44c9bb62f42fcb8ee1c05313c73e99432",
"sha256:6f5788168da2661b42f7468063b725cc73fdbeeb80f2704cb2d8c415e9a57c50",
"sha256:71eced071825005011cdc64efbae2e2c76b8209c18aa487dedf69796fe4b1e40",
"sha256:7730e60e751cfcfe7fcb223cf03c0b979e9a064c239783ad37929d340a364cef",
"sha256:8245e85fd793f58edf29b8a9e3be47e8ecf76ea1a1e8240545f2746181ca5787",
"sha256:85948b303534b69fd771126764cf883fde2af9b003eb5778cb60f3b46f93d3f6",
"sha256:87027ff7b2edeb14476900261ef04d4beae949e1dfa0a3eb3ad6a6efbf9d0e1d",
"sha256:87bdbd37d0a41e025879863fe9b17bab15c0421313bc33e77e5e1aa54215c9c5",
"sha256:8dc25473319afabe49150267e54648ac559c33b0fc2a80c8caecfbbc2948a820",
"sha256:8ddd58324dc9a77e2e56d7b7aea7dbd0575b6f7cd1333c3ca9d388ac70978344",
"sha256:9403764017d20ff570f7ce973a8b9637f08a6109118f4e0ce6c7493d8849a0d3",
"sha256:9dd40505ccc526acaf9a5db1b3029e237c64b58f1249983b28a291c2d6a1d0fa",
"sha256:a4de03085afb3b80fab341afaf8e60dfe06ce439b6dfed55d657cf34a7bc3c40",
"sha256:a68b91ac7e6bb26100a540a033f54c95fe06d9c0aa51312c2a52d07d1bde78f4",
"sha256:b53387d4e59432ff221540a4ffb5ee9669c69417805e4faf0148a00d701c61f9",
"sha256:c1effccef0cea2d4da9feeed22079adf6786f92c800a7d0d2ef2104318a1c66c",
"sha256:c9756a8e69f6e1f76d47eb42132175b6814da1fbeae0545304c6d0fc2aae252a",
"sha256:d0161ebf87518ecfe0980c942d5f0d5df0e080c1746ebaab2027a969967014b7",
"sha256:e2d1b7225666f7e1bcc94c0bc9c587a82e3e8691da4757e357e5c2515222ee37",
"sha256:e3c116e779fbbf421a9e4d3060db259a9bb486d98f4e3c5a0877c599bd173582",
"sha256:e4c8b5a243dd29d50289d694e931bd6cb6ae0b5bd654d12c647543d63862540c",
"sha256:e632f66218811d4cf8b7a2a649e25ec15406c3c498f72d19e2bcf8377f38445d",
"sha256:fad858519bd6d52dbfeebdbe04d00dd8e932ed436f1c535e61bcc970a96c11e4"
],
"index": "pypi",
"version": "==3.6.1"
},
"networkx": {
"hashes": [
"sha256:15cdf7f7c157637107ea690cabbc488018f8256fa28242aed0fb24c93c03a06d",
"sha256:815383fd52ece0a7024b5fd8408cc13a389ea350cd912178b82eed8b96f82cd3"
],
"markers": "python_version >= '3.8'",
"version": "==2.8.7"
},
"numba": { "numba": {
"hashes": [ "hashes": [
"sha256:0744cf4214ed795eb2df3ed1635d77a6ffcbd990a66a06125548b5fb8ee46323", "sha256:0744cf4214ed795eb2df3ed1635d77a6ffcbd990a66a06125548b5fb8ee46323",
@@ -217,6 +445,173 @@
"index": "pypi", "index": "pypi",
"version": "==4.6.0.66" "version": "==4.6.0.66"
}, },
"packaging": {
"hashes": [
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
],
"markers": "python_version >= '3.6'",
"version": "==21.3"
},
"pandas": {
"hashes": [
"sha256:04e51b01d5192499390c0015630975f57836cc95c7411415b499b599b05c0c96",
"sha256:05c527c64ee02a47a24031c880ee0ded05af0623163494173204c5b72ddce658",
"sha256:0a78e05ec09731c5b3bd7a9805927ea631fe6f6cb06f0e7c63191a9a778d52b4",
"sha256:17da7035d9e6f9ea9cdc3a513161f8739b8f8489d31dc932bc5a29a27243f93d",
"sha256:249cec5f2a5b22096440bd85c33106b6102e0672204abd2d5c014106459804ee",
"sha256:2c25e5c16ee5c0feb6cf9d982b869eec94a22ddfda9aa2fbed00842cbb697624",
"sha256:32e3d9f65606b3f6e76555bfd1d0b68d94aff0929d82010b791b6254bf5a4b96",
"sha256:36aa1f8f680d7584e9b572c3203b20d22d697c31b71189322f16811d4ecfecd3",
"sha256:5b0c970e2215572197b42f1cff58a908d734503ea54b326412c70d4692256391",
"sha256:5cee0c74e93ed4f9d39007e439debcaadc519d7ea5c0afc3d590a3a7b2edf060",
"sha256:669c8605dba6c798c1863157aefde959c1796671ffb342b80fcb80a4c0bc4c26",
"sha256:66a1ad667b56e679e06ba73bb88c7309b3f48a4c279bd3afea29f65a766e9036",
"sha256:683779e5728ac9138406c59a11e09cd98c7d2c12f0a5fc2b9c5eecdbb4a00075",
"sha256:6bb391659a747cf4f181a227c3e64b6d197100d53da98dcd766cc158bdd9ec68",
"sha256:81f0674fa50b38b6793cd84fae5d67f58f74c2d974d2cb4e476d26eee33343d0",
"sha256:927e59c694e039c75d7023465d311277a1fc29ed7236b5746e9dddf180393113",
"sha256:932d2d7d3cab44cfa275601c982f30c2d874722ef6396bb539e41e4dc4618ed4",
"sha256:a52419d9ba5906db516109660b114faf791136c94c1a636ed6b29cbfff9187ee",
"sha256:b156a971bc451c68c9e1f97567c94fd44155f073e3bceb1b0d195fd98ed12048",
"sha256:bcf1a82b770b8f8c1e495b19a20d8296f875a796c4fe6e91da5ef107f18c5ecb",
"sha256:cb2a9cf1150302d69bb99861c5cddc9c25aceacb0a4ef5299785d0f5389a3209",
"sha256:d8c709f4700573deb2036d240d140934df7e852520f4a584b2a8d5443b71f54d",
"sha256:db45b94885000981522fb92349e6b76f5aee0924cc5315881239c7859883117d",
"sha256:ddf46b940ef815af4e542697eaf071f0531449407a7607dd731bf23d156e20a7",
"sha256:e675f8fe9aa6c418dc8d3aac0087b5294c1a4527f1eacf9fe5ea671685285454",
"sha256:eb7e8cf2cf11a2580088009b43de84cabbf6f5dae94ceb489f28dba01a17cb77",
"sha256:f340331a3f411910adfb4bbe46c2ed5872d9e473a783d7f14ecf49bc0869c594"
],
"index": "pypi",
"version": "==1.5.1"
},
"pillow": {
"hashes": [
"sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927",
"sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14",
"sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc",
"sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58",
"sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60",
"sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76",
"sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c",
"sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac",
"sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490",
"sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1",
"sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f",
"sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d",
"sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f",
"sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069",
"sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402",
"sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437",
"sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885",
"sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e",
"sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be",
"sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff",
"sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da",
"sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004",
"sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f",
"sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20",
"sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d",
"sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c",
"sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544",
"sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3",
"sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04",
"sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c",
"sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5",
"sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4",
"sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb",
"sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4",
"sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c",
"sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467",
"sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e",
"sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421",
"sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b",
"sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8",
"sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb",
"sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3",
"sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc",
"sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf",
"sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1",
"sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a",
"sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28",
"sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0",
"sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1",
"sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8",
"sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd",
"sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4",
"sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8",
"sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f",
"sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013",
"sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59",
"sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc",
"sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"
],
"markers": "python_version >= '3.7'",
"version": "==9.2.0"
},
"plotly": {
"hashes": [
"sha256:4efef479c2ec1d86dcdac8405b6ca70ca65649a77408e39a7e84a1ea2db6c787",
"sha256:52fd74b08aa4fd5a55b9d3034a30dbb746e572d7ed84897422f927fdf687ea5f"
],
"index": "pypi",
"version": "==5.11.0"
},
"pyparsing": {
"hashes": [
"sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
"sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
],
"markers": "python_full_version >= '3.6.8'",
"version": "==3.0.9"
},
"python-dateutil": {
"hashes": [
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.2"
},
"pytz": {
"hashes": [
"sha256:335ab46900b1465e714b4fda4963d87363264eb662aab5e65da039c25f1f5b22",
"sha256:c4d88f472f54d615e9cd582a5004d1e5f624854a6a27a6211591c251f22a6914"
],
"version": "==2022.5"
},
"pywavelets": {
"hashes": [
"sha256:030670a213ee8fefa56f6387b0c8e7d970c7f7ad6850dc048bd7c89364771b9b",
"sha256:058b46434eac4c04dd89aeef6fa39e4b6496a951d78c500b6641fd5b2cc2f9f4",
"sha256:231b0e0b1cdc1112f4af3c24eea7bf181c418d37922a67670e9bf6cfa2d544d4",
"sha256:23bafd60350b2b868076d976bdd92f950b3944f119b4754b1d7ff22b7acbf6c6",
"sha256:3f19327f2129fb7977bc59b966b4974dfd72879c093e44a7287500a7032695de",
"sha256:47cac4fa25bed76a45bc781a293c26ac63e8eaae9eb8f9be961758d22b58649c",
"sha256:578af438a02a86b70f1975b546f68aaaf38f28fb082a61ceb799816049ed18aa",
"sha256:6437af3ddf083118c26d8f97ab43b0724b956c9f958e9ea788659f6a2834ba93",
"sha256:64c6bac6204327321db30b775060fbe8e8642316e6bff17f06b9f34936f88875",
"sha256:67a0d28a08909f21400cb09ff62ba94c064882ffd9e3a6b27880a111211d59bd",
"sha256:71ab30f51ee4470741bb55fc6b197b4a2b612232e30f6ac069106f0156342356",
"sha256:7231461d7a8eb3bdc7aa2d97d9f67ea5a9f8902522818e7e2ead9c2b3408eeb1",
"sha256:754fa5085768227c4f4a26c1e0c78bc509a266d9ebd0eb69a278be7e3ece943c",
"sha256:7ab8d9db0fe549ab2ee0bea61f614e658dd2df419d5b75fba47baa761e95f8f2",
"sha256:875d4d620eee655346e3589a16a73790cf9f8917abba062234439b594e706784",
"sha256:88aa5449e109d8f5e7f0adef85f7f73b1ab086102865be64421a3a3d02d277f4",
"sha256:91d3d393cffa634f0e550d88c0e3f217c96cfb9e32781f2960876f1808d9b45b",
"sha256:9cb5ca8d11d3f98e89e65796a2125be98424d22e5ada360a0dbabff659fca0fc",
"sha256:ab7da0a17822cd2f6545626946d3b82d1a8e106afc4b50e3387719ba01c7b966",
"sha256:ad987748f60418d5f4138db89d82ba0cb49b086e0cbb8fd5c3ed4a814cfb705e",
"sha256:d0e56cd7a53aed3cceca91a04d62feb3a0aca6725b1912d29546c26f6ea90426",
"sha256:d854411eb5ee9cb4bc5d0e66e3634aeb8f594210f6a1bed96dbed57ec70f181c",
"sha256:da7b9c006171be1f9ddb12cc6e0d3d703b95f7f43cb5e2c6f5f15d3233fcf202",
"sha256:daf0aa79842b571308d7c31a9c43bc99a30b6328e6aea3f50388cd8f69ba7dbc",
"sha256:de7cd61a88a982edfec01ea755b0740e94766e00a1ceceeafef3ed4c85c605cd"
],
"markers": "python_version >= '3.8'",
"version": "==1.4.1"
},
"pyyaml": { "pyyaml": {
"hashes": [ "hashes": [
"sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf",
@@ -263,6 +658,67 @@
"index": "pypi", "index": "pypi",
"version": "==6.0" "version": "==6.0"
}, },
"scikit-image": {
"hashes": [
"sha256:03779a7e1736fdf89d83c0ba67d44110496edd736a3bfce61a2b5177a1c8a099",
"sha256:0b0a199157ce8487c77de4fde0edc0b42d6d42818881c11f459262351d678b2d",
"sha256:19a21a101a20c587a3b611a2cf6f86c35aae9f8d9563279b987e83ee1c9a9790",
"sha256:24b5367de1762da6ee126dd8f30cc4e7efda474e0d7d70685433f0e3aa2ec450",
"sha256:2a02d1bd0e2b53e36b952bd5fd6118d9ccc3ee51de35705d63d8eb1f2e86adef",
"sha256:2f50b923f8099c1045fcde7418d86b206c87e333e43da980f41d8577b9605245",
"sha256:32fb88cc36203b99c9672fb972c9ef98635deaa5fc889fe969f3e11c44f22919",
"sha256:33dfd463ee6cc509defa279b963829f2230c9e0639ccd3931045be055878eea6",
"sha256:3a01372ae4bca223873304b0bff79b9d92446ac6d6177f73d89b45561e2d09d8",
"sha256:651de1c2ce1fbee834753b46b8e7d81cb12a5594898babba63ac82b30ddad49d",
"sha256:6b6a8f98f2ac9bb73706461fd1dec875f6a5141759ed526850a5a49e90003d19",
"sha256:7f9f8a1387afc6c70f2bed007c3854a2d7489f9f7713c242f16f32ee05934bc2",
"sha256:84baa3179f3ae983c3a5d81c1e404bc92dcf7daeb41bfe9369badcda3fb22b92",
"sha256:8d8917fcf85b987b1f287f823f3a1a7dac38b70aaca759bc0200f3bc292d5ced",
"sha256:9439e5294de3f18d6e82ec8eee2c46590231cf9c690da80545e83a0733b7a69e",
"sha256:9fb0923a3bfa99457c5e17888f27b3b8a83a3600b4fef317992e7b7234764732",
"sha256:a7c3985c68bfe05f7571167ee021d14f5b8d1a4a250c91f0b13be7fb07e6af34",
"sha256:a8714348ddd671f819457a797c97d4c672166f093def66d66c3254cbd1d43f83",
"sha256:ad5d8000207a264d1a55681a9276e6a739d3f05cf4429004ad00d61d1892235f",
"sha256:cc24177de3fdceca5d04807ad9c87d665f0bf01032ed94a9055cd1ed2b3f33e9",
"sha256:ce3d2207f253b8eb2c824e30d145a9f07a34a14212d57f3beca9f7e03c383cbe",
"sha256:cfbb073f23deb48e0e60c47f8741d8089121d89cc78629ea8c5b51096efc5be7",
"sha256:e207c6ce5ce121d7d9b9d2b61b9adca57d1abed112c902d8ffbfdc20fb42c12b",
"sha256:fd9dd3994bb6f9f7a35f228323f3c4dc44b3cf2ff15fd72d895216e9333550c6",
"sha256:fdf48d9b1f13af69e4e2c78e05067e322e9c8c97463c315cd0ecb47a94e259fc",
"sha256:ff3b1025356508d41f4fe48528e509d95f9e4015e90cf158cd58c56dc63e0ac5"
],
"index": "pypi",
"version": "==0.19.3"
},
"scipy": {
"hashes": [
"sha256:02b567e722d62bddd4ac253dafb01ce7ed8742cf8031aea030a41414b86c1125",
"sha256:1166514aa3bbf04cb5941027c6e294a000bba0cf00f5cdac6c77f2dad479b434",
"sha256:1da52b45ce1a24a4a22db6c157c38b39885a990a566748fc904ec9f03ed8c6ba",
"sha256:23b22fbeef3807966ea42d8163322366dd89da9bebdc075da7034cee3a1441ca",
"sha256:28d2cab0c6ac5aa131cc5071a3a1d8e1366dad82288d9ec2ca44df78fb50e649",
"sha256:2ef0fbc8bcf102c1998c1f16f15befe7cffba90895d6e84861cd6c6a33fb54f6",
"sha256:3b69b90c9419884efeffaac2c38376d6ef566e6e730a231e15722b0ab58f0328",
"sha256:4b93ec6f4c3c4d041b26b5f179a6aab8f5045423117ae7a45ba9710301d7e462",
"sha256:4e53a55f6a4f22de01ffe1d2f016e30adedb67a699a310cdcac312806807ca81",
"sha256:6311e3ae9cc75f77c33076cb2794fb0606f14c8f1b1c9ff8ce6005ba2c283621",
"sha256:65b77f20202599c51eb2771d11a6b899b97989159b7975e9b5259594f1d35ef4",
"sha256:6cc6b33139eb63f30725d5f7fa175763dc2df6a8f38ddf8df971f7c345b652dc",
"sha256:70de2f11bf64ca9921fda018864c78af7147025e467ce9f4a11bc877266900a6",
"sha256:70ebc84134cf0c504ce6a5f12d6db92cb2a8a53a49437a6bb4edca0bc101f11c",
"sha256:83606129247e7610b58d0e1e93d2c5133959e9cf93555d3c27e536892f1ba1f2",
"sha256:93d07494a8900d55492401917a119948ed330b8c3f1d700e0b904a578f10ead4",
"sha256:9c4e3ae8a716c8b3151e16c05edb1daf4cb4d866caa385e861556aff41300c14",
"sha256:9dd4012ac599a1e7eb63c114d1eee1bcfc6dc75a29b589ff0ad0bb3d9412034f",
"sha256:9e3fb1b0e896f14a85aa9a28d5f755daaeeb54c897b746df7a55ccb02b340f33",
"sha256:a0aa8220b89b2e3748a2836fbfa116194378910f1a6e78e4675a095bcd2c762d",
"sha256:d3b3c8924252caaffc54d4a99f1360aeec001e61267595561089f8b5900821bb",
"sha256:e013aed00ed776d790be4cb32826adb72799c61e318676172495383ba4570aa4",
"sha256:f3e7a8867f307e3359cc0ed2c63b61a1e33a19080f92fe377bc7d49f646f2ec1"
],
"index": "pypi",
"version": "==1.8.1"
},
"setuptools": { "setuptools": {
"hashes": [ "hashes": [
"sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17", "sha256:512e5536220e38146176efb833d4a62aa726b7bbff82cfbc8ba9eaa3996e0b17",
@@ -271,6 +727,30 @@
"markers": "python_version >= '3.7'", "markers": "python_version >= '3.7'",
"version": "==65.5.0" "version": "==65.5.0"
}, },
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"tenacity": {
"hashes": [
"sha256:35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac",
"sha256:e48c437fdf9340f5666b92cd7990e96bc5fc955e1298baf4a907e3972067a445"
],
"markers": "python_version >= '3.6'",
"version": "==8.1.0"
},
"tifffile": {
"hashes": [
"sha256:50b61ba943b866d191295bc38a00191c9fdab23ece063544c7f1a264e3f6aa8e",
"sha256:87f3aee8a0d06b74655269a105de75c1958a24653e1930d523eb516100043503"
],
"markers": "python_version >= '3.8'",
"version": "==2022.10.10"
},
"werkzeug": { "werkzeug": {
"hashes": [ "hashes": [
"sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f", "sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f",

View File

@@ -1,18 +1,31 @@
# Pyrometry image processing # Fire Lab Work
## Interface Screenshots ## Interface Screenshots
| Input View | Results | | Input View | Results | Temp. Distribution |
| --- | --- | --- |
| ![](screenshots/pyro_input.png) | ![](screenshots/pyro_results.png) | ![](screenshots/temp_dist_plot.png)
| Labeling Input | Labeling Results |
| --- | --- | | --- | --- |
| ![](screenshots/pyro_input.png) | ![](screenshots/pyro_results.png) | ![](screenshots/projected_area_in.png) | ![](screenshots/projected_area_out.png) |
## Using the web version ## Using the web version
### Ratio Pyrometry
1. Go to [pyro.turtlebasket.ml](https://pyro.turtlebasket.ml). 1. Go to [pyro.turtlebasket.ml](https://pyro.turtlebasket.ml).
2. Select an input image. 2. Select an input image.
3. Enter your DSLR camera settings. 3. Enter your DSLR camera settings.
4. Click "Generate Heatmap". 4. Click "Generate Heatmap".
### Projected Object Area
1. Go to [pyro.turtlebasket.ml](https://pyro.turtlebasket.ml).
2. Navigate to "Object Area".
3. Select an input image.
4. Click "Generate Projected Sizes".
## Using the local (batch) version ## Using the local (batch) version
Create a new config file: Create a new config file:
@@ -67,23 +80,3 @@ To autoreload on source file changes:
``` ```
gunicorn flask_frontend:app --reload gunicorn flask_frontend:app --reload
``` ```
## Temperature maps
**Grayscale pyrometry:** currently basic; uses grayscale opencv import, then just applies a jet filter. Doesn't yet copy the full impl in the paper.
**Ratio pyrometry:** pretty damn close to what's in the paper but it's very broken atm
**Test image:**
![](examples/01-0001-cropped.png)
**Ratio pyrometry result (with convolutional smoothing):**
According to general researcher consensus, ratio pyrometry is supposed to be more accurate.
![](examples/01-0001-cropped-transformed-ratio.png)
**Grayscale pyrometry result:**
![](examples/01-0001-transformed-grayscale.png)

View File

@@ -2,14 +2,15 @@ import yaml
import cv2 as cv import cv2 as cv
import numpy as np import numpy as np
import os import os
from matplotlib import pyplot as plt, image as mpimg
from ratio_pyrometry import rg_ratio_normalize from ratio_pyrometry import rg_ratio_normalize
config = {} config = {}
with open("./config.yaml", "r") as yaml_stream: with open("./config.yaml", "r") as yaml_stream:
config = yaml.safe_load(yaml_stream) config = yaml.safe_load(yaml_stream)
img_in_dir = "./images-input" img_input_dir = "images-input"
img_out_dir = "./images-output" img_out_dir = "images-output"
accepted_formats = [ accepted_formats = [
".jpg", ".jpg",
".jpeg", ".jpeg",
@@ -19,44 +20,64 @@ accepted_formats = [
files = [] files = []
for file in os.listdir(img_in_dir): for file in os.listdir(img_input_dir):
filename = os.fsdecode(file) filename = os.fsdecode(file)
valid = False valid = False
for fmt in accepted_formats: for fmt in accepted_formats:
if filename.endswith(fmt): if filename.endswith(fmt):
files.append(os.path.join(img_in_dir, filename)) files.append(filename)
valid = True valid = True
break break
if not valid: if not valid and filename != ".gitkeep":
print(f"Invalid file extension for {filename}.") print(f"Invalid file extension for {filename}.")
exit exit
for filename in files: for filename in files:
with open(filename) as imgfile: # read image & crop
# read image & crop img_orig = cv.imread(f'{img_input_dir}/{filename}', cv.IMREAD_UNCHANGED)
img_orig = cv.imread(imgfile, cv.IMREAD_UNCHANGED)
img = rg_ratio_normalize( img = rg_ratio_normalize(
img_orig, img_orig,
config['i-darkcurrent'], config['i-darkcurrent'],
config['f-stop'], config['f-stop'],
config['exposure-time'], config['exposure-time'],
config['iso'], config['iso'],
config['min-temp'], config['min-temp'],
config['max-temp'], config['max-temp'],
config['scaling-factor'], config['scaling-factor'],
) img_out=False
)
# build & apply smoothing conv kernel # build & apply smoothing conv kernel
k = [] k = []
smoothing_radius = config['smoothing-radius'] smoothing_radius = config['smoothing-radius']
for i in range(smoothing_radius): for i in range(smoothing_radius):
k.append([1/(smoothing_radius**2) for i in range(smoothing_radius)]) k.append([1/(smoothing_radius**2) for i in range(smoothing_radius)])
kernel = np.array(k) kernel = np.array(k)
img = cv.filter2D(src=img, ddepth=-1, kernel=kernel) img = cv.filter2D(src=img, ddepth=-1, kernel=kernel)
# write colormapped image # chop off alphas & reverse bgr
img_jet = cv.applyColorMap(img, cv.COLORMAP_JET) img_orig = img_orig[:,:,:3]
img_orig = img_orig[:,:,::-1]
# TODO: GENERTE TEMP KEY & OUTPUT MATPLOTLIB fig = plt.figure()
ax = fig.add_subplot(1, 2, 1)
ax.set_title("Original Image")
imgplot_orig = plt.imshow(img_orig)
ax2 = fig.add_subplot(1, 2, 2)
ax2.set_title("Output Heatmap")
imgplot_final = plt.imshow(img, cmap="plasma")
ticks = np.linspace(
config['min-temp'],
config['max-temp'],
4
).tolist()
cbar = plt.colorbar(
orientation="horizontal",
)
cbar.ax.set_xticklabels([str(t) for t in ticks])
name = filename.split(".")[0]
extension = filename.split(".")[1]
fig.savefig(f"{img_out_dir}/{name}-transformed.{extension}", dpi=120)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1,21 +0,0 @@
# MONOCHROME EDGE DETECTION
import cv2 as cv
import numpy as np
file = '01-0001-cropped.png'
file_name = file.split(".")[0]
file_ext = file.split(".")[1]
img = cv.imread(file)
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
kernel = np.array([
[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1],
])
img = cv.filter2D(src=img, ddepth=-1, kernel=kernel)
cv.imwrite(f'{file_name}-edge-detection.{file_ext}', img)

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@@ -0,0 +1,80 @@
import cv2 as cv
import numpy as np
from skimage import measure, morphology, color, segmentation
import matplotlib.pyplot as plt
file = 'proj-area-3.jpg'
original = cv.imread(file)
original = cv.cvtColor(original, cv.COLOR_BGR2RGB)
img = original
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
retval, thresh_gray = cv.threshold(img, 200, 255, cv.THRESH_BINARY)
def remove_dirt(image):
image = morphology.area_closing(image, area_threshold=250, connectivity=1)
# image = morphology.opening(image, morphology.square(5))
return image
def calculate_area(countour):
c = np.expand_dims(countour.astype(np.float32), 1)
c = cv.UMat(c)
return cv.contourArea(c)
def center_of_mass(X):
x = X[:,0]
y = X[:,1]
g = (x[:-1]*y[1:] - x[1:]*y[:-1])
A = 0.5*g.sum()
cx = ((x[:-1] + x[1:])*g).sum()
cy = ((y[:-1] + y[1:])*g).sum()
return 1./(6*A)*np.array([cx,cy])
img = remove_dirt(thresh_gray)
# alpha = 1 # Contrast control (1.0-3.0)
# beta = 1 # Brightness control (0-100)
# img = cv.convertScaleAbs(img, alpha=alpha, beta=beta)
# img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# img = cv.medianBlur(img, 5)
# retval, thresh_gray = cv.threshold(img, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
# img = cv.medianBlur(img, 5)
# img = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 51, 15)
contours = measure.find_contours(array=img, level=100)
fig, ax = plt.subplots()
ax.imshow(img, cmap=plt.cm.gray, alpha=0)
index = 1
for contour in contours:
if calculate_area(contour) > 300:
ax.plot(contour[:, 1], contour[:, 0], linewidth=0.5, color='orangered')
cX, cY = center_of_mass(contour)
plt.text(cY, cX, index, color='black', fontsize=6)
index += 1
ax.axis('image')
ax.set_xticks([])
ax.set_yticks([])
plt.savefig('output.png', dpi=300)
# cv.imwrite('proj-area-1-processed.jpg', remove_dirt(img))

View File

Before

Width:  |  Height:  |  Size: 263 KiB

After

Width:  |  Height:  |  Size: 263 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 513 KiB

After

Width:  |  Height:  |  Size: 513 KiB

View File

Before

Width:  |  Height:  |  Size: 986 KiB

After

Width:  |  Height:  |  Size: 986 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 414 KiB

After

Width:  |  Height:  |  Size: 414 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

Before

Width:  |  Height:  |  Size: 354 KiB

After

Width:  |  Height:  |  Size: 354 KiB

View File

Before

Width:  |  Height:  |  Size: 841 KiB

After

Width:  |  Height:  |  Size: 841 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 MiB

View File

Before

Width:  |  Height:  |  Size: 15 MiB

After

Width:  |  Height:  |  Size: 15 MiB

BIN
examples/pyrometry/asdf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,78 @@
# MONOCHROME EDGE DETECTION
import cv2 as cv
import numpy as np
from skimage import measure, morphology, color, segmentation
import matplotlib.pyplot as plt
file = 'streaktest2.png'
img = cv.imread(file)
# blurred = cv.GaussianBlur(img, (8, 8), 0)
retval, thresh_gray = cv.threshold(img, 120, 255, cv.THRESH_BINARY)
kernel = np.ones((7, 7), np.uint8)
image = cv.morphologyEx(thresh_gray, cv.MORPH_CLOSE, kernel, iterations=1)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
retval, gray = cv.threshold(gray, 0, 255, cv.THRESH_BINARY)
gray = cv.copyMakeBorder(
gray,
20,
20,
20,
20,
cv.BORDER_CONSTANT,
value=0
)
# cv.imshow('gray', gray)
# cv.waitKey(0)
# contours = measure.find_contours(array=gray, level=100)
_img, contours = cv.findContours(gray, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)[0]
fig, ax = plt.subplots()
ax.imshow(gray, cmap=plt.cm.gray, alpha=1)
def calculate_area(countour):
c = np.expand_dims(countour.astype(np.float32), 1)
c = cv.UMat(c)
return cv.contourArea(c)
def center_of_mass(X):
x = X[:,0]
y = X[:,1]
g = (x[:-1]*y[1:] - x[1:]*y[:-1])
A = 0.5*g.sum()
cx = ((x[:-1] + x[1:])*g).sum()
cy = ((y[:-1] + y[1:])*g).sum()
return 1./(6*A)*np.array([cx,cy])
img_new = cv.cvtColor(gray, cv.COLOR_GRAY2BGR)
for contour in contours:
area = calculate_area(contour)
# if area > 250:
# cnt = np.array(contour).reshape((-1, 1, 2)).astype(np.int32)
# cv.drawContours(img_new, [cnt], -1, (0, 200, 255), thickness=10)
cv.drawContours(img_new, [contour], -1, (0, 200, 255), thickness=3)
# ax.plot(contour[:, 1], contour[:, 0], linewidth=0.5, color='orangered')
# cv.imshow('contours', img_new)
# cv.waitKey(0)
cv.imwrite("firebrand_contours_opencv.png", img_new)
ax.axis('image')
ax.set_xticks([])
ax.set_yticks([])
plt.savefig("edge_detection_figure.png", dpi=500)

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 KiB

0
firebrand_detection.py Normal file
View File

View File

@@ -1,6 +1,8 @@
from flask import Flask, render_template, request from flask import Flask, render_template, request, send_file
import numpy as np import numpy as np
from plotly_util import generate_plotly_temperature_pdf
from ratio_pyrometry import ratio_pyrometry_pipeline from ratio_pyrometry import ratio_pyrometry_pipeline
from size_projection import get_projected_area
import base64 import base64
import cv2 as cv import cv2 as cv
@@ -12,13 +14,13 @@ app = Flask(
@app.route('/', methods=['GET']) @app.route('/', methods=['GET'])
def index(): def index():
return render_template('index.jinja2') return render_template('index.html')
@app.route('/ratio_pyro', methods=['POST']) @app.route('/ratio_pyro', methods=['POST'])
def ratio_pyro(): def ratio_pyro():
f = request.files['file'] f = request.files['file']
f_bytes = np.fromstring(f.read(), np.uint8) f_bytes = np.fromstring(f.read(), np.uint8)
img_orig, img_res, key = ratio_pyrometry_pipeline( img_orig, img_res, key, ptemps, indiv_firebrands = ratio_pyrometry_pipeline(
f_bytes, f_bytes,
ISO=float(request.form['iso']), ISO=float(request.form['iso']),
I_Darkcurrent=float(request.form['i_darkcurrent']), I_Darkcurrent=float(request.form['i_darkcurrent']),
@@ -28,15 +30,64 @@ def ratio_pyro():
MIN_TEMP=float(request.form['min_temp']), MIN_TEMP=float(request.form['min_temp']),
smoothing_radius=int(request.form['smoothing_radius']), smoothing_radius=int(request.form['smoothing_radius']),
key_entries=int(request.form['legend_entries']), key_entries=int(request.form['legend_entries']),
eqn_scaling_factor=float(request.form['equation_scaling_factor']) eqn_scaling_factor=float(request.form['equation_scaling_factor']),
firebrand_min_intensity_threshold=float(request.form['intensity_threshold']),
firebrand_min_area=float(request.form['min_area']),
) )
# get base64 encoded images
img_orig_b64 = base64.b64encode(cv.imencode('.png', img_orig)[1]).decode(encoding='utf-8') img_orig_b64 = base64.b64encode(cv.imencode('.png', img_orig)[1]).decode(encoding='utf-8')
img_res_b64 = base64.b64encode(cv.imencode('.png', img_res)[1]).decode(encoding='utf-8') img_res_b64 = base64.b64encode(cv.imencode('.png', img_res)[1]).decode(encoding='utf-8')
ptemps_list = [ptemps]
for i in range(len(indiv_firebrands)):
# base64 encode image data
brand_data = indiv_firebrands[i]
unencoded = brand_data["img_data"]
brand_data["img_data"] = base64.b64encode(cv.imencode('.png', unencoded)[1]).decode(encoding='utf-8')
indiv_firebrands[i] = brand_data
# add ptemp data to list
ptemps_list.append(brand_data["ptemps"])
freq_plot, csvstrs = generate_plotly_temperature_pdf(ptemps_list)
return render_template( return render_template(
'results.jinja2', 'pyrometry-results.html',
img_orig_b64=img_orig_b64, img_orig_b64=img_orig_b64,
img_res_b64=img_res_b64, img_res_b64=img_res_b64,
legend=key legend=key,
freq_plot=freq_plot,
csv_data=csvstrs[0],
individual_firebrands=indiv_firebrands,
) )
@app.route('/projected_area')
def projected_area():
return render_template('projected-area.html')
@app.route('/projected_area_results', methods=['POST'])
def projected_area_results():
f = request.files['file']
f_bytes = np.fromstring(f.read(), np.uint8)
img, dtable = get_projected_area(
f_bytes,
int(request.form['area_threshold']),
int(request.form['min_display_threshold']),
float(request.form['paper_width']),
float(request.form['paper_width'])
)
return render_template(
'projected-area-results.html',
img_b64=img,
dtable=dtable
)
# @app.route("/download_pyrometry_temps")
# def download_pyrometry_temps():
# return send_file()

64
plotly_util.py Normal file
View File

@@ -0,0 +1,64 @@
from typing import List
import plotly.figure_factory as ff
import pandas as pd
def generate_plotly_temperature_pdf(ptemps_list: List[list]):
"""
Generate plotly graph HTML & raw CSV data for temperature pdf
ptemps: pixel temperature LIST in order of:
- Ptemps of firebrands "overview" image
- Ptemps list for each individual firebrand
plotname: what to call the plot
Returns result in form (plot_html, csv_data)
"""
# generate prob. distribution histogram & return embed
labels = ["Full Image"]
for i in range(len(ptemps_list[1:])):
labels.append(f"Firebrand {i+1}")
labels.reverse()
fig = ff.create_distplot(
ptemps_list,
group_labels=labels,
show_rug=False,
show_hist=False,
)
fig.update_layout(
autosize=False,
width=800,
height=600,
)
fig.update_xaxes(
title_text="Temperature (°C)",
)
fig.update_yaxes(
title_text="Probability (1/°C)",
)
freq_plot = fig.to_html()
# create csv-formatted stuff
csvstrs = []
plot_data=fig.to_dict()
for i in range(len(plot_data["data"])):
x_data = plot_data["data"][i]["x"]
y_data = plot_data["data"][i]["y"]
tdata = [["Temperature", "Frequency"]]
for i in range(len(x_data)):
r = []
r.append(x_data[i])
r.append(y_data[i])
tdata.append(r)
csvstr = pd.DataFrame(tdata).to_csv(index=False, header=False)
csvstrs.append(csvstr)
return (
freq_plot,
csvstrs
)

View File

@@ -3,6 +3,7 @@ from multiprocessing.sharedctypes import Value
import cv2 as cv import cv2 as cv
import numpy as np import numpy as np
from numba import jit from numba import jit
from skimage import measure
@jit(nopython=True) @jit(nopython=True)
def rg_ratio_normalize( def rg_ratio_normalize(
@@ -13,11 +14,16 @@ def rg_ratio_normalize(
ISO, ISO,
MIN_TEMP, MIN_TEMP,
MAX_TEMP, MAX_TEMP,
eqn_scaling_factor eqn_scaling_factor,
): ):
"""
Get normalized G/R -> temperature data + list of all temperatures
"""
# copy image into new array & chop off alpha values (if applicable) # copy image into new array & chop off alpha values (if applicable)
imgnew = imgarr.copy()[:,:,:3] imgnew = imgarr.copy()[:,:,:3]
positive_temps = []
for i in range(len(imgarr)): for i in range(len(imgarr)):
for j in range(len(imgarr[i])): for j in range(len(imgarr[i])):
px = imgarr[i][j] px = imgarr[i][j]
@@ -32,12 +38,14 @@ def rg_ratio_normalize(
# remove pixels outside calibration range # remove pixels outside calibration range
if (MIN_TEMP != None and temp_C < MIN_TEMP) or (MAX_TEMP != None and temp_C > MAX_TEMP): if (MIN_TEMP != None and temp_C < MIN_TEMP) or (MAX_TEMP != None and temp_C > MAX_TEMP):
temp_C = MIN_TEMP temp_C = MIN_TEMP
elif temp_C > MIN_TEMP:
positive_temps.append(temp_C)
# scale light intensity to calculated temperature # scale light intensity to calculated temperature
pix_i = scale_temp(temp_C, MIN_TEMP, MAX_TEMP) pix_i = scale_temp(temp_C, MIN_TEMP, MAX_TEMP)
imgnew[i][j] = [pix_i, pix_i, pix_i] imgnew[i][j] = [pix_i, pix_i, pix_i]
return imgnew return imgnew, positive_temps
@jit(nopython=True) @jit(nopython=True)
@@ -78,12 +86,105 @@ def ratio_pyrometry_pipeline(
smoothing_radius: int, smoothing_radius: int,
key_entries: int, key_entries: int,
eqn_scaling_factor: float, eqn_scaling_factor: float,
# firebrand detection
firebrand_min_intensity_threshold: float,
firebrand_min_area: float
): ):
# read image & crop # read image & crop
img_orig = cv.imdecode(file_bytes, cv.IMREAD_UNCHANGED) img_orig = cv.imdecode(file_bytes, cv.IMREAD_UNCHANGED)
img = rg_ratio_normalize( # ---------------------------------------------------------
# -- Firebrand detection
# ---------------------------------------------------------
img = cv.copyMakeBorder(
img_orig,
20,
20,
20,
20,
cv.BORDER_CONSTANT,
value=0
)
retval, thresh_gray = cv.threshold(img, firebrand_min_intensity_threshold, 255, cv.THRESH_BINARY)
kernel = np.ones((7, 7), np.uint8)
image = cv.morphologyEx(thresh_gray, cv.MORPH_CLOSE, kernel, iterations=1)
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
retval, gray = cv.threshold(gray, 0, 255, cv.THRESH_BINARY)
contours = measure.find_contours(array=gray, level=100)
def calculate_area(countour):
c = np.expand_dims(countour.astype(np.float32), 1)
c = cv.UMat(c)
return cv.contourArea(c)
individual_firebrands = []
for contour in contours:
if calculate_area(contour) > firebrand_min_area:
mask = np.zeros(img.shape[0:2], dtype='uint8')
cv.fillPoly(mask, pts=np.int32([np.flip(contour, 1)]), color=(255,255,255))
retval, mask = cv.threshold(mask, 0, 255, cv.THRESH_BINARY)
#apply the mask to the img
masked = cv.bitwise_and(img, img, mask=mask)
masked_ratio_rg, ptemps_indiv = rg_ratio_normalize(
masked,
I_Darkcurrent,
f_stop,
exposure_time,
ISO,
MIN_TEMP,
MAX_TEMP,
eqn_scaling_factor,
)
# build & apply smoothing conv kernel
k = []
for i in range(smoothing_radius):
k.append([1/(smoothing_radius**2) for i in range(smoothing_radius)])
kernel = np.array(k)
masked_ratio_rg = cv.filter2D(src=masked_ratio_rg, ddepth=-1, kernel=kernel)
# write colormapped image
masked_ratio_rg_jet = cv.applyColorMap(masked_ratio_rg, cv.COLORMAP_JET)
# Generate key
step = (MAX_TEMP - MIN_TEMP) / (key_entries-1)
temps = []
key_img_arr = [[]]
for i in range(key_entries):
res_temp = MIN_TEMP + (i * step)
res_color = scale_temp(res_temp, MIN_TEMP, MAX_TEMP)
temps.append(math.floor(res_temp))
key_img_arr[0].append([res_color, res_color, res_color])
key_img = np.array(key_img_arr).astype(np.uint8)
key_img_jet = cv.applyColorMap(key_img, cv.COLORMAP_JET)
tempkey = {}
for i in range(len(temps)):
c = key_img_jet[0][i]
tempkey[temps[i]] = f"rgb({c[2]}, {c[1]}, {c[0]})"
individual_firebrands.append({
"img_data": masked_ratio_rg_jet,
"legend": tempkey,
"ptemps": ptemps_indiv
})
img, ptemps = rg_ratio_normalize(
img_orig, img_orig,
I_Darkcurrent, I_Darkcurrent,
f_stop, f_stop,
@@ -91,7 +192,7 @@ def ratio_pyrometry_pipeline(
ISO, ISO,
MIN_TEMP, MIN_TEMP,
MAX_TEMP, MAX_TEMP,
eqn_scaling_factor eqn_scaling_factor,
) )
# build & apply smoothing conv kernel # build & apply smoothing conv kernel
@@ -105,7 +206,9 @@ def ratio_pyrometry_pipeline(
# write colormapped image # write colormapped image
img_jet = cv.applyColorMap(img, cv.COLORMAP_JET) img_jet = cv.applyColorMap(img, cv.COLORMAP_JET)
# --- Generate temperature key --- # ---------------------------------------------------------
# -- Generate temperature key
# ---------------------------------------------------------
# Generate key # Generate key
step = (MAX_TEMP - MIN_TEMP) / (key_entries-1) step = (MAX_TEMP - MIN_TEMP) / (key_entries-1)
@@ -126,4 +229,4 @@ def ratio_pyrometry_pipeline(
tempkey[temps[i]] = f"rgb({c[2]}, {c[1]}, {c[0]})" tempkey[temps[i]] = f"rgb({c[2]}, {c[1]}, {c[0]})"
# original, transformed, legend # original, transformed, legend
return img_orig, img_jet, tempkey return img_orig, img_jet, tempkey, ptemps, individual_firebrands

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

75
size_projection.py Normal file
View File

@@ -0,0 +1,75 @@
# use headless backend
import matplotlib
matplotlib.use("Agg")
import base64
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
from skimage import measure, morphology, color, segmentation
import io
def get_projected_area(image, area_threshold, display_threshold, paper_width, paper_height):
total_px = image.size
total_mm = paper_width * paper_height * 25.4
output = []
original = cv.imdecode(image, cv.IMREAD_UNCHANGED)
original = cv.cvtColor(original, cv.COLOR_BGR2RGB)
img = cv.cvtColor(original, cv.COLOR_BGR2GRAY)
_retval, thresh_gray = cv.threshold(img, 200, 255, cv.THRESH_BINARY)
img = morphology.area_closing(thresh_gray, area_threshold=area_threshold, connectivity=1)
contours = measure.find_contours(image=img, level=100)
fig, ax = plt.subplots()
ax.imshow(original, cmap=plt.cm.gray, alpha=0.3)
index = 1
for contour in contours:
area = calculate_area(contour)
if calculate_area(contour) > display_threshold:
ax.plot(contour[:, 1], contour[:, 0], linewidth=0.5, color='orangered')
cX, cY = center_of_mass(contour)
plt.text(cY, cX, index, color='black', fontsize=6)
output.append((index, round(area / total_px * total_mm, 2)))
# print(area, total_px)
index += 1
ax.axis('image')
ax.set_xticks([])
ax.set_yticks([])
ax.margins(0)
my_stringIObytes = io.BytesIO()
plt.savefig(my_stringIObytes, format='png', dpi=500, bbox_inches='tight')
my_stringIObytes.seek(0)
image_arr = base64.b64encode(my_stringIObytes.read()).decode(encoding='utf-8')
return image_arr, output
def calculate_area(countour):
c = np.expand_dims(countour.astype(np.float32), 1)
c = cv.UMat(c)
return cv.contourArea(c)
def center_of_mass(X):
x = X[:,0]
y = X[:,1]
g = (x[:-1]*y[1:] - x[1:]*y[:-1])
A = 0.5*g.sum()
cx = ((x[:-1] + x[1:])*g).sum()
cy = ((y[:-1] + y[1:])*g).sum()
return 1./(6*A)*np.array([cx,cy])

77
static/app.css Normal file
View File

@@ -0,0 +1,77 @@
* {
font-family: sans-serif;
}
html {
margin: 0px;
padding: 0px;
}
.navbar {
display: flex;
flex-direction: row;
align-items: center;
padding: 0px 2rem;
background-color: #e0e0e0;
border-radius: 0.8rem;
}
.navbar-links {
display: flex;
flex-direction: row;
align-items: center;
margin-left: auto;
}
.navbar-link {
display: flex;
margin-left: 3rem;
}
.content {
display: flex;
margin: 0rem 1rem;
}
.form {
display: flex;
flex-direction: column;
}
#img-preview {
width: 18rem;
}
#pyro-eqn {
width: 800px;
}
.img-table-heading {
padding: 4px 10px;
}
.img-table-cell {
padding: 10px 20px;
}
.img-out {
width: 32rem;
}
.image-out-pa {
width: 60rem;
}
.legend {
border-spacing: 0px;
border-collapse: collapse;
}
.legend-heading {
padding: 4px;
}
.legend-cell {
border-width: 0px;
padding: 0px 20px;
}

28
static/js/csv_download.js Normal file
View File

@@ -0,0 +1,28 @@
function saveData(csvStr, filename) {
// string rep
// var csvStr = "";
// for (let r = 0; r < csvData.length; r++) {
// let row = csvData[r]
// for (let c = 0; c < row.length; c++) {
// let item = row[c]
// csvStr += item;
// if (c < row.length - 1)
// csvStr += ",";
// }
// if (r < csvStr.length - 1)
// csvStr += "\r\n";
// }
// define data blob
var data = new Blob([csvStr]);
// create & click temp link
// slightly modded https://stackoverflow.com/a/15832662
var link = document.createElement("a");
link.download = filename;
link.href = URL.createObjectURL(data);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}

9
static/js/img_preview.js Normal file
View File

@@ -0,0 +1,9 @@
let imgPreview = document.getElementById('img-preview');
let imgUpload = document.getElementById('img-upload');
imgUpload.onchange = event => {
const [file] = imgUpload.files;
if (file) {
console.log(file)
imgPreview.src = URL.createObjectURL(file);
}
};

View File

@@ -1,4 +0,0 @@
.form {
display: flex;
flex-direction: column;
}

22
templates/base.html Normal file
View File

@@ -0,0 +1,22 @@
<!DOCTYPE html>
<head>
<title>Pyrometry Application</title>
<link rel="stylesheet" href="{{ url_for('static', filename='app.css') }}">
{% block head %}
{% endblock %}
</head>
<body>
<div class="navbar">
<h3>Pyrometry Toolkit</h3>
<div class="navbar-links">
<a class="navbar-link" href="/">Ratio Pyrometry</a>
<a class="navbar-link" href="/projected_area">Projected Area</a>
</div>
</div>
<br>
<div class="content">
{% block content required %}
{% endblock %}
</div>
<br><br><br>
</body>

View File

@@ -1,15 +0,0 @@
<!DOCTYPE html>
<head>
<title>Pyrometry Application</title>
<link rel="app.css">
</head>
<body>
{% block content required %}
{% endblock %}
</body>
<style>
* {
font-family: sans-serif;
}
</style>

View File

@@ -1,7 +1,11 @@
{% extends "base.jinja2" %} {% extends "base.html" %}
{% block head %}
{% endblock %}
{% block content %} {% block content %}
<form action="/ratio_pyro" method="POST" enctype="multipart/form-data"> <form action="/ratio_pyro" method="POST" enctype="multipart/form-data">
<h2>Simple Ratio Pyrometry Interface</h2> <h2>Ratio Pyrometry Interface</h2>
<img src="#" id="img-preview" type="file"/> <img src="#" id="img-preview" type="file"/>
<br> <br>
@@ -44,6 +48,16 @@
<input type="number" name="equation_scaling_factor" value="0.55" step="0.001"/> <input type="number" name="equation_scaling_factor" value="0.55" step="0.001"/>
<br> <br>
<h4>Firebrand Detection Settings</h4>
<label for="intensity_threshold">intensity threshold (0-255)</label>
<input type="number" name="intensity_threshold" value="250", step="0.1"/>
<br>
<label for="min_area">min area (removes small particles)</label>
<input type="number" name="min_area" value="115", step="0.1"/>
<br>
<h4>Output Settings</h4> <h4>Output Settings</h4>
<label for="smoothing_radius">Smoothing Radius (px)</label> <label for="smoothing_radius">Smoothing Radius (px)</label>
@@ -58,25 +72,7 @@
<input type="submit" value="Generate Heatmap"/> <input type="submit" value="Generate Heatmap"/>
</form> </form>
<script> <!-- Image Preview -->
let imgPreview = document.getElementById('img-preview'); <script src="/s/js/img_preview.js"></script>
let imgUpload = document.getElementById('img-upload');
imgUpload.onchange = event => {
const [file] = imgUpload.files;
if (file) {
console.log(file)
imgPreview.src = URL.createObjectURL(file);
}
};
</script>
<style>
#img-preview {
width: 18rem;
}
#pyro-eqn {
width: 800px;
}
</style>
{% endblock %} {% endblock %}

View File

@@ -0,0 +1,30 @@
{% extends "base.html" %}
{% block content %}
<h2>Results</h2>
<a href="/projected_area">Process another image</a>
<div style="display: flex; align-items: start;">
<img class="image-out-pa" src="data:image/png;base64,{{ img_b64 }}" alt="original image">
<div style="overflow-y: scroll;">
<table style="background: #f1f1f1">
<tr>
<th class="legend-heading">Index</th>
<th class="legend-heading">Area (mm²)</th>
<th class="legend-heading">Copy</th>
</tr>
{% for item in dtable %}
<tr>
<td class="legend-cell">{{ item.0 }}</td>
<td class="legend-cell">{{ item.1 }}</td>
<td>
<button onclick="() => navigator.clipboard.writeText('{{ item.1 }}')">Copy</button>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,38 @@
{% extends "base.html" %}
{% block content %}
<form action="/projected_area_results" method="POST" enctype="multipart/form-data">
<h2>Projected Area Interface</h2>
<img src="#" id="img-preview" type="file"/>
<br>
<input id="img-upload" type="file" name="file" accept=".png,.jpg,.jpeg,.tiff" value="Choose Image"/>
<h4>Settings</h4>
<label for="area_threshold">Area threshold (to remove dust particles) in px</label>
<input type="number" name="area_threshold" value="250"/>
<br>
<br>
<label for="min_display_threshold">Minimum display threshold (in px)</label>
<input type="number" name="min_display_threshold" value="300"/>
<br>
<br>
<label for="min_display_threshold">Page size</label>
<input type="number" name="paper_width" value="8.5"/>
X
<input type="number" name="paper_height" value="11"/> inches
<br>
<br>
<br>
<input type="submit" value="Generate Projected Sizes"/>
</form>
<!-- Image Preview -->
<script src="/s/js/img_preview.js"></script>
{% endblock %}

View File

@@ -0,0 +1,99 @@
{% extends "base.html" %}
{% block head %}
<script src="/s/js/csv_download.js"></script>
{% endblock %}
{% block content %}
<div style="display:flex; flex-direction: column;">
<h2>General Results</h2>
<table class="img-table">
<tr>
<th class="img-table-heading">Input Image</th>
<th class="img-table-heading">Output Heatmap</th>
<th class="img-table-heading">Legend</th>
</tr>
<tr>
{# Original image #}
<td class="img-table-cell" id="orig-cell">
<img class="img-out" src="data:image/png;base64,{{ img_orig_b64 }}" alt="original image">
</td>
{# Result image #}
<td class="img-table-cell" id="res-cell">
<img class="img-out" src="data:image/png;base64,{{ img_res_b64 }}" alt="result image">
</td>
{# Legend #}
<td>
<table class="legend" id="legend">
<tr>
<th class="legend-heading">Color</th>
<th class="legend-heading">Temperature</th>
</tr>
{% for temp, color in legend.items() %}
<tr>
<td class="legend-cell"><div style="width:30px;height:20px;background-color:{{ color }};"></div></td>
<td class="legend-cell">{{ temp }}°C</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
</table>
<h2>Individual Firebrands</h2>
<table>
<tr>
<th>Output Heatmap</th>
<th>Legend</th>
</tr>
{% for item in individual_firebrands %}
<tr>
{# output heatmap #}
<td>
<img class="img-out" src="data:image/png;base64,{{ item['img_data'] }}" alt="result image">
</td>
</td>
{# legend #}
<td>
<h3>Firebrand {{ loop.index }}</h3>
<table class="legend" id="legend">
<tr>
<th class="legend-heading">Color</th>
<th class="legend-heading">Temperature</th>
</tr>
{% for temp, color in item["legend"].items() %}
<tr>
<td class="legend-cell"><div style="width:30px;height:20px;background-color:{{ color }};"></div></td>
<td class="legend-cell">{{ temp }}°C</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
{% endfor %}
</table>
<br>
{# Temperature Frequency Plot #}
<div style="display: flex; flex-direction: row; align-items: center;">
<strong>Temperature Distribution</strong>
<button
style="width: 10rem; height: 2rem; margin-left: 1rem;"
onclick="saveData(`{{csv_data}}`, 'temperature-data.csv')">Download Data as CSV</button>
</div>
{{ freq_plot | safe }}
<!-- Firebrands: {{ individual_firebrands }} -->
</div>
{% endblock %}

View File

@@ -1,67 +0,0 @@
{% extends "base.jinja2" %}
{% block content %}
<table class="img-table">
<tr>
<th class="img-table-heading">Input Image</th>
<th class="img-table-heading">Output Heatmap</th>
</tr>
<tr>
{# Original image #}
<td class="img-table-cell" id="orig-cell">
<img class="img-out" src="data:image/png;base64,{{ img_orig_b64 }}" alt="original image">
</td>
{# Result image #}
<td class="img-table-cell" id="res-cell">
<img class="img-out" src="data:image/png;base64,{{ img_res_b64 }}" alt="result image">
</td>
</tr>
{# Legend #}
<tr>
<td class="img-table-cell"></td>
<td class="img-table-cell">
<table class="legend" id="legend">
<tr>
<th class="legend-heading">Color</th>
<th class="legend-heading">Temperature</th>
</tr>
{% for temp, color in legend.items() %}
<tr>
<td class="legend-cell"><div style="width:30px;height:20px;background-color:{{ color }};"></div></td>
<td class="legend-cell">{{ temp }}°C</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
</table>
<style>
.img-table-heading {
padding: 4px 10px;
}
.img-table-cell {
padding: 10px 20px;
}
.img-out {
width: 32rem;
}
.legend {
border-spacing: 0px;
border-collapse: collapse;
}
.legend-heading {
padding: 4px;
}
.legend-cell {
border-width: 0px;
padding: 0px 20px;
}
</style>
{% endblock %}