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,189 @@
|
|
|
1
|
+
# pro/crop_preset.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
import math
|
|
4
|
+
from typing import Sequence
|
|
5
|
+
import numpy as np
|
|
6
|
+
import cv2
|
|
7
|
+
|
|
8
|
+
from setiastro.saspro.legacy.image_manager import load_image, save_image # not used here, but matches other preset files
|
|
9
|
+
from setiastro.saspro.wcs_update import update_wcs_after_crop
|
|
10
|
+
|
|
11
|
+
def _as_float01(img: np.ndarray) -> np.ndarray:
|
|
12
|
+
arr = np.asarray(img)
|
|
13
|
+
if arr.dtype.kind in "ui":
|
|
14
|
+
arr = arr.astype(np.float32) / np.iinfo(img.dtype).max
|
|
15
|
+
else:
|
|
16
|
+
arr = arr.astype(np.float32, copy=False)
|
|
17
|
+
if arr.ndim == 3 and arr.shape[2] == 1:
|
|
18
|
+
arr = arr[..., 0]
|
|
19
|
+
return np.clip(arr, 0.0, 1.0)
|
|
20
|
+
|
|
21
|
+
def _quad_from_rect_norm(w: int, h: int, rect: dict) -> np.ndarray:
|
|
22
|
+
"""
|
|
23
|
+
rect = {"x":float,"y":float,"w":float,"h":float,"angle_deg":float}
|
|
24
|
+
All values in [0..1] except angle (deg). (x,y) is top-left of the rect before rotation.
|
|
25
|
+
Rotation is around the rect center, positive CCW.
|
|
26
|
+
"""
|
|
27
|
+
x = float(rect.get("x", 0.0))
|
|
28
|
+
y = float(rect.get("y", 0.0))
|
|
29
|
+
rw = float(rect.get("w", 1.0))
|
|
30
|
+
rh = float(rect.get("h", 1.0))
|
|
31
|
+
ang = float(rect.get("angle_deg", 0.0))
|
|
32
|
+
# pixel-space axis-aligned box
|
|
33
|
+
px = x * w
|
|
34
|
+
py = y * h
|
|
35
|
+
pw = max(1.0, rw * w)
|
|
36
|
+
ph = max(1.0, rh * h)
|
|
37
|
+
|
|
38
|
+
# corners (TL, TR, BR, BL) before rotation
|
|
39
|
+
cx = px + pw * 0.5
|
|
40
|
+
cy = py + ph * 0.5
|
|
41
|
+
pts = np.array([
|
|
42
|
+
[px, py ], # TL
|
|
43
|
+
[px + pw, py ], # TR
|
|
44
|
+
[px + pw, py + ph ], # BR
|
|
45
|
+
[px, py + ph ], # BL
|
|
46
|
+
], dtype=np.float32)
|
|
47
|
+
|
|
48
|
+
if abs(ang) < 1e-6:
|
|
49
|
+
return pts
|
|
50
|
+
|
|
51
|
+
rad = math.radians(ang)
|
|
52
|
+
s, c = math.sin(rad), math.cos(rad)
|
|
53
|
+
R = np.array([[c, -s], [s, c]], dtype=np.float32)
|
|
54
|
+
pts_c = pts - np.array([cx, cy], dtype=np.float32)
|
|
55
|
+
pts_r = (R @ pts_c.T).T + np.array([cx, cy], dtype=np.float32)
|
|
56
|
+
return pts_r.astype(np.float32)
|
|
57
|
+
|
|
58
|
+
def _dst_size_from_quad(q: np.ndarray) -> tuple[int, int]:
|
|
59
|
+
"""
|
|
60
|
+
q: 4x2 TL, TR, BR, BL in pixels.
|
|
61
|
+
"""
|
|
62
|
+
q = np.asarray(q, np.float32)
|
|
63
|
+
w_top = np.linalg.norm(q[1] - q[0])
|
|
64
|
+
w_bot = np.linalg.norm(q[2] - q[3])
|
|
65
|
+
h_left = np.linalg.norm(q[3] - q[0])
|
|
66
|
+
h_right= np.linalg.norm(q[2] - q[1])
|
|
67
|
+
w_out = int(round(max(w_top, w_bot)))
|
|
68
|
+
h_out = int(round(max(h_left, h_right)))
|
|
69
|
+
w_out = max(1, w_out); h_out = max(1, h_out)
|
|
70
|
+
return w_out, h_out
|
|
71
|
+
|
|
72
|
+
def _quad_from_margins(w: int, h: int, margins: dict) -> np.ndarray:
|
|
73
|
+
t = max(0, int(margins.get("top", 0)))
|
|
74
|
+
r = max(0, int(margins.get("right", 0)))
|
|
75
|
+
b = max(0, int(margins.get("bottom", 0)))
|
|
76
|
+
l = max(0, int(margins.get("left", 0)))
|
|
77
|
+
# clamp
|
|
78
|
+
t = min(t, h); b = min(b, h); l = min(l, w); r = min(r, w)
|
|
79
|
+
x0, y0 = float(l), float(t)
|
|
80
|
+
x1, y1 = float(w - r), float(h - b)
|
|
81
|
+
# TL, TR, BR, BL
|
|
82
|
+
return np.array([[x0, y0], [x1, y0], [x1, y1], [x0, y1]], dtype=np.float32)
|
|
83
|
+
|
|
84
|
+
def apply_crop_via_preset(mw, doc, preset: dict) -> np.ndarray:
|
|
85
|
+
"""
|
|
86
|
+
Headless crop runner.
|
|
87
|
+
|
|
88
|
+
Preset schema (choose ONE of the three inputs):
|
|
89
|
+
1) Margins (pixels):
|
|
90
|
+
{"mode":"margins",
|
|
91
|
+
"margins":{"top":0,"right":0,"bottom":0,"left":0},
|
|
92
|
+
"create_new_view": false}
|
|
93
|
+
|
|
94
|
+
2) Axis-aligned rect in normalized coords + optional rotation (deg):
|
|
95
|
+
{"mode":"rect_norm",
|
|
96
|
+
"rect":{"x":0.05,"y":0.08,"w":0.85,"h":0.80,"angle_deg": 0.0},
|
|
97
|
+
"create_new_view": false}
|
|
98
|
+
|
|
99
|
+
3) Explicit quad in normalized coords (TL,TR,BR,BL):
|
|
100
|
+
{"mode":"quad_norm",
|
|
101
|
+
"quad":[[xTL,yTL],[xTR,yTR],[xBR,yBR],[xBL,yBL]],
|
|
102
|
+
"create_new_view": false}
|
|
103
|
+
|
|
104
|
+
Common options:
|
|
105
|
+
- "create_new_view": bool (default False → overwrite target doc)
|
|
106
|
+
- "title": optional title if creating a new view
|
|
107
|
+
|
|
108
|
+
Returns the cropped float32 image in [0..1].
|
|
109
|
+
"""
|
|
110
|
+
pr = dict(preset or {})
|
|
111
|
+
mode = str(pr.get("mode", "margins")).lower()
|
|
112
|
+
create_new = bool(pr.get("create_new_view", False))
|
|
113
|
+
title = pr.get("title") or "Crop"
|
|
114
|
+
|
|
115
|
+
img01 = _as_float01(getattr(doc, "image"))
|
|
116
|
+
h, w = img01.shape[:2]
|
|
117
|
+
|
|
118
|
+
if mode == "margins":
|
|
119
|
+
quad = _quad_from_margins(w, h, pr.get("margins", {}) or {})
|
|
120
|
+
elif mode == "rect_norm":
|
|
121
|
+
quad = _quad_from_rect_norm(w, h, pr.get("rect", {}) or {})
|
|
122
|
+
elif mode == "quad_norm":
|
|
123
|
+
qn = np.array(pr.get("quad", []), dtype=np.float32)
|
|
124
|
+
if qn.shape != (4, 2):
|
|
125
|
+
raise ValueError("quad_norm expects 4×2 list of [x,y] in [0..1].")
|
|
126
|
+
quad = qn * np.array([w, h], dtype=np.float32)
|
|
127
|
+
else:
|
|
128
|
+
raise ValueError(f"Unknown crop mode: {mode}")
|
|
129
|
+
|
|
130
|
+
# Destination geometry (axis-aligned)
|
|
131
|
+
w_out, h_out = _dst_size_from_quad(quad)
|
|
132
|
+
dst = np.array([[0, 0], [w_out, 0], [w_out, h_out], [0, h_out]], dtype=np.float32)
|
|
133
|
+
|
|
134
|
+
# Homography and crop
|
|
135
|
+
M = cv2.getPerspectiveTransform(quad.astype(np.float32), dst)
|
|
136
|
+
out = cv2.warpPerspective(img01, M, (w_out, h_out), flags=cv2.INTER_LINEAR)
|
|
137
|
+
|
|
138
|
+
# Build metadata / WCS
|
|
139
|
+
meta = dict(getattr(doc, "metadata", {}) or {})
|
|
140
|
+
try:
|
|
141
|
+
if update_wcs_after_crop is not None:
|
|
142
|
+
meta = update_wcs_after_crop(meta, M_src_to_dst=M, out_w=w_out, out_h=h_out)
|
|
143
|
+
except Exception:
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
# Apply to document or open new
|
|
147
|
+
if create_new:
|
|
148
|
+
dm = getattr(mw, "docman", None) or getattr(mw, "doc_manager", None)
|
|
149
|
+
if dm is None:
|
|
150
|
+
raise RuntimeError("Document manager unavailable for create_new_view=True.")
|
|
151
|
+
newdoc = dm.open_array(out.copy(), metadata={**meta, "step_name": "Crop"}, title=title)
|
|
152
|
+
if hasattr(mw, "_spawn_subwindow_for"):
|
|
153
|
+
mw._spawn_subwindow_for(newdoc)
|
|
154
|
+
else:
|
|
155
|
+
# overwrite
|
|
156
|
+
if hasattr(doc, "apply_edit"):
|
|
157
|
+
doc.apply_edit(out.copy(), metadata={**meta, "step_name": "Crop"}, step_name="Crop")
|
|
158
|
+
else:
|
|
159
|
+
# fallback if apply_edit not present
|
|
160
|
+
setattr(doc, "image", out.copy())
|
|
161
|
+
setattr(doc, "metadata", {**meta, "step_name": "Crop"})
|
|
162
|
+
if hasattr(doc, "changed"):
|
|
163
|
+
try: doc.changed.emit()
|
|
164
|
+
except Exception as e:
|
|
165
|
+
import logging
|
|
166
|
+
logging.debug(f"Exception suppressed: {type(e).__name__}: {e}")
|
|
167
|
+
|
|
168
|
+
return out
|
|
169
|
+
|
|
170
|
+
def run_crop_via_preset(mw, preset: dict, target_doc=None) -> bool:
|
|
171
|
+
"""
|
|
172
|
+
Convenience for non-drag invocations (similar to star_alignment_via_preset).
|
|
173
|
+
"""
|
|
174
|
+
# resolve active document if not provided
|
|
175
|
+
doc = target_doc
|
|
176
|
+
if doc is None:
|
|
177
|
+
try:
|
|
178
|
+
if hasattr(mw, "_active_doc"):
|
|
179
|
+
doc = mw._active_doc()
|
|
180
|
+
except Exception:
|
|
181
|
+
doc = None
|
|
182
|
+
if doc is None and hasattr(mw, "mdi"):
|
|
183
|
+
asw = mw.mdi.activeSubWindow()
|
|
184
|
+
if asw:
|
|
185
|
+
doc = getattr(asw.widget(), "document", None)
|
|
186
|
+
if doc is None:
|
|
187
|
+
raise RuntimeError("No active document for crop.")
|
|
188
|
+
apply_crop_via_preset(mw, doc, preset or {})
|
|
189
|
+
return True
|