shinestacker 1.0.4.post2__py3-none-any.whl → 1.2.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/__init__.py +4 -1
- shinestacker/algorithms/align.py +128 -14
- shinestacker/algorithms/balance.py +362 -163
- shinestacker/algorithms/base_stack_algo.py +33 -4
- shinestacker/algorithms/depth_map.py +9 -12
- shinestacker/algorithms/multilayer.py +12 -2
- shinestacker/algorithms/noise_detection.py +8 -3
- shinestacker/algorithms/pyramid.py +57 -42
- shinestacker/algorithms/pyramid_auto.py +141 -0
- shinestacker/algorithms/pyramid_tiles.py +264 -0
- shinestacker/algorithms/stack.py +14 -11
- shinestacker/algorithms/stack_framework.py +17 -11
- shinestacker/algorithms/utils.py +180 -1
- shinestacker/algorithms/vignetting.py +23 -5
- shinestacker/config/constants.py +31 -5
- shinestacker/gui/action_config.py +6 -7
- shinestacker/gui/action_config_dialog.py +425 -258
- shinestacker/gui/base_form_dialog.py +11 -6
- shinestacker/gui/flow_layout.py +105 -0
- shinestacker/gui/gui_run.py +24 -19
- shinestacker/gui/main_window.py +4 -3
- shinestacker/gui/menu_manager.py +12 -2
- shinestacker/gui/new_project.py +28 -22
- shinestacker/gui/project_controller.py +40 -23
- shinestacker/gui/project_converter.py +6 -6
- shinestacker/gui/project_editor.py +21 -7
- shinestacker/gui/time_progress_bar.py +2 -2
- shinestacker/retouch/exif_data.py +5 -5
- shinestacker/retouch/shortcuts_help.py +4 -4
- shinestacker/retouch/vignetting_filter.py +12 -8
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/METADATA +20 -1
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/RECORD +37 -34
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/WHEEL +0 -0
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.0.4.post2.dist-info → shinestacker-1.2.0.dist-info}/top_level.txt +0 -0
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
# pylint: disable=E0606, W0718, R1702, W0102, W0221
|
|
3
3
|
import traceback
|
|
4
4
|
from typing import Dict, Any
|
|
5
|
-
from PySide6.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QLabel,
|
|
6
|
-
QMessageBox, QStackedWidget, QFormLayout)
|
|
5
|
+
from PySide6.QtWidgets import (QWidget, QPushButton, QHBoxLayout, QLabel, QScrollArea,
|
|
6
|
+
QMessageBox, QStackedWidget, QFormLayout, QDialog)
|
|
7
7
|
from PySide6.QtCore import Qt, QTimer
|
|
8
8
|
from .. config.constants import constants
|
|
9
9
|
from .. algorithms.align import validate_align_config
|
|
10
10
|
from .project_model import ActionConfig
|
|
11
|
-
from .base_form_dialog import
|
|
11
|
+
from .base_form_dialog import create_form_layout
|
|
12
12
|
from . action_config import (
|
|
13
13
|
FieldBuilder, ActionConfigurator,
|
|
14
14
|
FIELD_TEXT, FIELD_ABS_PATH, FIELD_REL_PATH, FIELD_FLOAT,
|
|
@@ -16,13 +16,24 @@ from . action_config import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class ActionConfigDialog(
|
|
19
|
+
class ActionConfigDialog(QDialog):
|
|
20
20
|
def __init__(self, action: ActionConfig, current_wd, parent=None):
|
|
21
|
-
super().__init__(
|
|
21
|
+
super().__init__(parent)
|
|
22
|
+
self.setWindowTitle(f"Configure {action.type_name}")
|
|
23
|
+
self.form_layout = create_form_layout(self)
|
|
22
24
|
self.current_wd = current_wd
|
|
23
25
|
self.action = action
|
|
26
|
+
scroll_area = QScrollArea()
|
|
27
|
+
scroll_area.setWidgetResizable(True)
|
|
28
|
+
container_widget = QWidget()
|
|
29
|
+
self.container_layout = QFormLayout(container_widget)
|
|
30
|
+
self.container_layout.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
|
|
31
|
+
self.container_layout.setRowWrapPolicy(QFormLayout.DontWrapRows)
|
|
32
|
+
self.container_layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop)
|
|
33
|
+
self.container_layout.setLabelAlignment(Qt.AlignLeft)
|
|
24
34
|
self.configurator = self.get_configurator(action.type_name)
|
|
25
|
-
self.configurator.create_form(self.
|
|
35
|
+
self.configurator.create_form(self.container_layout, action)
|
|
36
|
+
scroll_area.setWidget(container_widget)
|
|
26
37
|
button_box = QHBoxLayout()
|
|
27
38
|
ok_button = QPushButton("OK")
|
|
28
39
|
ok_button.setFocus()
|
|
@@ -32,10 +43,47 @@ class ActionConfigDialog(BaseFormDialog):
|
|
|
32
43
|
button_box.addWidget(cancel_button)
|
|
33
44
|
button_box.addWidget(reset_button)
|
|
34
45
|
reset_button.clicked.connect(self.reset_to_defaults)
|
|
35
|
-
self.
|
|
46
|
+
self.form_layout.addRow(scroll_area)
|
|
47
|
+
self.form_layout.addRow(button_box)
|
|
48
|
+
QTimer.singleShot(0, self.adjust_dialog_size)
|
|
36
49
|
ok_button.clicked.connect(self.accept)
|
|
37
50
|
cancel_button.clicked.connect(self.reject)
|
|
38
51
|
|
|
52
|
+
def adjust_dialog_size(self):
|
|
53
|
+
screen_geometry = self.screen().availableGeometry()
|
|
54
|
+
screen_height = screen_geometry.height()
|
|
55
|
+
screen_width = screen_geometry.width()
|
|
56
|
+
scroll_area = self.findChild(QScrollArea)
|
|
57
|
+
container_widget = scroll_area.widget()
|
|
58
|
+
container_size = container_widget.sizeHint()
|
|
59
|
+
container_height = container_size.height()
|
|
60
|
+
container_width = container_size.width()
|
|
61
|
+
button_row_height = 50 # Approx height of button row
|
|
62
|
+
margins_height = 40 # Approx. height of margins
|
|
63
|
+
total_height_needed = container_height + button_row_height + margins_height
|
|
64
|
+
if total_height_needed < screen_height * 0.8:
|
|
65
|
+
width = max(container_width + 40, 600)
|
|
66
|
+
height = total_height_needed
|
|
67
|
+
self.resize(width, height)
|
|
68
|
+
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
69
|
+
else:
|
|
70
|
+
max_height = int(screen_height * 0.9)
|
|
71
|
+
width = max(container_width + 40, 600)
|
|
72
|
+
width = min(width, int(screen_width * 0.9))
|
|
73
|
+
self.resize(width, max_height)
|
|
74
|
+
self.setMaximumHeight(max_height)
|
|
75
|
+
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
|
76
|
+
self.setMinimumHeight(min(max_height, 500))
|
|
77
|
+
self.setMinimumWidth(width)
|
|
78
|
+
self.center_on_screen()
|
|
79
|
+
|
|
80
|
+
def center_on_screen(self):
|
|
81
|
+
screen_geometry = self.screen().availableGeometry()
|
|
82
|
+
center_point = screen_geometry.center()
|
|
83
|
+
frame_geometry = self.frameGeometry()
|
|
84
|
+
frame_geometry.moveCenter(center_point)
|
|
85
|
+
self.move(frame_geometry.topLeft())
|
|
86
|
+
|
|
39
87
|
def get_configurator(self, action_type: str) -> ActionConfigurator:
|
|
40
88
|
configurators = {
|
|
41
89
|
constants.ACTION_JOB: JobConfigurator,
|
|
@@ -83,79 +131,105 @@ class NoNameActionConfigurator(ActionConfigurator):
|
|
|
83
131
|
def add_bold_label(self, label):
|
|
84
132
|
label = QLabel(label)
|
|
85
133
|
label.setStyleSheet("font-weight: bold")
|
|
86
|
-
self.
|
|
134
|
+
self.add_row(label)
|
|
135
|
+
|
|
136
|
+
def add_row(self, row):
|
|
137
|
+
self.builder.main_layout.addRow(row)
|
|
138
|
+
|
|
139
|
+
def add_field(self, tag, field_type, label,
|
|
140
|
+
required=False, add_to_layout=None, **kwargs):
|
|
141
|
+
return self.builder.add_field(tag, field_type, label, required, add_to_layout, **kwargs)
|
|
87
142
|
|
|
88
143
|
|
|
89
144
|
class DefaultActionConfigurator(NoNameActionConfigurator):
|
|
90
145
|
def create_form(self, layout, action, tag='Action'):
|
|
91
146
|
self.builder = FieldBuilder(layout, action, self.current_wd)
|
|
92
|
-
self.
|
|
147
|
+
self.add_field(
|
|
148
|
+
'name', FIELD_TEXT, f'{tag} name', required=True)
|
|
93
149
|
|
|
94
150
|
|
|
95
151
|
class JobConfigurator(DefaultActionConfigurator):
|
|
96
152
|
def create_form(self, layout, action):
|
|
97
153
|
super().create_form(layout, action, "Job")
|
|
98
|
-
self.
|
|
99
|
-
|
|
100
|
-
|
|
154
|
+
self.add_field(
|
|
155
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=True)
|
|
156
|
+
self.add_field(
|
|
157
|
+
'input_path', FIELD_REL_PATH, 'Input path', required=False,
|
|
158
|
+
must_exist=True, placeholder='relative to working path')
|
|
101
159
|
|
|
102
160
|
|
|
103
161
|
class NoiseDetectionConfigurator(DefaultActionConfigurator):
|
|
104
162
|
def create_form(self, layout, action):
|
|
105
163
|
super().create_form(layout, action)
|
|
106
|
-
self.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
self.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
164
|
+
self.add_field(
|
|
165
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=True,
|
|
166
|
+
placeholder='inherit from job')
|
|
167
|
+
self.add_field(
|
|
168
|
+
'input_path', FIELD_REL_PATH,
|
|
169
|
+
f'Input path (separate by {constants.PATH_SEPARATOR})',
|
|
170
|
+
required=False, multiple_entries=True,
|
|
171
|
+
placeholder='relative to working path')
|
|
172
|
+
self.add_field(
|
|
173
|
+
'max_frames', FIELD_INT, 'Max. num. of frames (0 = All)',
|
|
174
|
+
required=False,
|
|
175
|
+
default=constants.DEFAULT_NOISE_MAX_FRAMES, min_val=0, max_val=1000)
|
|
176
|
+
self.add_field(
|
|
177
|
+
'channel_thresholds', FIELD_INT_TUPLE, 'Noise threshold',
|
|
178
|
+
required=False, size=3,
|
|
179
|
+
default=constants.DEFAULT_CHANNEL_THRESHOLDS,
|
|
180
|
+
labels=constants.RGB_LABELS, min_val=[1] * 3, max_val=[1000] * 3)
|
|
119
181
|
if self.expert:
|
|
120
|
-
self.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
self.add_field(
|
|
183
|
+
'blur_size', FIELD_INT, 'Blur size (px)', required=False,
|
|
184
|
+
default=constants.DEFAULT_BLUR_SIZE, min_val=1, max_val=50)
|
|
185
|
+
self.add_field(
|
|
186
|
+
'file_name', FIELD_TEXT, 'File name', required=False,
|
|
187
|
+
default=constants.DEFAULT_NOISE_MAP_FILENAME,
|
|
188
|
+
placeholder=constants.DEFAULT_NOISE_MAP_FILENAME)
|
|
125
189
|
self.add_bold_label("Miscellanea:")
|
|
126
|
-
self.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
190
|
+
self.add_field(
|
|
191
|
+
'plot_histograms', FIELD_BOOL, 'Plot histograms', required=False,
|
|
192
|
+
default=False)
|
|
193
|
+
self.add_field(
|
|
194
|
+
'plot_path', FIELD_REL_PATH, 'Plots path', required=False,
|
|
195
|
+
default=constants.DEFAULT_PLOTS_PATH,
|
|
196
|
+
placeholder='relative to working path')
|
|
197
|
+
self.add_field(
|
|
198
|
+
'plot_range', FIELD_INT_TUPLE, 'Plot range', required=False,
|
|
199
|
+
size=2, default=constants.DEFAULT_NOISE_PLOT_RANGE,
|
|
200
|
+
labels=['min', 'max'], min_val=[0] * 2, max_val=[1000] * 2)
|
|
134
201
|
|
|
135
202
|
|
|
136
203
|
class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
137
204
|
ENERGY_OPTIONS = ['Laplacian', 'Sobel']
|
|
138
205
|
MAP_TYPE_OPTIONS = ['Average', 'Maximum']
|
|
139
206
|
FLOAT_OPTIONS = ['float 32 bits', 'float 64 bits']
|
|
207
|
+
MODE_OPTIONS = ['Auto', 'All in memory', 'Tiled I/O buffered']
|
|
140
208
|
|
|
141
209
|
def create_form(self, layout, action):
|
|
142
210
|
super().create_form(layout, action)
|
|
143
211
|
if self.expert:
|
|
144
|
-
self.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
212
|
+
self.add_field(
|
|
213
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=False)
|
|
214
|
+
self.add_field(
|
|
215
|
+
'input_path', FIELD_REL_PATH, 'Input path', required=False,
|
|
216
|
+
placeholder='relative to working path')
|
|
217
|
+
self.add_field(
|
|
218
|
+
'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
219
|
+
placeholder='relative to working path')
|
|
220
|
+
self.add_field(
|
|
221
|
+
'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
222
|
+
required=False, default=True)
|
|
151
223
|
|
|
152
224
|
def common_fields(self, layout):
|
|
153
|
-
self.
|
|
154
|
-
|
|
225
|
+
self.add_field(
|
|
226
|
+
'denoise_amount', FIELD_FLOAT, 'Denoise', required=False,
|
|
227
|
+
default=0, min_val=0, max_val=10)
|
|
155
228
|
self.add_bold_label("Stacking algorithm:")
|
|
156
|
-
combo = self.
|
|
157
|
-
|
|
158
|
-
|
|
229
|
+
combo = self.add_field(
|
|
230
|
+
'stacker', FIELD_COMBO, 'Stacking algorithm', required=True,
|
|
231
|
+
options=constants.STACK_ALGO_OPTIONS,
|
|
232
|
+
default=constants.STACK_ALGO_DEFAULT)
|
|
159
233
|
q_pyramid, q_depthmap = QWidget(), QWidget()
|
|
160
234
|
for q in [q_pyramid, q_depthmap]:
|
|
161
235
|
layout = QFormLayout()
|
|
@@ -170,61 +244,109 @@ class FocusStackBaseConfigurator(DefaultActionConfigurator):
|
|
|
170
244
|
|
|
171
245
|
def change():
|
|
172
246
|
text = combo.currentText()
|
|
173
|
-
if text ==
|
|
247
|
+
if text == constants.STACK_ALGO_PYRAMID:
|
|
174
248
|
stacked.setCurrentWidget(q_pyramid)
|
|
175
|
-
elif text ==
|
|
249
|
+
elif text == constants.STACK_ALGO_DEPTH_MAP:
|
|
176
250
|
stacked.setCurrentWidget(q_depthmap)
|
|
177
251
|
change()
|
|
178
252
|
if self.expert:
|
|
179
|
-
self.
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
253
|
+
self.add_field(
|
|
254
|
+
'pyramid_min_size', FIELD_INT, 'Minimum size (px)',
|
|
255
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
256
|
+
default=constants.DEFAULT_PY_MIN_SIZE, min_val=2, max_val=256)
|
|
257
|
+
self.add_field(
|
|
258
|
+
'pyramid_kernel_size', FIELD_INT, 'Kernel size (px)',
|
|
259
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
260
|
+
default=constants.DEFAULT_PY_KERNEL_SIZE, min_val=3, max_val=21)
|
|
261
|
+
self.add_field(
|
|
262
|
+
'pyramid_gen_kernel', FIELD_FLOAT, 'Gen. kernel',
|
|
263
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
264
|
+
default=constants.DEFAULT_PY_GEN_KERNEL,
|
|
265
|
+
min_val=0.0, max_val=2.0)
|
|
266
|
+
self.add_field(
|
|
267
|
+
'pyramid_float_type', FIELD_COMBO, 'Precision', required=False,
|
|
268
|
+
add_to_layout=q_pyramid.layout(),
|
|
269
|
+
options=self.FLOAT_OPTIONS, values=constants.VALID_FLOATS,
|
|
270
|
+
default=dict(zip(constants.VALID_FLOATS,
|
|
271
|
+
self.FLOAT_OPTIONS))[constants.DEFAULT_PY_FLOAT])
|
|
272
|
+
mode = self.add_field(
|
|
273
|
+
'pyramid_mode', FIELD_COMBO, 'Mode',
|
|
274
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
275
|
+
options=self.MODE_OPTIONS, values=constants.PY_VALID_MODES,
|
|
276
|
+
default=dict(zip(constants.PY_VALID_MODES,
|
|
277
|
+
self.MODE_OPTIONS))[constants.DEFAULT_PY_MODE])
|
|
278
|
+
memory_limit = self.add_field(
|
|
279
|
+
'pyramid_memory_limit', FIELD_FLOAT, 'Memory limit (approx., GBytes)',
|
|
280
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
281
|
+
default=constants.DEFAULT_PY_MEMORY_LIMIT_GB,
|
|
282
|
+
min_val=1.0, max_val=64.0)
|
|
283
|
+
max_threads = self.add_field(
|
|
284
|
+
'pyramid_max_threads', FIELD_INT, 'Max num. of cores',
|
|
285
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
286
|
+
default=constants.DEFAULT_PY_MAX_THREADS,
|
|
287
|
+
min_val=1, max_val=64)
|
|
288
|
+
tile_size = self.add_field(
|
|
289
|
+
'pyramid_tile_size', FIELD_INT, 'Tile size (px)',
|
|
290
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
291
|
+
default=constants.DEFAULT_PY_TILE_SIZE,
|
|
292
|
+
min_val=128, max_val=2048)
|
|
293
|
+
n_tiled_layers = self.add_field(
|
|
294
|
+
'pyramid_n_tiled_layers', FIELD_INT, 'Num. tiled layers',
|
|
295
|
+
required=False, add_to_layout=q_pyramid.layout(),
|
|
296
|
+
default=constants.DEFAULT_PY_N_TILED_LAYERS,
|
|
297
|
+
min_val=0, max_val=6)
|
|
298
|
+
|
|
299
|
+
def change_mode():
|
|
300
|
+
text = mode.currentText()
|
|
301
|
+
enabled = text == self.MODE_OPTIONS[2]
|
|
302
|
+
tile_size.setEnabled(enabled)
|
|
303
|
+
n_tiled_layers.setEnabled(enabled)
|
|
304
|
+
memory_limit.setEnabled(text == self.MODE_OPTIONS[0])
|
|
305
|
+
max_threads.setEnabled(text != self.MODE_OPTIONS[1])
|
|
306
|
+
|
|
307
|
+
mode.currentIndexChanged.connect(change_mode)
|
|
308
|
+
change_mode()
|
|
309
|
+
self.add_field(
|
|
310
|
+
'depthmap_energy', FIELD_COMBO, 'Energy', required=False,
|
|
311
|
+
add_to_layout=q_depthmap.layout(),
|
|
312
|
+
options=self.ENERGY_OPTIONS, values=constants.VALID_DM_ENERGY,
|
|
313
|
+
default=dict(zip(constants.VALID_DM_ENERGY,
|
|
314
|
+
self.ENERGY_OPTIONS))[constants.DEFAULT_DM_ENERGY])
|
|
315
|
+
self.add_field(
|
|
316
|
+
'map_type', FIELD_COMBO, 'Map type', required=False,
|
|
317
|
+
add_to_layout=q_depthmap.layout(),
|
|
318
|
+
options=self.MAP_TYPE_OPTIONS, values=constants.VALID_DM_MAP,
|
|
319
|
+
default=dict(zip(constants.VALID_DM_MAP,
|
|
320
|
+
self.MAP_TYPE_OPTIONS))[constants.DEFAULT_DM_MAP])
|
|
204
321
|
if self.expert:
|
|
205
|
-
self.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
self.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
322
|
+
self.add_field(
|
|
323
|
+
'depthmap_kernel_size', FIELD_INT, 'Kernel size (px)',
|
|
324
|
+
required=False, add_to_layout=q_depthmap.layout(),
|
|
325
|
+
default=constants.DEFAULT_DM_KERNEL_SIZE, min_val=3, max_val=21)
|
|
326
|
+
self.add_field(
|
|
327
|
+
'depthmap_blur_size', FIELD_INT, 'Blurl size (px)',
|
|
328
|
+
required=False, add_to_layout=q_depthmap.layout(),
|
|
329
|
+
default=constants.DEFAULT_DM_BLUR_SIZE, min_val=1, max_val=21)
|
|
330
|
+
self.add_field(
|
|
331
|
+
'depthmap_smooth_size', FIELD_INT, 'Smooth size (px)',
|
|
332
|
+
required=False, add_to_layout=q_depthmap.layout(),
|
|
333
|
+
default=constants.DEFAULT_DM_SMOOTH_SIZE, min_val=0, max_val=256)
|
|
334
|
+
self.add_field(
|
|
335
|
+
'depthmap_temperature', FIELD_FLOAT, 'Temperature',
|
|
336
|
+
required=False, add_to_layout=q_depthmap.layout(),
|
|
337
|
+
default=constants.DEFAULT_DM_TEMPERATURE,
|
|
338
|
+
min_val=0, max_val=1, step=0.05)
|
|
339
|
+
self.add_field(
|
|
340
|
+
'depthmap_levels', FIELD_INT, 'Levels', required=False,
|
|
341
|
+
add_to_layout=q_depthmap.layout(),
|
|
342
|
+
default=constants.DEFAULT_DM_LEVELS, min_val=2, max_val=6)
|
|
343
|
+
self.add_field(
|
|
344
|
+
'depthmap_float_type', FIELD_COMBO, 'Precision', required=False,
|
|
345
|
+
add_to_layout=q_depthmap.layout(), options=self.FLOAT_OPTIONS,
|
|
346
|
+
values=constants.VALID_FLOATS,
|
|
347
|
+
default=dict(zip(constants.VALID_FLOATS,
|
|
348
|
+
self.FLOAT_OPTIONS))[constants.DEFAULT_DM_FLOAT])
|
|
349
|
+
self.add_row(stacked)
|
|
228
350
|
combo.currentIndexChanged.connect(change)
|
|
229
351
|
|
|
230
352
|
|
|
@@ -232,25 +354,31 @@ class FocusStackConfigurator(FocusStackBaseConfigurator):
|
|
|
232
354
|
def create_form(self, layout, action):
|
|
233
355
|
super().create_form(layout, action)
|
|
234
356
|
if self.expert:
|
|
235
|
-
self.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
357
|
+
self.add_field(
|
|
358
|
+
'exif_path', FIELD_REL_PATH, 'Exif data path', required=False,
|
|
359
|
+
placeholder='relative to working path')
|
|
360
|
+
self.add_field(
|
|
361
|
+
'prefix', FIELD_TEXT, 'Ouptut filename prefix', required=False,
|
|
362
|
+
default=constants.DEFAULT_STACK_PREFIX,
|
|
363
|
+
placeholder=constants.DEFAULT_STACK_PREFIX)
|
|
364
|
+
self.add_field(
|
|
365
|
+
'plot_stack', FIELD_BOOL, 'Plot stack', required=False,
|
|
366
|
+
default=constants.DEFAULT_PLOT_STACK)
|
|
242
367
|
super().common_fields(layout)
|
|
243
368
|
|
|
244
369
|
|
|
245
370
|
class FocusStackBunchConfigurator(FocusStackBaseConfigurator):
|
|
246
371
|
def create_form(self, layout, action):
|
|
247
372
|
super().create_form(layout, action)
|
|
248
|
-
self.
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
373
|
+
self.add_field(
|
|
374
|
+
'frames', FIELD_INT, 'Frames', required=False,
|
|
375
|
+
default=constants.DEFAULT_FRAMES, min_val=1, max_val=100)
|
|
376
|
+
self.add_field(
|
|
377
|
+
'overlap', FIELD_INT, 'Overlapping frames', required=False,
|
|
378
|
+
default=constants.DEFAULT_OVERLAP, min_val=0, max_val=100)
|
|
379
|
+
self.add_field(
|
|
380
|
+
'plot_stack', FIELD_BOOL, 'Plot stack', required=False,
|
|
381
|
+
default=constants.DEFAULT_PLOT_STACK_BUNCH)
|
|
254
382
|
super().common_fields(layout)
|
|
255
383
|
|
|
256
384
|
|
|
@@ -258,83 +386,101 @@ class MultiLayerConfigurator(DefaultActionConfigurator):
|
|
|
258
386
|
def create_form(self, layout, action):
|
|
259
387
|
super().create_form(layout, action)
|
|
260
388
|
if self.expert:
|
|
261
|
-
self.
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
389
|
+
self.add_field(
|
|
390
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=False)
|
|
391
|
+
self.add_field(
|
|
392
|
+
'input_path', FIELD_REL_PATH,
|
|
393
|
+
f'Input path (separate by {constants.PATH_SEPARATOR})',
|
|
394
|
+
required=False, multiple_entries=True,
|
|
395
|
+
placeholder='relative to working path')
|
|
266
396
|
if self.expert:
|
|
267
|
-
self.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
self.
|
|
274
|
-
|
|
275
|
-
|
|
397
|
+
self.add_field(
|
|
398
|
+
'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
399
|
+
placeholder='relative to working path')
|
|
400
|
+
self.add_field(
|
|
401
|
+
'exif_path', FIELD_REL_PATH, 'Exif data path', required=False,
|
|
402
|
+
placeholder='relative to working path')
|
|
403
|
+
self.add_field(
|
|
404
|
+
'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
405
|
+
required=False, default=True)
|
|
406
|
+
self.add_field(
|
|
407
|
+
'reverse_order', FIELD_BOOL, 'Reverse file order', required=False,
|
|
408
|
+
default=constants.DEFAULT_MULTILAYER_FILE_REVERSE_ORDER)
|
|
276
409
|
|
|
277
410
|
|
|
278
411
|
class CombinedActionsConfigurator(DefaultActionConfigurator):
|
|
279
412
|
def create_form(self, layout, action):
|
|
280
413
|
super().create_form(layout, action)
|
|
281
414
|
if self.expert:
|
|
282
|
-
self.
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
415
|
+
self.add_field(
|
|
416
|
+
'working_path', FIELD_ABS_PATH, 'Working path', required=False)
|
|
417
|
+
self.add_field(
|
|
418
|
+
'input_path', FIELD_REL_PATH, 'Input path', required=False,
|
|
419
|
+
must_exist=True, placeholder='relative to working path')
|
|
420
|
+
self.add_field(
|
|
421
|
+
'output_path', FIELD_REL_PATH, 'Output path', required=False,
|
|
422
|
+
placeholder='relative to working path')
|
|
423
|
+
self.add_field(
|
|
424
|
+
'scratch_output_dir', FIELD_BOOL, 'Scratch output dir.',
|
|
425
|
+
required=False, default=True)
|
|
289
426
|
if self.expert:
|
|
290
|
-
self.
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
self.
|
|
297
|
-
|
|
427
|
+
self.add_field(
|
|
428
|
+
'plot_path', FIELD_REL_PATH, 'Plots path', required=False,
|
|
429
|
+
default="plots", placeholder='relative to working path')
|
|
430
|
+
self.add_field(
|
|
431
|
+
'resample', FIELD_INT, 'Resample frame stack', required=False,
|
|
432
|
+
default=1, min_val=1, max_val=100)
|
|
433
|
+
self.add_field(
|
|
434
|
+
'ref_idx', FIELD_INT, 'Reference frame index', required=False,
|
|
435
|
+
default=-1, min_val=-1, max_val=1000)
|
|
436
|
+
self.add_field(
|
|
437
|
+
'step_process', FIELD_BOOL, 'Step process', required=False,
|
|
438
|
+
default=True)
|
|
298
439
|
|
|
299
440
|
|
|
300
441
|
class MaskNoiseConfigurator(DefaultActionConfigurator):
|
|
301
442
|
def create_form(self, layout, action):
|
|
302
443
|
super().create_form(layout, action)
|
|
303
|
-
self.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
444
|
+
self.add_field(
|
|
445
|
+
'noise_mask', FIELD_REL_PATH, 'Noise mask file', required=False,
|
|
446
|
+
path_type='file', must_exist=True,
|
|
447
|
+
default=constants.DEFAULT_NOISE_MAP_FILENAME,
|
|
448
|
+
placeholder=constants.DEFAULT_NOISE_MAP_FILENAME)
|
|
307
449
|
if self.expert:
|
|
308
|
-
self.
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
450
|
+
self.add_field(
|
|
451
|
+
'kernel_size', FIELD_INT, 'Kernel size', required=False,
|
|
452
|
+
default=constants.DEFAULT_MN_KERNEL_SIZE, min_val=1, max_val=10)
|
|
453
|
+
self.add_field(
|
|
454
|
+
'method', FIELD_COMBO, 'Interpolation method', required=False,
|
|
455
|
+
options=['Mean', 'Median'], default='Mean')
|
|
312
456
|
|
|
313
457
|
|
|
314
|
-
class
|
|
315
|
-
def
|
|
316
|
-
super().
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
self.
|
|
331
|
-
self.builder.add_field('plot_correction', FIELD_BOOL, 'Plot correction', required=False,
|
|
332
|
-
default=False)
|
|
333
|
-
self.builder.add_field('plot_summary', FIELD_BOOL, 'Plot summary', required=False,
|
|
334
|
-
default=False)
|
|
458
|
+
class SubsampleActionConfigurator(DefaultActionConfigurator):
|
|
459
|
+
def __init__(self, expert, current_wd):
|
|
460
|
+
super().__init__(expert, current_wd)
|
|
461
|
+
self.subsample_field = None
|
|
462
|
+
self.fast_subsampling_field = None
|
|
463
|
+
|
|
464
|
+
def add_subsample_fields(self):
|
|
465
|
+
self.subsample_field = self.add_field(
|
|
466
|
+
'subsample', FIELD_COMBO, 'Subsample', required=False,
|
|
467
|
+
options=constants.FIELD_SUBSAMPLE_OPTIONS,
|
|
468
|
+
values=constants.FIELD_SUBSAMPLE_VALUES,
|
|
469
|
+
default=constants.FIELD_SUBSAMPLE_DEFAULT)
|
|
470
|
+
self.fast_subsampling_field = self.add_field(
|
|
471
|
+
'fast_subsampling', FIELD_BOOL, 'Fast subsampling', required=False,
|
|
472
|
+
default=constants.DEFAULT_ALIGN_FAST_SUBSAMPLING)
|
|
473
|
+
|
|
474
|
+
self.subsample_field.currentTextChanged.connect(self.change_subsample)
|
|
335
475
|
|
|
476
|
+
self.change_subsample()
|
|
336
477
|
|
|
337
|
-
|
|
478
|
+
def change_subsample(self):
|
|
479
|
+
self.fast_subsampling_field.setEnabled(
|
|
480
|
+
self.subsample_field.currentText() not in constants.FIELD_SUBSAMPLE_OPTIONS[:2])
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class AlignFramesConfigurator(SubsampleActionConfigurator):
|
|
338
484
|
BORDER_MODE_OPTIONS = ['Constant', 'Replicate', 'Replicate and blur']
|
|
339
485
|
TRANSFORM_OPTIONS = ['Rigid', 'Homography']
|
|
340
486
|
METHOD_OPTIONS = ['Random Sample Consensus (RANSAC)', 'Least Median (LMEDS)']
|
|
@@ -390,21 +536,18 @@ class AlignFramesConfigurator(DefaultActionConfigurator):
|
|
|
390
536
|
self.matching_method_field = None
|
|
391
537
|
if self.expert:
|
|
392
538
|
self.add_bold_label("Feature identification:")
|
|
393
|
-
|
|
394
539
|
self.info_label = QLabel()
|
|
395
540
|
self.info_label.setStyleSheet("color: orange; font-style: italic;")
|
|
396
541
|
self.info_label.setVisible(False)
|
|
397
542
|
layout.addRow(self.info_label)
|
|
398
|
-
|
|
399
|
-
self.detector_field = self.builder.add_field(
|
|
543
|
+
self.detector_field = self.add_field(
|
|
400
544
|
'detector', FIELD_COMBO, 'Detector', required=False,
|
|
401
545
|
options=constants.VALID_DETECTORS, default=constants.DEFAULT_DETECTOR)
|
|
402
|
-
self.descriptor_field = self.
|
|
546
|
+
self.descriptor_field = self.add_field(
|
|
403
547
|
'descriptor', FIELD_COMBO, 'Descriptor', required=False,
|
|
404
548
|
options=constants.VALID_DESCRIPTORS, default=constants.DEFAULT_DESCRIPTOR)
|
|
405
|
-
|
|
406
549
|
self.add_bold_label("Feature matching:")
|
|
407
|
-
self.matching_method_field = self.
|
|
550
|
+
self.matching_method_field = self.add_field(
|
|
408
551
|
'match_method', FIELD_COMBO, 'Match method', required=False,
|
|
409
552
|
options=self.MATCHING_METHOD_OPTIONS, values=constants.VALID_MATCHING_METHODS,
|
|
410
553
|
default=constants.DEFAULT_MATCHING_METHOD)
|
|
@@ -412,46 +555,45 @@ class AlignFramesConfigurator(DefaultActionConfigurator):
|
|
|
412
555
|
"SIFT: Requires SIFT descriptor and K-NN matching\n"
|
|
413
556
|
"ORB/AKAZE: Work best with Hamming distance"
|
|
414
557
|
)
|
|
415
|
-
|
|
416
558
|
self.descriptor_field.setToolTip(
|
|
417
559
|
"SIFT: Requires K-NN matching\n"
|
|
418
560
|
"ORB/AKAZE: Require Hamming distance with ORB/AKAZE detectors"
|
|
419
561
|
)
|
|
420
|
-
|
|
421
562
|
self.matching_method_field.setToolTip(
|
|
422
563
|
"Automatically selected based on detector/descriptor combination"
|
|
423
564
|
)
|
|
424
|
-
|
|
425
565
|
self.detector_field.currentIndexChanged.connect(self.change_match_config)
|
|
426
566
|
self.descriptor_field.currentIndexChanged.connect(self.change_match_config)
|
|
427
567
|
self.matching_method_field.currentIndexChanged.connect(self.change_match_config)
|
|
428
|
-
self.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
self.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
568
|
+
self.add_field(
|
|
569
|
+
'flann_idx_kdtree', FIELD_INT, 'Flann idx kdtree', required=False,
|
|
570
|
+
default=constants.DEFAULT_FLANN_IDX_KDTREE,
|
|
571
|
+
min_val=0, max_val=10)
|
|
572
|
+
self.add_field(
|
|
573
|
+
'flann_trees', FIELD_INT, 'Flann trees', required=False,
|
|
574
|
+
default=constants.DEFAULT_FLANN_TREES,
|
|
575
|
+
min_val=0, max_val=10)
|
|
576
|
+
self.add_field(
|
|
577
|
+
'flann_checks', FIELD_INT, 'Flann checks', required=False,
|
|
578
|
+
default=constants.DEFAULT_FLANN_CHECKS,
|
|
579
|
+
min_val=0, max_val=1000)
|
|
580
|
+
self.add_field(
|
|
581
|
+
'threshold', FIELD_FLOAT, 'Threshold', required=False,
|
|
582
|
+
default=constants.DEFAULT_ALIGN_THRESHOLD,
|
|
583
|
+
min_val=0, max_val=1, step=0.05)
|
|
442
584
|
self.add_bold_label("Transform:")
|
|
443
|
-
transform = self.
|
|
585
|
+
transform = self.add_field(
|
|
444
586
|
'transform', FIELD_COMBO, 'Transform', required=False,
|
|
445
587
|
options=self.TRANSFORM_OPTIONS, values=constants.VALID_TRANSFORMS,
|
|
446
588
|
default=constants.DEFAULT_TRANSFORM)
|
|
447
|
-
method = self.
|
|
589
|
+
method = self.add_field(
|
|
448
590
|
'align_method', FIELD_COMBO, 'Align method', required=False,
|
|
449
591
|
options=self.METHOD_OPTIONS, values=constants.VALID_ALIGN_METHODS,
|
|
450
592
|
default=constants.DEFAULT_ALIGN_METHOD)
|
|
451
|
-
rans_threshold = self.
|
|
593
|
+
rans_threshold = self.add_field(
|
|
452
594
|
'rans_threshold', FIELD_FLOAT, 'RANSAC threshold (px)', required=False,
|
|
453
595
|
default=constants.DEFAULT_RANS_THRESHOLD, min_val=0, max_val=20, step=0.1)
|
|
454
|
-
self.
|
|
596
|
+
self.add_field(
|
|
455
597
|
'min_good_matches', FIELD_INT, "Min. good matches", required=False,
|
|
456
598
|
default=constants.DEFAULT_ALIGN_MIN_GOOD_MATCHES, min_val=0, max_val=500)
|
|
457
599
|
|
|
@@ -461,17 +603,19 @@ class AlignFramesConfigurator(DefaultActionConfigurator):
|
|
|
461
603
|
rans_threshold.setEnabled(True)
|
|
462
604
|
elif text == self.METHOD_OPTIONS[1]:
|
|
463
605
|
rans_threshold.setEnabled(False)
|
|
606
|
+
|
|
464
607
|
method.currentIndexChanged.connect(change_method)
|
|
465
608
|
change_method()
|
|
466
|
-
self.
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
609
|
+
self.add_field(
|
|
610
|
+
'align_confidence', FIELD_FLOAT, 'Confidence (%)',
|
|
611
|
+
required=False, decimals=1,
|
|
612
|
+
default=constants.DEFAULT_ALIGN_CONFIDENCE,
|
|
613
|
+
min_val=70.0, max_val=100.0, step=0.1)
|
|
470
614
|
|
|
471
|
-
refine_iters = self.
|
|
615
|
+
refine_iters = self.add_field(
|
|
472
616
|
'refine_iters', FIELD_INT, 'Refinement iterations (Rigid)', required=False,
|
|
473
617
|
default=constants.DEFAULT_REFINE_ITERS, min_val=0, max_val=1000)
|
|
474
|
-
max_iters = self.
|
|
618
|
+
max_iters = self.add_field(
|
|
475
619
|
'max_iters', FIELD_INT, 'Max. iterations (Homography)', required=False,
|
|
476
620
|
default=constants.DEFAULT_ALIGN_MAX_ITERS, min_val=0, max_val=5000)
|
|
477
621
|
|
|
@@ -483,37 +627,36 @@ class AlignFramesConfigurator(DefaultActionConfigurator):
|
|
|
483
627
|
elif text == self.TRANSFORM_OPTIONS[1]:
|
|
484
628
|
refine_iters.setEnabled(False)
|
|
485
629
|
max_iters.setEnabled(True)
|
|
630
|
+
|
|
486
631
|
transform.currentIndexChanged.connect(change_transform)
|
|
487
632
|
change_transform()
|
|
488
|
-
|
|
489
|
-
'
|
|
490
|
-
default=constants.
|
|
491
|
-
|
|
492
|
-
'fast_subsampling', FIELD_BOOL, 'Fast subsampling', required=False,
|
|
493
|
-
default=constants.DEFAULT_ALIGN_FAST_SUBSAMPLING)
|
|
494
|
-
|
|
495
|
-
def change_subsample():
|
|
496
|
-
fast_subsampling.setEnabled(subsample.value() > 1)
|
|
497
|
-
subsample.valueChanged.connect(change_subsample)
|
|
498
|
-
change_subsample()
|
|
633
|
+
self.add_field(
|
|
634
|
+
'abort_abnormal', FIELD_BOOL, 'Abort on abnormal transf.',
|
|
635
|
+
required=False, default=constants.DEFAULT_ALIGN_ABORT_ABNORMAL)
|
|
636
|
+
self.add_subsample_fields()
|
|
499
637
|
self.add_bold_label("Border:")
|
|
500
|
-
self.
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
638
|
+
self.add_field(
|
|
639
|
+
'border_mode', FIELD_COMBO, 'Border mode', required=False,
|
|
640
|
+
options=self.BORDER_MODE_OPTIONS,
|
|
641
|
+
values=constants.VALID_BORDER_MODES,
|
|
642
|
+
default=constants.DEFAULT_BORDER_MODE)
|
|
643
|
+
self.add_field(
|
|
644
|
+
'border_value', FIELD_INT_TUPLE,
|
|
645
|
+
'Border value (if constant)', required=False, size=4,
|
|
646
|
+
default=constants.DEFAULT_BORDER_VALUE,
|
|
647
|
+
labels=constants.RGBA_LABELS,
|
|
648
|
+
min_val=constants.DEFAULT_BORDER_VALUE, max_val=[255] * 4)
|
|
649
|
+
self.add_field(
|
|
650
|
+
'border_blur', FIELD_FLOAT, 'Border blur', required=False,
|
|
651
|
+
default=constants.DEFAULT_BORDER_BLUR,
|
|
652
|
+
min_val=0, max_val=1000, step=1)
|
|
512
653
|
self.add_bold_label("Miscellanea:")
|
|
513
|
-
self.
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
654
|
+
self.add_field(
|
|
655
|
+
'plot_summary', FIELD_BOOL, 'Plot summary',
|
|
656
|
+
required=False, default=False)
|
|
657
|
+
self.add_field(
|
|
658
|
+
'plot_matches', FIELD_BOOL, 'Plot matches',
|
|
659
|
+
required=False, default=False)
|
|
517
660
|
|
|
518
661
|
def update_params(self, params: Dict[str, Any]) -> bool:
|
|
519
662
|
if self.detector_field and self.descriptor_field and self.matching_method_field:
|
|
@@ -533,35 +676,59 @@ class AlignFramesConfigurator(DefaultActionConfigurator):
|
|
|
533
676
|
return super().update_params(params)
|
|
534
677
|
|
|
535
678
|
|
|
536
|
-
class BalanceFramesConfigurator(
|
|
679
|
+
class BalanceFramesConfigurator(SubsampleActionConfigurator):
|
|
537
680
|
CORRECTION_MAP_OPTIONS = ['Linear', 'Gamma', 'Match histograms']
|
|
538
|
-
CHANNEL_OPTIONS = ['Luminosity', 'RGB', 'HSV', 'HLS']
|
|
681
|
+
CHANNEL_OPTIONS = ['Luminosity', 'RGB', 'HSV', 'HLS', 'LAB']
|
|
682
|
+
|
|
683
|
+
def create_form(self, layout, action):
|
|
684
|
+
super().create_form(layout, action)
|
|
685
|
+
if self.expert:
|
|
686
|
+
self.add_field(
|
|
687
|
+
'mask_size', FIELD_FLOAT, 'Mask size', required=False,
|
|
688
|
+
default=0, min_val=0, max_val=5, step=0.1)
|
|
689
|
+
self.add_field(
|
|
690
|
+
'intensity_interval', FIELD_INT_TUPLE, 'Intensity range',
|
|
691
|
+
required=False, size=2,
|
|
692
|
+
default=[v for k, v in constants.DEFAULT_INTENSITY_INTERVAL.items()],
|
|
693
|
+
labels=['min', 'max'], min_val=[-1] * 2, max_val=[65536] * 2)
|
|
694
|
+
self.add_subsample_fields()
|
|
695
|
+
self.add_field(
|
|
696
|
+
'corr_map', FIELD_COMBO, 'Correction map', required=False,
|
|
697
|
+
options=self.CORRECTION_MAP_OPTIONS, values=constants.VALID_BALANCE,
|
|
698
|
+
default='Linear')
|
|
699
|
+
self.add_field(
|
|
700
|
+
'channel', FIELD_COMBO, 'Channel', required=False,
|
|
701
|
+
options=self.CHANNEL_OPTIONS, values=constants.VALID_BALANCE_CHANNELS,
|
|
702
|
+
default='Luminosity')
|
|
703
|
+
self.add_bold_label("Miscellanea:")
|
|
704
|
+
self.add_field(
|
|
705
|
+
'plot_summary', FIELD_BOOL, 'Plot summary',
|
|
706
|
+
required=False, default=False)
|
|
707
|
+
self.add_field(
|
|
708
|
+
'plot_histograms', FIELD_BOOL, 'Plot histograms',
|
|
709
|
+
required=False, default=False)
|
|
710
|
+
|
|
539
711
|
|
|
712
|
+
class VignettingConfigurator(SubsampleActionConfigurator):
|
|
540
713
|
def create_form(self, layout, action):
|
|
541
714
|
super().create_form(layout, action)
|
|
542
715
|
if self.expert:
|
|
543
|
-
self.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
self.
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
default=constants.DEFAULT_BALANCE_FAST_SUBSAMPLING)
|
|
556
|
-
self.builder.add_field('corr_map', FIELD_COMBO, 'Correction map', required=False,
|
|
557
|
-
options=self.CORRECTION_MAP_OPTIONS, values=constants.VALID_BALANCE,
|
|
558
|
-
default='Linear')
|
|
559
|
-
self.builder.add_field('channel', FIELD_COMBO, 'Channel', required=False,
|
|
560
|
-
options=self.CHANNEL_OPTIONS,
|
|
561
|
-
values=constants.VALID_BALANCE_CHANNELS,
|
|
562
|
-
default='Luminosity')
|
|
716
|
+
self.add_field(
|
|
717
|
+
'r_steps', FIELD_INT, 'Radial steps', required=False,
|
|
718
|
+
default=constants.DEFAULT_R_STEPS, min_val=1, max_val=1000)
|
|
719
|
+
self.add_field(
|
|
720
|
+
'black_threshold', FIELD_INT, 'Black intensity threshold',
|
|
721
|
+
required=False, default=constants.DEFAULT_BLACK_THRESHOLD,
|
|
722
|
+
min_val=0, max_val=1000)
|
|
723
|
+
self.add_subsample_fields()
|
|
724
|
+
self.add_field(
|
|
725
|
+
'max_correction', FIELD_FLOAT, 'Max. correction', required=False,
|
|
726
|
+
default=constants.DEFAULT_MAX_CORRECTION,
|
|
727
|
+
min_val=0, max_val=1, step=0.05)
|
|
563
728
|
self.add_bold_label("Miscellanea:")
|
|
564
|
-
self.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
729
|
+
self.add_field(
|
|
730
|
+
'plot_correction', FIELD_BOOL, 'Plot correction', required=False,
|
|
731
|
+
default=False)
|
|
732
|
+
self.add_field(
|
|
733
|
+
'plot_summary', FIELD_BOOL, 'Plot summary', required=False,
|
|
734
|
+
default=False)
|