shinestacker 1.3.1__py3-none-any.whl → 1.5.0__py3-none-any.whl
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/_version.py +1 -1
- shinestacker/algorithms/align.py +198 -18
- shinestacker/algorithms/align_parallel.py +17 -1
- shinestacker/algorithms/balance.py +23 -13
- shinestacker/algorithms/noise_detection.py +3 -1
- shinestacker/algorithms/utils.py +21 -10
- shinestacker/algorithms/vignetting.py +2 -0
- shinestacker/app/main.py +1 -1
- shinestacker/config/gui_constants.py +7 -2
- shinestacker/core/core_utils.py +10 -1
- shinestacker/gui/action_config.py +172 -7
- shinestacker/gui/action_config_dialog.py +246 -285
- shinestacker/gui/gui_run.py +2 -2
- shinestacker/gui/main_window.py +14 -5
- shinestacker/gui/menu_manager.py +26 -2
- shinestacker/gui/project_controller.py +4 -0
- shinestacker/gui/recent_file_manager.py +93 -0
- shinestacker/retouch/base_filter.py +13 -15
- shinestacker/retouch/brush_preview.py +3 -1
- shinestacker/retouch/brush_tool.py +11 -11
- shinestacker/retouch/display_manager.py +43 -59
- shinestacker/retouch/image_editor_ui.py +161 -82
- shinestacker/retouch/image_view_status.py +65 -0
- shinestacker/retouch/image_viewer.py +95 -431
- shinestacker/retouch/io_gui_handler.py +12 -2
- shinestacker/retouch/layer_collection.py +3 -0
- shinestacker/retouch/overlaid_view.py +215 -0
- shinestacker/retouch/shortcuts_help.py +13 -3
- shinestacker/retouch/sidebyside_view.py +477 -0
- shinestacker/retouch/transformation_manager.py +43 -0
- shinestacker/retouch/undo_manager.py +22 -3
- shinestacker/retouch/view_strategy.py +557 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/METADATA +7 -7
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/RECORD +38 -32
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/WHEEL +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.3.1.dist-info → shinestacker-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, E0611, R0913, R0917, R0915, R0912
|
|
2
|
-
# pylint: disable=E0606, W0718, R1702, W0102, W0221, R0914
|
|
2
|
+
# pylint: disable=E0606, W0718, R1702, W0102, W0221, R0914, C0302
|
|
3
3
|
import os
|
|
4
4
|
import traceback
|
|
5
|
-
from PySide6.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QLabel, QScrollArea, QSizePolicy,
|
|
6
|
-
QMessageBox, QStackedWidget, QFormLayout, QDialog, QTabWidget)
|
|
7
5
|
from PySide6.QtCore import Qt, QTimer
|
|
6
|
+
from PySide6.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QLabel, QScrollArea, QMessageBox,
|
|
7
|
+
QStackedWidget, QFormLayout, QDialog)
|
|
8
8
|
from .. config.constants import constants
|
|
9
9
|
from .. algorithms.align import validate_align_config
|
|
10
|
-
from .project_model import ActionConfig
|
|
11
10
|
from .base_form_dialog import create_form_layout
|
|
12
11
|
from . action_config import (
|
|
13
|
-
|
|
12
|
+
DefaultActionConfigurator,
|
|
14
13
|
FIELD_TEXT, FIELD_ABS_PATH, FIELD_REL_PATH, FIELD_FLOAT,
|
|
15
14
|
FIELD_INT, FIELD_INT_TUPLE, FIELD_BOOL, FIELD_COMBO, FIELD_REF_IDX
|
|
16
15
|
)
|
|
@@ -18,7 +17,7 @@ from .folder_file_selection import FolderFileSelectionWidget
|
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class ActionConfigDialog(QDialog):
|
|
21
|
-
def __init__(self, action
|
|
20
|
+
def __init__(self, action, current_wd, parent=None):
|
|
22
21
|
super().__init__(parent)
|
|
23
22
|
self.setWindowTitle(f"Configure {action.type_name}")
|
|
24
23
|
self.form_layout = create_form_layout(self)
|
|
@@ -85,7 +84,7 @@ class ActionConfigDialog(QDialog):
|
|
|
85
84
|
frame_geometry.moveCenter(center_point)
|
|
86
85
|
self.move(frame_geometry.topLeft())
|
|
87
86
|
|
|
88
|
-
def get_configurator(self, action_type
|
|
87
|
+
def get_configurator(self, action_type):
|
|
89
88
|
configurators = {
|
|
90
89
|
constants.ACTION_JOB: JobConfigurator,
|
|
91
90
|
constants.ACTION_COMBO: CombinedActionsConfigurator,
|
|
@@ -115,83 +114,9 @@ class ActionConfigDialog(QDialog):
|
|
|
115
114
|
return self.parent().expert_options
|
|
116
115
|
|
|
117
116
|
|
|
118
|
-
class NoNameActionConfigurator(ActionConfigurator):
|
|
119
|
-
def __init__(self, expert, current_wd):
|
|
120
|
-
super().__init__(expert, current_wd)
|
|
121
|
-
self.builder = None
|
|
122
|
-
|
|
123
|
-
def get_builder(self):
|
|
124
|
-
return self.builder
|
|
125
|
-
|
|
126
|
-
def update_params(self, params):
|
|
127
|
-
return self.builder.update_params(params)
|
|
128
|
-
|
|
129
|
-
def add_bold_label(self, label):
|
|
130
|
-
label = QLabel(label)
|
|
131
|
-
label.setStyleSheet("font-weight: bold")
|
|
132
|
-
self.add_row(label)
|
|
133
|
-
|
|
134
|
-
def add_row(self, row):
|
|
135
|
-
self.builder.main_layout.addRow(row)
|
|
136
|
-
|
|
137
|
-
def add_field(self, tag, field_type, label,
|
|
138
|
-
required=False, add_to_layout=None, **kwargs):
|
|
139
|
-
return self.builder.add_field(tag, field_type, label, required, add_to_layout, **kwargs)
|
|
140
|
-
|
|
141
|
-
def labelled_widget(self, label, widget):
|
|
142
|
-
row = QWidget()
|
|
143
|
-
layout = QHBoxLayout()
|
|
144
|
-
layout.setContentsMargins(2, 2, 2, 2)
|
|
145
|
-
layout.setSpacing(8)
|
|
146
|
-
label_widget = QLabel(label)
|
|
147
|
-
label_widget.setFixedWidth(120)
|
|
148
|
-
label_widget.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
|
|
149
|
-
layout.addWidget(label_widget)
|
|
150
|
-
layout.addWidget(widget)
|
|
151
|
-
layout.setStretch(0, 1)
|
|
152
|
-
layout.setStretch(1, 3)
|
|
153
|
-
row.setLayout(layout)
|
|
154
|
-
return row
|
|
155
|
-
|
|
156
|
-
def add_labelled_row(self, label, widget):
|
|
157
|
-
self.add_row(self.labelled_widget(label, widget))
|
|
158
|
-
|
|
159
|
-
def create_tab_widget(self, layout):
|
|
160
|
-
tab_widget = QTabWidget()
|
|
161
|
-
layout.addRow(tab_widget)
|
|
162
|
-
return tab_widget
|
|
163
|
-
|
|
164
|
-
def add_tab(self, tab_widget, title):
|
|
165
|
-
tab = QWidget()
|
|
166
|
-
tab_layout = QFormLayout()
|
|
167
|
-
tab_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
|
|
168
|
-
tab_layout.setRowWrapPolicy(QFormLayout.DontWrapRows)
|
|
169
|
-
tab_layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)
|
|
170
|
-
tab_layout.setLabelAlignment(Qt.AlignLeft)
|
|
171
|
-
tab.setLayout(tab_layout)
|
|
172
|
-
tab_widget.addTab(tab, title)
|
|
173
|
-
return tab_layout
|
|
174
|
-
|
|
175
|
-
def add_field_to_layout(self, layout, tag, field_type, label, required=False, **kwargs):
|
|
176
|
-
return self.add_field(tag, field_type, label, required, add_to_layout=layout, **kwargs)
|
|
177
|
-
|
|
178
|
-
def add_bold_label_to_layout(self, layout, label):
|
|
179
|
-
label_widget = QLabel(label)
|
|
180
|
-
label_widget.setStyleSheet("font-weight: bold")
|
|
181
|
-
layout.addRow(label_widget)
|
|
182
|
-
return label_widget
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
class DefaultActionConfigurator(NoNameActionConfigurator):
|
|
186
|
-
def create_form(self, layout, action, tag='Action'):
|
|
187
|
-
self.builder = FieldBuilder(layout, action, self.current_wd)
|
|
188
|
-
self.add_field(
|
|
189
|
-
'name', FIELD_TEXT, f'{tag} name', required=True)
|
|
190
|
-
|
|
191
|
-
|
|
192
117
|
class JobConfigurator(DefaultActionConfigurator):
|
|
193
118
|
def __init__(self, expert, current_wd):
|
|
194
|
-
super().__init__(expert, current_wd)
|
|
119
|
+
super().__init__(expert, current_wd, expert_toggle=False)
|
|
195
120
|
self.working_path_label = None
|
|
196
121
|
self.input_path_label = None
|
|
197
122
|
self.frames_label = None
|
|
@@ -291,10 +216,10 @@ class NoiseDetectionConfigurator(DefaultActionConfigurator):
|
|
|
291
216
|
required=False, size=3,
|
|
292
217
|
default=constants.DEFAULT_CHANNEL_THRESHOLDS,
|
|
293
218
|
labels=constants.RGB_LABELS, min_val=[1] * 3, max_val=[1000] * 3)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
219
|
+
self.add_field(
|
|
220
|
+
'blur_size', FIELD_INT, 'Blur size (px)', required=False,
|
|
221
|
+
expert=True,
|
|
222
|
+
default=constants.DEFAULT_BLUR_SIZE, min_val=1, max_val=50)
|
|
298
223
|
self.add_field(
|
|
299
224
|
'file_name', FIELD_TEXT, 'File name', required=False,
|
|
300
225
|
default=constants.DEFAULT_NOISE_MAP_FILENAME,
|
|
@@ -334,15 +259,17 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
334
259
|
self.create_algorithm_tab(self.algorithm_tab_layout)
|
|
335
260
|
|
|
336
261
|
def create_general_tab(self, layout):
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
262
|
+
self.add_field_to_layout(
|
|
263
|
+
layout, 'working_path', FIELD_ABS_PATH, 'Working path', required=False,
|
|
264
|
+
expert=True)
|
|
265
|
+
self.add_field_to_layout(
|
|
266
|
+
layout, 'input_path', FIELD_REL_PATH, 'Input path', required=False,
|
|
267
|
+
expert=True,
|
|
268
|
+
placeholder='relative to working path')
|
|
269
|
+
self.add_field_to_layout(
|
|
270
|
+
layout, 'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
271
|
+
expert=True,
|
|
272
|
+
placeholder='relative to working path')
|
|
346
273
|
self.add_field_to_layout(
|
|
347
274
|
layout, 'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
348
275
|
required=False, default=True)
|
|
@@ -355,12 +282,7 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
355
282
|
default=constants.STACK_ALGO_DEFAULT)
|
|
356
283
|
q_pyramid, q_depthmap = QWidget(), QWidget()
|
|
357
284
|
for q in [q_pyramid, q_depthmap]:
|
|
358
|
-
|
|
359
|
-
tab_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
|
|
360
|
-
tab_layout.setRowWrapPolicy(QFormLayout.DontWrapRows)
|
|
361
|
-
tab_layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)
|
|
362
|
-
tab_layout.setLabelAlignment(Qt.AlignLeft)
|
|
363
|
-
q.setLayout(tab_layout)
|
|
285
|
+
q.setLayout(self.create_tab_layout())
|
|
364
286
|
stacked = QStackedWidget()
|
|
365
287
|
stacked.addWidget(q_pyramid)
|
|
366
288
|
stacked.addWidget(q_depthmap)
|
|
@@ -373,55 +295,63 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
373
295
|
stacked.setCurrentWidget(q_depthmap)
|
|
374
296
|
|
|
375
297
|
change()
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
298
|
+
self.add_field_to_layout(
|
|
299
|
+
q_pyramid.layout(), 'pyramid_min_size', FIELD_INT, 'Minimum size (px)',
|
|
300
|
+
expert=True,
|
|
301
|
+
required=False, default=constants.DEFAULT_PY_MIN_SIZE, min_val=2, max_val=256)
|
|
302
|
+
self.add_field_to_layout(
|
|
303
|
+
q_pyramid.layout(), 'pyramid_kernel_size', FIELD_INT, 'Kernel size (px)',
|
|
304
|
+
expert=True,
|
|
305
|
+
required=False, default=constants.DEFAULT_PY_KERNEL_SIZE, min_val=3, max_val=21)
|
|
306
|
+
self.add_field_to_layout(
|
|
307
|
+
q_pyramid.layout(), 'pyramid_gen_kernel', FIELD_FLOAT, 'Gen. kernel',
|
|
308
|
+
expert=True,
|
|
309
|
+
required=False, default=constants.DEFAULT_PY_GEN_KERNEL,
|
|
310
|
+
min_val=0.0, max_val=2.0)
|
|
311
|
+
self.add_field_to_layout(
|
|
312
|
+
q_pyramid.layout(), 'pyramid_float_type', FIELD_COMBO, 'Precision', required=False,
|
|
313
|
+
expert=True,
|
|
314
|
+
options=self.FLOAT_OPTIONS, values=constants.VALID_FLOATS,
|
|
315
|
+
default=dict(zip(constants.VALID_FLOATS,
|
|
316
|
+
self.FLOAT_OPTIONS))[constants.DEFAULT_PY_FLOAT])
|
|
317
|
+
mode = self.add_field_to_layout(
|
|
318
|
+
q_pyramid.layout(), 'pyramid_mode', FIELD_COMBO, 'Mode',
|
|
319
|
+
expert=True,
|
|
320
|
+
required=False, options=self.MODE_OPTIONS, values=constants.PY_VALID_MODES,
|
|
321
|
+
default=dict(zip(constants.PY_VALID_MODES,
|
|
322
|
+
self.MODE_OPTIONS))[constants.DEFAULT_PY_MODE])
|
|
323
|
+
memory_limit = self.add_field_to_layout(
|
|
324
|
+
q_pyramid.layout(), 'pyramid_memory_limit', FIELD_FLOAT,
|
|
325
|
+
'Memory limit (approx., GBytes)',
|
|
326
|
+
expert=True,
|
|
327
|
+
required=False, default=constants.DEFAULT_PY_MEMORY_LIMIT_GB,
|
|
328
|
+
min_val=1.0, max_val=64.0)
|
|
329
|
+
max_threads = self.add_field_to_layout(
|
|
330
|
+
q_pyramid.layout(), 'pyramid_max_threads', FIELD_INT, 'Max num. of cores',
|
|
331
|
+
expert=True,
|
|
332
|
+
required=False, default=constants.DEFAULT_PY_MAX_THREADS,
|
|
333
|
+
min_val=1, max_val=64)
|
|
334
|
+
tile_size = self.add_field_to_layout(
|
|
335
|
+
q_pyramid.layout(), 'pyramid_tile_size', FIELD_INT, 'Tile size (px)',
|
|
336
|
+
expert=True,
|
|
337
|
+
required=False, default=constants.DEFAULT_PY_TILE_SIZE,
|
|
338
|
+
min_val=128, max_val=2048)
|
|
339
|
+
n_tiled_layers = self.add_field_to_layout(
|
|
340
|
+
q_pyramid.layout(), 'pyramid_n_tiled_layers', FIELD_INT, 'Num. tiled layers',
|
|
341
|
+
expert=True,
|
|
342
|
+
required=False, default=constants.DEFAULT_PY_N_TILED_LAYERS,
|
|
343
|
+
min_val=0, max_val=6)
|
|
344
|
+
|
|
345
|
+
def change_mode():
|
|
346
|
+
text = mode.currentText()
|
|
347
|
+
enabled = text == self.MODE_OPTIONS[2]
|
|
348
|
+
tile_size.setEnabled(enabled)
|
|
349
|
+
n_tiled_layers.setEnabled(enabled)
|
|
350
|
+
memory_limit.setEnabled(text == self.MODE_OPTIONS[0])
|
|
351
|
+
max_threads.setEnabled(text != self.MODE_OPTIONS[1])
|
|
352
|
+
|
|
353
|
+
mode.currentIndexChanged.connect(change_mode)
|
|
354
|
+
change_mode()
|
|
425
355
|
|
|
426
356
|
self.add_field_to_layout(
|
|
427
357
|
q_depthmap.layout(), 'depthmap_energy', FIELD_COMBO, 'Energy', required=False,
|
|
@@ -433,29 +363,34 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
433
363
|
options=self.MAP_TYPE_OPTIONS, values=constants.VALID_DM_MAP,
|
|
434
364
|
default=dict(zip(constants.VALID_DM_MAP,
|
|
435
365
|
self.MAP_TYPE_OPTIONS))[constants.DEFAULT_DM_MAP])
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
366
|
+
self.add_field_to_layout(
|
|
367
|
+
q_depthmap.layout(), 'depthmap_kernel_size', FIELD_INT, 'Kernel size (px)',
|
|
368
|
+
expert=True,
|
|
369
|
+
required=False, default=constants.DEFAULT_DM_KERNEL_SIZE, min_val=3, max_val=21)
|
|
370
|
+
self.add_field_to_layout(
|
|
371
|
+
q_depthmap.layout(), 'depthmap_blur_size', FIELD_INT, 'Blurl size (px)',
|
|
372
|
+
expert=True,
|
|
373
|
+
required=False, default=constants.DEFAULT_DM_BLUR_SIZE, min_val=1, max_val=21)
|
|
374
|
+
self.add_field_to_layout(
|
|
375
|
+
q_depthmap.layout(), 'depthmap_smooth_size', FIELD_INT, 'Smooth size (px)',
|
|
376
|
+
expert=True,
|
|
377
|
+
required=False, default=constants.DEFAULT_DM_SMOOTH_SIZE, min_val=0, max_val=256)
|
|
378
|
+
self.add_field_to_layout(
|
|
379
|
+
q_depthmap.layout(), 'depthmap_temperature', FIELD_FLOAT, 'Temperature',
|
|
380
|
+
expert=True,
|
|
381
|
+
required=False, default=constants.DEFAULT_DM_TEMPERATURE,
|
|
382
|
+
min_val=0, max_val=1, step=0.05)
|
|
383
|
+
self.add_field_to_layout(
|
|
384
|
+
q_depthmap.layout(), 'depthmap_levels', FIELD_INT, 'Levels', required=False,
|
|
385
|
+
expert=True,
|
|
386
|
+
default=constants.DEFAULT_DM_LEVELS, min_val=2, max_val=6)
|
|
387
|
+
self.add_field_to_layout(
|
|
388
|
+
q_depthmap.layout(), 'depthmap_float_type', FIELD_COMBO,
|
|
389
|
+
'Precision', required=False,
|
|
390
|
+
expert=True,
|
|
391
|
+
options=self.FLOAT_OPTIONS, values=constants.VALID_FLOATS,
|
|
392
|
+
default=dict(zip(constants.VALID_FLOATS,
|
|
393
|
+
self.FLOAT_OPTIONS))[constants.DEFAULT_DM_FLOAT])
|
|
459
394
|
layout.addRow(stacked)
|
|
460
395
|
combo.currentIndexChanged.connect(change)
|
|
461
396
|
|
|
@@ -463,16 +398,17 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
463
398
|
class FocusStackConfigurator(FocusStackBaseConfigurator):
|
|
464
399
|
def create_form(self, layout, action):
|
|
465
400
|
super().create_form(layout, action)
|
|
466
|
-
|
|
467
|
-
self.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
401
|
+
self.add_field_to_layout(
|
|
402
|
+
self.general_tab_layout, 'exif_path', FIELD_REL_PATH,
|
|
403
|
+
'Exif data path', required=False,
|
|
404
|
+
expert=True,
|
|
405
|
+
placeholder='relative to working path')
|
|
406
|
+
self.add_field_to_layout(
|
|
407
|
+
self.general_tab_layout, 'prefix', FIELD_TEXT,
|
|
408
|
+
'Output filename prefix', required=False,
|
|
409
|
+
expert=True,
|
|
410
|
+
default=constants.DEFAULT_STACK_PREFIX,
|
|
411
|
+
placeholder=constants.DEFAULT_STACK_PREFIX)
|
|
476
412
|
self.add_field_to_layout(
|
|
477
413
|
self.general_tab_layout, 'plot_stack', FIELD_BOOL, 'Plot stack', required=False,
|
|
478
414
|
default=constants.DEFAULT_PLOT_STACK)
|
|
@@ -495,21 +431,22 @@ class FocusStackBunchConfigurator(FocusStackBaseConfigurator):
|
|
|
495
431
|
class MultiLayerConfigurator(DefaultActionConfigurator):
|
|
496
432
|
def create_form(self, layout, action):
|
|
497
433
|
super().create_form(layout, action)
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
434
|
+
self.add_field(
|
|
435
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=False,
|
|
436
|
+
expert=True)
|
|
501
437
|
self.add_field(
|
|
502
438
|
'input_path', FIELD_REL_PATH,
|
|
503
439
|
f'Input path (separate by {constants.PATH_SEPARATOR})',
|
|
504
440
|
required=False, multiple_entries=True,
|
|
505
441
|
placeholder='relative to working path')
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
442
|
+
self.add_field(
|
|
443
|
+
'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
444
|
+
expert=True,
|
|
445
|
+
placeholder='relative to working path')
|
|
446
|
+
self.add_field(
|
|
447
|
+
'exif_path', FIELD_REL_PATH, 'Exif data path', required=False,
|
|
448
|
+
expert=True,
|
|
449
|
+
placeholder='relative to working path')
|
|
513
450
|
self.add_field(
|
|
514
451
|
'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
515
452
|
required=False, default=True)
|
|
@@ -521,38 +458,45 @@ class MultiLayerConfigurator(DefaultActionConfigurator):
|
|
|
521
458
|
class CombinedActionsConfigurator(DefaultActionConfigurator):
|
|
522
459
|
def create_form(self, layout, action):
|
|
523
460
|
super().create_form(layout, action)
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
461
|
+
self.add_field(
|
|
462
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=False,
|
|
463
|
+
expert=True)
|
|
464
|
+
self.add_field(
|
|
465
|
+
'input_path', FIELD_REL_PATH, 'Input path', required=False,
|
|
466
|
+
expert=True,
|
|
467
|
+
must_exist=True, placeholder='relative to working path')
|
|
468
|
+
self.add_field(
|
|
469
|
+
'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
470
|
+
expert=True,
|
|
471
|
+
placeholder='relative to working path')
|
|
533
472
|
self.add_field(
|
|
534
473
|
'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
535
474
|
required=False, default=True)
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
475
|
+
self.add_field(
|
|
476
|
+
'plot_path', FIELD_REL_PATH, 'Plots path', required=False,
|
|
477
|
+
expert=True,
|
|
478
|
+
default="plots", placeholder='relative to working path')
|
|
479
|
+
self.add_field(
|
|
480
|
+
'resample', FIELD_INT, 'Resample frame stack', required=False,
|
|
481
|
+
expert=True,
|
|
482
|
+
default=1, min_val=1, max_val=100)
|
|
483
|
+
self.add_field(
|
|
484
|
+
'reference_index', FIELD_REF_IDX, 'Reference frame', required=False,
|
|
485
|
+
expert=True,
|
|
486
|
+
default=0)
|
|
487
|
+
self.add_field(
|
|
488
|
+
'step_process', FIELD_BOOL, 'Step process', required=False,
|
|
489
|
+
expert=True,
|
|
490
|
+
default=True)
|
|
491
|
+
self.add_field(
|
|
492
|
+
'max_threads', FIELD_INT, 'Max num. of cores',
|
|
493
|
+
required=False, default=constants.DEFAULT_MAX_FWK_THREADS,
|
|
494
|
+
expert=True,
|
|
495
|
+
min_val=1, max_val=64)
|
|
496
|
+
self.add_field(
|
|
497
|
+
'chunk_submit', FIELD_BOOL, 'Submit in chunks',
|
|
498
|
+
expert=True,
|
|
499
|
+
required=False, default=constants.DEFAULT_MAX_FWK_CHUNK_SUBMIT)
|
|
556
500
|
|
|
557
501
|
|
|
558
502
|
class MaskNoiseConfigurator(DefaultActionConfigurator):
|
|
@@ -563,13 +507,14 @@ class MaskNoiseConfigurator(DefaultActionConfigurator):
|
|
|
563
507
|
path_type='file', must_exist=True,
|
|
564
508
|
default=constants.DEFAULT_NOISE_MAP_FILENAME,
|
|
565
509
|
placeholder=constants.DEFAULT_NOISE_MAP_FILENAME)
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
510
|
+
self.add_field(
|
|
511
|
+
'kernel_size', FIELD_INT, 'Kernel size', required=False,
|
|
512
|
+
expert=True,
|
|
513
|
+
default=constants.DEFAULT_MN_KERNEL_SIZE, min_val=1, max_val=10)
|
|
514
|
+
self.add_field(
|
|
515
|
+
'method', FIELD_COMBO, 'Interpolation method', required=False,
|
|
516
|
+
expert=True,
|
|
517
|
+
options=['Mean', 'Median'], default='Mean')
|
|
573
518
|
|
|
574
519
|
|
|
575
520
|
class SubsampleActionConfigurator(DefaultActionConfigurator):
|
|
@@ -583,12 +528,14 @@ class SubsampleActionConfigurator(DefaultActionConfigurator):
|
|
|
583
528
|
add_to_layout = self.builder.main_layout
|
|
584
529
|
self.subsample_field = self.add_field(
|
|
585
530
|
'subsample', FIELD_COMBO, 'Subsample', required=False,
|
|
531
|
+
expert=True,
|
|
586
532
|
options=constants.FIELD_SUBSAMPLE_OPTIONS,
|
|
587
533
|
values=constants.FIELD_SUBSAMPLE_VALUES,
|
|
588
534
|
default=constants.FIELD_SUBSAMPLE_DEFAULT,
|
|
589
535
|
add_to_layout=add_to_layout)
|
|
590
536
|
self.fast_subsampling_field = self.add_field(
|
|
591
537
|
'fast_subsampling', FIELD_BOOL, 'Fast subsampling', required=False,
|
|
538
|
+
expert=True,
|
|
592
539
|
default=constants.DEFAULT_ALIGN_FAST_SUBSAMPLING,
|
|
593
540
|
add_to_layout=add_to_layout)
|
|
594
541
|
|
|
@@ -657,13 +604,12 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
657
604
|
self.descriptor_field = None
|
|
658
605
|
self.matching_method_field = None
|
|
659
606
|
self.tab_widget = self.create_tab_widget(layout)
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
self.create_border_tab(border_layout)
|
|
607
|
+
feature_layout = self.add_tab(self.tab_widget, "Feature extraction")
|
|
608
|
+
self.create_feature_tab(feature_layout)
|
|
609
|
+
transform_layout = self.add_tab(self.tab_widget, "Transform")
|
|
610
|
+
self.create_transform_tab(transform_layout)
|
|
611
|
+
border_layout = self.add_tab(self.tab_widget, "Border")
|
|
612
|
+
self.create_border_tab(border_layout)
|
|
667
613
|
misc_layout = self.add_tab(self.tab_widget, "Miscellanea")
|
|
668
614
|
self.create_miscellanea_tab(misc_layout)
|
|
669
615
|
|
|
@@ -699,18 +645,22 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
699
645
|
self.matching_method_field.currentIndexChanged.connect(self.change_match_config)
|
|
700
646
|
self.add_field_to_layout(
|
|
701
647
|
layout, 'flann_idx_kdtree', FIELD_INT, 'Flann idx kdtree', required=False,
|
|
648
|
+
expert=True,
|
|
702
649
|
default=constants.DEFAULT_FLANN_IDX_KDTREE,
|
|
703
650
|
min_val=0, max_val=10)
|
|
704
651
|
self.add_field_to_layout(
|
|
705
652
|
layout, 'flann_trees', FIELD_INT, 'Flann trees', required=False,
|
|
653
|
+
expert=True,
|
|
706
654
|
default=constants.DEFAULT_FLANN_TREES,
|
|
707
655
|
min_val=0, max_val=10)
|
|
708
656
|
self.add_field_to_layout(
|
|
709
657
|
layout, 'flann_checks', FIELD_INT, 'Flann checks', required=False,
|
|
658
|
+
expert=True,
|
|
710
659
|
default=constants.DEFAULT_FLANN_CHECKS,
|
|
711
660
|
min_val=0, max_val=1000)
|
|
712
661
|
self.add_field_to_layout(
|
|
713
662
|
layout, 'threshold', FIELD_FLOAT, 'Threshold', required=False,
|
|
663
|
+
expert=True,
|
|
714
664
|
default=constants.DEFAULT_ALIGN_THRESHOLD,
|
|
715
665
|
min_val=0, max_val=1, step=0.05)
|
|
716
666
|
self.add_subsample_fields(add_to_layout=layout)
|
|
@@ -727,9 +677,11 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
727
677
|
default=constants.DEFAULT_ALIGN_METHOD)
|
|
728
678
|
rans_threshold = self.add_field_to_layout(
|
|
729
679
|
layout, 'rans_threshold', FIELD_FLOAT, 'RANSAC threshold (px)', required=False,
|
|
680
|
+
expert=True,
|
|
730
681
|
default=constants.DEFAULT_RANS_THRESHOLD, min_val=0, max_val=20, step=0.1)
|
|
731
682
|
self.add_field_to_layout(
|
|
732
683
|
layout, 'min_good_matches', FIELD_INT, "Min. good matches", required=False,
|
|
684
|
+
expert=True,
|
|
733
685
|
default=constants.DEFAULT_ALIGN_MIN_GOOD_MATCHES, min_val=0, max_val=500)
|
|
734
686
|
|
|
735
687
|
def change_method():
|
|
@@ -744,13 +696,16 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
744
696
|
self.add_field_to_layout(
|
|
745
697
|
layout, 'align_confidence', FIELD_FLOAT, 'Confidence (%)',
|
|
746
698
|
required=False, decimals=1,
|
|
699
|
+
expert=True,
|
|
747
700
|
default=constants.DEFAULT_ALIGN_CONFIDENCE,
|
|
748
701
|
min_val=70.0, max_val=100.0, step=0.1)
|
|
749
702
|
refine_iters = self.add_field_to_layout(
|
|
750
703
|
layout, 'refine_iters', FIELD_INT, 'Refinement iterations (Rigid)', required=False,
|
|
704
|
+
expert=True,
|
|
751
705
|
default=constants.DEFAULT_REFINE_ITERS, min_val=0, max_val=1000)
|
|
752
706
|
max_iters = self.add_field_to_layout(
|
|
753
707
|
layout, 'max_iters', FIELD_INT, 'Max. iterations (Homography)', required=False,
|
|
708
|
+
expert=True,
|
|
754
709
|
default=constants.DEFAULT_ALIGN_MAX_ITERS, min_val=0, max_val=5000)
|
|
755
710
|
|
|
756
711
|
def change_transform():
|
|
@@ -766,6 +721,7 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
766
721
|
change_transform()
|
|
767
722
|
self.add_field_to_layout(
|
|
768
723
|
layout, 'abort_abnormal', FIELD_BOOL, 'Abort on abnormal transf.',
|
|
724
|
+
expert=True,
|
|
769
725
|
required=False, default=constants.DEFAULT_ALIGN_ABORT_ABNORMAL)
|
|
770
726
|
|
|
771
727
|
def create_border_tab(self, layout):
|
|
@@ -778,46 +734,49 @@ class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
|
778
734
|
self.add_field_to_layout(
|
|
779
735
|
layout, 'border_value', FIELD_INT_TUPLE,
|
|
780
736
|
'Border value (if constant)', required=False, size=4,
|
|
737
|
+
expert=True,
|
|
781
738
|
default=constants.DEFAULT_BORDER_VALUE,
|
|
782
739
|
labels=constants.RGBA_LABELS,
|
|
783
740
|
min_val=constants.DEFAULT_BORDER_VALUE, max_val=[255] * 4)
|
|
784
741
|
self.add_field_to_layout(
|
|
785
742
|
layout, 'border_blur', FIELD_FLOAT, 'Border blur', required=False,
|
|
743
|
+
expert=True,
|
|
786
744
|
default=constants.DEFAULT_BORDER_BLUR,
|
|
787
745
|
min_val=0, max_val=1000, step=1)
|
|
788
746
|
|
|
789
747
|
def create_miscellanea_tab(self, layout):
|
|
790
748
|
self.add_bold_label_to_layout(layout, "Miscellanea:")
|
|
791
|
-
|
|
792
|
-
mode
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
memory_limit
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
max_threads
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
chunk_submit
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
749
|
+
mode = self.add_field_to_layout(
|
|
750
|
+
layout, 'mode', FIELD_COMBO, 'Mode',
|
|
751
|
+
required=False, options=self.MODE_OPTIONS, values=constants.ALIGN_VALID_MODES,
|
|
752
|
+
default=dict(zip(constants.ALIGN_VALID_MODES,
|
|
753
|
+
self.MODE_OPTIONS))[constants.DEFAULT_ALIGN_MODE])
|
|
754
|
+
memory_limit = self.add_field_to_layout(
|
|
755
|
+
layout, 'memory_limit', FIELD_FLOAT, 'Memory limit (approx., GBytes)',
|
|
756
|
+
required=False, default=constants.DEFAULT_ALIGN_MEMORY_LIMIT_GB,
|
|
757
|
+
min_val=1.0, max_val=64.0)
|
|
758
|
+
max_threads = self.add_field_to_layout(
|
|
759
|
+
layout, 'max_threads', FIELD_INT, 'Max num. of cores',
|
|
760
|
+
required=False, default=constants.DEFAULT_ALIGN_MAX_THREADS,
|
|
761
|
+
min_val=1, max_val=64)
|
|
762
|
+
chunk_submit = self.add_field_to_layout(
|
|
763
|
+
layout, 'chunk_submit', FIELD_BOOL, 'Submit in chunks',
|
|
764
|
+
expert=True,
|
|
765
|
+
required=False, default=constants.DEFAULT_ALIGN_CHUNK_SUBMIT)
|
|
766
|
+
bw_matching = self.add_field_to_layout(
|
|
767
|
+
layout, 'bw_matching', FIELD_BOOL, 'Match using black & white',
|
|
768
|
+
expert=True,
|
|
769
|
+
required=False, default=constants.DEFAULT_ALIGN_BW_MATCHING)
|
|
770
|
+
|
|
771
|
+
def change_mode():
|
|
772
|
+
text = mode.currentText()
|
|
773
|
+
enabled = text != self.MODE_OPTIONS[1]
|
|
774
|
+
memory_limit.setEnabled(enabled)
|
|
775
|
+
max_threads.setEnabled(enabled)
|
|
776
|
+
chunk_submit.setEnabled(enabled)
|
|
777
|
+
bw_matching.setEnabled(enabled)
|
|
778
|
+
|
|
779
|
+
mode.currentIndexChanged.connect(change_mode)
|
|
821
780
|
|
|
822
781
|
self.add_field_to_layout(
|
|
823
782
|
layout, 'plot_summary', FIELD_BOOL, 'Plot summary',
|
|
@@ -851,16 +810,17 @@ class BalanceFramesConfigurator(SubsampleActionConfigurator):
|
|
|
851
810
|
|
|
852
811
|
def create_form(self, layout, action):
|
|
853
812
|
super().create_form(layout, action)
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
813
|
+
self.add_field(
|
|
814
|
+
'mask_size', FIELD_FLOAT, 'Mask size', required=False,
|
|
815
|
+
expert=True,
|
|
816
|
+
default=0, min_val=0, max_val=5, step=0.1)
|
|
817
|
+
self.add_field(
|
|
818
|
+
'intensity_interval', FIELD_INT_TUPLE, 'Intensity range',
|
|
819
|
+
required=False, size=2,
|
|
820
|
+
expert=True,
|
|
821
|
+
default=[v for k, v in constants.DEFAULT_INTENSITY_INTERVAL.items()],
|
|
822
|
+
labels=['min', 'max'], min_val=[-1] * 2, max_val=[65536] * 2)
|
|
823
|
+
self.add_subsample_fields()
|
|
864
824
|
self.add_field(
|
|
865
825
|
'corr_map', FIELD_COMBO, 'Correction map', required=False,
|
|
866
826
|
options=self.CORRECTION_MAP_OPTIONS, values=constants.VALID_BALANCE,
|
|
@@ -881,15 +841,16 @@ class BalanceFramesConfigurator(SubsampleActionConfigurator):
|
|
|
881
841
|
class VignettingConfigurator(SubsampleActionConfigurator):
|
|
882
842
|
def create_form(self, layout, action):
|
|
883
843
|
super().create_form(layout, action)
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
844
|
+
self.add_field(
|
|
845
|
+
'r_steps', FIELD_INT, 'Radial steps', required=False,
|
|
846
|
+
expert=True,
|
|
847
|
+
default=constants.DEFAULT_R_STEPS, min_val=1, max_val=1000)
|
|
848
|
+
self.add_field(
|
|
849
|
+
'black_threshold', FIELD_INT, 'Black intensity threshold',
|
|
850
|
+
expert=True,
|
|
851
|
+
required=False, default=constants.DEFAULT_BLACK_THRESHOLD,
|
|
852
|
+
min_val=0, max_val=1000)
|
|
853
|
+
self.add_subsample_fields()
|
|
893
854
|
self.add_field(
|
|
894
855
|
'max_correction', FIELD_FLOAT, 'Max. correction', required=False,
|
|
895
856
|
default=constants.DEFAULT_MAX_CORRECTION,
|