setiastrosuitepro 1.6.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 setiastrosuitepro might be problematic. Click here for more details.
- setiastro/__init__.py +2 -0
- setiastro/saspro/__init__.py +20 -0
- setiastro/saspro/__main__.py +784 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +2 -0
- setiastro/saspro/abe.py +1295 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +694 -0
- setiastro/saspro/aberration_ai_preset.py +224 -0
- setiastro/saspro/accel_installer.py +218 -0
- setiastro/saspro/accel_workers.py +30 -0
- setiastro/saspro/add_stars.py +621 -0
- setiastro/saspro/astrobin_exporter.py +1007 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1839 -0
- setiastro/saspro/autostretch.py +196 -0
- setiastro/saspro/backgroundneutral.py +560 -0
- setiastro/saspro/batch_convert.py +325 -0
- setiastro/saspro/batch_renamer.py +519 -0
- setiastro/saspro/blemish_blaster.py +488 -0
- setiastro/saspro/blink_comparator_pro.py +2923 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +168 -0
- setiastro/saspro/clahe.py +342 -0
- setiastro/saspro/comet_stacking.py +1377 -0
- setiastro/saspro/config.py +38 -0
- setiastro/saspro/config_bootstrap.py +40 -0
- setiastro/saspro/config_manager.py +316 -0
- setiastro/saspro/continuum_subtract.py +1617 -0
- setiastro/saspro/convo.py +1397 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +187 -0
- setiastro/saspro/cosmicclarity.py +1564 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +948 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2544 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +670 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2634 -0
- setiastro/saspro/exoplanet_detector.py +2166 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +744 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1343 -0
- setiastro/saspro/function_bundle.py +1594 -0
- setiastro/saspro/ghs_dialog_pro.py +660 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +634 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8494 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +263 -0
- setiastro/saspro/gui/mixins/file_mixin.py +445 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +403 -0
- setiastro/saspro/gui/mixins/header_mixin.py +441 -0
- setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
- setiastro/saspro/gui/mixins/menu_mixin.py +361 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1324 -0
- setiastro/saspro/gui/mixins/update_mixin.py +309 -0
- setiastro/saspro/gui/mixins/view_mixin.py +435 -0
- setiastro/saspro/halobgon.py +462 -0
- setiastro/saspro/header_viewer.py +445 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +753 -0
- setiastro/saspro/history_explorer.py +939 -0
- setiastro/saspro/image_combine.py +414 -0
- setiastro/saspro/image_peeker_pro.py +1596 -0
- setiastro/saspro/imageops/__init__.py +37 -0
- setiastro/saspro/imageops/mdi_snap.py +292 -0
- setiastro/saspro/imageops/scnr.py +36 -0
- setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
- setiastro/saspro/imageops/stretch.py +244 -0
- setiastro/saspro/isophote.py +1179 -0
- setiastro/saspro/layers.py +208 -0
- setiastro/saspro/layers_dock.py +714 -0
- setiastro/saspro/lazy_imports.py +193 -0
- setiastro/saspro/legacy/__init__.py +2 -0
- setiastro/saspro/legacy/image_manager.py +2226 -0
- setiastro/saspro/legacy/numba_utils.py +3659 -0
- setiastro/saspro/legacy/xisf.py +1071 -0
- setiastro/saspro/linear_fit.py +534 -0
- setiastro/saspro/live_stacking.py +1830 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +309 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +928 -0
- setiastro/saspro/masks_core.py +56 -0
- setiastro/saspro/mdi_widgets.py +353 -0
- setiastro/saspro/memory_utils.py +666 -0
- setiastro/saspro/metadata_patcher.py +75 -0
- setiastro/saspro/mfdeconv.py +3826 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3263 -0
- setiastro/saspro/mfdeconvsport.py +2382 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +382 -0
- setiastro/saspro/multiscale_decomp.py +1290 -0
- setiastro/saspro/nbtorgb_stars.py +531 -0
- setiastro/saspro/numba_utils.py +3044 -0
- setiastro/saspro/numba_warmup.py +141 -0
- setiastro/saspro/ops/__init__.py +9 -0
- setiastro/saspro/ops/command_help_dialog.py +623 -0
- setiastro/saspro/ops/command_runner.py +217 -0
- setiastro/saspro/ops/commands.py +1594 -0
- setiastro/saspro/ops/script_editor.py +1102 -0
- setiastro/saspro/ops/scripts.py +1413 -0
- setiastro/saspro/ops/settings.py +560 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1053 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1600 -0
- setiastro/saspro/plate_solver.py +2435 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +549 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +314 -0
- setiastro/saspro/remove_stars.py +1625 -0
- setiastro/saspro/remove_stars_preset.py +404 -0
- setiastro/saspro/resources.py +472 -0
- setiastro/saspro/rgb_combination.py +207 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +723 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +72 -0
- setiastro/saspro/selective_color.py +1552 -0
- setiastro/saspro/sfcc.py +1425 -0
- setiastro/saspro/shortcuts.py +2807 -0
- setiastro/saspro/signature_insert.py +1099 -0
- setiastro/saspro/stacking_suite.py +17712 -0
- setiastro/saspro/star_alignment.py +7420 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +681 -0
- setiastro/saspro/star_stretch.py +470 -0
- setiastro/saspro/stat_stretch.py +502 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3267 -0
- setiastro/saspro/supernovaasteroidhunter.py +1712 -0
- setiastro/saspro/swap_manager.py +99 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- setiastro/saspro/view_bundle.py +1555 -0
- setiastro/saspro/wavescale_hdr.py +624 -0
- setiastro/saspro/wavescale_hdr_preset.py +100 -0
- setiastro/saspro/wavescalede.py +657 -0
- setiastro/saspro/wavescalede_preset.py +228 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +456 -0
- setiastro/saspro/widgets/__init__.py +48 -0
- setiastro/saspro/widgets/common_utilities.py +305 -0
- setiastro/saspro/widgets/graphics_views.py +122 -0
- setiastro/saspro/widgets/image_utils.py +518 -0
- setiastro/saspro/widgets/preview_dialogs.py +280 -0
- setiastro/saspro/widgets/spinboxes.py +275 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +299 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1123 -0
- setiastrosuitepro-1.6.0.dist-info/METADATA +266 -0
- setiastrosuitepro-1.6.0.dist-info/RECORD +174 -0
- setiastrosuitepro-1.6.0.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.0.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.0.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.0.dist-info/licenses/license.txt +2580 -0
|
@@ -0,0 +1,1594 @@
|
|
|
1
|
+
# ops/commands.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
# Preset / Command metadata models
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class PresetSpec:
|
|
14
|
+
"""
|
|
15
|
+
Describes one preset key for a command.
|
|
16
|
+
"""
|
|
17
|
+
key: str
|
|
18
|
+
type: str # "float" | "int" | "bool" | "str" | "enum" | "dict"
|
|
19
|
+
default: Any = None
|
|
20
|
+
min: float | None = None
|
|
21
|
+
max: float | None = None
|
|
22
|
+
enum: list[str] | None = None
|
|
23
|
+
|
|
24
|
+
# prefer desc, but accept help= for backward-compat
|
|
25
|
+
desc: str = "" # human description
|
|
26
|
+
help: str = "" # DEPRECATED alias for desc
|
|
27
|
+
|
|
28
|
+
optional: bool = True # if False, UI/docs treat as required
|
|
29
|
+
|
|
30
|
+
def __post_init__(self):
|
|
31
|
+
if (not self.desc) and self.help:
|
|
32
|
+
self.desc = self.help
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class CommandSpec:
|
|
37
|
+
"""
|
|
38
|
+
One command in SASpro.
|
|
39
|
+
"""
|
|
40
|
+
id: str
|
|
41
|
+
|
|
42
|
+
# prefer name/notes, but accept title/summary
|
|
43
|
+
name: str = ""
|
|
44
|
+
notes: str = ""
|
|
45
|
+
|
|
46
|
+
title: str = "" # DEPRECATED alias for name
|
|
47
|
+
summary: str = "" # DEPRECATED alias for notes
|
|
48
|
+
|
|
49
|
+
group: str = "General"
|
|
50
|
+
|
|
51
|
+
# how scripts should call it (preferred)
|
|
52
|
+
call_style: str = "ctx.run_command" # or "direct_import"
|
|
53
|
+
|
|
54
|
+
# Optional: lazy callable import for headless apply
|
|
55
|
+
# Use either import_path+callable_name OR ui_method/headless_method names.
|
|
56
|
+
import_path: str | None = None # e.g. "pro.whitebalance"
|
|
57
|
+
callable_name: str | None = None # e.g. "apply_white_balance_to_doc"
|
|
58
|
+
|
|
59
|
+
# If command is handled by AstroSuiteProMainWindow methods:
|
|
60
|
+
ui_method: str | None = None # e.g. "_open_wavescale_hdr"
|
|
61
|
+
headless_method: str | None = None # e.g. "_apply_star_stretch_preset_to_doc"
|
|
62
|
+
|
|
63
|
+
replay_apply_name: str | None = None
|
|
64
|
+
|
|
65
|
+
presets: list[PresetSpec] = field(default_factory=list)
|
|
66
|
+
|
|
67
|
+
examples: list[str] = field(default_factory=list)
|
|
68
|
+
aliases: list[str] = field(default_factory=list)
|
|
69
|
+
|
|
70
|
+
supports_mono: bool = True
|
|
71
|
+
supports_rgb: bool = True
|
|
72
|
+
supports_linear: bool = True
|
|
73
|
+
supports_nonlinear: bool = True
|
|
74
|
+
|
|
75
|
+
def __post_init__(self):
|
|
76
|
+
# allow old style title/summary usage
|
|
77
|
+
if not self.name and self.title:
|
|
78
|
+
self.name = self.title
|
|
79
|
+
if not self.notes and self.summary:
|
|
80
|
+
self.notes = self.summary
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# -----------------------------------------------------------------------------
|
|
84
|
+
# Registry container + helpers
|
|
85
|
+
# -----------------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
COMMAND_REGISTRY: Dict[str, CommandSpec] = {}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def register(spec: CommandSpec) -> CommandSpec:
|
|
91
|
+
COMMAND_REGISTRY[spec.id] = spec
|
|
92
|
+
return spec
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# -----------------------------------------------------------------------------
|
|
96
|
+
# CID normalization + aliases (lifted from _cid_norm)
|
|
97
|
+
# -----------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
ALIASES: Dict[str, str] = {
|
|
100
|
+
# geometry short ↔ long ids
|
|
101
|
+
"flip_horizontal": "geom_flip_horizontal",
|
|
102
|
+
"geom_flip_h": "geom_flip_horizontal",
|
|
103
|
+
"geom_flip_horizontal": "geom_flip_horizontal",
|
|
104
|
+
|
|
105
|
+
"flip_vertical": "geom_flip_vertical",
|
|
106
|
+
"geom_flip_v": "geom_flip_vertical",
|
|
107
|
+
"geom_rotate_clockwise": "geom_rotate_clockwise",
|
|
108
|
+
"rotate_clockwise": "geom_rotate_clockwise",
|
|
109
|
+
"geom_rot_cw": "geom_rotate_clockwise",
|
|
110
|
+
|
|
111
|
+
"rotate_counterclockwise": "geom_rotate_counterclockwise",
|
|
112
|
+
"geom_rot_ccw": "geom_rotate_counterclockwise",
|
|
113
|
+
"geom_rotate_counterclockwise": "geom_rotate_counterclockwise",
|
|
114
|
+
|
|
115
|
+
"rotate_180": "geom_rotate_180",
|
|
116
|
+
"geom_rotate_180": "geom_rotate_180",
|
|
117
|
+
|
|
118
|
+
"invert": "geom_invert",
|
|
119
|
+
"geom_invert": "geom_invert",
|
|
120
|
+
|
|
121
|
+
"rescale": "geom_rescale",
|
|
122
|
+
"geom_rescale": "geom_rescale",
|
|
123
|
+
|
|
124
|
+
# stretches / gradients
|
|
125
|
+
"ghs": "ghs",
|
|
126
|
+
"hyperbolic_stretch": "ghs",
|
|
127
|
+
"universal_hyperbolic_stretch": "ghs",
|
|
128
|
+
|
|
129
|
+
"abe": "abe",
|
|
130
|
+
"automatic_background_extraction": "abe",
|
|
131
|
+
|
|
132
|
+
"graxpert": "graxpert",
|
|
133
|
+
"grax": "graxpert",
|
|
134
|
+
"remove_gradient_graxpert": "graxpert",
|
|
135
|
+
|
|
136
|
+
# star removal
|
|
137
|
+
"remove_stars": "remove_stars",
|
|
138
|
+
"star_removal": "remove_stars",
|
|
139
|
+
"starnet": "remove_stars",
|
|
140
|
+
"darkstar": "remove_stars",
|
|
141
|
+
|
|
142
|
+
# AI tools ✅ FIXED
|
|
143
|
+
"aberrationai": "aberration_ai",
|
|
144
|
+
"aberration_ai": "aberration_ai", # explicit canonical alias
|
|
145
|
+
"aberration": "aberration_ai",
|
|
146
|
+
"ai_aberration": "aberration_ai",
|
|
147
|
+
|
|
148
|
+
"cosmic": "cosmic_clarity",
|
|
149
|
+
"cosmicclarity": "cosmic_clarity",
|
|
150
|
+
"cosmic_clarity": "cosmic_clarity",
|
|
151
|
+
|
|
152
|
+
# misc
|
|
153
|
+
"crop": "crop",
|
|
154
|
+
"geom_crop": "crop",
|
|
155
|
+
|
|
156
|
+
"wavescale_hdr": "wavescale_hdr",
|
|
157
|
+
"wavescalehdr": "wavescale_hdr",
|
|
158
|
+
"wavescale": "wavescale_hdr",
|
|
159
|
+
|
|
160
|
+
"wavescale_dark_enhance": "wavescale_dark_enhance",
|
|
161
|
+
"wavescale_dark_enhancer": "wavescale_dark_enhance",
|
|
162
|
+
"wsde": "wavescale_dark_enhance",
|
|
163
|
+
"dark_enhancer": "wavescale_dark_enhance",
|
|
164
|
+
|
|
165
|
+
"star_alignment": "star_align",
|
|
166
|
+
"align_stars": "star_align",
|
|
167
|
+
"align": "star_align",
|
|
168
|
+
|
|
169
|
+
"convo": "convo",
|
|
170
|
+
"convolution": "convo",
|
|
171
|
+
"deconvolution": "convo",
|
|
172
|
+
"convo_deconvo": "convo",
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def normalize_cid(cid: str | None) -> str:
|
|
177
|
+
c = (cid or "").strip().lower()
|
|
178
|
+
return ALIASES.get(c, c)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def get_spec(cid: str | None) -> CommandSpec | None:
|
|
182
|
+
return COMMAND_REGISTRY.get(normalize_cid(cid))
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def list_commands() -> Dict[str, str]:
|
|
186
|
+
return {cid: spec.name for cid, spec in COMMAND_REGISTRY.items()}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# -----------------------------------------------------------------------------
|
|
190
|
+
# Registry population (starter set)
|
|
191
|
+
# -----------------------------------------------------------------------------
|
|
192
|
+
|
|
193
|
+
# Bundles
|
|
194
|
+
register(CommandSpec(
|
|
195
|
+
id="function_bundle",
|
|
196
|
+
title="Function Bundle",
|
|
197
|
+
group="Bundles",
|
|
198
|
+
summary=(
|
|
199
|
+
"Runs a sequence of steps from a saved Function Bundle or an inline "
|
|
200
|
+
"steps list. "
|
|
201
|
+
"Config: name/bundle_name='Bundle Name' OR steps=[...], "
|
|
202
|
+
"optional targets, inherit_target."
|
|
203
|
+
),
|
|
204
|
+
call_style="ctx.run_command",
|
|
205
|
+
import_path="pro.function_bundle", # <── important
|
|
206
|
+
callable_name="run_function_bundle_command",# <── important
|
|
207
|
+
notes=(
|
|
208
|
+
"Use this command from scripts to run a saved Function Bundle or an "
|
|
209
|
+
"inline list of steps.\n\n"
|
|
210
|
+
"- For saved bundles, specify `bundle_name` (or `name`).\n"
|
|
211
|
+
"- `inherit_target=True` forwards the current target (active view / ROI) "
|
|
212
|
+
"into each step.\n"
|
|
213
|
+
"- This is the same mechanism used by the bundled 'Run Function Bundle…' script."
|
|
214
|
+
),
|
|
215
|
+
presets=[
|
|
216
|
+
PresetSpec(
|
|
217
|
+
key="bundle_name",
|
|
218
|
+
type="str",
|
|
219
|
+
desc="Name of the saved Function Bundle to run (same as shown in the Function Bundles dialog).",
|
|
220
|
+
optional=True,
|
|
221
|
+
),
|
|
222
|
+
PresetSpec(
|
|
223
|
+
key="name",
|
|
224
|
+
type="str",
|
|
225
|
+
desc="Alias of `bundle_name` for backward compatibility.",
|
|
226
|
+
optional=True,
|
|
227
|
+
),
|
|
228
|
+
PresetSpec(
|
|
229
|
+
key="steps",
|
|
230
|
+
type="list",
|
|
231
|
+
desc="Inline steps list (advanced). If given, this is used instead of a saved bundle.",
|
|
232
|
+
optional=True,
|
|
233
|
+
),
|
|
234
|
+
PresetSpec(
|
|
235
|
+
key="inherit_target",
|
|
236
|
+
type="bool",
|
|
237
|
+
default=True,
|
|
238
|
+
desc="If True, each step runs on the same target (active view / ROI) as the bundle call.",
|
|
239
|
+
optional=True,
|
|
240
|
+
),
|
|
241
|
+
PresetSpec(
|
|
242
|
+
key="target",
|
|
243
|
+
type="dict",
|
|
244
|
+
desc="Optional explicit target override (advanced; normally you just let inherit_target=True).",
|
|
245
|
+
optional=True,
|
|
246
|
+
),
|
|
247
|
+
],
|
|
248
|
+
examples=[
|
|
249
|
+
# Mirrors your run_function_bundle.py config, but simplified
|
|
250
|
+
"def run(ctx):\n"
|
|
251
|
+
" cfg = {\n"
|
|
252
|
+
" 'bundle_name': 'PreProcess', # name from Function Bundles dialog\n"
|
|
253
|
+
" 'inherit_target': True,\n"
|
|
254
|
+
" }\n"
|
|
255
|
+
" ctx.run_command('function_bundle', cfg)\n",
|
|
256
|
+
|
|
257
|
+
# Inline steps example (for power users)
|
|
258
|
+
"def run(ctx):\n"
|
|
259
|
+
" steps = [\n"
|
|
260
|
+
" {'id': 'stat_stretch', 'preset': {'target_median': 0.25}},\n"
|
|
261
|
+
" {'id': 'remove_green', 'preset': {'amount': 0.6}},\n"
|
|
262
|
+
" ]\n"
|
|
263
|
+
" ctx.run_command('function_bundle', {\n"
|
|
264
|
+
" 'steps': steps,\n"
|
|
265
|
+
" 'inherit_target': True,\n"
|
|
266
|
+
" })\n",
|
|
267
|
+
],
|
|
268
|
+
))
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
register(CommandSpec(
|
|
272
|
+
id="bundle",
|
|
273
|
+
title="Bundle Exec",
|
|
274
|
+
group="Bundles",
|
|
275
|
+
summary="Internal bundle runner. steps=[...], targets='all_open'|[doc_ptrs], stop_on_error.",
|
|
276
|
+
call_style="ctx.run_command",
|
|
277
|
+
import_path="pro.function_bundle",
|
|
278
|
+
callable_name="run_function_bundle_command",
|
|
279
|
+
))
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
# ---------------- Stretches / tone ----------------
|
|
283
|
+
|
|
284
|
+
register(CommandSpec(
|
|
285
|
+
id="stat_stretch",
|
|
286
|
+
title="Statistical Stretch",
|
|
287
|
+
group="Stretch",
|
|
288
|
+
summary=(
|
|
289
|
+
"Stretch linear data to a target median using Statistical Stretch. "
|
|
290
|
+
"Supports linked/unlinked color stretch, optional normalization, "
|
|
291
|
+
"and optional curves boost."
|
|
292
|
+
),
|
|
293
|
+
headless_method="_apply_stat_stretch_preset_to_doc",
|
|
294
|
+
ui_method="_open_statistical_stretch_with_preset",
|
|
295
|
+
presets=[
|
|
296
|
+
PresetSpec(
|
|
297
|
+
key="target_median",
|
|
298
|
+
type="float",
|
|
299
|
+
default=0.25,
|
|
300
|
+
min=0.0, max=1.0,
|
|
301
|
+
help="Target median after stretch. Typical values 0.20–0.30."
|
|
302
|
+
),
|
|
303
|
+
PresetSpec(
|
|
304
|
+
key="linked",
|
|
305
|
+
type="bool",
|
|
306
|
+
default=True,
|
|
307
|
+
help="If True, stretch RGB channels together (linked). If False, unlinked."
|
|
308
|
+
),
|
|
309
|
+
PresetSpec(
|
|
310
|
+
key="normalize",
|
|
311
|
+
type="bool",
|
|
312
|
+
default=True,
|
|
313
|
+
help="If True, normalize channels/whitepoint after stretch."
|
|
314
|
+
),
|
|
315
|
+
PresetSpec(
|
|
316
|
+
key="apply_curves",
|
|
317
|
+
type="bool",
|
|
318
|
+
default=False,
|
|
319
|
+
help="If True, apply the optional curves adjustment pass."
|
|
320
|
+
),
|
|
321
|
+
PresetSpec(
|
|
322
|
+
key="curves_boost",
|
|
323
|
+
type="float",
|
|
324
|
+
default=0.0,
|
|
325
|
+
min=0.0, max=1.0,
|
|
326
|
+
help="Curves boost strength in [0,1]. Only used if apply_curves=True."
|
|
327
|
+
),
|
|
328
|
+
],
|
|
329
|
+
examples=[
|
|
330
|
+
"ctx.run_command('stat_stretch', {'target_median': 0.25, 'linked': True})",
|
|
331
|
+
"ctx.run_command('stat_stretch', {'target_median': 0.22, 'linked': False, "
|
|
332
|
+
"'normalize': False, 'apply_curves': True, 'curves_boost': 0.15})",
|
|
333
|
+
],
|
|
334
|
+
aliases=["statistical_stretch", "statstretch"],
|
|
335
|
+
))
|
|
336
|
+
|
|
337
|
+
register(CommandSpec(
|
|
338
|
+
id="star_stretch",
|
|
339
|
+
name="Star Stretch",
|
|
340
|
+
group="Stretch",
|
|
341
|
+
ui_method="_open_star_stretch_with_preset",
|
|
342
|
+
headless_method="_apply_star_stretch_preset_to_doc",
|
|
343
|
+
summary=(
|
|
344
|
+
"Stretches stars on linear data using your Star Stretch kernel. "
|
|
345
|
+
"Supports optional color boost and SCNR green neutralization."
|
|
346
|
+
),
|
|
347
|
+
presets=[
|
|
348
|
+
PresetSpec(
|
|
349
|
+
key="stretch_factor",
|
|
350
|
+
type="float",
|
|
351
|
+
default=5.0,
|
|
352
|
+
min=0.0,
|
|
353
|
+
max=8.0,
|
|
354
|
+
desc="Star stretch strength. Typical range: 3–6. (Aliases: stretch_amount, amount)"
|
|
355
|
+
),
|
|
356
|
+
PresetSpec(
|
|
357
|
+
key="color_boost",
|
|
358
|
+
type="float",
|
|
359
|
+
default=1.0,
|
|
360
|
+
min=0.0,
|
|
361
|
+
max=2.0,
|
|
362
|
+
desc="Color saturation boost multiplier. 1.0 = no change. (Alias: saturation)"
|
|
363
|
+
),
|
|
364
|
+
PresetSpec(
|
|
365
|
+
key="scnr_green",
|
|
366
|
+
type="bool",
|
|
367
|
+
default=False,
|
|
368
|
+
desc="If True, apply SCNR-like green neutralization. (Alias: scnr)"
|
|
369
|
+
),
|
|
370
|
+
],
|
|
371
|
+
aliases=[
|
|
372
|
+
"starstretch",
|
|
373
|
+
"stretch_stars",
|
|
374
|
+
],
|
|
375
|
+
examples=[
|
|
376
|
+
"ctx.run_command('star_stretch', {'stretch_factor': 5.0})",
|
|
377
|
+
"ctx.run_command('star_stretch', {'stretch_factor': 4.2, 'color_boost': 1.3})",
|
|
378
|
+
"ctx.run_command('star_stretch', {'amount': 5.5, 'saturation': 1.15, 'scnr': True})",
|
|
379
|
+
],
|
|
380
|
+
supports_mono=True, # your headless path supports mono via temp RGB + collapse
|
|
381
|
+
supports_rgb=True,
|
|
382
|
+
supports_linear=True,
|
|
383
|
+
supports_nonlinear=False, # star stretch is intended for star images / linear use
|
|
384
|
+
))
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
register(CommandSpec(
|
|
388
|
+
id="ghs",
|
|
389
|
+
name="Generalized Hyperbolic Stretch",
|
|
390
|
+
group="Stretch",
|
|
391
|
+
import_path="pro.ghs_preset",
|
|
392
|
+
callable_name="apply_ghs_via_preset",
|
|
393
|
+
ui_method="open_ghs_with_preset",
|
|
394
|
+
summary=(
|
|
395
|
+
"Universal / Generalized Hyperbolic Stretch. Builds a monotone control curve from "
|
|
396
|
+
"alpha/beta/gamma with a pivot symmetry point and optional LP/HP protection. "
|
|
397
|
+
"Applies to K (brightness) or individual RGB channels, with active-mask blending."
|
|
398
|
+
),
|
|
399
|
+
presets=[
|
|
400
|
+
PresetSpec(
|
|
401
|
+
key="alpha",
|
|
402
|
+
type="float",
|
|
403
|
+
default=1.0,
|
|
404
|
+
min=0.02,
|
|
405
|
+
max=10.0,
|
|
406
|
+
desc=(
|
|
407
|
+
"Hyperbolic alpha (controls left/right curve rolloff). "
|
|
408
|
+
"Dialog slider stores alpha*50. Range ≈0.02–10."
|
|
409
|
+
)
|
|
410
|
+
),
|
|
411
|
+
PresetSpec(
|
|
412
|
+
key="beta",
|
|
413
|
+
type="float",
|
|
414
|
+
default=1.0,
|
|
415
|
+
min=0.02,
|
|
416
|
+
max=10.0,
|
|
417
|
+
desc=(
|
|
418
|
+
"Hyperbolic beta (asymmetry between shadows/highlights). "
|
|
419
|
+
"Dialog slider stores beta*50. Range ≈0.02–10."
|
|
420
|
+
)
|
|
421
|
+
),
|
|
422
|
+
PresetSpec(
|
|
423
|
+
key="gamma",
|
|
424
|
+
type="float",
|
|
425
|
+
default=1.0,
|
|
426
|
+
min=0.01,
|
|
427
|
+
max=5.0,
|
|
428
|
+
desc=(
|
|
429
|
+
"Gamma lift after hyperbolic mapping. "
|
|
430
|
+
"Dialog slider stores gamma*100. Range ≈0.01–5."
|
|
431
|
+
)
|
|
432
|
+
),
|
|
433
|
+
PresetSpec(
|
|
434
|
+
key="pivot",
|
|
435
|
+
type="float",
|
|
436
|
+
default=0.5,
|
|
437
|
+
min=0.0,
|
|
438
|
+
max=1.0,
|
|
439
|
+
desc=(
|
|
440
|
+
"Symmetry / pivot point in normalized domain. "
|
|
441
|
+
"0.5 is neutral midtone pivot."
|
|
442
|
+
)
|
|
443
|
+
),
|
|
444
|
+
PresetSpec(
|
|
445
|
+
key="lp",
|
|
446
|
+
type="float",
|
|
447
|
+
default=0.0,
|
|
448
|
+
min=0.0,
|
|
449
|
+
max=1.0,
|
|
450
|
+
desc=(
|
|
451
|
+
"Low-protect (LP). Blends left side toward identity y=x. "
|
|
452
|
+
"Dialog slider stores lp*360."
|
|
453
|
+
)
|
|
454
|
+
),
|
|
455
|
+
PresetSpec(
|
|
456
|
+
key="hp",
|
|
457
|
+
type="float",
|
|
458
|
+
default=0.0,
|
|
459
|
+
min=0.0,
|
|
460
|
+
max=1.0,
|
|
461
|
+
desc=(
|
|
462
|
+
"High-protect (HP). Blends right side toward identity y=x. "
|
|
463
|
+
"Dialog slider stores hp*360."
|
|
464
|
+
)
|
|
465
|
+
),
|
|
466
|
+
PresetSpec(
|
|
467
|
+
key="channel",
|
|
468
|
+
type="enum",
|
|
469
|
+
default="K (Brightness)",
|
|
470
|
+
enum=["K (Brightness)", "R", "G", "B"],
|
|
471
|
+
desc=(
|
|
472
|
+
"Target channel. 'K (Brightness)' applies to luminance/brightness. "
|
|
473
|
+
"R/G/B apply to individual color channels. "
|
|
474
|
+
"Aliases accepted: k, brightness, rgb, r, g, b."
|
|
475
|
+
)
|
|
476
|
+
),
|
|
477
|
+
],
|
|
478
|
+
aliases=[
|
|
479
|
+
"hyperbolic_stretch",
|
|
480
|
+
"universal_hyperbolic_stretch",
|
|
481
|
+
"uhs",
|
|
482
|
+
],
|
|
483
|
+
examples=[
|
|
484
|
+
# gentle linked luminance stretch
|
|
485
|
+
"ctx.run_command('ghs', {'alpha': 1.0, 'beta': 1.0, 'gamma': 1.0, 'pivot': 0.5})",
|
|
486
|
+
# stronger contrast with protection
|
|
487
|
+
"ctx.run_command('ghs', {'alpha': 2.2, 'beta': 1.4, 'gamma': 1.1, 'pivot': 0.45, 'lp': 0.10, 'hp': 0.20})",
|
|
488
|
+
# per-channel tweak
|
|
489
|
+
"ctx.run_command('ghs', {'alpha': 1.6, 'beta': 1.0, 'gamma': 0.95, 'pivot': 0.5, 'channel': 'R'})",
|
|
490
|
+
],
|
|
491
|
+
supports_mono=True, # K works on mono; RGB channels are ignored/treated safely by _apply_mode_any
|
|
492
|
+
supports_rgb=True,
|
|
493
|
+
supports_linear=True,
|
|
494
|
+
supports_nonlinear=True,
|
|
495
|
+
))
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
register(CommandSpec(
|
|
499
|
+
id="curves",
|
|
500
|
+
title="Curves",
|
|
501
|
+
group="Stretch",
|
|
502
|
+
import_path="pro.curves_preset",
|
|
503
|
+
callable_name="apply_curves_via_preset",
|
|
504
|
+
ui_method="open_curves_with_preset",
|
|
505
|
+
summary=(
|
|
506
|
+
"Preset schema: {mode, shape, amount, points_norm?}. "
|
|
507
|
+
"mode applies to K/R/G/B or Lab/LCh-style channels. "
|
|
508
|
+
"shape selects a built-in curve unless shape='custom'. "
|
|
509
|
+
"amount is 0..1 intensity for non-custom shapes. "
|
|
510
|
+
"custom uses points_norm (normalized 0..1). "
|
|
511
|
+
"Advanced: preset may also include points_scene/handles/control_points."
|
|
512
|
+
),
|
|
513
|
+
presets=[
|
|
514
|
+
PresetSpec(
|
|
515
|
+
key="mode",
|
|
516
|
+
type="enum",
|
|
517
|
+
default="K (Brightness)",
|
|
518
|
+
enum=[
|
|
519
|
+
"K (Brightness)",
|
|
520
|
+
"R", "G", "B",
|
|
521
|
+
"L*", "a*", "b*",
|
|
522
|
+
"Chroma",
|
|
523
|
+
"Saturation",
|
|
524
|
+
],
|
|
525
|
+
help=(
|
|
526
|
+
"Channel/mode to apply curve to. "
|
|
527
|
+
"Aliases accepted: k, brightness, rgb -> K (Brightness); "
|
|
528
|
+
"lum/l/lab_l -> L*; lab_a -> a*; lab_b -> b*; "
|
|
529
|
+
"chroma -> Chroma; sat/s -> Saturation."
|
|
530
|
+
),
|
|
531
|
+
),
|
|
532
|
+
PresetSpec(
|
|
533
|
+
key="shape",
|
|
534
|
+
type="enum",
|
|
535
|
+
default="linear",
|
|
536
|
+
enum=[
|
|
537
|
+
"linear",
|
|
538
|
+
"s_mild",
|
|
539
|
+
"s_med",
|
|
540
|
+
"s_strong",
|
|
541
|
+
"lift_shadows",
|
|
542
|
+
"crush_shadows",
|
|
543
|
+
"fade_blacks",
|
|
544
|
+
"rolloff_highlights",
|
|
545
|
+
"flatten",
|
|
546
|
+
"custom",
|
|
547
|
+
],
|
|
548
|
+
help=(
|
|
549
|
+
"Built-in curve shape. "
|
|
550
|
+
"If 'custom', provide points_norm (or points_scene/handles)."
|
|
551
|
+
),
|
|
552
|
+
),
|
|
553
|
+
PresetSpec(
|
|
554
|
+
key="amount",
|
|
555
|
+
type="float",
|
|
556
|
+
default=0.5,
|
|
557
|
+
min=0.0,
|
|
558
|
+
max=1.0,
|
|
559
|
+
help=(
|
|
560
|
+
"Intensity for built-in shapes (0..1). "
|
|
561
|
+
"Ignored when shape='custom'."
|
|
562
|
+
),
|
|
563
|
+
),
|
|
564
|
+
PresetSpec(
|
|
565
|
+
key="points_norm",
|
|
566
|
+
type="dict",
|
|
567
|
+
default=None,
|
|
568
|
+
optional=True,
|
|
569
|
+
help=(
|
|
570
|
+
"For shape='custom': normalized control points "
|
|
571
|
+
"as [[x,y], ...] with x,y in [0..1]. "
|
|
572
|
+
"Example: [[0,0],[0.25,0.2],[0.5,0.5],[0.75,0.85],[1,1]]."
|
|
573
|
+
),
|
|
574
|
+
),
|
|
575
|
+
PresetSpec(
|
|
576
|
+
key="points_scene",
|
|
577
|
+
type="dict",
|
|
578
|
+
default=None,
|
|
579
|
+
optional=True,
|
|
580
|
+
help=(
|
|
581
|
+
"Advanced custom curve in scene coords [[x,y],...], "
|
|
582
|
+
"x,y in [0..360]. Synonyms accepted by engine: "
|
|
583
|
+
"scene_points, handles, control_points."
|
|
584
|
+
),
|
|
585
|
+
),
|
|
586
|
+
],
|
|
587
|
+
supports_mono=True,
|
|
588
|
+
supports_rgb=True,
|
|
589
|
+
supports_linear=True,
|
|
590
|
+
supports_nonlinear=True,
|
|
591
|
+
))
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
# ---------------- Gradient / background ----------------
|
|
595
|
+
|
|
596
|
+
register(CommandSpec(
|
|
597
|
+
id="abe",
|
|
598
|
+
title="Automatic Background Extraction",
|
|
599
|
+
group="Background",
|
|
600
|
+
import_path="pro.abe_preset",
|
|
601
|
+
callable_name="apply_abe_via_preset",
|
|
602
|
+
ui_method="open_abe_with_preset", # ✅ matches your pro/abe_preset.py
|
|
603
|
+
summary=(
|
|
604
|
+
"Automatic Background Extraction (headless). "
|
|
605
|
+
"Runs abe_run() with polynomial degree + RBF option. "
|
|
606
|
+
"Headless mode does NOT support exclusion polygons (exclusion_mask=None). "
|
|
607
|
+
"If an active mask is present, blends result as m*out + (1-m)*src. "
|
|
608
|
+
"Optional: create a separate background document."
|
|
609
|
+
),
|
|
610
|
+
presets=[
|
|
611
|
+
PresetSpec(
|
|
612
|
+
key="degree",
|
|
613
|
+
type="int",
|
|
614
|
+
default=2,
|
|
615
|
+
min=0, max=6,
|
|
616
|
+
help=(
|
|
617
|
+
"Polynomial degree for background model. "
|
|
618
|
+
"0 = RBF-only (allowed in headless). "
|
|
619
|
+
"Dialog range is 0–6."
|
|
620
|
+
),
|
|
621
|
+
),
|
|
622
|
+
PresetSpec(
|
|
623
|
+
key="samples",
|
|
624
|
+
type="int",
|
|
625
|
+
default=120,
|
|
626
|
+
min=20, max=100000,
|
|
627
|
+
help="Number of sample points used for background fitting.",
|
|
628
|
+
),
|
|
629
|
+
PresetSpec(
|
|
630
|
+
key="downsample",
|
|
631
|
+
type="int",
|
|
632
|
+
default=6,
|
|
633
|
+
min=1, max=64,
|
|
634
|
+
help="Downsample factor for analysis grid (higher = faster, coarser).",
|
|
635
|
+
),
|
|
636
|
+
PresetSpec(
|
|
637
|
+
key="patch",
|
|
638
|
+
type="int",
|
|
639
|
+
default=15,
|
|
640
|
+
min=5, max=151,
|
|
641
|
+
help="Patch size (px) for local background sampling.",
|
|
642
|
+
),
|
|
643
|
+
PresetSpec(
|
|
644
|
+
key="rbf",
|
|
645
|
+
type="bool",
|
|
646
|
+
default=True,
|
|
647
|
+
help="If True, include RBF smoothing component in the model.",
|
|
648
|
+
),
|
|
649
|
+
PresetSpec(
|
|
650
|
+
key="rbf_smooth",
|
|
651
|
+
type="float",
|
|
652
|
+
default=1.0,
|
|
653
|
+
min=0.0, max=1000.0,
|
|
654
|
+
help=(
|
|
655
|
+
"RBF smoothness. Dialog stores rbf_smooth*100, "
|
|
656
|
+
"so 1.0 here corresponds to slider=100."
|
|
657
|
+
),
|
|
658
|
+
),
|
|
659
|
+
PresetSpec(
|
|
660
|
+
key="make_background_doc",
|
|
661
|
+
type="bool",
|
|
662
|
+
default=False,
|
|
663
|
+
help="If True, also open a background-only document.",
|
|
664
|
+
),
|
|
665
|
+
],
|
|
666
|
+
aliases=[
|
|
667
|
+
"automatic_background_extraction",
|
|
668
|
+
"background_extraction",
|
|
669
|
+
],
|
|
670
|
+
examples=[
|
|
671
|
+
"ctx.run_command('abe', {'degree': 2, 'samples': 120, 'downsample': 6, 'patch': 15})",
|
|
672
|
+
"ctx.run_command('abe', {'degree': 0, 'rbf': True, 'rbf_smooth': 0.8})",
|
|
673
|
+
"ctx.run_command('abe', {'degree': 3, 'samples': 250, 'make_background_doc': True})",
|
|
674
|
+
],
|
|
675
|
+
supports_mono=True,
|
|
676
|
+
supports_rgb=True,
|
|
677
|
+
supports_linear=True,
|
|
678
|
+
supports_nonlinear=True,
|
|
679
|
+
))
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
register(CommandSpec(
|
|
683
|
+
id="graxpert",
|
|
684
|
+
title="GraXpert Gradient / Denoise",
|
|
685
|
+
group="Background",
|
|
686
|
+
import_path="pro.graxpert_preset",
|
|
687
|
+
callable_name="run_graxpert_via_preset",
|
|
688
|
+
# no ui_method here unless you want to open your optional preset dialog from drops
|
|
689
|
+
# ui_method="open_graxpert_with_preset", # (only if/when you add one)
|
|
690
|
+
summary=(
|
|
691
|
+
"GraXpert headless runner. "
|
|
692
|
+
"op='background' runs background-extraction with smoothing. "
|
|
693
|
+
"op='denoise' runs denoising with strength, optional ai_version, and batch_size. "
|
|
694
|
+
"Uses GPU by default, but honors preset['gpu'] or saved QSettings graxpert/use_gpu. "
|
|
695
|
+
"Writes temporary float32 TIFF and runs GraXpert CLI like SASv2."
|
|
696
|
+
),
|
|
697
|
+
presets=[
|
|
698
|
+
PresetSpec(
|
|
699
|
+
key="op",
|
|
700
|
+
type="enum",
|
|
701
|
+
default="background",
|
|
702
|
+
enum=["background", "denoise"],
|
|
703
|
+
help=(
|
|
704
|
+
"Operation mode. "
|
|
705
|
+
"'background' = gradient removal (background-extraction). "
|
|
706
|
+
"'denoise' = GraXpert denoising."
|
|
707
|
+
),
|
|
708
|
+
),
|
|
709
|
+
|
|
710
|
+
# --- background mode ---
|
|
711
|
+
PresetSpec(
|
|
712
|
+
key="smoothing",
|
|
713
|
+
type="float",
|
|
714
|
+
default=0.10,
|
|
715
|
+
min=0.0,
|
|
716
|
+
max=1.0,
|
|
717
|
+
optional=True,
|
|
718
|
+
help=(
|
|
719
|
+
"Background mode only: smoothing value (0..1). "
|
|
720
|
+
"Ignored when op='denoise'."
|
|
721
|
+
),
|
|
722
|
+
),
|
|
723
|
+
|
|
724
|
+
# --- denoise mode ---
|
|
725
|
+
PresetSpec(
|
|
726
|
+
key="strength",
|
|
727
|
+
type="float",
|
|
728
|
+
default=0.50,
|
|
729
|
+
min=0.0,
|
|
730
|
+
max=1.0,
|
|
731
|
+
optional=True,
|
|
732
|
+
help=(
|
|
733
|
+
"Denoise mode only: denoise strength (0..1). "
|
|
734
|
+
"Ignored when op='background'."
|
|
735
|
+
),
|
|
736
|
+
),
|
|
737
|
+
PresetSpec(
|
|
738
|
+
key="ai_version",
|
|
739
|
+
type="str",
|
|
740
|
+
default="",
|
|
741
|
+
optional=True,
|
|
742
|
+
help=(
|
|
743
|
+
"Denoise mode only: explicit GraXpert AI model version "
|
|
744
|
+
"(e.g. '3.0.2'). Blank/omitted uses latest/auto."
|
|
745
|
+
),
|
|
746
|
+
),
|
|
747
|
+
PresetSpec(
|
|
748
|
+
key="batch_size",
|
|
749
|
+
type="int",
|
|
750
|
+
default=None,
|
|
751
|
+
min=1,
|
|
752
|
+
max=64,
|
|
753
|
+
optional=True,
|
|
754
|
+
help=(
|
|
755
|
+
"Denoise mode only: CLI batch size. "
|
|
756
|
+
"If omitted, runner uses 4 when gpu=True else 1."
|
|
757
|
+
),
|
|
758
|
+
),
|
|
759
|
+
|
|
760
|
+
# --- shared ---
|
|
761
|
+
PresetSpec(
|
|
762
|
+
key="gpu",
|
|
763
|
+
type="bool",
|
|
764
|
+
default=True,
|
|
765
|
+
optional=True,
|
|
766
|
+
help=(
|
|
767
|
+
"Use GPU if available. "
|
|
768
|
+
"If omitted, defaults from QSettings 'graxpert/use_gpu' "
|
|
769
|
+
"(falls back to True)."
|
|
770
|
+
),
|
|
771
|
+
),
|
|
772
|
+
|
|
773
|
+
# --- advanced / power-user ---
|
|
774
|
+
PresetSpec(
|
|
775
|
+
key="exe",
|
|
776
|
+
type="str",
|
|
777
|
+
default="",
|
|
778
|
+
optional=True,
|
|
779
|
+
help=(
|
|
780
|
+
"Optional explicit path to GraXpert executable. "
|
|
781
|
+
"If omitted, _resolve_graxpert_exec() is used."
|
|
782
|
+
),
|
|
783
|
+
),
|
|
784
|
+
],
|
|
785
|
+
aliases=[
|
|
786
|
+
"grax",
|
|
787
|
+
"remove_gradient_graxpert",
|
|
788
|
+
"graxpert_denoise",
|
|
789
|
+
"graxpert_background",
|
|
790
|
+
],
|
|
791
|
+
examples=[
|
|
792
|
+
# gradient removal
|
|
793
|
+
"ctx.run_command('graxpert', {'op': 'background', 'smoothing': 0.12})",
|
|
794
|
+
# denoise auto-model, GPU
|
|
795
|
+
"ctx.run_command('graxpert', {'op': 'denoise', 'strength': 0.45, 'gpu': True})",
|
|
796
|
+
# denoise specific model, CPU, explicit batch size
|
|
797
|
+
"ctx.run_command('graxpert', {'op': 'denoise', 'strength': 0.6, 'ai_version': '3.0.2', 'gpu': False, 'batch_size': 1})",
|
|
798
|
+
],
|
|
799
|
+
supports_mono=True,
|
|
800
|
+
supports_rgb=True,
|
|
801
|
+
supports_linear=True,
|
|
802
|
+
supports_nonlinear=True,
|
|
803
|
+
))
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
register(CommandSpec(
|
|
807
|
+
id="background_neutral",
|
|
808
|
+
name="Background Neutralization",
|
|
809
|
+
group="Background",
|
|
810
|
+
import_path="pro.backgroundneutral",
|
|
811
|
+
callable_name="run_background_neutral_via_preset",
|
|
812
|
+
summary=(
|
|
813
|
+
"Neutralizes RGB background either automatically or using a user-specified "
|
|
814
|
+
"normalized rectangle. Headless mode blends with active destination mask "
|
|
815
|
+
"before committing."
|
|
816
|
+
),
|
|
817
|
+
presets=[
|
|
818
|
+
PresetSpec(
|
|
819
|
+
key="mode",
|
|
820
|
+
type="enum",
|
|
821
|
+
default="auto",
|
|
822
|
+
enum=["auto", "rect"],
|
|
823
|
+
help=(
|
|
824
|
+
"Neutralization mode. "
|
|
825
|
+
"'auto' picks an automatic 50x50-ish dark background rect. "
|
|
826
|
+
"'rect' uses rect_norm=[x,y,w,h] in normalized 0..1 coords."
|
|
827
|
+
),
|
|
828
|
+
optional=True,
|
|
829
|
+
),
|
|
830
|
+
PresetSpec(
|
|
831
|
+
key="rect_norm",
|
|
832
|
+
type="dict",
|
|
833
|
+
default=None,
|
|
834
|
+
optional=True,
|
|
835
|
+
help=(
|
|
836
|
+
"Required only if mode='rect'. "
|
|
837
|
+
"Normalized rectangle [x0, y0, w, h], each in 0..1. "
|
|
838
|
+
"Example: [0.10, 0.12, 0.20, 0.18]."
|
|
839
|
+
),
|
|
840
|
+
),
|
|
841
|
+
],
|
|
842
|
+
aliases=[
|
|
843
|
+
"background_neutralization",
|
|
844
|
+
"neutralize_background",
|
|
845
|
+
"bn",
|
|
846
|
+
],
|
|
847
|
+
examples=[
|
|
848
|
+
# auto (default)
|
|
849
|
+
"ctx.run_command('background_neutral', {'mode': 'auto'})",
|
|
850
|
+
# rect mode with normalized ROI
|
|
851
|
+
"ctx.run_command('background_neutral', {'mode': 'rect', 'rect_norm': [0.1, 0.1, 0.2, 0.2]})",
|
|
852
|
+
# mode omitted -> auto
|
|
853
|
+
"ctx.run_command('background_neutral', {})",
|
|
854
|
+
],
|
|
855
|
+
supports_mono=False, # your headless code raises on non-RGB
|
|
856
|
+
supports_rgb=True,
|
|
857
|
+
supports_linear=True,
|
|
858
|
+
supports_nonlinear=True,
|
|
859
|
+
))
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
# ---------------- Color / WB ----------------
|
|
863
|
+
|
|
864
|
+
register(CommandSpec(
|
|
865
|
+
id="remove_green",
|
|
866
|
+
name="Remove Green (SCNR)",
|
|
867
|
+
group="Color",
|
|
868
|
+
import_path="pro.remove_green",
|
|
869
|
+
callable_name="apply_remove_green_preset_to_doc",
|
|
870
|
+
ui_method="open_remove_green_dialog",
|
|
871
|
+
summary=(
|
|
872
|
+
"Suppresses excess green using an SCNR-style operation. "
|
|
873
|
+
"Neutral comparator is derived from R/B using avg/max/min. "
|
|
874
|
+
"Optionally preserves perceived lightness (Rec.709 luma) "
|
|
875
|
+
"and blends with the active destination mask."
|
|
876
|
+
),
|
|
877
|
+
presets=[
|
|
878
|
+
PresetSpec(
|
|
879
|
+
key="amount",
|
|
880
|
+
type="float",
|
|
881
|
+
default=1.0,
|
|
882
|
+
min=0.0,
|
|
883
|
+
max=1.0,
|
|
884
|
+
desc=(
|
|
885
|
+
"Strength of green suppression (0..1). "
|
|
886
|
+
"Aliases accepted: strength, value."
|
|
887
|
+
),
|
|
888
|
+
),
|
|
889
|
+
PresetSpec(
|
|
890
|
+
key="mode",
|
|
891
|
+
type="enum",
|
|
892
|
+
default="avg",
|
|
893
|
+
enum=["avg", "max", "min"],
|
|
894
|
+
desc=(
|
|
895
|
+
"Neutral mode for comparing green against R/B: "
|
|
896
|
+
"avg = Average(R,B), max = Max(R,B), min = Min(R,B). "
|
|
897
|
+
"Unknown values fall back to 'avg'."
|
|
898
|
+
),
|
|
899
|
+
),
|
|
900
|
+
PresetSpec(
|
|
901
|
+
key="preserve_lightness",
|
|
902
|
+
type="bool",
|
|
903
|
+
default=True,
|
|
904
|
+
desc=(
|
|
905
|
+
"If True, rescales all channels to preserve perceived "
|
|
906
|
+
"lightness after green suppression (Rec.709 luma), "
|
|
907
|
+
"with highlight safety."
|
|
908
|
+
),
|
|
909
|
+
),
|
|
910
|
+
],
|
|
911
|
+
aliases=[
|
|
912
|
+
"scnr",
|
|
913
|
+
"remove_green_cast",
|
|
914
|
+
"green_neutralize",
|
|
915
|
+
],
|
|
916
|
+
examples=[
|
|
917
|
+
"ctx.run_command('remove_green', {'amount': 1.0, 'mode': 'avg'})",
|
|
918
|
+
"ctx.run_command('remove_green', {'amount': 0.7, 'mode': 'max'})",
|
|
919
|
+
"ctx.run_command('remove_green', {'strength': 0.5, 'mode': 'min', 'preserve_lightness': False})",
|
|
920
|
+
],
|
|
921
|
+
supports_mono=False, # _ensure_rgb returns None on mono; headless becomes no-op
|
|
922
|
+
supports_rgb=True,
|
|
923
|
+
supports_linear=True,
|
|
924
|
+
supports_nonlinear=True,
|
|
925
|
+
))
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
register(CommandSpec(
|
|
929
|
+
id="white_balance",
|
|
930
|
+
name="White Balance",
|
|
931
|
+
group="Color",
|
|
932
|
+
headless_method="_apply_white_balance_preset_to_doc",
|
|
933
|
+
summary=(
|
|
934
|
+
"White balance for RGB images. Modes: "
|
|
935
|
+
"star (SEP-based), auto (grid/brightest region), manual (per-channel gains). "
|
|
936
|
+
"Star mode falls back to Auto if detection fails."
|
|
937
|
+
),
|
|
938
|
+
presets=[
|
|
939
|
+
PresetSpec(
|
|
940
|
+
key="mode",
|
|
941
|
+
type="enum",
|
|
942
|
+
default="star",
|
|
943
|
+
enum=["star", "auto", "manual"],
|
|
944
|
+
desc=(
|
|
945
|
+
"White balance mode. "
|
|
946
|
+
"'star' uses SEP star colors; "
|
|
947
|
+
"'auto' uses headless auto WB; "
|
|
948
|
+
"'manual' uses r/g/b gains."
|
|
949
|
+
),
|
|
950
|
+
),
|
|
951
|
+
PresetSpec(
|
|
952
|
+
key="threshold",
|
|
953
|
+
type="float",
|
|
954
|
+
default=50.0,
|
|
955
|
+
min=1.0,
|
|
956
|
+
max=100.0,
|
|
957
|
+
optional=True,
|
|
958
|
+
desc=(
|
|
959
|
+
"SEP star threshold (sigma) for star mode. "
|
|
960
|
+
"Higher = fewer/brighter stars."
|
|
961
|
+
),
|
|
962
|
+
),
|
|
963
|
+
PresetSpec(
|
|
964
|
+
key="reuse_cached_sources",
|
|
965
|
+
type="bool",
|
|
966
|
+
default=True,
|
|
967
|
+
optional=True,
|
|
968
|
+
desc=(
|
|
969
|
+
"Reuse cached SEP detections for speed (star mode)."
|
|
970
|
+
),
|
|
971
|
+
),
|
|
972
|
+
PresetSpec(
|
|
973
|
+
key="r_gain",
|
|
974
|
+
type="float",
|
|
975
|
+
default=1.0,
|
|
976
|
+
min=0.5,
|
|
977
|
+
max=2.0,
|
|
978
|
+
optional=True,
|
|
979
|
+
desc="Manual red gain (manual mode).",
|
|
980
|
+
),
|
|
981
|
+
PresetSpec(
|
|
982
|
+
key="g_gain",
|
|
983
|
+
type="float",
|
|
984
|
+
default=1.0,
|
|
985
|
+
min=0.5,
|
|
986
|
+
max=2.0,
|
|
987
|
+
optional=True,
|
|
988
|
+
desc="Manual green gain (manual mode).",
|
|
989
|
+
),
|
|
990
|
+
PresetSpec(
|
|
991
|
+
key="b_gain",
|
|
992
|
+
type="float",
|
|
993
|
+
default=1.0,
|
|
994
|
+
min=0.5,
|
|
995
|
+
max=2.0,
|
|
996
|
+
optional=True,
|
|
997
|
+
desc="Manual blue gain (manual mode).",
|
|
998
|
+
),
|
|
999
|
+
],
|
|
1000
|
+
examples=[
|
|
1001
|
+
"ctx.run_command('white_balance', {'mode': 'star', 'threshold': 45})",
|
|
1002
|
+
"ctx.run_command('white_balance', {'mode': 'auto'})",
|
|
1003
|
+
"ctx.run_command('white_balance', {'mode': 'manual', 'r_gain': 1.12, 'g_gain': 1.0, 'b_gain': 0.94})",
|
|
1004
|
+
],
|
|
1005
|
+
supports_mono=False,
|
|
1006
|
+
supports_rgb=True,
|
|
1007
|
+
supports_linear=True,
|
|
1008
|
+
supports_nonlinear=True,
|
|
1009
|
+
))
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
# ---------------- Luminance tools ----------------
|
|
1013
|
+
|
|
1014
|
+
register(CommandSpec(
|
|
1015
|
+
id="extract_luminance",
|
|
1016
|
+
name="Extract Luminance",
|
|
1017
|
+
group="Luminance",
|
|
1018
|
+
ui_method="_extract_luminance", # now accepts preset optionally
|
|
1019
|
+
headless_method="_apply_extract_luminance_preset_to_doc",
|
|
1020
|
+
summary=(
|
|
1021
|
+
"Create a new mono luminance document from RGB using selectable methods "
|
|
1022
|
+
"(Rec.709/601/2020, max, median, equal, or SNR-weighted)."
|
|
1023
|
+
),
|
|
1024
|
+
presets=[
|
|
1025
|
+
PresetSpec(
|
|
1026
|
+
key="mode",
|
|
1027
|
+
type="enum",
|
|
1028
|
+
default="rec709",
|
|
1029
|
+
enum=["rec709", "rec601", "rec2020", "max", "snr", "equal", "median"],
|
|
1030
|
+
desc=(
|
|
1031
|
+
"Luminance extraction method. "
|
|
1032
|
+
"Aliases accepted: method, luma_method, nb_max→max, snr_unequal→snr."
|
|
1033
|
+
),
|
|
1034
|
+
),
|
|
1035
|
+
],
|
|
1036
|
+
supports_mono=False,
|
|
1037
|
+
supports_rgb=True,
|
|
1038
|
+
supports_linear=True,
|
|
1039
|
+
supports_nonlinear=True,
|
|
1040
|
+
))
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
register(CommandSpec(
|
|
1044
|
+
id="recombine_luminance",
|
|
1045
|
+
name="Recombine Luminance",
|
|
1046
|
+
group="Luminance",
|
|
1047
|
+
import_path="pro.luminancerecombine",
|
|
1048
|
+
callable_name="run_recombine_luminance_via_preset",
|
|
1049
|
+
ui_method="_recombine_luminance_ui",
|
|
1050
|
+
notes=(
|
|
1051
|
+
"Replaces target RGB luminance using another open view (mono or RGB). "
|
|
1052
|
+
"Headless preset may specify the luminance source by title or doc_ptr. "
|
|
1053
|
+
"If omitted, first eligible non-target open doc is used."
|
|
1054
|
+
),
|
|
1055
|
+
presets=[
|
|
1056
|
+
# ---- luminance source selection ----
|
|
1057
|
+
PresetSpec(
|
|
1058
|
+
key="source_title",
|
|
1059
|
+
type="str",
|
|
1060
|
+
default=None,
|
|
1061
|
+
optional=True,
|
|
1062
|
+
desc=(
|
|
1063
|
+
"Title/name of the open document to use as luminance source. "
|
|
1064
|
+
"Matches subwindow title or doc.display_name()."
|
|
1065
|
+
),
|
|
1066
|
+
),
|
|
1067
|
+
PresetSpec(
|
|
1068
|
+
key="source_doc_ptr",
|
|
1069
|
+
type="int",
|
|
1070
|
+
default=None,
|
|
1071
|
+
optional=True,
|
|
1072
|
+
desc=(
|
|
1073
|
+
"Doc identity pointer (id(doc)) for luminance source. "
|
|
1074
|
+
"Useful for replay or scripts that stored doc_ptr."
|
|
1075
|
+
),
|
|
1076
|
+
),
|
|
1077
|
+
|
|
1078
|
+
# ---- luminance compute method ----
|
|
1079
|
+
PresetSpec(
|
|
1080
|
+
key="method",
|
|
1081
|
+
type="enum",
|
|
1082
|
+
default="rec709",
|
|
1083
|
+
enum=["rec709", "rec601", "rec2020", "max", "snr", "equal", "median"],
|
|
1084
|
+
desc=(
|
|
1085
|
+
"How to compute luminance if the source is RGB. "
|
|
1086
|
+
"rec709/601/2020 use standard weights; "
|
|
1087
|
+
"max uses channel max (narrowband style); "
|
|
1088
|
+
"snr uses noise-weighted mean; "
|
|
1089
|
+
"equal is average RGB; "
|
|
1090
|
+
"median is per-pixel median."
|
|
1091
|
+
),
|
|
1092
|
+
),
|
|
1093
|
+
|
|
1094
|
+
# ---- optional explicit weights ----
|
|
1095
|
+
PresetSpec(
|
|
1096
|
+
key="weights",
|
|
1097
|
+
type="dict",
|
|
1098
|
+
default=None,
|
|
1099
|
+
optional=True,
|
|
1100
|
+
desc=(
|
|
1101
|
+
"Optional custom RGB weights as [wr,wg,wb]. "
|
|
1102
|
+
"Overrides method weights when provided."
|
|
1103
|
+
),
|
|
1104
|
+
),
|
|
1105
|
+
|
|
1106
|
+
# ---- blend / protection ----
|
|
1107
|
+
PresetSpec(
|
|
1108
|
+
key="blend",
|
|
1109
|
+
type="float",
|
|
1110
|
+
default=1.0,
|
|
1111
|
+
min=0.0, max=1.0,
|
|
1112
|
+
desc="Blend factor. 1.0 = full replace, 0.0 = no change.",
|
|
1113
|
+
),
|
|
1114
|
+
PresetSpec(
|
|
1115
|
+
key="soft_knee",
|
|
1116
|
+
type="float",
|
|
1117
|
+
default=0.0,
|
|
1118
|
+
min=0.0, max=1.0,
|
|
1119
|
+
desc=(
|
|
1120
|
+
"Highlight protection strength. "
|
|
1121
|
+
"0 = off, higher compresses extreme up-scaling."
|
|
1122
|
+
),
|
|
1123
|
+
),
|
|
1124
|
+
],
|
|
1125
|
+
examples=[
|
|
1126
|
+
# simplest: auto-pick first eligible luminance view
|
|
1127
|
+
"ctx.run_command('recombine_luminance', {'method': 'rec709'})",
|
|
1128
|
+
# specify a source by title
|
|
1129
|
+
"ctx.run_command('recombine_luminance', {'source_title':'M33 — Luminance', 'method':'rec709'})",
|
|
1130
|
+
# narrowband / max-style source
|
|
1131
|
+
"ctx.run_command('recombine_luminance', {'source_title':'NB Stars', 'method':'max', 'blend':1.0})",
|
|
1132
|
+
# custom weights + mild highlight protection
|
|
1133
|
+
"ctx.run_command('recombine_luminance', {'weights':[0.2,0.7,0.1], 'soft_knee':0.15})",
|
|
1134
|
+
],
|
|
1135
|
+
supports_mono=False,
|
|
1136
|
+
supports_rgb=True,
|
|
1137
|
+
supports_linear=True,
|
|
1138
|
+
supports_nonlinear=True,
|
|
1139
|
+
))
|
|
1140
|
+
|
|
1141
|
+
# ---------------- WaveScale family ----------------
|
|
1142
|
+
|
|
1143
|
+
register(CommandSpec(
|
|
1144
|
+
id="wavescale_hdr",
|
|
1145
|
+
name="WaveScale HDR",
|
|
1146
|
+
group="Contrast",
|
|
1147
|
+
import_path="pro.wavescale_hdr_preset",
|
|
1148
|
+
callable_name="run_wavescale_hdr_via_preset",
|
|
1149
|
+
ui_method="_open_wavescale_hdr", # or whatever your main window uses
|
|
1150
|
+
summary=(
|
|
1151
|
+
"Wavelet-based HDR compression. Builds a luminance mask and compresses "
|
|
1152
|
+
"coarse scales to recover dynamic range. Mask gamma controls protection."
|
|
1153
|
+
),
|
|
1154
|
+
presets=[
|
|
1155
|
+
PresetSpec(
|
|
1156
|
+
key="n_scales",
|
|
1157
|
+
type="int",
|
|
1158
|
+
default=5,
|
|
1159
|
+
min=2, max=10,
|
|
1160
|
+
desc="Number of wavelet scales. Typical 4–6."
|
|
1161
|
+
),
|
|
1162
|
+
PresetSpec(
|
|
1163
|
+
key="compression_factor",
|
|
1164
|
+
type="float",
|
|
1165
|
+
default=1.5,
|
|
1166
|
+
min=0.10, max=5.00,
|
|
1167
|
+
desc="Coarse-scale compression strength. Higher = more HDR."
|
|
1168
|
+
),
|
|
1169
|
+
PresetSpec(
|
|
1170
|
+
key="mask_gamma",
|
|
1171
|
+
type="float",
|
|
1172
|
+
default=5.0,
|
|
1173
|
+
min=0.10, max=10.00,
|
|
1174
|
+
desc="Gamma shaping for the luminance protection mask."
|
|
1175
|
+
),
|
|
1176
|
+
],
|
|
1177
|
+
examples=[
|
|
1178
|
+
"ctx.run_command('wavescale_hdr', {'n_scales': 5, 'compression_factor': 1.5, 'mask_gamma': 5.0})",
|
|
1179
|
+
"ctx.run_command('wavescale_hdr', {'n_scales': 4, 'compression_factor': 2.2})",
|
|
1180
|
+
],
|
|
1181
|
+
supports_mono=True,
|
|
1182
|
+
supports_rgb=True,
|
|
1183
|
+
supports_linear=True,
|
|
1184
|
+
supports_nonlinear=True,
|
|
1185
|
+
))
|
|
1186
|
+
|
|
1187
|
+
register(CommandSpec(
|
|
1188
|
+
id="wavescale_dark_enhance",
|
|
1189
|
+
name="WaveScale Dark Enhance",
|
|
1190
|
+
group="Contrast",
|
|
1191
|
+
import_path="pro.wavescalede_preset",
|
|
1192
|
+
callable_name="run_wavescalede_via_preset",
|
|
1193
|
+
ui_method="_open_wavescale_dark_enhance", # adjust if your main window uses a different name
|
|
1194
|
+
summary=(
|
|
1195
|
+
"Wavelet-based enhancement of dark / low-contrast structures. "
|
|
1196
|
+
"Builds a luminance mask, boosts dark-scale content, and optionally iterates."
|
|
1197
|
+
),
|
|
1198
|
+
presets=[
|
|
1199
|
+
PresetSpec(
|
|
1200
|
+
key="n_scales",
|
|
1201
|
+
type="int",
|
|
1202
|
+
default=6,
|
|
1203
|
+
min=2, max=10,
|
|
1204
|
+
desc="Number of wavelet scales. Typical 5–7."
|
|
1205
|
+
),
|
|
1206
|
+
PresetSpec(
|
|
1207
|
+
key="boost_factor",
|
|
1208
|
+
type="float",
|
|
1209
|
+
default=5.0,
|
|
1210
|
+
min=0.1, max=10.0, # ✅ match preset dialog
|
|
1211
|
+
desc="Boost factor for dark structures."
|
|
1212
|
+
),
|
|
1213
|
+
PresetSpec(
|
|
1214
|
+
key="mask_gamma",
|
|
1215
|
+
type="float",
|
|
1216
|
+
default=1.0,
|
|
1217
|
+
min=0.1, max=10.0,
|
|
1218
|
+
desc="Gamma shaping for the protection mask."
|
|
1219
|
+
),
|
|
1220
|
+
PresetSpec(
|
|
1221
|
+
key="iterations",
|
|
1222
|
+
type="int",
|
|
1223
|
+
default=2,
|
|
1224
|
+
min=1, max=10,
|
|
1225
|
+
desc="Extra enhancement passes."
|
|
1226
|
+
),
|
|
1227
|
+
],
|
|
1228
|
+
examples=[
|
|
1229
|
+
"ctx.run_command('wavescale_dark_enhance', {'n_scales': 6, 'boost_factor': 5.0})",
|
|
1230
|
+
"ctx.run_command('wavescale_dark_enhance', {'n_scales': 7, 'boost_factor': 6.5, 'mask_gamma': 1.3, 'iterations': 3})",
|
|
1231
|
+
],
|
|
1232
|
+
supports_mono=True,
|
|
1233
|
+
supports_rgb=True,
|
|
1234
|
+
supports_linear=True,
|
|
1235
|
+
supports_nonlinear=True,
|
|
1236
|
+
))
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
# ---------------- Geometry (headless) ----------------
|
|
1240
|
+
|
|
1241
|
+
register(CommandSpec(
|
|
1242
|
+
id="geom_invert",
|
|
1243
|
+
title="Invert",
|
|
1244
|
+
group="Geometry",
|
|
1245
|
+
headless_method="_apply_geom_invert_to_doc",
|
|
1246
|
+
))
|
|
1247
|
+
|
|
1248
|
+
register(CommandSpec(
|
|
1249
|
+
id="geom_flip_horizontal",
|
|
1250
|
+
title="Flip Horizontal",
|
|
1251
|
+
group="Geometry",
|
|
1252
|
+
headless_method="_apply_geom_flip_h_to_doc",
|
|
1253
|
+
))
|
|
1254
|
+
|
|
1255
|
+
register(CommandSpec(
|
|
1256
|
+
id="geom_flip_vertical",
|
|
1257
|
+
title="Flip Vertical",
|
|
1258
|
+
group="Geometry",
|
|
1259
|
+
headless_method="_apply_geom_flip_v_to_doc",
|
|
1260
|
+
))
|
|
1261
|
+
|
|
1262
|
+
register(CommandSpec(
|
|
1263
|
+
id="geom_rotate_clockwise",
|
|
1264
|
+
title="Rotate 90° CW",
|
|
1265
|
+
group="Geometry",
|
|
1266
|
+
headless_method="_apply_geom_rot_cw_to_doc",
|
|
1267
|
+
))
|
|
1268
|
+
|
|
1269
|
+
register(CommandSpec(
|
|
1270
|
+
id="geom_rotate_counterclockwise",
|
|
1271
|
+
title="Rotate 90° CCW",
|
|
1272
|
+
group="Geometry",
|
|
1273
|
+
headless_method="_apply_geom_rot_ccw_to_doc",
|
|
1274
|
+
))
|
|
1275
|
+
|
|
1276
|
+
register(CommandSpec(
|
|
1277
|
+
id="geom_rotate_180",
|
|
1278
|
+
title="Rotate 180°",
|
|
1279
|
+
group="Geometry",
|
|
1280
|
+
headless_method="_apply_geom_rot_180_to_doc",
|
|
1281
|
+
))
|
|
1282
|
+
|
|
1283
|
+
register(CommandSpec(
|
|
1284
|
+
id="geom_rescale",
|
|
1285
|
+
title="Rescale",
|
|
1286
|
+
group="Geometry",
|
|
1287
|
+
headless_method="_apply_geom_rescale_preset_to_doc",
|
|
1288
|
+
presets=[
|
|
1289
|
+
PresetSpec("factor", "float", default=1.0, min=0.05, max=20.0,
|
|
1290
|
+
desc="Scale multiplier."),
|
|
1291
|
+
],
|
|
1292
|
+
))
|
|
1293
|
+
|
|
1294
|
+
register(CommandSpec(
|
|
1295
|
+
id="aberration_ai",
|
|
1296
|
+
title="Aberration AI",
|
|
1297
|
+
group="Optics",
|
|
1298
|
+
import_path="pro.aberration_ai_preset",
|
|
1299
|
+
callable_name="run_aberration_ai_via_preset",
|
|
1300
|
+
# ui_method="open_aberration_ai_dialog", # if you have one; otherwise omit
|
|
1301
|
+
presets=[
|
|
1302
|
+
PresetSpec(
|
|
1303
|
+
"model", "path", default="",
|
|
1304
|
+
desc="Path to .onnx model. If empty, uses QSettings('AberrationAI/model_path')."
|
|
1305
|
+
),
|
|
1306
|
+
PresetSpec(
|
|
1307
|
+
"patch", "int", default=512, min=128, max=2048,
|
|
1308
|
+
desc="Patch size for tiled inference. CoreML is clamped to 128."
|
|
1309
|
+
),
|
|
1310
|
+
PresetSpec(
|
|
1311
|
+
"overlap", "int", default=64, min=16, max=512,
|
|
1312
|
+
desc="Overlap between patches."
|
|
1313
|
+
),
|
|
1314
|
+
PresetSpec(
|
|
1315
|
+
"border_px", "int", default=10, min=0, max=64,
|
|
1316
|
+
desc="Border in pixels to preserve from the original."
|
|
1317
|
+
),
|
|
1318
|
+
PresetSpec(
|
|
1319
|
+
"auto_gpu", "bool", default=True,
|
|
1320
|
+
desc="Auto-pick best GPU provider if available (forced off on Apple Silicon)."
|
|
1321
|
+
),
|
|
1322
|
+
PresetSpec(
|
|
1323
|
+
"provider", "enum", default="CPUExecutionProvider",
|
|
1324
|
+
enum=[
|
|
1325
|
+
"CPUExecutionProvider",
|
|
1326
|
+
"DmlExecutionProvider",
|
|
1327
|
+
"CUDAExecutionProvider",
|
|
1328
|
+
"CoreMLExecutionProvider",
|
|
1329
|
+
],
|
|
1330
|
+
desc="Explicit provider when auto_gpu=False."
|
|
1331
|
+
),
|
|
1332
|
+
],
|
|
1333
|
+
supports_mono=True,
|
|
1334
|
+
supports_rgb=True,
|
|
1335
|
+
))
|
|
1336
|
+
|
|
1337
|
+
register(CommandSpec(
|
|
1338
|
+
id="convo",
|
|
1339
|
+
title="Convolution / Deconvolution",
|
|
1340
|
+
group="Blur & Sharpen",
|
|
1341
|
+
import_path="pro.convo_preset",
|
|
1342
|
+
callable_name="run_convo_via_preset",
|
|
1343
|
+
aliases=[
|
|
1344
|
+
"convolution",
|
|
1345
|
+
"deconvolution",
|
|
1346
|
+
"convo_deconvo", # keep backward compat
|
|
1347
|
+
],
|
|
1348
|
+
presets=[
|
|
1349
|
+
PresetSpec("op", "enum", default="convolution",
|
|
1350
|
+
enum=["convolution", "deconvolution", "tv"],
|
|
1351
|
+
desc="Operation type."),
|
|
1352
|
+
|
|
1353
|
+
# shared strength (used by all ops)
|
|
1354
|
+
PresetSpec("strength", "float", default=1.0, min=0.0, max=1.0,
|
|
1355
|
+
desc="Blend strength."),
|
|
1356
|
+
|
|
1357
|
+
# --- convolution ---
|
|
1358
|
+
PresetSpec("radius", "float", default=5.0, min=0.1, max=200.0,
|
|
1359
|
+
desc="Convolution PSF radius (px)."),
|
|
1360
|
+
PresetSpec("kurtosis", "float", default=2.0, min=0.1, max=10.0,
|
|
1361
|
+
desc="Convolution PSF kurtosis (σ)."),
|
|
1362
|
+
PresetSpec("aspect", "float", default=1.0, min=0.1, max=10.0,
|
|
1363
|
+
desc="Convolution PSF aspect ratio."),
|
|
1364
|
+
PresetSpec("rotation", "float", default=0.0, min=0.0, max=360.0,
|
|
1365
|
+
desc="Convolution PSF rotation (deg)."),
|
|
1366
|
+
|
|
1367
|
+
# --- deconvolution general ---
|
|
1368
|
+
PresetSpec("algo", "enum", default="Richardson-Lucy",
|
|
1369
|
+
enum=["Richardson-Lucy", "Wiener", "Larson-Sekanina", "Van Cittert"],
|
|
1370
|
+
desc="Deconvolution algorithm."),
|
|
1371
|
+
|
|
1372
|
+
# RL/Wiener PSF
|
|
1373
|
+
PresetSpec("psf_radius", "float", default=3.0, min=0.1, max=100.0,
|
|
1374
|
+
desc="Deconvolution PSF radius (px)."),
|
|
1375
|
+
PresetSpec("psf_kurtosis", "float", default=2.0, min=0.1, max=10.0,
|
|
1376
|
+
desc="Deconvolution PSF kurtosis (σ)."),
|
|
1377
|
+
PresetSpec("psf_aspect", "float", default=1.0, min=0.1, max=10.0,
|
|
1378
|
+
desc="Deconvolution PSF aspect ratio."),
|
|
1379
|
+
PresetSpec("psf_rotation", "float", default=0.0, min=0.0, max=360.0,
|
|
1380
|
+
desc="Deconvolution PSF rotation (deg)."),
|
|
1381
|
+
|
|
1382
|
+
# RL options
|
|
1383
|
+
PresetSpec("rl_iter", "int", default=30, min=1, max=200,
|
|
1384
|
+
desc="Richardson–Lucy iterations."),
|
|
1385
|
+
PresetSpec("rl_reg", "enum", default="None (Plain R–L)",
|
|
1386
|
+
enum=["None (Plain R–L)", "Tikhonov (L2)", "Total Variation (TV)"],
|
|
1387
|
+
desc="RL regularization."),
|
|
1388
|
+
PresetSpec("rl_dering", "bool", default=True,
|
|
1389
|
+
desc="RL de-ring bilateral pass."),
|
|
1390
|
+
PresetSpec("luminance_only", "bool", default=True,
|
|
1391
|
+
desc="Run RL/Wiener on L* only."),
|
|
1392
|
+
|
|
1393
|
+
# Wiener options
|
|
1394
|
+
PresetSpec("wiener_nsr", "float", default=0.01, min=0.0, max=1.0,
|
|
1395
|
+
desc="Wiener NSR."),
|
|
1396
|
+
PresetSpec("wiener_reg", "enum", default="None (Classical Wiener)",
|
|
1397
|
+
enum=["None (Classical Wiener)", "Tikhonov (L2)"],
|
|
1398
|
+
desc="Wiener regularization."),
|
|
1399
|
+
PresetSpec("wiener_dering", "bool", default=True,
|
|
1400
|
+
desc="Wiener de-ring pass."),
|
|
1401
|
+
|
|
1402
|
+
# Larson–Sekanina
|
|
1403
|
+
PresetSpec("ls_rstep", "float", default=0.0, min=0.0, max=50.0,
|
|
1404
|
+
desc="LS radial step (px)."),
|
|
1405
|
+
PresetSpec("ls_astep", "float", default=1.0, min=0.1, max=360.0,
|
|
1406
|
+
desc="LS angular step (deg)."),
|
|
1407
|
+
PresetSpec("ls_operator", "enum", default="Divide",
|
|
1408
|
+
enum=["Divide", "Subtract"],
|
|
1409
|
+
desc="LS operator."),
|
|
1410
|
+
PresetSpec("ls_blend", "enum", default="SoftLight",
|
|
1411
|
+
enum=["SoftLight", "Screen"],
|
|
1412
|
+
desc="LS blend mode."),
|
|
1413
|
+
|
|
1414
|
+
# Van Cittert
|
|
1415
|
+
PresetSpec("vc_iter", "int", default=10, min=1, max=1000,
|
|
1416
|
+
desc="Van Cittert iterations."),
|
|
1417
|
+
PresetSpec("vc_relax", "float", default=0.0, min=0.0, max=1.0,
|
|
1418
|
+
desc="Van Cittert relaxation."),
|
|
1419
|
+
|
|
1420
|
+
# --- TV ---
|
|
1421
|
+
PresetSpec("tv_weight", "float", default=0.10, min=0.0, max=1.0,
|
|
1422
|
+
desc="TV denoise weight."),
|
|
1423
|
+
PresetSpec("tv_iter", "int", default=10, min=1, max=100,
|
|
1424
|
+
desc="TV iterations."),
|
|
1425
|
+
PresetSpec("tv_multichannel", "bool", default=True,
|
|
1426
|
+
desc="TV multi-channel."),
|
|
1427
|
+
],
|
|
1428
|
+
supports_mono=True,
|
|
1429
|
+
supports_rgb=True,
|
|
1430
|
+
))
|
|
1431
|
+
|
|
1432
|
+
register(CommandSpec(
|
|
1433
|
+
id="cosmic_clarity",
|
|
1434
|
+
title="Cosmic Clarity",
|
|
1435
|
+
group="AI",
|
|
1436
|
+
import_path="pro.cosmicclarity_preset",
|
|
1437
|
+
callable_name="run_cosmicclarity_via_preset",
|
|
1438
|
+
presets=[
|
|
1439
|
+
PresetSpec("mode", "enum", default="sharpen",
|
|
1440
|
+
enum=["sharpen", "denoise", "both", "superres"],
|
|
1441
|
+
desc="Which CC pipeline to run."),
|
|
1442
|
+
|
|
1443
|
+
PresetSpec("gpu", "bool", default=True,
|
|
1444
|
+
desc="Use GPU acceleration when available."),
|
|
1445
|
+
|
|
1446
|
+
PresetSpec("create_new_view", "bool", default=False,
|
|
1447
|
+
desc="Create new view instead of overwriting active."),
|
|
1448
|
+
|
|
1449
|
+
# --- Sharpen presets ---
|
|
1450
|
+
PresetSpec("sharpening_mode", "enum", default="Both",
|
|
1451
|
+
enum=["Both", "Stellar Only", "Non-Stellar Only"],
|
|
1452
|
+
desc="Sharpening mode."),
|
|
1453
|
+
PresetSpec("auto_psf", "bool", default=True,
|
|
1454
|
+
desc="Auto-detect PSF for non-stellar sharpening."),
|
|
1455
|
+
PresetSpec("nonstellar_psf", "float", default=3.0, min=1.0, max=8.0,
|
|
1456
|
+
desc="Non-stellar PSF strength (1–8)."),
|
|
1457
|
+
PresetSpec("stellar_amount", "float", default=0.50, min=0.0, max=1.0,
|
|
1458
|
+
desc="Stellar sharpening amount."),
|
|
1459
|
+
PresetSpec("nonstellar_amount", "float", default=0.50, min=0.0, max=1.0,
|
|
1460
|
+
desc="Non-stellar sharpening amount."),
|
|
1461
|
+
PresetSpec("sharpen_channels_separately", "bool", default=False,
|
|
1462
|
+
desc="Sharpen R/G/B separately (RGB only)."),
|
|
1463
|
+
|
|
1464
|
+
# --- Denoise presets ---
|
|
1465
|
+
PresetSpec("denoise_luma", "float", default=0.50, min=0.0, max=1.0,
|
|
1466
|
+
desc="Luminance denoise strength."),
|
|
1467
|
+
PresetSpec("denoise_color", "float", default=0.50, min=0.0, max=1.0,
|
|
1468
|
+
desc="Color denoise strength."),
|
|
1469
|
+
PresetSpec("denoise_mode", "enum", default="full",
|
|
1470
|
+
enum=["full", "luminance"],
|
|
1471
|
+
desc="Denoise mode."),
|
|
1472
|
+
PresetSpec("separate_channels", "bool", default=False,
|
|
1473
|
+
desc="Denoise RGB channels separately."),
|
|
1474
|
+
|
|
1475
|
+
# --- SuperRes presets ---
|
|
1476
|
+
PresetSpec("scale", "int", default=2, min=2, max=4,
|
|
1477
|
+
desc="Super-resolution scale factor."),
|
|
1478
|
+
],
|
|
1479
|
+
supports_mono=True,
|
|
1480
|
+
supports_rgb=True,
|
|
1481
|
+
))
|
|
1482
|
+
|
|
1483
|
+
register(CommandSpec(
|
|
1484
|
+
id="debayer",
|
|
1485
|
+
title="Debayer",
|
|
1486
|
+
group="Color / CFA",
|
|
1487
|
+
import_path="pro.debayer",
|
|
1488
|
+
callable_name="run_debayer_via_preset",
|
|
1489
|
+
presets=[
|
|
1490
|
+
PresetSpec(
|
|
1491
|
+
"pattern", "enum", default="auto",
|
|
1492
|
+
enum=["auto", "RGGB", "BGGR", "GRBG", "GBRG"],
|
|
1493
|
+
desc="Bayer pattern to use. 'auto' tries header then scoring."
|
|
1494
|
+
),
|
|
1495
|
+
PresetSpec(
|
|
1496
|
+
"method", "enum", default="auto",
|
|
1497
|
+
enum=["auto", "edge", "bilinear", "AHD", "DHT"],
|
|
1498
|
+
desc="Debayer method. Edge/Bilinear for Bayer; AHD/DHT for X-Trans."
|
|
1499
|
+
),
|
|
1500
|
+
],
|
|
1501
|
+
supports_mono=True, # mosaic is mono input
|
|
1502
|
+
supports_rgb=False, # reject RGB in apply_debayer_preset_to_doc
|
|
1503
|
+
))
|
|
1504
|
+
|
|
1505
|
+
register(CommandSpec(
|
|
1506
|
+
id="linear_fit",
|
|
1507
|
+
title="Linear Fit",
|
|
1508
|
+
group="Calibration",
|
|
1509
|
+
import_path="pro.linear_fit",
|
|
1510
|
+
callable_name="run_linear_fit_via_preset",
|
|
1511
|
+
presets=[
|
|
1512
|
+
PresetSpec(
|
|
1513
|
+
"rgb_mode_idx", "int", default=0, min=0, max=4,
|
|
1514
|
+
desc="RGB target strategy: 0 highest median, 1 lowest, 2 R, 3 G, 4 B."
|
|
1515
|
+
),
|
|
1516
|
+
PresetSpec(
|
|
1517
|
+
"rescale_mode_idx", "int", default=1, min=0, max=2,
|
|
1518
|
+
desc="Out-of-range handling: 0 clip, 1 normalize if needed, 2 leave as-is."
|
|
1519
|
+
),
|
|
1520
|
+
],
|
|
1521
|
+
supports_mono=True,
|
|
1522
|
+
supports_rgb=True,
|
|
1523
|
+
replay_apply_name="apply_linear_fit_to_doc", # if your CommandSpec supports this hook
|
|
1524
|
+
))
|
|
1525
|
+
|
|
1526
|
+
register(CommandSpec(
|
|
1527
|
+
id="morphology",
|
|
1528
|
+
title="Morphology",
|
|
1529
|
+
group="Masks & Morphology",
|
|
1530
|
+
import_path="pro.morphology",
|
|
1531
|
+
callable_name="apply_morphology_to_doc",
|
|
1532
|
+
presets=[
|
|
1533
|
+
PresetSpec(
|
|
1534
|
+
"operation", "enum",
|
|
1535
|
+
default="erosion",
|
|
1536
|
+
enum=["erosion", "dilation", "opening", "closing"],
|
|
1537
|
+
desc="Morphological operation."
|
|
1538
|
+
),
|
|
1539
|
+
PresetSpec(
|
|
1540
|
+
"kernel", "int",
|
|
1541
|
+
default=3, min=1, max=31,
|
|
1542
|
+
desc="Kernel diameter (odd)."
|
|
1543
|
+
),
|
|
1544
|
+
PresetSpec(
|
|
1545
|
+
"iterations", "int",
|
|
1546
|
+
default=1, min=1, max=10,
|
|
1547
|
+
desc="Number of iterations."
|
|
1548
|
+
),
|
|
1549
|
+
],
|
|
1550
|
+
supports_mono=True,
|
|
1551
|
+
supports_rgb=True,
|
|
1552
|
+
replay_apply_name="apply_morphology_to_doc", # if your CommandSpec supports it
|
|
1553
|
+
))
|
|
1554
|
+
|
|
1555
|
+
register(CommandSpec(
|
|
1556
|
+
id="remove_stars",
|
|
1557
|
+
title="Remove Stars",
|
|
1558
|
+
group="Star Tools",
|
|
1559
|
+
import_path="pro.remove_stars_preset",
|
|
1560
|
+
callable_name="run_remove_stars_via_preset",
|
|
1561
|
+
replay_apply_name="apply_remove_stars_to_doc",
|
|
1562
|
+
presets=[
|
|
1563
|
+
PresetSpec("tool", "enum", default="starnet",
|
|
1564
|
+
enum=["starnet", "darkstar"],
|
|
1565
|
+
desc="Which star removal engine to use."),
|
|
1566
|
+
|
|
1567
|
+
# StarNet
|
|
1568
|
+
PresetSpec("linear", "bool", default=True,
|
|
1569
|
+
desc="Temporary stretch before StarNet then unstretch."),
|
|
1570
|
+
PresetSpec("starnet_exe", "path", default="",
|
|
1571
|
+
desc="Optional StarNet exe override; else uses QSettings."),
|
|
1572
|
+
|
|
1573
|
+
# DarkStar
|
|
1574
|
+
PresetSpec("disable_gpu", "bool", default=False,
|
|
1575
|
+
desc="Disable GPU for DarkStar."),
|
|
1576
|
+
PresetSpec("mode", "enum", default="unscreen",
|
|
1577
|
+
enum=["unscreen", "additive"],
|
|
1578
|
+
desc="DarkStar blending mode."),
|
|
1579
|
+
PresetSpec("show_extracted_stars", "bool", default=True,
|
|
1580
|
+
desc="If DarkStar produced stars-only, open it as a new view."),
|
|
1581
|
+
PresetSpec("stride", "int", default=512, min=64, max=1024,
|
|
1582
|
+
desc="Chunk/stride size for DarkStar."),
|
|
1583
|
+
PresetSpec("darkstar_exe", "path", default="",
|
|
1584
|
+
desc="Optional DarkStar exe override; else uses CosmicClarity root."),
|
|
1585
|
+
],
|
|
1586
|
+
supports_mono=True,
|
|
1587
|
+
supports_rgb=True,
|
|
1588
|
+
))
|
|
1589
|
+
|
|
1590
|
+
|
|
1591
|
+
|
|
1592
|
+
# -----------------------------------------------------------------------------
|
|
1593
|
+
# End of file
|
|
1594
|
+
# -----------------------------------------------------------------------------
|