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.

Files changed (200) hide show
  1. {shinestacker-0.3.0 → shinestacker-0.3.3}/CHANGELOG.md +36 -0
  2. shinestacker-0.3.3/MANIFEST.in +2 -0
  3. {shinestacker-0.3.0 → shinestacker-0.3.3}/PKG-INFO +3 -2
  4. {shinestacker-0.3.0 → shinestacker-0.3.3}/README.md +2 -1
  5. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/alignment.md +1 -1
  6. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/gui.md +3 -6
  7. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/job.md +20 -0
  8. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/main.md +5 -3
  9. shinestacker-0.3.3/img/coins.gif +0 -0
  10. shinestacker-0.3.3/img/coins_stack.jpg +0 -0
  11. shinestacker-0.3.3/img/gui-project-run.png +0 -0
  12. shinestacker-0.3.3/img/gui-retouch.png +0 -0
  13. {shinestacker-0.3.0 → shinestacker-0.3.3}/pyproject.toml +6 -0
  14. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/__init__.py +6 -6
  15. shinestacker-0.3.3/src/shinestacker/_version.py +1 -0
  16. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/balance.py +6 -7
  17. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/noise_detection.py +2 -0
  18. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/utils.py +4 -0
  19. shinestacker-0.3.3/src/shinestacker/algorithms/white_balance.py +13 -0
  20. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/open_frames.py +6 -4
  21. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/__init__.py +2 -1
  22. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/config.py +1 -0
  23. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/constants.py +1 -0
  24. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/config/gui_constants.py +1 -0
  25. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/__init__.py +4 -3
  26. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/colors.py +1 -0
  27. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/core_utils.py +6 -6
  28. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/exceptions.py +1 -0
  29. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/framework.py +2 -1
  30. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/action_config.py +47 -42
  31. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/actions_window.py +8 -5
  32. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/new_project.py +1 -0
  33. shinestacker-0.3.3/src/shinestacker/retouch/brush_gradient.py +20 -0
  34. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/brush_preview.py +10 -14
  35. shinestacker-0.3.3/src/shinestacker/retouch/brush_tool.py +164 -0
  36. shinestacker-0.3.3/src/shinestacker/retouch/denoise_filter.py +56 -0
  37. shinestacker-0.3.3/src/shinestacker/retouch/display_manager.py +177 -0
  38. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/exif_data.py +2 -1
  39. shinestacker-0.3.3/src/shinestacker/retouch/filter_base.py +114 -0
  40. shinestacker-0.3.3/src/shinestacker/retouch/filter_manager.py +14 -0
  41. shinestacker-0.3.3/src/shinestacker/retouch/image_editor.py +235 -0
  42. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/image_editor_ui.py +42 -75
  43. shinestacker-0.3.3/src/shinestacker/retouch/image_filters.py +67 -0
  44. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/image_viewer.py +31 -31
  45. shinestacker-0.3.3/src/shinestacker/retouch/io_gui_handler.py +208 -0
  46. shinestacker-0.3.3/src/shinestacker/retouch/io_manager.py +53 -0
  47. shinestacker-0.3.3/src/shinestacker/retouch/layer_collection.py +118 -0
  48. shinestacker-0.3.3/src/shinestacker/retouch/unsharp_mask_filter.py +84 -0
  49. shinestacker-0.3.3/src/shinestacker/retouch/white_balance_filter.py +111 -0
  50. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/PKG-INFO +3 -2
  51. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/SOURCES.txt +15 -70
  52. shinestacker-0.3.0/examples/balance-only.fsp +0 -1
  53. shinestacker-0.3.0/examples/complete-project.fsp +0 -1
  54. shinestacker-0.3.0/examples/focus-stack-1.ipynb +0 -163
  55. shinestacker-0.3.0/examples/focus-stack-2.ipynb +0 -174
  56. shinestacker-0.3.0/examples/input/img-jpg/0000.jpg +0 -0
  57. shinestacker-0.3.0/examples/input/img-jpg/0001.jpg +0 -0
  58. shinestacker-0.3.0/examples/input/img-jpg/0002.jpg +0 -0
  59. shinestacker-0.3.0/examples/input/img-jpg/0003.jpg +0 -0
  60. shinestacker-0.3.0/examples/input/img-jpg/0004.jpg +0 -0
  61. shinestacker-0.3.0/examples/input/img-jpg/0005.jpg +0 -0
  62. shinestacker-0.3.0/examples/input/img-noise/0001.jpg +0 -0
  63. shinestacker-0.3.0/examples/input/img-noise/0002.jpg +0 -0
  64. shinestacker-0.3.0/examples/input/img-noise/0003.jpg +0 -0
  65. shinestacker-0.3.0/examples/input/img-noise/0004.jpg +0 -0
  66. shinestacker-0.3.0/examples/input/img-noise/0005.jpg +0 -0
  67. shinestacker-0.3.0/examples/input/img-noise/0006.jpg +0 -0
  68. shinestacker-0.3.0/examples/input/img-tif/0000.tif +0 -0
  69. shinestacker-0.3.0/examples/input/img-tif/0001.tif +0 -0
  70. shinestacker-0.3.0/examples/input/img-tif/0002.tif +0 -0
  71. shinestacker-0.3.0/examples/input/img-tif/0003.tif +0 -0
  72. shinestacker-0.3.0/examples/input/img-tif/0004.tif +0 -0
  73. shinestacker-0.3.0/examples/input/img-tif/0005.tif +0 -0
  74. shinestacker-0.3.0/examples/input/img-vignetted/vig-0000.jpg +0 -0
  75. shinestacker-0.3.0/examples/input/img-vignetted/vig-0001.jpg +0 -0
  76. shinestacker-0.3.0/examples/input/img-vignetted/vig-0002.jpg +0 -0
  77. shinestacker-0.3.0/examples/input/img-vignetted/vig-0003.jpg +0 -0
  78. shinestacker-0.3.0/examples/stack-comparison.fsp +0 -1
  79. shinestacker-0.3.0/examples/stack-from-frames.fsp +0 -1
  80. shinestacker-0.3.0/examples/vignetting.fsp +0 -1
  81. shinestacker-0.3.0/img/gui-project-run.png +0 -0
  82. shinestacker-0.3.0/img/gui-retouch.png +0 -0
  83. shinestacker-0.3.0/src/shinestacker/_version.py +0 -1
  84. shinestacker-0.3.0/src/shinestacker/retouch/brush_controller.py +0 -57
  85. shinestacker-0.3.0/src/shinestacker/retouch/image_editor.py +0 -670
  86. shinestacker-0.3.0/src/shinestacker/retouch/image_filters.py +0 -463
  87. shinestacker-0.3.0/tests/test-align-balance.ipynb +0 -282
  88. shinestacker-0.3.0/tests/test-align.ipynb +0 -242
  89. shinestacker-0.3.0/tests/test-balance.ipynb +0 -918
  90. shinestacker-0.3.0/tests/test-exif.ipynb +0 -121
  91. shinestacker-0.3.0/tests/test-job.ipynb +0 -79
  92. shinestacker-0.3.0/tests/test-logging.ipynb +0 -93
  93. shinestacker-0.3.0/tests/test-multilayer.ipynb +0 -72
  94. shinestacker-0.3.0/tests/test-noise-detection.ipynb +0 -110
  95. shinestacker-0.3.0/tests/test-stack.ipynb +0 -97
  96. shinestacker-0.3.0/tests/test-vignetting.ipynb +0 -154
  97. shinestacker-0.3.0/tests/test_0000_logging.py +0 -66
  98. shinestacker-0.3.0/tests/test_0001_colors.py +0 -32
  99. shinestacker-0.3.0/tests/test_0002_config.py +0 -60
  100. shinestacker-0.3.0/tests/test_0005_make_test_img.py +0 -18
  101. shinestacker-0.3.0/tests/test_0006_exceptions.py +0 -99
  102. shinestacker-0.3.0/tests/test_0010_job.py +0 -49
  103. shinestacker-0.3.0/tests/test_0011_core_utils.py +0 -105
  104. shinestacker-0.3.0/tests/test_0020_noise_detection.py +0 -62
  105. shinestacker-0.3.0/tests/test_0030_align.py +0 -74
  106. shinestacker-0.3.0/tests/test_0031_align_precision.py +0 -111
  107. shinestacker-0.3.0/tests/test_0032_align_methods.py +0 -68
  108. shinestacker-0.3.0/tests/test_0040_balance.py +0 -90
  109. shinestacker-0.3.0/tests/test_0050_align_balance.py +0 -59
  110. shinestacker-0.3.0/tests/test_0051_denoise.py +0 -34
  111. shinestacker-0.3.0/tests/test_0052_sharpen.py +0 -34
  112. shinestacker-0.3.0/tests/test_0060_stack.py +0 -51
  113. shinestacker-0.3.0/tests/test_0061_depth_map.py +0 -84
  114. shinestacker-0.3.0/tests/test_0070_multilayer.py +0 -74
  115. shinestacker-0.3.0/tests/test_0080_exif.py +0 -220
  116. shinestacker-0.3.0/tests/test_0090_vignetting.py +0 -19
  117. shinestacker-0.3.0/tests/test_0091_vignetting_algo.py +0 -127
  118. shinestacker-0.3.0/tests/test_1000_brush_mask.py +0 -13
  119. shinestacker-0.3.0/tests/test_1010_gui.py +0 -42
  120. shinestacker-0.3.0/tests/test_1020_gui_images.py +0 -128
  121. shinestacker-0.3.0/tests/test_1030_gui_logging.py +0 -118
  122. shinestacker-0.3.0/tests/test_1040_action_config.py +0 -120
  123. shinestacker-0.3.0/tests/test_1050_project_converter.py +0 -157
  124. shinestacker-0.3.0/tests/test_1060_gui_run.py +0 -136
  125. shinestacker-0.3.0/tests/test_1070_project_editor.py +0 -180
  126. shinestacker-0.3.0/tests/test_1080_actions_window.py +0 -138
  127. {shinestacker-0.3.0 → shinestacker-0.3.3}/.coverage +0 -0
  128. {shinestacker-0.3.0 → shinestacker-0.3.3}/.coveragerc +0 -0
  129. {shinestacker-0.3.0 → shinestacker-0.3.3}/.flake8 +0 -0
  130. {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/ci-multiplatform.yml +0 -0
  131. {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/pypi-publish.yml +0 -0
  132. {shinestacker-0.3.0 → shinestacker-0.3.3}/.github/workflows/release.yml +0 -0
  133. {shinestacker-0.3.0 → shinestacker-0.3.3}/.gitignore +0 -0
  134. {shinestacker-0.3.0 → shinestacker-0.3.3}/.readthedocs.yaml +0 -0
  135. {shinestacker-0.3.0 → shinestacker-0.3.3}/LICENSE +0 -0
  136. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/api.md +0 -0
  137. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/balancing.md +0 -0
  138. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/conf.py +0 -0
  139. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/focus_stacking.md +0 -0
  140. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/index.md +0 -0
  141. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/multilayer.md +0 -0
  142. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/noise.md +0 -0
  143. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/requirements.txt +0 -0
  144. {shinestacker-0.3.0 → shinestacker-0.3.3}/docs/vignetting.md +0 -0
  145. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/extreme-vignetting.jpg +0 -0
  146. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flies.gif +0 -0
  147. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flies_stack.jpg +0 -0
  148. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/flow-diagram.png +0 -0
  149. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/gui-finder.png +0 -0
  150. {shinestacker-0.3.0 → shinestacker-0.3.3}/img/gui-project-new.png +0 -0
  151. {shinestacker-0.3.0 → shinestacker-0.3.3}/scripts/build_release.py +0 -0
  152. {shinestacker-0.3.0 → shinestacker-0.3.3}/scripts/validate-tomli.py +0 -0
  153. {shinestacker-0.3.0 → shinestacker-0.3.3}/setup.cfg +0 -0
  154. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/__init__.py +0 -0
  155. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/align.py +0 -0
  156. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/core_utils.py +0 -0
  157. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/denoise.py +0 -0
  158. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/depth_map.py +0 -0
  159. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/exif.py +0 -0
  160. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/multilayer.py +0 -0
  161. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/pyramid.py +0 -0
  162. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/sharpen.py +0 -0
  163. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/stack.py +0 -0
  164. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/stack_framework.py +0 -0
  165. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/algorithms/vignetting.py +0 -0
  166. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/__init__.py +0 -0
  167. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/about_dialog.py +0 -0
  168. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/app_config.py +0 -0
  169. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/gui_utils.py +0 -0
  170. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/help_menu.py +0 -0
  171. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/main.py +0 -0
  172. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/project.py +0 -0
  173. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/app/retouch.py +0 -0
  174. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/core/logging.py +0 -0
  175. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/__init__.py +0 -0
  176. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/colors.py +0 -0
  177. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_images.py +0 -0
  178. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_logging.py +0 -0
  179. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/gui_run.py +0 -0
  180. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/focus_stack_bkg.png +0 -0
  181. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.icns +0 -0
  182. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.ico +0 -0
  183. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/ico/shinestacker.png +0 -0
  184. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/close-round-line-icon.png +0 -0
  185. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/forward-button-icon.png +0 -0
  186. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/play-button-round-icon.png +0 -0
  187. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/img/plus-round-line-icon.png +0 -0
  188. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/main_window.py +0 -0
  189. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_converter.py +0 -0
  190. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_editor.py +0 -0
  191. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/gui/project_model.py +0 -0
  192. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/__init__.py +0 -0
  193. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/brush.py +0 -0
  194. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/file_loader.py +0 -0
  195. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/shortcuts_help.py +0 -0
  196. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker/retouch/undo_manager.py +0 -0
  197. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/dependency_links.txt +0 -0
  198. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/entry_points.txt +0 -0
  199. {shinestacker-0.3.0 → shinestacker-0.3.3}/src/shinestacker.egg-info/requires.txt +0 -0
  200. {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
 
@@ -0,0 +1,2 @@
1
+ prune examples
2
+ prune tests
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shinestacker
3
- Version: 0.3.0
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*: interactive final refinements to final blended image from individual frames.
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*: interactive final refinements to final blended image from individual frames.
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
- 3. **Export**:
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
  [![codecov](https://codecov.io/github/lucalista/shinestacker/graph/badge.svg?token=Y5NKW6VH5G)](https://codecov.io/github/lucalista/shinestacker)
9
9
  [![Documentation Status](https://readthedocs.org/projects/shinestacker/badge/?version=latest)](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 of 20Mpx respolution
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``` fail with 16-bit images | convert to 8-bit or use ```RGB``` or luminosity |
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
@@ -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
- #__all__ += config.__all__
15
- #__all__ += core.__all__
16
- #__all__ += algorithms.__all__
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 = image
138
+ image_sel = img_subsample
138
139
  else:
139
- height, width = image.shape[:2]
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 = image[(xv - width / 2) ** 2 + (yv - height / 2) ** 2 <= mask_radius ** 2]
143
- hist, bins = np.histogram((image_sel if self.subsample == 1
144
- else image_sel[::self.subsample, ::self.subsample]),
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
- if editor.loader_thread is None or editor.loader_thread.isRunning():
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,6 +1,7 @@
1
1
  # flake8: noqa F401
2
+ # pylint: disable=C0114
2
3
  from .config import config
3
4
  from .constants import constants
4
5
  from .gui_constants import gui_constants
5
6
 
6
- __all__ = ['config', 'constants', 'gui_constants']
7
+ __all__ = ['config', 'constants', 'gui_constants']
@@ -1,3 +1,4 @@
1
+ # pylint: disable=C0114, C0115, C0116, C0103, R0903, W0718, W0104, W0201, E0602
1
2
  class _Config:
2
3
  _initialized = False
3
4
  _instance = None
@@ -1,3 +1,4 @@
1
+ # pylint: disable=C0114, C0115, C0116, C0103, R0903
1
2
  import sys
2
3
  import re
3
4
 
@@ -1,3 +1,4 @@
1
+ # pylint: disable=C0114, C0115, C0116, C0103, R0903
1
2
  import math
2
3
 
3
4
 
@@ -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, AlignmentError,
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
  COLORS = {
2
3
  "black": 30,
3
4
  "red": 31,
@@ -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 Exception('Path does not exist: ' + path)
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
- bar = tqdm_notebook(desc=name, total=size)
20
+ tbar = tqdm_notebook(desc=name, total=size)
20
21
  else:
21
- bar = tqdm(desc=name, total=size, ncols=ncols)
22
- return bar
23
- else:
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, C0301
1
2
  class FocusStackError(Exception):
2
3
  pass
3
4
 
@@ -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 ("{:02d}:{:02d}:{:05.2f}s".format(hh, mm, ss))
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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=False):
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)