shinestacker 0.3.0__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of shinestacker might be problematic. Click here for more details.
- {shinestacker-0.3.0 → shinestacker-0.3.3}/CHANGELOG.md +36 -0
- shinestacker-0.3.3/MANIFEST.in +2 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/PKG-INFO +3 -2
- {shinestacker-0.3.0 → shinestacker-0.3.3}/README.md +2 -1
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/alignment.md +1 -1
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/gui.md +3 -6
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/job.md +20 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/main.md +5 -3
- shinestacker-0.3.3/img/coins.gif +0 -0
- shinestacker-0.3.3/img/coins_stack.jpg +0 -0
- shinestacker-0.3.3/img/gui-project-run.png +0 -0
- shinestacker-0.3.3/img/gui-retouch.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/pyproject.toml +6 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/__init__.py +6 -6
- shinestacker-0.3.3/src/shinestacker/_version.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/balance.py +6 -7
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/noise_detection.py +2 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/utils.py +4 -0
- shinestacker-0.3.3/src/shinestacker/algorithms/white_balance.py +13 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/open_frames.py +6 -4
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/__init__.py +2 -1
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/config.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/constants.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/gui_constants.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/__init__.py +4 -3
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/colors.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/core_utils.py +6 -6
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/exceptions.py +1 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/framework.py +2 -1
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/action_config.py +47 -42
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/actions_window.py +8 -5
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/new_project.py +1 -0
- shinestacker-0.3.3/src/shinestacker/retouch/brush_gradient.py +20 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/brush_preview.py +10 -14
- shinestacker-0.3.3/src/shinestacker/retouch/brush_tool.py +164 -0
- shinestacker-0.3.3/src/shinestacker/retouch/denoise_filter.py +56 -0
- shinestacker-0.3.3/src/shinestacker/retouch/display_manager.py +177 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/exif_data.py +2 -1
- shinestacker-0.3.3/src/shinestacker/retouch/filter_base.py +114 -0
- shinestacker-0.3.3/src/shinestacker/retouch/filter_manager.py +14 -0
- shinestacker-0.3.3/src/shinestacker/retouch/image_editor.py +235 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/image_editor_ui.py +42 -75
- shinestacker-0.3.3/src/shinestacker/retouch/image_filters.py +67 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/image_viewer.py +31 -31
- shinestacker-0.3.3/src/shinestacker/retouch/io_gui_handler.py +208 -0
- shinestacker-0.3.3/src/shinestacker/retouch/io_manager.py +53 -0
- shinestacker-0.3.3/src/shinestacker/retouch/layer_collection.py +118 -0
- shinestacker-0.3.3/src/shinestacker/retouch/unsharp_mask_filter.py +84 -0
- shinestacker-0.3.3/src/shinestacker/retouch/white_balance_filter.py +111 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/PKG-INFO +3 -2
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/SOURCES.txt +15 -70
- shinestacker-0.3.0/examples/balance-only.fsp +0 -1
- shinestacker-0.3.0/examples/complete-project.fsp +0 -1
- shinestacker-0.3.0/examples/focus-stack-1.ipynb +0 -163
- shinestacker-0.3.0/examples/focus-stack-2.ipynb +0 -174
- shinestacker-0.3.0/examples/input/img-jpg/0000.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-jpg/0001.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-jpg/0002.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-jpg/0003.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-jpg/0004.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-jpg/0005.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0001.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0002.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0003.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0004.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0005.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-noise/0006.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0000.tif +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0001.tif +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0002.tif +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0003.tif +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0004.tif +0 -0
- shinestacker-0.3.0/examples/input/img-tif/0005.tif +0 -0
- shinestacker-0.3.0/examples/input/img-vignetted/vig-0000.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-vignetted/vig-0001.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-vignetted/vig-0002.jpg +0 -0
- shinestacker-0.3.0/examples/input/img-vignetted/vig-0003.jpg +0 -0
- shinestacker-0.3.0/examples/stack-comparison.fsp +0 -1
- shinestacker-0.3.0/examples/stack-from-frames.fsp +0 -1
- shinestacker-0.3.0/examples/vignetting.fsp +0 -1
- shinestacker-0.3.0/img/gui-project-run.png +0 -0
- shinestacker-0.3.0/img/gui-retouch.png +0 -0
- shinestacker-0.3.0/src/shinestacker/_version.py +0 -1
- shinestacker-0.3.0/src/shinestacker/retouch/brush_controller.py +0 -57
- shinestacker-0.3.0/src/shinestacker/retouch/image_editor.py +0 -670
- shinestacker-0.3.0/src/shinestacker/retouch/image_filters.py +0 -463
- shinestacker-0.3.0/tests/test-align-balance.ipynb +0 -282
- shinestacker-0.3.0/tests/test-align.ipynb +0 -242
- shinestacker-0.3.0/tests/test-balance.ipynb +0 -918
- shinestacker-0.3.0/tests/test-exif.ipynb +0 -121
- shinestacker-0.3.0/tests/test-job.ipynb +0 -79
- shinestacker-0.3.0/tests/test-logging.ipynb +0 -93
- shinestacker-0.3.0/tests/test-multilayer.ipynb +0 -72
- shinestacker-0.3.0/tests/test-noise-detection.ipynb +0 -110
- shinestacker-0.3.0/tests/test-stack.ipynb +0 -97
- shinestacker-0.3.0/tests/test-vignetting.ipynb +0 -154
- shinestacker-0.3.0/tests/test_0000_logging.py +0 -66
- shinestacker-0.3.0/tests/test_0001_colors.py +0 -32
- shinestacker-0.3.0/tests/test_0002_config.py +0 -60
- shinestacker-0.3.0/tests/test_0005_make_test_img.py +0 -18
- shinestacker-0.3.0/tests/test_0006_exceptions.py +0 -99
- shinestacker-0.3.0/tests/test_0010_job.py +0 -49
- shinestacker-0.3.0/tests/test_0011_core_utils.py +0 -105
- shinestacker-0.3.0/tests/test_0020_noise_detection.py +0 -62
- shinestacker-0.3.0/tests/test_0030_align.py +0 -74
- shinestacker-0.3.0/tests/test_0031_align_precision.py +0 -111
- shinestacker-0.3.0/tests/test_0032_align_methods.py +0 -68
- shinestacker-0.3.0/tests/test_0040_balance.py +0 -90
- shinestacker-0.3.0/tests/test_0050_align_balance.py +0 -59
- shinestacker-0.3.0/tests/test_0051_denoise.py +0 -34
- shinestacker-0.3.0/tests/test_0052_sharpen.py +0 -34
- shinestacker-0.3.0/tests/test_0060_stack.py +0 -51
- shinestacker-0.3.0/tests/test_0061_depth_map.py +0 -84
- shinestacker-0.3.0/tests/test_0070_multilayer.py +0 -74
- shinestacker-0.3.0/tests/test_0080_exif.py +0 -220
- shinestacker-0.3.0/tests/test_0090_vignetting.py +0 -19
- shinestacker-0.3.0/tests/test_0091_vignetting_algo.py +0 -127
- shinestacker-0.3.0/tests/test_1000_brush_mask.py +0 -13
- shinestacker-0.3.0/tests/test_1010_gui.py +0 -42
- shinestacker-0.3.0/tests/test_1020_gui_images.py +0 -128
- shinestacker-0.3.0/tests/test_1030_gui_logging.py +0 -118
- shinestacker-0.3.0/tests/test_1040_action_config.py +0 -120
- shinestacker-0.3.0/tests/test_1050_project_converter.py +0 -157
- shinestacker-0.3.0/tests/test_1060_gui_run.py +0 -136
- shinestacker-0.3.0/tests/test_1070_project_editor.py +0 -180
- shinestacker-0.3.0/tests/test_1080_actions_window.py +0 -138
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.coverage +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.coveragerc +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.flake8 +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/ci-multiplatform.yml +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/pypi-publish.yml +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/release.yml +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.gitignore +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/.readthedocs.yaml +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/LICENSE +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/api.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/balancing.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/conf.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/focus_stacking.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/index.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/multilayer.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/noise.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/requirements.txt +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/vignetting.md +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/extreme-vignetting.jpg +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flies.gif +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flies_stack.jpg +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flow-diagram.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/gui-finder.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/img/gui-project-new.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/scripts/build_release.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/scripts/validate-tomli.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/setup.cfg +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/__init__.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/align.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/core_utils.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/denoise.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/depth_map.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/exif.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/multilayer.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/pyramid.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/sharpen.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/stack.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/stack_framework.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/vignetting.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/__init__.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/about_dialog.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/app_config.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/gui_utils.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/help_menu.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/main.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/project.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/retouch.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/logging.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/__init__.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/colors.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_images.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_logging.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_run.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/focus_stack_bkg.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.icns +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.ico +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/close-round-line-icon.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/forward-button-icon.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/play-button-round-icon.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/plus-round-line-icon.png +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/main_window.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_converter.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_editor.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_model.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/__init__.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/brush.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/file_loader.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/shortcuts_help.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/undo_manager.py +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/dependency_links.txt +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/entry_points.txt +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/requires.txt +0 -0
- {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/top_level.txt +0 -0
|
@@ -4,6 +4,42 @@ This page reports the main releases only and the main changes therein.
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
+
## [v0.3.2] - 2025-08-13
|
|
8
|
+
**Fixes and code refactoring**
|
|
9
|
+
|
|
10
|
+
### Changes
|
|
11
|
+
|
|
12
|
+
* fixed ```from shinestacker import *```
|
|
13
|
+
* restored jupyter support and updated examples
|
|
14
|
+
* several bug fixes
|
|
15
|
+
* several code refactoring reduces interclass dependencies
|
|
16
|
+
* updated documentation
|
|
17
|
+
* added new sample images and project files
|
|
18
|
+
* examples removed from PyPI distribution
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## [v0.3.1] - 2025-08-12
|
|
23
|
+
**Fixes and code refactoring**
|
|
24
|
+
|
|
25
|
+
### Changes
|
|
26
|
+
|
|
27
|
+
* some GUI fixes
|
|
28
|
+
* some code refactoring and cleanup
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## [v0.3.0] - 2025-08-11
|
|
33
|
+
**Filters added to retouch GUI**
|
|
34
|
+
|
|
35
|
+
### Changes
|
|
36
|
+
|
|
37
|
+
* added filters for sharpening, denoise and white balance
|
|
38
|
+
* updated documentation
|
|
39
|
+
* some bug fixes
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
7
43
|
## [v0.2.2] - 2025-07-28
|
|
8
44
|
**More stability and improved tests**
|
|
9
45
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shinestacker
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: ShineStacker
|
|
5
5
|
Author-email: Luca Lista <luka.lista@gmail.com>
|
|
6
6
|
License-Expression: LGPL-3.0
|
|
@@ -41,6 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
|
|
42
42
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
43
43
|
|
|
44
|
+
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
44
45
|
> **Focus stacking** for microscopy, macro photography, and computational imaging
|
|
45
46
|
|
|
46
47
|
## Key Features
|
|
@@ -58,7 +59,7 @@ The GUI has two main working areas:
|
|
|
58
59
|
|
|
59
60
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/gui-project-run.png' width="600" referrerpolicy="no-referrer">
|
|
60
61
|
|
|
61
|
-
* *Retouch*:
|
|
62
|
+
* *Retouch*: select interactively details from individual frames and apply final filters to the blended image.
|
|
62
63
|
|
|
63
64
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/gui-retouch.png' width="600" referrerpolicy="no-referrer">
|
|
64
65
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
12
12
|
|
|
13
|
+
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
13
14
|
> **Focus stacking** for microscopy, macro photography, and computational imaging
|
|
14
15
|
|
|
15
16
|
## Key Features
|
|
@@ -27,7 +28,7 @@ The GUI has two main working areas:
|
|
|
27
28
|
|
|
28
29
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/gui-project-run.png' width="600" referrerpolicy="no-referrer">
|
|
29
30
|
|
|
30
|
-
* *Retouch*:
|
|
31
|
+
* *Retouch*: select interactively details from individual frames and apply final filters to the blended image.
|
|
31
32
|
|
|
32
33
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/gui-retouch.png' width="600" referrerpolicy="no-referrer">
|
|
33
34
|
|
|
@@ -79,7 +79,7 @@ alignment_config = {
|
|
|
79
79
|
* ```refine_iters``` (optional, default: 100): refinement iterations. Used only if ```transform=ALIGN_RIGID```.
|
|
80
80
|
* ```align_confidence``` (optional, default: 99.9): alignment algorithm confidence (%). Used only if ```transform=ALIGN_RIGID```.
|
|
81
81
|
* ```max_iters``` (optional, default: 2000): maximum number of iterations. Used only if ```transform=ALIGN_HOMOGRAPHY```.
|
|
82
|
-
* ```subsample``` (optional, default: 1): subsample image for faster alignment. Faster, but alignment could be less accurate.
|
|
82
|
+
* ```subsample``` (optional, default: 1): subsample image for faster alignment. Faster, but alignment could be less accurate. It can save time, in particular for large images.
|
|
83
83
|
* ```fast_subsampling``` (optiona, default: ```False```): perform fast image subsampling without interpolation. Used if ```subsample``` is set to ```True```.
|
|
84
84
|
* ```border_mode``` (optional, default: ```BORDER_REPLICATE_BLUR```): border mode. See [Adding borders to your images](https://docs.opencv.org/3.4/dc/da3/tutorial_copyMakeBorder.html) for more details. Possible values are:
|
|
85
85
|
* ```BORDER_CONSTANT```: pad the image with a constant value. The border value is specified with the parameter ```border_value```.
|
|
@@ -99,7 +99,9 @@ Adjust in the top toolbar:
|
|
|
99
99
|
3. **Verify**:
|
|
100
100
|
- Toggle master view (`M`) to check results
|
|
101
101
|
- Compare before/after with `L`/`M` toggle
|
|
102
|
-
|
|
102
|
+
4. **Filters**:
|
|
103
|
+
- Improve the final image with sharpening, denoise and color balance
|
|
104
|
+
5. **Export**:
|
|
103
105
|
- ✅ Final image: Single TIFF/JPEG
|
|
104
106
|
- 🗂️ Editable: Multilayer TIFF (large)
|
|
105
107
|
|
|
@@ -123,9 +125,4 @@ See help menu for complete list of shortcuts.
|
|
|
123
125
|
**EXIF metadata**:
|
|
124
126
|
* EXIF data can be imported from source images and saved with final file.
|
|
125
127
|
|
|
126
|
-
## Final retouch
|
|
127
|
-
|
|
128
|
-
The final retouch, including color and luminosity balance, sharpness enhancement and
|
|
129
|
-
so on can be applied with your favorite image processing application, like [GIMP](https://www.gimp.org/)
|
|
130
|
-
or other.
|
|
131
128
|
|
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
Create a job, then schedule the desired actions in a job, then run the job.
|
|
4
4
|
|
|
5
|
+
Quick start example:
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from focus_stack import *
|
|
9
|
+
|
|
10
|
+
job = StackJob("job", "E:/Focus stacking/My image directory/", input_path="src")
|
|
11
|
+
job.add_action(NoiseDetection())
|
|
12
|
+
job.run()
|
|
13
|
+
|
|
14
|
+
job = StackJob("job", "E:/Focus stacking/My image directory/", input_path="src")
|
|
15
|
+
job.add_action(Actions("align", actions=[MaskNoise(),
|
|
16
|
+
AlignFrames(),
|
|
17
|
+
BalanceFrames(mask_size=0.9, i_min=150, i_max=65385)]))
|
|
18
|
+
job.add_action(FocusStackBunch("batches", PyramidStack(), frames=10, overlap=2, denoise=0.8))
|
|
19
|
+
job.add_action(FocusStack("stack", PyramidStack(), postfix='_py', denoise=0.8))
|
|
20
|
+
job.add_action(FocusStack("stack", DepthMapStack(), input_path='batches', postfix='_dm', denoise=0.8))
|
|
21
|
+
job.add_action(MultiLayer("multilayer", input_path=['batches', 'stack']))
|
|
22
|
+
job.run()
|
|
23
|
+
```
|
|
24
|
+
|
|
5
25
|
```python
|
|
6
26
|
job = StackJob(name, working_path [, input_path])
|
|
7
27
|
```
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
[](https://codecov.io/github/lucalista/shinestacker)
|
|
9
9
|
[](https://shinestacker.readthedocs.io/en/latest/?badge=latest)
|
|
10
10
|
|
|
11
|
-
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies.gif' width="400"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies_stack.jpg' width="400">
|
|
11
|
+
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/flies_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
12
|
+
|
|
13
|
+
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins.gif' width="400" referrerpolicy="no-referrer"> <img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/coins_stack.jpg' width="400" referrerpolicy="no-referrer">
|
|
12
14
|
|
|
13
15
|
> **Focus stacking** for microscopy, macro photography, and computational imaging
|
|
14
16
|
|
|
@@ -94,7 +96,7 @@ job.run()
|
|
|
94
96
|
## Requirements
|
|
95
97
|
|
|
96
98
|
* Python: 3.12 (3.13 may not work due to garbage collection issues)
|
|
97
|
-
* RAM: 16GB+ recommended for >15 images
|
|
99
|
+
* RAM: 16GB+ recommended for >15 images at 20Mpx resolution
|
|
98
100
|
|
|
99
101
|
## Dependencies
|
|
100
102
|
|
|
@@ -116,6 +118,6 @@ pip install ipywidgets
|
|
|
116
118
|
|
|
117
119
|
| Issue | Workaround |
|
|
118
120
|
|----------|----------------|
|
|
119
|
-
| Balance modes ```HSV```/```HLS```
|
|
121
|
+
| Balance modes ```HSV```/```HLS``` don't support 16-bit images | convert to 8-bit or use ```RGB``` or luminosity |
|
|
120
122
|
| PNG support untested | Convert to TIFF/JPEG first |
|
|
121
123
|
| GUI tests limited | Report bugs as GitHub issuse |
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -47,6 +47,12 @@ shinestacker = "shinestacker.app.main:main"
|
|
|
47
47
|
shinestacker-project = "shinestacker.app.project:main"
|
|
48
48
|
shinestacker-retouch = "shinestacker.app.retouch:main"
|
|
49
49
|
|
|
50
|
+
[tool.setuptools.exclude-package-data]
|
|
51
|
+
"*" = [
|
|
52
|
+
"examples/*",
|
|
53
|
+
"tests/*"
|
|
54
|
+
]
|
|
55
|
+
|
|
50
56
|
[tool.setuptools]
|
|
51
57
|
package-dir = {"" = "src"}
|
|
52
58
|
packages = [
|
|
@@ -3,14 +3,14 @@ from ._version import __version__
|
|
|
3
3
|
from . import config
|
|
4
4
|
from . import core
|
|
5
5
|
from . import algorithms
|
|
6
|
-
from .config import __all__
|
|
7
|
-
from .core import __all__
|
|
8
|
-
from .algorithms import __all__
|
|
6
|
+
from .config import __all__ as config_all
|
|
7
|
+
from .core import __all__ as core_all
|
|
8
|
+
from .algorithms import __all__ as algorithms_all
|
|
9
9
|
from .config import *
|
|
10
10
|
from .core import *
|
|
11
11
|
from .algorithms import *
|
|
12
12
|
|
|
13
13
|
__all__ = ['__version__']
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
__all__ += config_all
|
|
15
|
+
__all__ += core_all
|
|
16
|
+
__all__ += algorithms_all
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.3.3'
|
|
@@ -133,17 +133,16 @@ class Correction:
|
|
|
133
133
|
self.corrections = np.ones((size, self.channels))
|
|
134
134
|
|
|
135
135
|
def calc_hist_1ch(self, image):
|
|
136
|
+
img_subsample = image if self.subsample == 1 else image[::self.subsample, ::self.subsample]
|
|
136
137
|
if self.mask_size == 0:
|
|
137
|
-
image_sel =
|
|
138
|
+
image_sel = img_subsample
|
|
138
139
|
else:
|
|
139
|
-
height, width =
|
|
140
|
+
height, width = img_subsample.shape[:2]
|
|
140
141
|
xv, yv = np.meshgrid(np.linspace(0, width - 1, width), np.linspace(0, height - 1, height))
|
|
141
142
|
mask_radius = (min(width, height) * self.mask_size / 2)
|
|
142
|
-
image_sel =
|
|
143
|
-
hist, bins = np.histogram(
|
|
144
|
-
|
|
145
|
-
bins=np.linspace(-0.5, self.num_pixel_values - 0.5,
|
|
146
|
-
self.num_pixel_values + 1))
|
|
143
|
+
image_sel = img_subsample[(xv - width / 2) ** 2 + (yv - height / 2) ** 2 <= mask_radius ** 2]
|
|
144
|
+
hist, bins = np.histogram(image_sel, bins=np.linspace(-0.5, self.num_pixel_values - 0.5,
|
|
145
|
+
self.num_pixel_values + 1))
|
|
147
146
|
return hist
|
|
148
147
|
|
|
149
148
|
def balance(self, image, idx):
|
|
@@ -86,6 +86,8 @@ class NoiseDetection(FrameMultiDirectory, JobBase):
|
|
|
86
86
|
progress_callback=progress_callback)
|
|
87
87
|
if not config.DISABLE_TQDM:
|
|
88
88
|
self.bar.close()
|
|
89
|
+
if mean_img is None:
|
|
90
|
+
raise RuntimeError("Mean image is None")
|
|
89
91
|
blurred = cv2.GaussianBlur(mean_img, (self.blur_size, self.blur_size), 0)
|
|
90
92
|
diff = cv2.absdiff(mean_img, blurred)
|
|
91
93
|
channels = cv2.split(diff)
|
|
@@ -47,10 +47,14 @@ def img_bw(img):
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def get_img_metadata(img):
|
|
50
|
+
if img is None:
|
|
51
|
+
return None, None
|
|
50
52
|
return img.shape[:2], img.dtype
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
def validate_image(img, expected_shape=None, expected_dtype=None):
|
|
56
|
+
if img is None:
|
|
57
|
+
raise RuntimeError("Image is None")
|
|
54
58
|
shape, dtype = get_img_metadata(img)
|
|
55
59
|
if expected_shape and shape[:2] != expected_shape[:2]:
|
|
56
60
|
raise ShapeError(expected_shape, shape)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def white_balance_from_rgb(img, target_rgb):
|
|
5
|
+
img_float = img.astype(np.float64)
|
|
6
|
+
target_bgr = (target_rgb[2], target_rgb[1], target_rgb[0])
|
|
7
|
+
target_gray = sum(target_bgr) / 3.0
|
|
8
|
+
scales = [target_gray / val if val != 0 else 1.0 for val in target_bgr]
|
|
9
|
+
for c in range(3):
|
|
10
|
+
img_float[..., c] *= scales[c]
|
|
11
|
+
max_val = np.iinfo(img.dtype).max
|
|
12
|
+
img_float = np.clip(img_float, 0, max_val)
|
|
13
|
+
return img_float.astype(img.dtype)
|
|
@@ -5,15 +5,17 @@ from PySide6.QtCore import QTimer
|
|
|
5
5
|
|
|
6
6
|
def open_files(editor, filenames):
|
|
7
7
|
if len(filenames) == 1:
|
|
8
|
-
QTimer.singleShot(100, lambda: editor.open_file(filenames[0]))
|
|
8
|
+
QTimer.singleShot(100, lambda: editor.io_gui_handler.open_file(filenames[0]))
|
|
9
9
|
else:
|
|
10
10
|
def check_thread():
|
|
11
|
-
|
|
11
|
+
thread = editor.io_gui_handler.loader_thread
|
|
12
|
+
if thread is None or thread.isRunning():
|
|
12
13
|
QTimer.singleShot(100, check_thread)
|
|
13
14
|
else:
|
|
14
|
-
editor.import_frames_from_files(filenames[1:])
|
|
15
|
+
editor.io_gui_handler.import_frames_from_files(filenames[1:])
|
|
16
|
+
|
|
15
17
|
QTimer.singleShot(100, lambda: (
|
|
16
|
-
editor.open_file(filenames[0]),
|
|
18
|
+
editor.io_gui_handler.open_file(filenames[0]),
|
|
17
19
|
QTimer.singleShot(100, check_thread)
|
|
18
20
|
))
|
|
19
21
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# flake8: noqa F401
|
|
2
|
+
# pylint: disable=C0114
|
|
2
3
|
from .logging import setup_logging
|
|
3
|
-
from .exceptions import (FocusStackError, InvalidOptionError, ImageLoadError, ImageSaveError,
|
|
4
|
-
BitDepthError, ShapeError, RunStopException)
|
|
4
|
+
from .exceptions import (FocusStackError, InvalidOptionError, ImageLoadError, ImageSaveError,
|
|
5
|
+
AlignmentError, BitDepthError, ShapeError, RunStopException)
|
|
5
6
|
from .framework import Job
|
|
6
7
|
|
|
7
8
|
__all__ = [
|
|
8
9
|
'setup_logging',
|
|
9
10
|
'FocusStackError', 'InvalidOptionError', 'ImageLoadError', 'ImageSaveError',
|
|
10
11
|
'AlignmentError','BitDepthError', 'ShapeError', 'RunStopException',
|
|
11
|
-
'Job']
|
|
12
|
+
'Job']
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0116, C0201
|
|
1
2
|
import os
|
|
2
3
|
import sys
|
|
3
4
|
import platform
|
|
@@ -10,18 +11,17 @@ if not config.DISABLE_TQDM:
|
|
|
10
11
|
|
|
11
12
|
def check_path_exists(path):
|
|
12
13
|
if not os.path.exists(path):
|
|
13
|
-
raise
|
|
14
|
+
raise RuntimeError('Path does not exist: ' + path)
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
def make_tqdm_bar(name, size, ncols=80):
|
|
17
18
|
if not config.DISABLE_TQDM:
|
|
18
19
|
if config.JUPYTER_NOTEBOOK:
|
|
19
|
-
|
|
20
|
+
tbar = tqdm_notebook(desc=name, total=size)
|
|
20
21
|
else:
|
|
21
|
-
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
return None
|
|
22
|
+
tbar = tqdm(desc=name, total=size, ncols=ncols)
|
|
23
|
+
return tbar
|
|
24
|
+
return None
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def get_app_base_path():
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116
|
|
1
2
|
import time
|
|
2
3
|
import logging
|
|
3
4
|
from .. config.config import config
|
|
@@ -57,7 +58,7 @@ def elapsed_time_str(start):
|
|
|
57
58
|
ss = dt - mm * 60
|
|
58
59
|
hh = mm // 60
|
|
59
60
|
mm -= hh * 60
|
|
60
|
-
return
|
|
61
|
+
return "{:02d}:{:02d}:{:05.2f}s".format(hh, mm, ss)
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class JobBase:
|
|
@@ -22,8 +22,9 @@ FIELD_TYPES = [FIELD_TEXT, FIELD_ABS_PATH, FIELD_REL_PATH, FIELD_FLOAT,
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class ActionConfigurator(ABC):
|
|
25
|
-
def __init__(self, expert
|
|
25
|
+
def __init__(self, expert, current_wd):
|
|
26
26
|
self.expert = expert
|
|
27
|
+
self.current_wd = current_wd
|
|
27
28
|
|
|
28
29
|
@abstractmethod
|
|
29
30
|
def create_form(self, layout: QFormLayout, params: Dict[str, Any]):
|
|
@@ -35,9 +36,10 @@ class ActionConfigurator(ABC):
|
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class FieldBuilder:
|
|
38
|
-
def __init__(self, layout, action):
|
|
39
|
+
def __init__(self, layout, action, current_wd):
|
|
39
40
|
self.layout = layout
|
|
40
41
|
self.action = action
|
|
42
|
+
self.current_wd = current_wd
|
|
41
43
|
self.fields = {}
|
|
42
44
|
|
|
43
45
|
def add_field(self, tag: str, field_type: str, label: str,
|
|
@@ -159,6 +161,9 @@ class FieldBuilder:
|
|
|
159
161
|
if field['type'] == FIELD_REL_PATH and 'working_path' in params:
|
|
160
162
|
try:
|
|
161
163
|
working_path = self.get_working_path()
|
|
164
|
+
working_path_abs = os.path.isabs(working_path)
|
|
165
|
+
if not working_path_abs:
|
|
166
|
+
working_path = os.path.join(self.current_wd, working_path)
|
|
162
167
|
abs_path = os.path.normpath(os.path.join(working_path, params[tag]))
|
|
163
168
|
if not abs_path.startswith(os.path.normpath(working_path)):
|
|
164
169
|
QMessageBox.warning(None, "Invalid Path",
|
|
@@ -370,8 +375,9 @@ class FieldBuilder:
|
|
|
370
375
|
|
|
371
376
|
|
|
372
377
|
class ActionConfigDialog(QDialog):
|
|
373
|
-
def __init__(self, action: ActionConfig, parent=None):
|
|
378
|
+
def __init__(self, action: ActionConfig, current_wd, parent=None):
|
|
374
379
|
super().__init__(parent)
|
|
380
|
+
self.current_wd = current_wd
|
|
375
381
|
self.action = action
|
|
376
382
|
self.setWindowTitle(f"Configure {action.type_name}")
|
|
377
383
|
self.resize(500, self.height())
|
|
@@ -397,18 +403,18 @@ class ActionConfigDialog(QDialog):
|
|
|
397
403
|
|
|
398
404
|
def get_configurator(self, action_type: str) -> ActionConfigurator:
|
|
399
405
|
configurators = {
|
|
400
|
-
constants.ACTION_JOB: JobConfigurator(self.expert()),
|
|
401
|
-
constants.ACTION_COMBO: CombinedActionsConfigurator(self.expert()),
|
|
402
|
-
constants.ACTION_NOISEDETECTION: NoiseDetectionConfigurator(self.expert()),
|
|
403
|
-
constants.ACTION_FOCUSSTACK: FocusStackConfigurator(self.expert()),
|
|
404
|
-
constants.ACTION_FOCUSSTACKBUNCH: FocusStackBunchConfigurator(self.expert()),
|
|
405
|
-
constants.ACTION_MULTILAYER: MultiLayerConfigurator(self.expert()),
|
|
406
|
-
constants.ACTION_MASKNOISE: MaskNoiseConfigurator(self.expert()),
|
|
407
|
-
constants.ACTION_VIGNETTING: VignettingConfigurator(self.expert()),
|
|
408
|
-
constants.ACTION_ALIGNFRAMES: AlignFramesConfigurator(self.expert()),
|
|
409
|
-
constants.ACTION_BALANCEFRAMES: BalanceFramesConfigurator(self.expert()),
|
|
406
|
+
constants.ACTION_JOB: JobConfigurator(self.expert(), self.current_wd),
|
|
407
|
+
constants.ACTION_COMBO: CombinedActionsConfigurator(self.expert(), self.current_wd),
|
|
408
|
+
constants.ACTION_NOISEDETECTION: NoiseDetectionConfigurator(self.expert(), self.current_wd),
|
|
409
|
+
constants.ACTION_FOCUSSTACK: FocusStackConfigurator(self.expert(), self.current_wd),
|
|
410
|
+
constants.ACTION_FOCUSSTACKBUNCH: FocusStackBunchConfigurator(self.expert(), self.current_wd),
|
|
411
|
+
constants.ACTION_MULTILAYER: MultiLayerConfigurator(self.expert(), self.current_wd),
|
|
412
|
+
constants.ACTION_MASKNOISE: MaskNoiseConfigurator(self.expert(), self.current_wd),
|
|
413
|
+
constants.ACTION_VIGNETTING: VignettingConfigurator(self.expert(), self.current_wd),
|
|
414
|
+
constants.ACTION_ALIGNFRAMES: AlignFramesConfigurator(self.expert(), self.current_wd),
|
|
415
|
+
constants.ACTION_BALANCEFRAMES: BalanceFramesConfigurator(self.expert(), self.current_wd),
|
|
410
416
|
}
|
|
411
|
-
return configurators.get(action_type, DefaultActionConfigurator(self.expert()))
|
|
417
|
+
return configurators.get(action_type, DefaultActionConfigurator(self.expert(), self.current_wd))
|
|
412
418
|
|
|
413
419
|
def accept(self):
|
|
414
420
|
self.parent()._project_buffer.append(self.parent().project.clone())
|
|
@@ -428,8 +434,8 @@ class ActionConfigDialog(QDialog):
|
|
|
428
434
|
|
|
429
435
|
|
|
430
436
|
class NoNameActionConfigurator(ActionConfigurator):
|
|
431
|
-
def __init__(self, expert
|
|
432
|
-
super().__init__(expert)
|
|
437
|
+
def __init__(self, expert, current_wd):
|
|
438
|
+
super().__init__(expert, current_wd)
|
|
433
439
|
|
|
434
440
|
def get_builder(self):
|
|
435
441
|
return self.builder
|
|
@@ -444,17 +450,17 @@ class NoNameActionConfigurator(ActionConfigurator):
|
|
|
444
450
|
|
|
445
451
|
|
|
446
452
|
class DefaultActionConfigurator(NoNameActionConfigurator):
|
|
447
|
-
def __init__(self, expert
|
|
448
|
-
super().__init__(expert)
|
|
453
|
+
def __init__(self, expert, current_wd):
|
|
454
|
+
super().__init__(expert, current_wd)
|
|
449
455
|
|
|
450
456
|
def create_form(self, layout, action, tag='Action'):
|
|
451
|
-
self.builder = FieldBuilder(layout, action)
|
|
457
|
+
self.builder = FieldBuilder(layout, action, self.current_wd)
|
|
452
458
|
self.builder.add_field('name', FIELD_TEXT, f'{tag} name', required=True)
|
|
453
459
|
|
|
454
460
|
|
|
455
461
|
class JobConfigurator(DefaultActionConfigurator):
|
|
456
|
-
def __init__(self, expert
|
|
457
|
-
super().__init__(expert)
|
|
462
|
+
def __init__(self, expert, current_wd):
|
|
463
|
+
super().__init__(expert, current_wd)
|
|
458
464
|
|
|
459
465
|
def create_form(self, layout, action):
|
|
460
466
|
super().create_form(layout, action, "Job")
|
|
@@ -464,8 +470,8 @@ class JobConfigurator(DefaultActionConfigurator):
|
|
|
464
470
|
|
|
465
471
|
|
|
466
472
|
class NoiseDetectionConfigurator(DefaultActionConfigurator):
|
|
467
|
-
def __init__(self, expert
|
|
468
|
-
super().__init__(expert)
|
|
473
|
+
def __init__(self, expert, current_wd):
|
|
474
|
+
super().__init__(expert, current_wd)
|
|
469
475
|
|
|
470
476
|
def create_form(self, layout, action):
|
|
471
477
|
super().create_form(layout, action)
|
|
@@ -492,8 +498,8 @@ class NoiseDetectionConfigurator(DefaultActionConfigurator):
|
|
|
492
498
|
|
|
493
499
|
|
|
494
500
|
class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
495
|
-
def __init__(self, expert
|
|
496
|
-
super().__init__(expert)
|
|
501
|
+
def __init__(self, expert, current_wd):
|
|
502
|
+
super().__init__(expert, current_wd)
|
|
497
503
|
|
|
498
504
|
ENERGY_OPTIONS = ['Laplacian', 'Sobel']
|
|
499
505
|
MAP_TYPE_OPTIONS = ['Average', 'Maximum']
|
|
@@ -583,8 +589,8 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
583
589
|
|
|
584
590
|
|
|
585
591
|
class FocusStackConfigurator(FocusStackBaseConfigurator):
|
|
586
|
-
def __init__(self, expert
|
|
587
|
-
super().__init__(expert)
|
|
592
|
+
def __init__(self, expert, current_wd):
|
|
593
|
+
super().__init__(expert, current_wd)
|
|
588
594
|
|
|
589
595
|
def create_form(self, layout, action):
|
|
590
596
|
super().create_form(layout, action)
|
|
@@ -599,8 +605,8 @@ class FocusStackConfigurator(FocusStackBaseConfigurator):
|
|
|
599
605
|
|
|
600
606
|
|
|
601
607
|
class FocusStackBunchConfigurator(FocusStackBaseConfigurator):
|
|
602
|
-
def __init__(self, expert
|
|
603
|
-
super().__init__(expert)
|
|
608
|
+
def __init__(self, expert, current_wd):
|
|
609
|
+
super().__init__(expert, current_wd)
|
|
604
610
|
|
|
605
611
|
def create_form(self, layout, action):
|
|
606
612
|
super().create_form(layout, action)
|
|
@@ -614,8 +620,8 @@ class FocusStackBunchConfigurator(FocusStackBaseConfigurator):
|
|
|
614
620
|
|
|
615
621
|
|
|
616
622
|
class MultiLayerConfigurator(DefaultActionConfigurator):
|
|
617
|
-
def __init__(self, expert
|
|
618
|
-
super().__init__(expert)
|
|
623
|
+
def __init__(self, expert, current_wd):
|
|
624
|
+
super().__init__(expert, current_wd)
|
|
619
625
|
|
|
620
626
|
def create_form(self, layout, action):
|
|
621
627
|
super().create_form(layout, action)
|
|
@@ -635,8 +641,8 @@ class MultiLayerConfigurator(DefaultActionConfigurator):
|
|
|
635
641
|
|
|
636
642
|
|
|
637
643
|
class CombinedActionsConfigurator(DefaultActionConfigurator):
|
|
638
|
-
def __init__(self, expert
|
|
639
|
-
super().__init__(expert)
|
|
644
|
+
def __init__(self, expert, current_wd):
|
|
645
|
+
super().__init__(expert, current_wd)
|
|
640
646
|
|
|
641
647
|
def create_form(self, layout, action):
|
|
642
648
|
DefaultActionConfigurator.create_form(self, layout, action)
|
|
@@ -659,8 +665,8 @@ class CombinedActionsConfigurator(DefaultActionConfigurator):
|
|
|
659
665
|
|
|
660
666
|
|
|
661
667
|
class MaskNoiseConfigurator(NoNameActionConfigurator):
|
|
662
|
-
def __init__(self, expert
|
|
663
|
-
super().__init__(expert)
|
|
668
|
+
def __init__(self, expert, current_wd):
|
|
669
|
+
super().__init__(expert, current_wd)
|
|
664
670
|
|
|
665
671
|
def create_form(self, layout, action):
|
|
666
672
|
DefaultActionConfigurator.create_form(self, layout, action)
|
|
@@ -675,8 +681,8 @@ class MaskNoiseConfigurator(NoNameActionConfigurator):
|
|
|
675
681
|
|
|
676
682
|
|
|
677
683
|
class VignettingConfigurator(NoNameActionConfigurator):
|
|
678
|
-
def __init__(self, expert
|
|
679
|
-
super().__init__(expert)
|
|
684
|
+
def __init__(self, expert, current_wd):
|
|
685
|
+
super().__init__(expert, current_wd)
|
|
680
686
|
|
|
681
687
|
def create_form(self, layout, action):
|
|
682
688
|
DefaultActionConfigurator.create_form(self, layout, action)
|
|
@@ -699,8 +705,8 @@ class AlignFramesConfigurator(NoNameActionConfigurator):
|
|
|
699
705
|
METHOD_OPTIONS = ['Random Sample Consensus (RANSAC)', 'Least Median (LMEDS)']
|
|
700
706
|
MATCHING_METHOD_OPTIONS = ['K-nearest neighbors', 'Hamming distance']
|
|
701
707
|
|
|
702
|
-
def __init__(self, expert
|
|
703
|
-
super().__init__(expert)
|
|
708
|
+
def __init__(self, expert, current_wd):
|
|
709
|
+
super().__init__(expert, current_wd)
|
|
704
710
|
|
|
705
711
|
def show_info(self, message, timeout=3000):
|
|
706
712
|
self.info_label.setText(message)
|
|
@@ -713,7 +719,6 @@ class AlignFramesConfigurator(NoNameActionConfigurator):
|
|
|
713
719
|
match_method = {k: v for k, v in zip(self.MATCHING_METHOD_OPTIONS,
|
|
714
720
|
constants.VALID_MATCHING_METHODS)}[self.matching_method_field.currentText()]
|
|
715
721
|
try:
|
|
716
|
-
print(detector, descriptor, match_method)
|
|
717
722
|
validate_align_config(detector, descriptor, match_method)
|
|
718
723
|
except Exception as e:
|
|
719
724
|
self.show_info(str(e))
|
|
@@ -855,8 +860,8 @@ class BalanceFramesConfigurator(NoNameActionConfigurator):
|
|
|
855
860
|
CORRECTION_MAP_OPTIONS = ['Linear', 'Gamma', 'Match histograms']
|
|
856
861
|
CHANNEL_OPTIONS = ['Luminosity', 'RGB', 'HSV', 'HLS']
|
|
857
862
|
|
|
858
|
-
def __init__(self, expert
|
|
859
|
-
super().__init__(expert)
|
|
863
|
+
def __init__(self, expert, current_wd):
|
|
864
|
+
super().__init__(expert, current_wd)
|
|
860
865
|
|
|
861
866
|
def create_form(self, layout, action):
|
|
862
867
|
DefaultActionConfigurator.create_form(self, layout, action)
|