generated from dopt-python/py311
first improvements in speedup
This commit is contained in:
parent
f39a8cc5f3
commit
31bc992834
42
README.md
42
README.md
@ -1,26 +1,30 @@
|
||||
# Repository Template for Python 3.11 Projects
|
||||
|
||||
## Tools for Project and Package Management
|
||||
# KSG AOI image anomaly detection
|
||||
|
||||
[](https://pdm-project.org)
|
||||
[](https://github.com/astral-sh/ruff)
|
||||
|
||||
Python projects are managed with **PDM** ([link to GitHub Source](https://github.com/pdm-project/pdm)), a PEP-compliant project and dependency management tool.
|
||||
The applicable settings are contained within the PyProject-TOML file. In order to use a repo which was created with this template is to tell PDM which Python interpreter to use and then to install the whole project into the created virtual environment. If the interpreter is not available you will need to install it via PDM.
|
||||
## General
|
||||
|
||||
### Lib structure by Susanne
|
||||
|
||||
- configs:
|
||||
- ``config.py``: reduced version of original config to work as a small test example
|
||||
- ``config_for_test.py``: special parameters for test environment, minimal working example
|
||||
- main program:
|
||||
- ``main.py``: loads GUI and background worker to observe changes in folder directory
|
||||
- GUI:
|
||||
- ``window_manager.py``
|
||||
- ``gui_ai_on_off.py``
|
||||
- Logic:
|
||||
- ``monitor.py``: worker logic to observe changes in the relevant folders
|
||||
- function ``monitor_folder``
|
||||
- ``preparation.py``: main logic to process data ``class Preparation``, namely:
|
||||
- copy (backup) of found data to this app's saving directory (``config.py -- STORING_PATH``)
|
||||
- method ``copy_ngt_and_checkimg``
|
||||
- colourisation of images (only the first) (yellow)
|
||||
- method ``change_image_to_yellow``
|
||||
- fuse the different RGB layers to one image and save it
|
||||
- method ``create_rgb_images_and_patches``
|
||||
|
||||
```console
|
||||
pdm use 3.11.11 # example of a given version
|
||||
pdm install
|
||||
```
|
||||
|
||||
This installs all mandatory development dependencies such as:
|
||||
- Ruff (formatting and linting)
|
||||
- pytest (unittest framework)
|
||||
- coverage.py (measuring test coverage)
|
||||
- pytest-cov (integration of coverage into pytest)
|
||||
- pytest-xdist (allows to execute the tests on multiple CPU cores)
|
||||
- bump-my-version (CLI tool to manage version bumping)
|
||||
- Nox (Python runner, e.g. to run test suite on multiple Python versions)
|
||||
- pdoc (to auto-generate documentation from docstrings)
|
||||
- Jupyterlab and widgets (to perform fast prototyping and enable exploratory data analysis)
|
||||
|
||||
|
||||
318
pdm.lock
generated
318
pdm.lock
generated
@ -5,10 +5,10 @@
|
||||
groups = ["default", "dev", "lint", "nb", "tests"]
|
||||
strategy = ["inherit_metadata"]
|
||||
lock_version = "4.5.0"
|
||||
content_hash = "sha256:3a107981dc4305f031f87c89e3a57a6bb823954d397a52d074fef1c72ac639d0"
|
||||
content_hash = "sha256:326ca1095302e816f56644c4ba0929ea12b930348375c98eba139701e0388de6"
|
||||
|
||||
[[metadata.targets]]
|
||||
requires_python = ">=3.11"
|
||||
requires_python = ">=3.11,<3.15"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
@ -271,7 +271,7 @@ name = "cffi"
|
||||
version = "2.0.0"
|
||||
requires_python = ">=3.9"
|
||||
summary = "Foreign Function Interface for Python calling C code."
|
||||
groups = ["nb"]
|
||||
groups = ["default", "nb"]
|
||||
dependencies = [
|
||||
"pycparser; implementation_name != \"PyPy\"",
|
||||
]
|
||||
@ -1542,6 +1542,108 @@ files = [
|
||||
{file = "nox-2026.2.9.tar.gz", hash = "sha256:1bc8a202ee8cd69be7aaada63b2a7019126899a06fc930a7aee75585bf8ee41b"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "2.4.2"
|
||||
requires_python = ">=3.11"
|
||||
summary = "Fundamental package for array computing in Python"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "numpy-2.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7e88598032542bd49af7c4747541422884219056c268823ef6e5e89851c8825"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7edc794af8b36ca37ef5fcb5e0d128c7e0595c7b96a2318d1badb6fcd8ee86b1"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:6e9f61981ace1360e42737e2bae58b27bf28a1b27e781721047d84bd754d32e7"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cb7bbb88aa74908950d979eeaa24dbdf1a865e3c7e45ff0121d8f70387b55f73"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f069069931240b3fc703f1e23df63443dbd6390614c8c44a87d96cd0ec81eb1"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c02ef4401a506fb60b411467ad501e1429a3487abca4664871d9ae0b46c8ba32"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2653de5c24910e49c2b106499803124dde62a5a1fe0eedeaecf4309a5f639390"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1ae241bbfc6ae276f94a170b14785e561cb5e7f626b6688cf076af4110887413"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-win32.whl", hash = "sha256:df1b10187212b198dd45fa943d8985a3c8cf854aed4923796e0e019e113a1bda"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:b9c618d56a29c9cb1c4da979e9899be7578d2e0b3c24d52079c166324c9e8695"},
|
||||
{file = "numpy-2.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:47c5a6ed21d9452b10227e5e8a0e1c22979811cad7dcc19d8e3e2fb8fa03f1a3"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:21982668592194c609de53ba4933a7471880ccbaadcc52352694a59ecc860b3a"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40397bda92382fcec844066efb11f13e1c9a3e2a8e8f318fb72ed8b6db9f60f1"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:b3a24467af63c67829bfaa61eecf18d5432d4f11992688537be59ecd6ad32f5e"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:805cc8de9fd6e7a22da5aed858e0ab16be5a4db6c873dde1d7451c541553aa27"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6d82351358ffbcdcd7b686b90742a9b86632d6c1c051016484fa0b326a0a1548"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e35d3e0144137d9fdae62912e869136164534d64a169f86438bc9561b6ad49f"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adb6ed2ad29b9e15321d167d152ee909ec73395901b70936f029c3bc6d7f4460"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8906e71fd8afcb76580404e2a950caef2685df3d2a57fe82a86ac8d33cc007ba"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-win32.whl", hash = "sha256:ec055f6dae239a6299cace477b479cca2fc125c5675482daf1dd886933a1076f"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:209fae046e62d0ce6435fcfe3b1a10537e858249b3d9b05829e2a05218296a85"},
|
||||
{file = "numpy-2.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:fbde1b0c6e81d56f5dccd95dd4a711d9b95df1ae4009a60887e56b27e8d903fa"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25f2059807faea4b077a2b6837391b5d830864b3543627f381821c646f31a63c"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bd3a7a9f5847d2fb8c2c6d1c862fa109c31a9abeca1a3c2bd5a64572955b2979"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8e4549f8a3c6d13d55041925e912bfd834285ef1dd64d6bc7d542583355e2e98"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:aea4f66ff44dfddf8c2cffd66ba6538c5ec67d389285292fe428cb2c738c8aef"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3cd545784805de05aafe1dde61752ea49a359ccba9760c1e5d1c88a93bbf2b7"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0d9b7c93578baafcbc5f0b83eaf17b79d345c6f36917ba0c67f45226911d499"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f74f0f7779cc7ae07d1810aab8ac6b1464c3eafb9e283a40da7309d5e6e48fbb"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c7ac672d699bf36275c035e16b65539931347d68b70667d28984c9fb34e07fa7"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-win32.whl", hash = "sha256:8e9afaeb0beff068b4d9cd20d322ba0ee1cecfb0b08db145e4ab4dd44a6b5110"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:7df2de1e4fba69a51c06c28f5a3de36731eb9639feb8e1cf7e4a7b0daf4cf622"},
|
||||
{file = "numpy-2.4.2-cp313-cp313-win_arm64.whl", hash = "sha256:0fece1d1f0a89c16b03442eae5c56dc0be0c7883b5d388e0c03f53019a4bfd71"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5633c0da313330fd20c484c78cdd3f9b175b55e1a766c4a174230c6b70ad8262"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d9f64d786b3b1dd742c946c42d15b07497ed14af1a1f3ce840cce27daa0ce913"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:b21041e8cb6a1eb5312dd1d2f80a94d91efffb7a06b70597d44f1bd2dfc315ab"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:00ab83c56211a1d7c07c25e3217ea6695e50a3e2f255053686b081dc0b091a82"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fb882da679409066b4603579619341c6d6898fc83a8995199d5249f986e8e8f"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:66cb9422236317f9d44b67b4d18f44efe6e9c7f8794ac0462978513359461554"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0f01dcf33e73d80bd8dc0f20a71303abbafa26a19e23f6b68d1aa9990af90257"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-win32.whl", hash = "sha256:52b913ec40ff7ae845687b0b34d8d93b60cb66dcee06996dd5c99f2fc9328657"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-win_amd64.whl", hash = "sha256:5eea80d908b2c1f91486eb95b3fb6fab187e569ec9752ab7d9333d2e66bf2d6b"},
|
||||
{file = "numpy-2.4.2-cp313-cp313t-win_arm64.whl", hash = "sha256:fd49860271d52127d61197bb50b64f58454e9f578cb4b2c001a6de8b1f50b0b1"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:444be170853f1f9d528428eceb55f12918e4fda5d8805480f36a002f1415e09b"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1240d50adff70c2a88217698ca844723068533f3f5c5fa6ee2e3220e3bdb000"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:7cdde6de52fb6664b00b056341265441192d1291c130e99183ec0d4b110ff8b1"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:cda077c2e5b780200b6b3e09d0b42205a3d1c68f30c6dceb90401c13bff8fe74"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d30291931c915b2ab5717c2974bb95ee891a1cf22ebc16a8006bd59cd210d40a"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bba37bc29d4d85761deed3954a1bc62be7cf462b9510b51d367b769a8c8df325"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b2f0073ed0868db1dcd86e052d37279eef185b9c8db5bf61f30f46adac63c909"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7f54844851cdb630ceb623dcec4db3240d1ac13d4990532446761baede94996a"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-win32.whl", hash = "sha256:12e26134a0331d8dbd9351620f037ec470b7c75929cb8a1537f6bfe411152a1a"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-win_amd64.whl", hash = "sha256:068cdb2d0d644cdb45670810894f6a0600797a69c05f1ac478e8d31670b8ee75"},
|
||||
{file = "numpy-2.4.2-cp314-cp314-win_arm64.whl", hash = "sha256:6ed0be1ee58eef41231a5c943d7d1375f093142702d5723ca2eb07db9b934b05"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:98f16a80e917003a12c0580f97b5f875853ebc33e2eaa4bccfc8201ac6869308"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:20abd069b9cda45874498b245c8015b18ace6de8546bf50dfa8cea1696ed06ef"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:e98c97502435b53741540a5717a6749ac2ada901056c7db951d33e11c885cc7d"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:da6cad4e82cb893db4b69105c604d805e0c3ce11501a55b5e9f9083b47d2ffe8"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e4424677ce4b47fe73c8b5556d876571f7c6945d264201180db2dc34f676ab5"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2b8f157c8a6f20eb657e240f8985cc135598b2b46985c5bccbde7616dc9c6b1e"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5daf6f3914a733336dab21a05cdec343144600e964d2fcdabaac0c0269874b2a"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-win32.whl", hash = "sha256:8c50dd1fc8826f5b26a5ee4d77ca55d88a895f4e4819c7ecc2a9f5905047a443"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-win_amd64.whl", hash = "sha256:fcf92bee92742edd401ba41135185866f7026c502617f422eb432cfeca4fe236"},
|
||||
{file = "numpy-2.4.2-cp314-cp314t-win_arm64.whl", hash = "sha256:1f92f53998a17265194018d1cc321b2e96e900ca52d54c7c77837b71b9465181"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:89f7268c009bc492f506abd6f5265defa7cb3f7487dc21d357c3d290add45082"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6dee3bb76aa4009d5a912180bf5b2de012532998d094acee25d9cb8dee3e44a"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:cd2bd2bbed13e213d6b55dc1d035a4f91748a7d3edc9480c13898b0353708920"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:cf28c0c1d4c4bf00f509fa7eb02c58d7caf221b50b467bcb0d9bbf1584d5c821"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e04ae107ac591763a47398bb45b568fc38f02dbc4aa44c063f67a131f99346cb"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:602f65afdef699cda27ec0b9224ae5dc43e328f4c24c689deaf77133dbee74d0"},
|
||||
{file = "numpy-2.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be71bf1edb48ebbbf7f6337b5bfd2f895d1902f6335a5830b20141fc126ffba0"},
|
||||
{file = "numpy-2.4.2.tar.gz", hash = "sha256:659a6107e31a83c4e33f763942275fd278b21d095094044eb35569e86a21ddae"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opencv-python"
|
||||
version = "4.13.0.92"
|
||||
requires_python = ">=3.6"
|
||||
summary = "Wrapper package for OpenCV python bindings."
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"numpy<2.0; python_version < \"3.9\"",
|
||||
"numpy>=2; python_version >= \"3.9\"",
|
||||
]
|
||||
files = [
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:5868a8c028a0b37561579bfb8ac1875babdc69546d236249fff296a8c010ccf9"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bc2596e68f972ca452d80f444bc404e08807d021fbba40df26b61b18e01838a"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:402033cddf9d294693094de5ef532339f14ce821da3ad7df7c9f6e8316da32cf"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bccaabf9eb7f897ca61880ce2869dcd9b25b72129c28478e7f2a5e8dee945616"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:620d602b8f7d8b8dab5f4b99c6eb353e78d3fb8b0f53db1bd258bb1aa001c1d5"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-win32.whl", hash = "sha256:372fe164a3148ac1ca51e5f3ad0541a4a276452273f503441d718fab9c5e5f59"},
|
||||
{file = "opencv_python-4.13.0.92-cp37-abi3-win_amd64.whl", hash = "sha256:423d934c9fafb91aad38edf26efb46da91ffbc05f3f59c4b0c72e699720706f5"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overrides"
|
||||
version = "7.7.0"
|
||||
@ -1619,6 +1721,95 @@ files = [
|
||||
{file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.1.1"
|
||||
requires_python = ">=3.10"
|
||||
summary = "Python Imaging Library (fork)"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563"},
|
||||
{file = "pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6"},
|
||||
{file = "pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d242e8ac078781f1de88bf823d70c1a9b3c7950a44cdf4b7c012e22ccbcd8e4e"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:02f84dfad02693676692746df05b89cf25597560db2857363a208e393429f5e9"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:e65498daf4b583091ccbb2556c7000abf0f3349fcd57ef7adc9a84a394ed29f6"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c6db3b84c87d48d0088943bf33440e0c42370b99b1c2a7989216f7b42eede60"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8b7e5304e34942bf62e15184219a7b5ad4ff7f3bb5cca4d984f37df1a0e1aee2"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5bddd742a44b7e6b1e773ab5db102bd7a94c32555ba656e76d319d19c3850"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc44ef1f3de4f45b50ccf9136999d71abb99dca7706bc75d222ed350b9fd2289"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a8eb7ed8d4198bccbd07058416eeec51686b498e784eda166395a23eb99138e"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47b94983da0c642de92ced1702c5b6c292a84bd3a8e1d1702ff923f183594717"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:518a48c2aab7ce596d3bf79d0e275661b846e86e4d0e7dec34712c30fe07f02a"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a550ae29b95c6dc13cf69e2c9dc5747f814c54eeb2e32d683e5e93af56caa029"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win32.whl", hash = "sha256:a003d7422449f6d1e3a34e3dd4110c22148336918ddbfc6a32581cd54b2e0b2b"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:344cf1e3dab3be4b1fa08e449323d98a2a3f819ad20f4b22e77a0ede31f0faa1"},
|
||||
{file = "pillow-12.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:5c0dd1636633e7e6a0afe7bf6a51a14992b7f8e60de5789018ebbdfae55b040a"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0330d233c1a0ead844fc097a7d16c0abff4c12e856c0b325f231820fee1f39da"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dae5f21afb91322f2ff791895ddd8889e5e947ff59f71b46041c8ce6db790bc"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e0c664be47252947d870ac0d327fea7e63985a08794758aa8af5b6cb6ec0c9c"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:691ab2ac363b8217f7d31b3497108fb1f50faab2f75dfb03284ec2f217e87bf8"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9e8064fb1cc019296958595f6db671fba95209e3ceb0c4734c9baf97de04b20"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:472a8d7ded663e6162dafdf20015c486a7009483ca671cece7a9279b512fcb13"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:89b54027a766529136a06cfebeecb3a04900397a3590fd252160b888479517bf"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:86172b0831b82ce4f7877f280055892b31179e1576aa00d0df3bb1bbf8c3e524"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win32.whl", hash = "sha256:44ce27545b6efcf0fdbdceb31c9a5bdea9333e664cda58a7e674bb74608b3986"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win_amd64.whl", hash = "sha256:a285e3eb7a5a45a2ff504e31f4a8d1b12ef62e84e5411c6804a42197c1cf586c"},
|
||||
{file = "pillow-12.1.1-cp313-cp313t-win_arm64.whl", hash = "sha256:cc7d296b5ea4d29e6570dabeaed58d31c3fea35a633a69679fb03d7664f43fb3"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:417423db963cb4be8bac3fc1204fe61610f6abeed1580a7a2cbb2fbda20f12af"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:b957b71c6b2387610f556a7eb0828afbe40b4a98036fc0d2acfa5a44a0c2036f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:097690ba1f2efdeb165a20469d59d8bb03c55fb6621eb2041a060ae8ea3e9642"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2815a87ab27848db0321fb78c7f0b2c8649dee134b7f2b80c6a45c6831d75ccd"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:f7ed2c6543bad5a7d5530eb9e78c53132f93dfa44a28492db88b41cdab885202"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:652a2c9ccfb556235b2b501a3a7cf3742148cd22e04b5625c5fe057ea3e3191f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6e4571eedf43af33d0fc233a382a76e849badbccdf1ac438841308652a08e1f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b574c51cf7d5d62e9be37ba446224b59a2da26dc4c1bb2ecbe936a4fb1a7cb7f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a37691702ed687799de29a518d63d4682d9016932db66d4e90c345831b02fb4e"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f95c00d5d6700b2b890479664a06e754974848afaae5e21beb4d83c106923fd0"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:559b38da23606e68681337ad74622c4dbba02254fc9cb4488a305dd5975c7eeb"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win32.whl", hash = "sha256:03edcc34d688572014ff223c125a3f77fb08091e4607e7745002fc214070b35f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:50480dcd74fa63b8e78235957d302d98d98d82ccbfac4c7e12108ba9ecbdba15"},
|
||||
{file = "pillow-12.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:5cb1785d97b0c3d1d1a16bc1d710c4a0049daefc4935f3a8f31f827f4d3d2e7f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:1f90cff8aa76835cba5769f0b3121a22bd4eb9e6884cfe338216e557a9a548b8"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1f1be78ce9466a7ee64bfda57bdba0f7cc499d9794d518b854816c41bf0aa4e9"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:42fc1f4677106188ad9a55562bbade416f8b55456f522430fadab3cef7cd4e60"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98edb152429ab62a1818039744d8fbb3ccab98a7c29fc3d5fcef158f3f1f68b7"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d470ab1178551dd17fdba0fef463359c41aaa613cdcd7ff8373f54be629f9f8f"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6408a7b064595afcab0a49393a413732a35788f2a5092fdc6266952ed67de586"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5d8c41325b382c07799a3682c1c258469ea2ff97103c53717b7893862d0c98ce"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c7697918b5be27424e9ce568193efd13d925c4481dd364e43f5dff72d33e10f8"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win32.whl", hash = "sha256:d2912fd8114fc5545aa3a4b5576512f64c55a03f3ebcca4c10194d593d43ea36"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:4ceb838d4bd9dab43e06c363cab2eebf63846d6a4aeaea283bbdfd8f1a8ed58b"},
|
||||
{file = "pillow-12.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7b03048319bfc6170e93bd60728a1af51d3dd7704935feb228c4d4faab35d334"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735"},
|
||||
{file = "pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e"},
|
||||
{file = "pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.9.2"
|
||||
@ -1722,7 +1913,7 @@ name = "pycparser"
|
||||
version = "3.0"
|
||||
requires_python = ">=3.10"
|
||||
summary = "C parser in Python"
|
||||
groups = ["nb"]
|
||||
groups = ["default", "nb"]
|
||||
marker = "implementation_name != \"PyPy\""
|
||||
files = [
|
||||
{file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"},
|
||||
@ -1864,6 +2055,60 @@ files = [
|
||||
{file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6"
|
||||
version = "6.10.2"
|
||||
requires_python = "<3.15,>=3.9"
|
||||
summary = "Python bindings for the Qt cross-platform application and UI framework"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"PySide6-Addons==6.10.2",
|
||||
"PySide6-Essentials==6.10.2",
|
||||
"shiboken6==6.10.2",
|
||||
]
|
||||
files = [
|
||||
{file = "pyside6-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:4b084293caa7845d0064aaf6af258e0f7caae03a14a33537d0a552131afddaf0"},
|
||||
{file = "pyside6-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:1b89ce8558d4b4f35b85bff1db90d680912e4d3ce9e79ff804d6fef1d1a151ef"},
|
||||
{file = "pyside6-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:0439f5e9b10ebe6177981bac9e219096ec970ac6ec215bef055279802ba50601"},
|
||||
{file = "pyside6-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:032bad6b18a17fcbf4dddd0397f49b07f8aae7f1a45b7e4de7037bf7fd6e0edf"},
|
||||
{file = "pyside6-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:65a59ad0bc92525639e3268d590948ce07a80ee97b55e7a9200db41d493cac31"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-addons"
|
||||
version = "6.10.2"
|
||||
requires_python = "<3.15,>=3.9"
|
||||
summary = "Python bindings for the Qt cross-platform application and UI framework (Addons)"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"PySide6-Essentials==6.10.2",
|
||||
"shiboken6==6.10.2",
|
||||
]
|
||||
files = [
|
||||
{file = "pyside6_addons-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:0de7d0c9535e17d5e3b634b61314a1867f3b0f6d35c3d7cdc99efc353192faff"},
|
||||
{file = "pyside6_addons-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:030a851163b51dbf0063be59e9ddb6a9e760bde89a28e461ccc81a224d286eaf"},
|
||||
{file = "pyside6_addons-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:fcee0373e3fd7b98f014094e5e37b4a39e4de7c5a47c13f654a7d557d4a426ad"},
|
||||
{file = "pyside6_addons-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:c20150068525a17494f3b6576c5d61c417cf9a5870659e29f5ebd83cd20a78ea"},
|
||||
{file = "pyside6_addons-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:3d18db739b46946ba7b722d8ad4cc2097135033aa6ea57076e64d591e6a345f3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-essentials"
|
||||
version = "6.10.2"
|
||||
requires_python = "<3.15,>=3.9"
|
||||
summary = "Python bindings for the Qt cross-platform application and UI framework (Essentials)"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"shiboken6==6.10.2",
|
||||
]
|
||||
files = [
|
||||
{file = "pyside6_essentials-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:1dee2cb9803ff135f881dadeb5c0edcef793d1ec4f8a9140a1348cecb71074e1"},
|
||||
{file = "pyside6_essentials-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:660aea45bfa36f1e06f799b934c2a7df963bd31abc5083e8bb8a5bfaef45686b"},
|
||||
{file = "pyside6_essentials-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:c2b028e4c6f8047a02c31f373408e23b4eedfd405f56c6aba8d0525c29472835"},
|
||||
{file = "pyside6_essentials-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:0741018c2b6395038cad4c41775cfae3f13a409e87995ac9f7d89e5b1fb6b22a"},
|
||||
{file = "pyside6_essentials-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:db5f4913648bb6afddb8b347edae151ee2378f12bceb03c8b2515a530a4b38d9"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.0.2"
|
||||
@ -1970,6 +2215,57 @@ files = [
|
||||
{file = "python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyvips"
|
||||
version = "3.1.1"
|
||||
requires_python = ">=3.7"
|
||||
summary = "binding for the libvips image processing library"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"cffi>=1.0.0",
|
||||
]
|
||||
files = [
|
||||
{file = "pyvips-3.1.1.tar.gz", hash = "sha256:84fe744d023b1084ac2516bb17064cacd41c7f8aabf8e524dd383534941b9301"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyvips-binary"
|
||||
version = "8.18.0"
|
||||
requires_python = ">=3.7"
|
||||
summary = "Binary distribution of libvips and dependencies for use with pyvips"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"cffi>=1.0.0",
|
||||
]
|
||||
files = [
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-macosx_10_15_x86_64.whl", hash = "sha256:6ff72bd6c60bb6cf75b7827083b64e275a15a7d862628b5716998350c17426c8"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a570dbf76bb620efc9745d82d6493da504d56b21b035ccd876e358a0c182e018"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dad3012233b7b12f48180f2a407a50854e44654f37168fa8d42583d9e4f15882"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-manylinux_2_26_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0906be336b8f775e2d33dfe61ffc480ff83c91c08d5eeff904c27c2c5164ff3a"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4ddd4d344f758483d1630a9a08f201ab95162599acc6a8e6c62bb1563e94fe0"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:076fb0affa2901af0fee90c728ded6eed2c72f00356af9895fa7a1fb6c9a2288"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:659ef1e4af04b3472e7762a95caa1038fdeea530807c84a23a0f4c706af0338f"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-win32.whl", hash = "sha256:fd331bcd75bff8651d73d09687d55ac8fb9014baa5682b770a4ea0fbcedf5f97"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-win_amd64.whl", hash = "sha256:a67d73683f70c21bf2c336b6d5ddc2bd54ec36db72cc54ab63cb48bc2373feac"},
|
||||
{file = "pyvips_binary-8.18.0-cp37-abi3-win_arm64.whl", hash = "sha256:0c1f9af910866bc8c2d55182e7a6e8684a828ee4d6084dd814e88e2ee9ec4be3"},
|
||||
{file = "pyvips_binary-8.18.0.tar.gz", hash = "sha256:2f9e509de6d0cf04ea9b429ff0649130a9cf04de8a4f0887d2bcb72e3973225a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyvips"
|
||||
version = "3.1.1"
|
||||
extras = ["binary"]
|
||||
requires_python = ">=3.7"
|
||||
summary = "binding for the libvips image processing library"
|
||||
groups = ["default"]
|
||||
dependencies = [
|
||||
"pyvips-binary",
|
||||
"pyvips==3.1.1",
|
||||
]
|
||||
files = [
|
||||
{file = "pyvips-3.1.1.tar.gz", hash = "sha256:84fe744d023b1084ac2516bb17064cacd41c7f8aabf8e524dd383534941b9301"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pywinpty"
|
||||
version = "3.0.3"
|
||||
@ -2387,6 +2683,20 @@ files = [
|
||||
{file = "setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shiboken6"
|
||||
version = "6.10.2"
|
||||
requires_python = "<3.15,>=3.9"
|
||||
summary = "Python/C++ bindings helper module"
|
||||
groups = ["default"]
|
||||
files = [
|
||||
{file = "shiboken6-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:3bd4e94e9a3c8c1fa8362fd752d399ef39265d5264e4e37bae61cdaa2a00c8c7"},
|
||||
{file = "shiboken6-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ace0790032d9cb0adda644b94ee28d59410180d9773643bb6cf8438c361987ad"},
|
||||
{file = "shiboken6-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:f74d3ed1f92658077d0630c39e694eb043aeb1d830a5d275176c45d07147427f"},
|
||||
{file = "shiboken6-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:10f3c8c5e1b8bee779346f21c10dbc14cff068f0b0b4e62420c82a6bf36ac2e7"},
|
||||
{file = "shiboken6-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:20c671645d70835af212ee05df60361d734c5305edb2746e9875c6a31283f963"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.17.0"
|
||||
|
||||
@ -6,8 +6,8 @@ authors = [
|
||||
{name = "Susanne Franke", email = "s.franke@d-opt.de"},
|
||||
{name = "Florian Förster", email = "f.foerster@d-opt.com"},
|
||||
]
|
||||
dependencies = []
|
||||
requires-python = ">=3.11"
|
||||
dependencies = ["PySide6>=6.10.2", "numpy>=2.4.2", "pillow>=12.1.1", "opencv-python>=4.13.0.92", "pyvips[binary]>=3.1.1"]
|
||||
requires-python = "<3.15,>=3.11"
|
||||
readme = "README.md"
|
||||
license = {text = "LicenseRef-Proprietary"}
|
||||
|
||||
|
||||
32
src/KSG_anomaly_detection/_prepare_env.py
Normal file
32
src/KSG_anomaly_detection/_prepare_env.py
Normal file
@ -0,0 +1,32 @@
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from KSG_anomaly_detection.config_for_test import PATH
|
||||
|
||||
BASE_PATH = Path(PATH)
|
||||
|
||||
|
||||
# delete "Daten"
|
||||
def recreate_folder(folder_name: str) -> Path:
|
||||
p_data = BASE_PATH / folder_name
|
||||
if p_data.exists():
|
||||
shutil.rmtree(p_data)
|
||||
p_data.mkdir(parents=True)
|
||||
return p_data
|
||||
|
||||
|
||||
def main() -> None:
|
||||
_ = recreate_folder("Daten")
|
||||
_ = recreate_folder("KI")
|
||||
p_data = recreate_folder(
|
||||
"./Verifizierdaten_1/20260225/614706_helles Entek/614706_helles Entek[3136761]_1"
|
||||
)
|
||||
p_orig_data = (
|
||||
BASE_PATH / "_Originaldaten/614706_helles Entek/614706_helles Entek[3136761]_1"
|
||||
)
|
||||
assert p_orig_data.exists(), "original data not existing"
|
||||
shutil.copytree(p_orig_data, p_data, dirs_exist_ok=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
27
src/KSG_anomaly_detection/_profile.py
Normal file
27
src/KSG_anomaly_detection/_profile.py
Normal file
@ -0,0 +1,27 @@
|
||||
import cProfile
|
||||
import pstats
|
||||
|
||||
from KSG_anomaly_detection import _prepare_env
|
||||
from KSG_anomaly_detection.monitor import monitor_folder_simple
|
||||
|
||||
profiler = cProfile.Profile()
|
||||
|
||||
PROFILE = True
|
||||
USE_NEW_IMPL = True
|
||||
|
||||
|
||||
def main() -> None:
|
||||
_prepare_env.main()
|
||||
if PROFILE:
|
||||
profiler.enable()
|
||||
monitor_folder_simple(use_new=USE_NEW_IMPL)
|
||||
profiler.disable()
|
||||
|
||||
stats = pstats.Stats(profiler).sort_stats("cumtime")
|
||||
stats.print_stats(15)
|
||||
else:
|
||||
monitor_folder_simple(use_new=USE_NEW_IMPL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
src/KSG_anomaly_detection/_run.py
Normal file
9
src/KSG_anomaly_detection/_run.py
Normal file
@ -0,0 +1,9 @@
|
||||
from time import perf_counter
|
||||
|
||||
from KSG_anomaly_detection.monitor import monitor_folder_simple
|
||||
|
||||
if __name__ == "__main__":
|
||||
t1 = perf_counter()
|
||||
monitor_folder_simple()
|
||||
t2 = perf_counter()
|
||||
print(f"Elasped time: {(t2 - t1)} s")
|
||||
17
src/KSG_anomaly_detection/config.py
Normal file
17
src/KSG_anomaly_detection/config.py
Normal file
@ -0,0 +1,17 @@
|
||||
import config_for_test
|
||||
|
||||
# Monitoring
|
||||
START_DATE = "20260225"
|
||||
MONITOR_PATH = rf"{config_for_test.PATH}"
|
||||
AGE_THRESHOLD = (
|
||||
10 # how long nothing new is allowed to have been created within the folder (in seconds)
|
||||
)
|
||||
|
||||
|
||||
# Processing: turned depending on AI on/off, we decide whether the folder is used for anomaly detection or not
|
||||
V_1 = "Verifizierdaten_1" # Name des Ordners der Daten von Verifizierstation 1
|
||||
CURRENT_PATH_RGB = rf"{config_for_test.PATH}\Daten" # dort werden die Ordner mit den RGB-AOI-Bildern abgelegt
|
||||
|
||||
|
||||
# Fileserver: Datensicherung
|
||||
STORING_PATH = rf"{config_for_test.PATH}\KI"
|
||||
9
src/KSG_anomaly_detection/config_for_test.py
Normal file
9
src/KSG_anomaly_detection/config_for_test.py
Normal file
@ -0,0 +1,9 @@
|
||||
# BITTE ANPASSEN
|
||||
|
||||
# Pfad zu dem Ordner, in dem die Ordner 'KI' und 'Verifizierdaten_1' liegen
|
||||
PATH = r"B:\projects\KSG\Ordnerstruktur"
|
||||
|
||||
# Pfad zu den einzelnen Päckchen, die untersucht werden sollen
|
||||
FOLDER_LIST = [
|
||||
r"B:\projects\KSG\Ordnerstruktur\Verifizierdaten_1\20260225\614706_helles Entek\614706_helles Entek[3136761]_1"
|
||||
]
|
||||
87
src/KSG_anomaly_detection/gui_ai_on_off.py
Normal file
87
src/KSG_anomaly_detection/gui_ai_on_off.py
Normal file
@ -0,0 +1,87 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
from PySide6.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
|
||||
class ToggleGUI(QWidget):
|
||||
def __init__(self, title, background_colour):
|
||||
super().__init__()
|
||||
self.title = title
|
||||
self.bg_colour = background_colour
|
||||
|
||||
self.setWindowTitle("KI-Algorithmus")
|
||||
self.setMinimumSize(300, 200)
|
||||
|
||||
# Label
|
||||
self.label = QLabel(self.title) # Visper 1 or Visper 2
|
||||
self.label.setAlignment(Qt.AlignCenter)
|
||||
font = QFont("Arial", 42, QFont.Bold)
|
||||
self.label.setFont(font)
|
||||
self.label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
# Buttons for turning KI on/off
|
||||
self.btn_on = QPushButton("KI eingeschaltet")
|
||||
self.btn_off = QPushButton("KI ausgeschaltet")
|
||||
|
||||
for btn in (self.btn_on, self.btn_off):
|
||||
btn.setCheckable(True)
|
||||
btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
self.set_button_style(btn, "lightgrey")
|
||||
|
||||
self.btn_on.clicked.connect(lambda: self.handle_toggle(self.btn_on))
|
||||
self.btn_off.clicked.connect(lambda: self.handle_toggle(self.btn_off))
|
||||
|
||||
# Layouts for positioning
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.setSpacing(20)
|
||||
btn_layout.addWidget(self.btn_on)
|
||||
btn_layout.addWidget(self.btn_off)
|
||||
|
||||
main_layout = QVBoxLayout()
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(40, 40, 40, 40)
|
||||
main_layout.addWidget(self.label)
|
||||
main_layout.addLayout(btn_layout)
|
||||
main_layout.addStretch(1)
|
||||
|
||||
self.setLayout(main_layout)
|
||||
|
||||
# default state: ON
|
||||
self.handle_toggle(self.btn_on)
|
||||
|
||||
# background colour to distinguish the different GUIs from eacht other
|
||||
self.setStyleSheet(f"background-color: {self.bg_colour};")
|
||||
|
||||
def set_button_style(self, button, color):
|
||||
button.setStyleSheet(f"""
|
||||
QPushButton {{
|
||||
background-color: {color};
|
||||
padding: 20px;
|
||||
font-size: 24px;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
}}
|
||||
""")
|
||||
|
||||
def handle_toggle(self, clicked_button):
|
||||
if clicked_button == self.btn_on:
|
||||
self.btn_on.setChecked(True)
|
||||
self.btn_off.setChecked(False)
|
||||
self.set_button_style(self.btn_on, "lightgreen")
|
||||
self.set_button_style(self.btn_off, "lightgrey")
|
||||
else:
|
||||
self.btn_off.setChecked(True)
|
||||
self.btn_on.setChecked(False)
|
||||
self.set_button_style(self.btn_off, "lightcoral")
|
||||
self.set_button_style(self.btn_on, "lightgrey")
|
||||
|
||||
def is_enabled(self):
|
||||
# we return True if 'KI eingeschaltet' is active
|
||||
return self.btn_on.isChecked()
|
||||
22
src/KSG_anomaly_detection/main.py
Normal file
22
src/KSG_anomaly_detection/main.py
Normal file
@ -0,0 +1,22 @@
|
||||
import sys
|
||||
import threading
|
||||
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
from KSG_anomaly_detection.monitor import (
|
||||
monitor_folder, # Check für neue Ordner und Auslösen des KI-Algorithmus
|
||||
)
|
||||
from KSG_anomaly_detection.window_manager import WindowManager # zum Erzeugen der GUI
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
manager = WindowManager()
|
||||
manager._create_v1()
|
||||
# manager._create_v2()
|
||||
# manager._create_stats()
|
||||
|
||||
monitor_thread = threading.Thread(target=monitor_folder, args=(manager,), daemon=True)
|
||||
monitor_thread.start()
|
||||
|
||||
sys.exit(app.exec())
|
||||
179
src/KSG_anomaly_detection/monitor.py
Normal file
179
src/KSG_anomaly_detection/monitor.py
Normal file
@ -0,0 +1,179 @@
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
from KSG_anomaly_detection import config, config_for_test
|
||||
from KSG_anomaly_detection.preparation import Preparation
|
||||
from KSG_anomaly_detection.window_manager import WindowManager
|
||||
|
||||
|
||||
# Identifikation aller Unterordner jeweils in Verifizierstation_1 und Verifizierstation_2, eindeutige Lose
|
||||
def get_third_level_subfolders(path):
|
||||
seen_basenames = set()
|
||||
result = set()
|
||||
|
||||
pattern = re.compile(r"^(.*)_\d+$")
|
||||
|
||||
for level1 in os.listdir(path):
|
||||
level1_path = os.path.join(path, level1)
|
||||
if not os.path.isdir(level1_path):
|
||||
continue
|
||||
if not level1 >= config.START_DATE:
|
||||
continue
|
||||
|
||||
for level2 in os.listdir(level1_path):
|
||||
level2_path = os.path.join(level1_path, level2)
|
||||
if not os.path.isdir(level2_path):
|
||||
continue
|
||||
|
||||
for level3 in os.listdir(level2_path):
|
||||
level3_path = os.path.join(level2_path, level3)
|
||||
if not os.path.isdir(level3_path):
|
||||
continue
|
||||
|
||||
match = pattern.match(level3)
|
||||
if match:
|
||||
base_name = level3
|
||||
|
||||
if base_name not in seen_basenames:
|
||||
seen_basenames.add(base_name)
|
||||
|
||||
base_path = os.path.join(level2_path, base_name)
|
||||
result.add(base_path)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# zur Identifikation, ob wir uns in Verifizierstation_1 und Verifizierstation_2 befinden
|
||||
def get_first_level_name(folder_path):
|
||||
# returns the name of the immediate parent folder (e.g., V1 or V2)
|
||||
return Path(folder_path).parts[-4]
|
||||
|
||||
|
||||
def is_entire_folder_unchanged(folder_path, threshold_seconds=300):
|
||||
now = time.time()
|
||||
for root, dirs, files in os.walk(folder_path):
|
||||
for entry in dirs + files:
|
||||
try:
|
||||
entry_path = os.path.join(root, entry)
|
||||
mtime = os.path.getmtime(entry_path)
|
||||
if now - mtime < threshold_seconds:
|
||||
return False
|
||||
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def are_all_matching_folders_unchanged(base_path, name_substring, threshold_seconds):
|
||||
for root, dirs, _ in os.walk(base_path):
|
||||
for d in dirs:
|
||||
if name_substring in d:
|
||||
folder_path = os.path.join(root, d)
|
||||
if not is_entire_folder_unchanged(folder_path, threshold_seconds):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# Hauptfunktion: Check auf neue Ordner und ggf. Auslösen des KI-Algorithmus
|
||||
def monitor_folder(manager: WindowManager):
|
||||
print("starting thread...")
|
||||
|
||||
while True:
|
||||
for folder in config_for_test.FOLDER_LIST:
|
||||
try:
|
||||
if are_all_matching_folders_unchanged(
|
||||
os.path.dirname(folder),
|
||||
os.path.basename(folder),
|
||||
threshold_seconds=config.AGE_THRESHOLD,
|
||||
):
|
||||
# prüfen, ob Verifizierstation_1 oder Verifizierstation_2
|
||||
first_level = get_first_level_name(folder)
|
||||
|
||||
# ein zu Verifizierstation_1 zugehöriger Ordner und KI-Algorithmus soll durchgeführt werden
|
||||
if first_level == config.V_1 and manager.get_checkbox_state_v1():
|
||||
# Vorbereitung
|
||||
preparation = Preparation(folder)
|
||||
|
||||
# Aufgabe 2: NGT und check_img von Originalordner in KI kopieren
|
||||
# Rückgabewert: Ordner Fileserver/KI auf dem Fileserver, wo dann die Heatmaps abgelegt werden
|
||||
file_ki_folder, result = preparation.copy_ngt_and_checkimg()
|
||||
if result: # d. h. Fehler ist aufgetreten
|
||||
continue # zu nächstem neuen folder springen
|
||||
|
||||
# Aufgabe 3: check_img im Originalordner anpassen (d. h. gelbe Farbe: work in progress)
|
||||
preparation.change_image_to_yellow()
|
||||
|
||||
# Aufgabe 4: AOI-Bilder in RGB überführen und zwischenspeichern
|
||||
# wir erhalten hier den Speicherort sowie ggf. Fehlermeldungen zurück
|
||||
current_folder, result = preparation.create_rgb_images_and_patches()
|
||||
|
||||
print("finished routine")
|
||||
|
||||
if result is not None:
|
||||
print(result)
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
tb = traceback.extract_tb(e.__traceback__)
|
||||
no = tb[-1].lineno
|
||||
print(e, no)
|
||||
|
||||
time.sleep(60)
|
||||
|
||||
|
||||
def monitor_folder_simple(use_new: bool):
|
||||
print("starting thread...")
|
||||
|
||||
for folder in config_for_test.FOLDER_LIST:
|
||||
# try:
|
||||
if are_all_matching_folders_unchanged(
|
||||
os.path.dirname(folder),
|
||||
os.path.basename(folder),
|
||||
threshold_seconds=config.AGE_THRESHOLD,
|
||||
):
|
||||
# prüfen, ob Verifizierstation_1 oder Verifizierstation_2
|
||||
first_level = get_first_level_name(folder)
|
||||
|
||||
# ein zu Verifizierstation_1 zugehöriger Ordner und KI-Algorithmus soll durchgeführt werden
|
||||
if first_level == config.V_1:
|
||||
# Vorbereitung
|
||||
preparation = Preparation(folder)
|
||||
|
||||
# Aufgabe 2: NGT und check_img von Originalordner in KI kopieren
|
||||
# Rückgabewert: Ordner Fileserver/KI auf dem Fileserver, wo dann die Heatmaps abgelegt werden
|
||||
print("'copy_ngt_and_checkimg'...")
|
||||
file_ki_folder, result = preparation.copy_ngt_and_checkimg()
|
||||
if result: # d. h. Fehler ist aufgetreten
|
||||
continue # zu nächstem neuen folder springen
|
||||
|
||||
# Aufgabe 3: check_img im Originalordner anpassen (d. h. gelbe Farbe: work in progress)
|
||||
print("'change_image_to_yellow'...")
|
||||
if use_new:
|
||||
preparation.change_image_to_yellow_new()
|
||||
else:
|
||||
preparation.change_image_to_yellow()
|
||||
|
||||
# Aufgabe 4: AOI-Bilder in RGB überführen und zwischenspeichern
|
||||
# wir erhalten hier den Speicherort sowie ggf. Fehlermeldungen zurück
|
||||
print("'create_rgb_images_and_patches'...")
|
||||
if use_new:
|
||||
current_folder, result = preparation.create_rgb_images_and_patches_new()
|
||||
else:
|
||||
current_folder, result = preparation.create_rgb_images_and_patches()
|
||||
|
||||
print("finished routine")
|
||||
|
||||
if result is not None:
|
||||
print(result)
|
||||
continue
|
||||
|
||||
# except Exception as e:
|
||||
# tb = traceback.extract_tb(e.__traceback__)
|
||||
# no = tb[-1].lineno
|
||||
# print(e, no)
|
||||
|
||||
# time.sleep(60)
|
||||
283
src/KSG_anomaly_detection/preparation.py
Normal file
283
src/KSG_anomaly_detection/preparation.py
Normal file
@ -0,0 +1,283 @@
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
from shutil import copytree
|
||||
from typing import Literal, cast
|
||||
|
||||
import pyvips
|
||||
from PIL import Image
|
||||
from pyvips import Image as vipsImage
|
||||
|
||||
from KSG_anomaly_detection import config
|
||||
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
COLOUR_ASSIGNMENT = {"R": [255, 0, 0], "G": [0, 255, 0], "B": [0, 0, 0]}
|
||||
|
||||
|
||||
class Preparation:
|
||||
def __init__(self, folder):
|
||||
self.folder_path = (
|
||||
folder # der aktuelle Ordner mit neuen AOI-Bilddateien auf dem KI-Rechner
|
||||
)
|
||||
self.visper = Path(self.folder_path).parts[-4]
|
||||
self.original_data_path = (
|
||||
Path(config.STORING_PATH)
|
||||
/ self.visper
|
||||
/ Path(self.folder_path).parent.parent.name
|
||||
/ Path(self.folder_path).parent.name
|
||||
) # Pfad zu Fileserver/KI/...
|
||||
|
||||
print(f"[{self.visper}] {Path(self.folder_path).name} Vorbereitung gestartet...")
|
||||
|
||||
# ------------------------------------- Zweite Aufgabe: ngt und check_img kopieren ------------------------------------
|
||||
def copy_ngt_and_checkimg(self):
|
||||
try:
|
||||
# extract last level name because we need to copy all folders containing this name
|
||||
target_name = os.path.basename(self.folder_path)
|
||||
base_path = Path(self.folder_path).parent
|
||||
|
||||
folders_to_copy = []
|
||||
|
||||
with os.scandir(base_path) as entries:
|
||||
for entry in entries:
|
||||
if entry.is_dir() and target_name in entry.name:
|
||||
folders_to_copy.append(entry.path)
|
||||
|
||||
for src in folders_to_copy:
|
||||
# TODO duplicate -> "self.original_data_path"
|
||||
dst = (
|
||||
Path(config.STORING_PATH)
|
||||
/ self.visper
|
||||
/ Path(self.folder_path).parent.parent.name
|
||||
/ Path(self.folder_path).parent.name
|
||||
/ Path(src).name
|
||||
)
|
||||
copytree(src, dst, dirs_exist_ok=True)
|
||||
|
||||
return Path(config.STORING_PATH) / self.visper / Path(
|
||||
self.folder_path
|
||||
).parent.parent / Path(self.folder_path).parent, None
|
||||
|
||||
except FileExistsError:
|
||||
return (
|
||||
None,
|
||||
f"Fehlermeldung: Ordner {Path(self.folder_path).parts[-1]} existiert bereits.",
|
||||
)
|
||||
except Exception as e:
|
||||
tb = traceback.extract_tb(e.__traceback__)
|
||||
no = tb[-1].lineno
|
||||
return None, f"Fehlermeldung: {e}, {no}"
|
||||
|
||||
# --------------------------- Dritte Aufgabe: check_img auf dem Fileserver auf Gelb ("Work in Progress") ändern --------------------------
|
||||
def change_image_to_yellow(self):
|
||||
# first we define for R, G and B which coour has to be adapted
|
||||
colour_assignment = {"R": (255, 0, 0), "G": (0, 255, 0), "B": (0, 0, 0)}
|
||||
|
||||
base_path = Path(self.folder_path).parent
|
||||
|
||||
# iterate over all 'checkimg' folders recursively
|
||||
for img_folder in base_path.rglob("checkimg"):
|
||||
if not img_folder.is_dir():
|
||||
continue
|
||||
|
||||
# iterate over image files inside this 'checkimg' folder and only change first ones (because these are the ones to be shown at the Verifizierstation)
|
||||
for image_file in img_folder.glob("????1_1*"):
|
||||
# from the file name, we extract whether it is the R, G or B part of the RGB image
|
||||
# i.e. these are still the Einzelkanalfarbbilder
|
||||
colour_channel = image_file.stem[0]
|
||||
|
||||
# change image
|
||||
####################### ist eigentlich bekannt über DB #######################
|
||||
with Image.open(image_file) as img:
|
||||
size = img.size
|
||||
####################### ist eigentlich bekannt über DB #######################
|
||||
new_img = Image.new("RGB", size, colour_assignment[colour_channel])
|
||||
# save the modified image
|
||||
new_img.save(image_file)
|
||||
|
||||
def pyvips_blank_image(
|
||||
self,
|
||||
size: tuple[int, int],
|
||||
channel: Literal["R", "G", "B"],
|
||||
) -> vipsImage:
|
||||
img = pyvips.Image.black(size[0], size[1], bands=3) + COLOUR_ASSIGNMENT[channel] # type: ignore
|
||||
img = img.cast("uchar") # type: ignore
|
||||
img = img.copy(interpretation="srgb")
|
||||
return img
|
||||
|
||||
def change_image_to_yellow_new(self):
|
||||
base_path = Path(self.folder_path).parent
|
||||
|
||||
# iterate over all 'checkimg' folders recursively
|
||||
# !! check needed
|
||||
# sizes should be the same for the same camera, only obtain once
|
||||
# dict: {camera_number: (width, height)}
|
||||
cam_img_sizes: dict[str, tuple[int, int]] = {}
|
||||
cam_rgb_pictures: dict[str, dict[str, vipsImage]] = {
|
||||
cam_no: {} for cam_no in ("1", "2")
|
||||
}
|
||||
|
||||
for image_file in base_path.rglob("checkimg/????1_1*"):
|
||||
# print("processing image file: ", image_file)
|
||||
# from the file name, we extract whether it is the R, G or B part of the RGB image
|
||||
# i.e. these are still the Einzelkanalfarbbilder
|
||||
colour_channel = image_file.stem[0]
|
||||
camera_num = str(image_file.parents[1])[-1]
|
||||
|
||||
if camera_num not in cam_img_sizes:
|
||||
img_read = pyvips.Image.new_from_file(image_file, access="random")
|
||||
size = img_read.width, img_read.height
|
||||
cam_img_sizes[camera_num] = size
|
||||
if (
|
||||
camera_num not in cam_rgb_pictures
|
||||
or colour_channel not in cam_rgb_pictures[camera_num]
|
||||
):
|
||||
blank_img = self.pyvips_blank_image(size, colour_channel)
|
||||
cam_rgb_pictures[camera_num][colour_channel] = blank_img
|
||||
|
||||
img = cam_rgb_pictures[camera_num][colour_channel]
|
||||
img_file_temp = (image_file.parent / (image_file.stem + "_temp")).with_suffix(
|
||||
image_file.suffix
|
||||
)
|
||||
img.write_to_file(img_file_temp)
|
||||
os.replace(img_file_temp, image_file)
|
||||
|
||||
# --------------------------- Vierte Aufgabe: AOI-Einzelkanalfarbbilder zur RGB-Bildern zusammenfügen --------------------------
|
||||
# within the current folder to be inspected (i.e., self.folder_path), there are subfolders for the different A/B sides
|
||||
# we have to extract the relative path starting from self.folder_path
|
||||
def extract_folder_path_within_one_AOI_folder(
|
||||
self, current_folder_to_inspect, checkimg_folders, folder_type
|
||||
):
|
||||
for folder_to_inspect in checkimg_folders:
|
||||
if folder_to_inspect.is_dir() and (
|
||||
Path(folder_to_inspect).parts[-2] == Path(current_folder_to_inspect).parts[-2]
|
||||
):
|
||||
relative_path = current_folder_to_inspect.relative_to(self.original_data_path)
|
||||
relative_path = Path(*relative_path.parts[1:])
|
||||
return relative_path
|
||||
|
||||
def create_rgb_images_and_patches(self):
|
||||
# in the folders of interest, we iterate over all images and search for the three that belong together
|
||||
# (because in advance we do not know how many there are)
|
||||
pattern = re.compile(r"R_NG(\d+)_(\d+)\.jpg$")
|
||||
|
||||
# create folder name in our temp folder "Backup" and store it
|
||||
# therefore, first extract the name of the current folder from the whole path
|
||||
folder_name = Path(self.folder_path).name
|
||||
new_folder_path = Path(config.CURRENT_PATH_RGB) / folder_name
|
||||
|
||||
try:
|
||||
new_folder_path.mkdir(parents=True, exist_ok=False)
|
||||
except FileExistsError:
|
||||
return (
|
||||
None,
|
||||
f"Fehlermeldung: Ordner {Path(self.folder_path).parts[-1]} existiert bereits.",
|
||||
)
|
||||
except Exception as e:
|
||||
return None, f"Fehlermeldung: {e}"
|
||||
|
||||
# find all checkimg folders within the folder
|
||||
checkimg_folders = [
|
||||
p for p in self.original_data_path.rglob("checkimg") if p.is_dir()
|
||||
]
|
||||
|
||||
# iterate through all 'checkimg' folders recursively
|
||||
for current_folder_to_inspect in checkimg_folders:
|
||||
# identify the path starting from self.folder_path until the checkimg folder
|
||||
relative_path = self.extract_folder_path_within_one_AOI_folder(
|
||||
current_folder_to_inspect, checkimg_folders, "checkimg"
|
||||
)
|
||||
|
||||
save_path_rgb = new_folder_path / relative_path
|
||||
save_path_rgb.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for file_path in current_folder_to_inspect.glob("R_NG*_*.jpg"):
|
||||
# find match according to pattern defined at the very beginning
|
||||
match = pattern.match(file_path.name)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
num1, num2 = match.groups()
|
||||
|
||||
# find all three images belonging together
|
||||
r_path = file_path
|
||||
g_path = current_folder_to_inspect / f"G_NG{num1}_{num2}.jpg"
|
||||
b_path = current_folder_to_inspect / f"B_NG{num1}_{num2}.jpg"
|
||||
|
||||
# open all three images and combine them to RGB
|
||||
with (
|
||||
Image.open(r_path) as r,
|
||||
Image.open(g_path) as g,
|
||||
Image.open(b_path) as b,
|
||||
):
|
||||
r = r.convert("L")
|
||||
g = g.convert("L")
|
||||
b = b.convert("L")
|
||||
|
||||
rgb_image = Image.merge("RGB", (r, g, b))
|
||||
|
||||
filename = f"RGB_NG{num1}_{num2}.png"
|
||||
rgb_image.save(save_path_rgb / filename)
|
||||
|
||||
return "folder_name", None
|
||||
|
||||
def create_rgb_images_and_patches_new(self):
|
||||
# in the folders of interest, we iterate over all images and search for the three that belong together
|
||||
# (because in advance we do not know how many there are)
|
||||
pattern = re.compile(r"R_NG(\d+)_(\d+)\.jpg$")
|
||||
|
||||
# create folder name in our temp folder "Backup" and store it
|
||||
# therefore, first extract the name of the current folder from the whole path
|
||||
folder_name = Path(self.folder_path).name
|
||||
new_folder_path = Path(config.CURRENT_PATH_RGB) / folder_name
|
||||
|
||||
try:
|
||||
new_folder_path.mkdir(parents=True, exist_ok=False)
|
||||
except FileExistsError:
|
||||
return (
|
||||
None,
|
||||
f"Fehlermeldung: Ordner {Path(self.folder_path).parts[-1]} existiert bereits.",
|
||||
)
|
||||
except Exception as e:
|
||||
return None, f"Fehlermeldung: {e}"
|
||||
|
||||
# find all checkimg folders within the folder
|
||||
checkimg_folders = [
|
||||
p for p in self.original_data_path.rglob("checkimg") if p.is_dir()
|
||||
]
|
||||
|
||||
# iterate through all 'checkimg' folders recursively
|
||||
for current_folder_to_inspect in checkimg_folders:
|
||||
# identify the path starting from self.folder_path until the checkimg folder
|
||||
relative_path = self.extract_folder_path_within_one_AOI_folder(
|
||||
current_folder_to_inspect, checkimg_folders, "checkimg"
|
||||
)
|
||||
|
||||
save_path_rgb = new_folder_path / relative_path
|
||||
save_path_rgb.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for file_path in current_folder_to_inspect.glob("R_NG*_*.jpg"):
|
||||
# find match according to pattern defined at the very beginning
|
||||
match = pattern.match(file_path.name)
|
||||
if not match:
|
||||
continue
|
||||
|
||||
num1, num2 = match.groups()
|
||||
|
||||
# find all three images belonging together
|
||||
r_path = file_path
|
||||
g_path = current_folder_to_inspect / f"G_NG{num1}_{num2}.jpg"
|
||||
b_path = current_folder_to_inspect / f"B_NG{num1}_{num2}.jpg"
|
||||
|
||||
# open all three images and combine them to RGB
|
||||
r = pyvips.Image.new_from_file(r_path, access="sequential")
|
||||
g = pyvips.Image.new_from_file(g_path, access="sequential")
|
||||
b = pyvips.Image.new_from_file(b_path, access="sequential")
|
||||
rgb_image = r.bandjoin([g, b])
|
||||
rgb_image = rgb_image.copy(interpretation="srgb")
|
||||
filename = f"RGB_NG{num1}_{num2}.png"
|
||||
rgb_image.write_to_file(save_path_rgb / filename)
|
||||
|
||||
return "folder_name", None
|
||||
22
src/KSG_anomaly_detection/window_manager.py
Normal file
22
src/KSG_anomaly_detection/window_manager.py
Normal file
@ -0,0 +1,22 @@
|
||||
from PySide6.QtCore import QObject, Signal, Slot
|
||||
|
||||
from KSG_anomaly_detection.gui_ai_on_off import ToggleGUI
|
||||
|
||||
|
||||
class WindowManager(QObject):
|
||||
recreate_v1 = Signal()
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.v1 = None
|
||||
|
||||
self.recreate_v1.connect(self._create_v1)
|
||||
|
||||
@Slot()
|
||||
def _create_v1(self):
|
||||
self.v1 = ToggleGUI("Visper 1", "#e6e6fa")
|
||||
self.v1.move(100, 100)
|
||||
self.v1.show()
|
||||
|
||||
def get_checkbox_state_v1(self):
|
||||
return self.v1 and self.v1.is_enabled()
|
||||
Loading…
x
Reference in New Issue
Block a user