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.

Files changed (174) hide show
  1. setiastro/__init__.py +2 -0
  2. setiastro/saspro/__init__.py +20 -0
  3. setiastro/saspro/__main__.py +784 -0
  4. setiastro/saspro/_generated/__init__.py +7 -0
  5. setiastro/saspro/_generated/build_info.py +2 -0
  6. setiastro/saspro/abe.py +1295 -0
  7. setiastro/saspro/abe_preset.py +196 -0
  8. setiastro/saspro/aberration_ai.py +694 -0
  9. setiastro/saspro/aberration_ai_preset.py +224 -0
  10. setiastro/saspro/accel_installer.py +218 -0
  11. setiastro/saspro/accel_workers.py +30 -0
  12. setiastro/saspro/add_stars.py +621 -0
  13. setiastro/saspro/astrobin_exporter.py +1007 -0
  14. setiastro/saspro/astrospike.py +153 -0
  15. setiastro/saspro/astrospike_python.py +1839 -0
  16. setiastro/saspro/autostretch.py +196 -0
  17. setiastro/saspro/backgroundneutral.py +560 -0
  18. setiastro/saspro/batch_convert.py +325 -0
  19. setiastro/saspro/batch_renamer.py +519 -0
  20. setiastro/saspro/blemish_blaster.py +488 -0
  21. setiastro/saspro/blink_comparator_pro.py +2923 -0
  22. setiastro/saspro/bundles.py +61 -0
  23. setiastro/saspro/bundles_dock.py +114 -0
  24. setiastro/saspro/cheat_sheet.py +168 -0
  25. setiastro/saspro/clahe.py +342 -0
  26. setiastro/saspro/comet_stacking.py +1377 -0
  27. setiastro/saspro/config.py +38 -0
  28. setiastro/saspro/config_bootstrap.py +40 -0
  29. setiastro/saspro/config_manager.py +316 -0
  30. setiastro/saspro/continuum_subtract.py +1617 -0
  31. setiastro/saspro/convo.py +1397 -0
  32. setiastro/saspro/convo_preset.py +414 -0
  33. setiastro/saspro/copyastro.py +187 -0
  34. setiastro/saspro/cosmicclarity.py +1564 -0
  35. setiastro/saspro/cosmicclarity_preset.py +407 -0
  36. setiastro/saspro/crop_dialog_pro.py +948 -0
  37. setiastro/saspro/crop_preset.py +189 -0
  38. setiastro/saspro/curve_editor_pro.py +2544 -0
  39. setiastro/saspro/curves_preset.py +375 -0
  40. setiastro/saspro/debayer.py +670 -0
  41. setiastro/saspro/debug_utils.py +29 -0
  42. setiastro/saspro/dnd_mime.py +35 -0
  43. setiastro/saspro/doc_manager.py +2634 -0
  44. setiastro/saspro/exoplanet_detector.py +2166 -0
  45. setiastro/saspro/file_utils.py +284 -0
  46. setiastro/saspro/fitsmodifier.py +744 -0
  47. setiastro/saspro/free_torch_memory.py +48 -0
  48. setiastro/saspro/frequency_separation.py +1343 -0
  49. setiastro/saspro/function_bundle.py +1594 -0
  50. setiastro/saspro/ghs_dialog_pro.py +660 -0
  51. setiastro/saspro/ghs_preset.py +284 -0
  52. setiastro/saspro/graxpert.py +634 -0
  53. setiastro/saspro/graxpert_preset.py +287 -0
  54. setiastro/saspro/gui/__init__.py +0 -0
  55. setiastro/saspro/gui/main_window.py +8494 -0
  56. setiastro/saspro/gui/mixins/__init__.py +33 -0
  57. setiastro/saspro/gui/mixins/dock_mixin.py +263 -0
  58. setiastro/saspro/gui/mixins/file_mixin.py +445 -0
  59. setiastro/saspro/gui/mixins/geometry_mixin.py +403 -0
  60. setiastro/saspro/gui/mixins/header_mixin.py +441 -0
  61. setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
  62. setiastro/saspro/gui/mixins/menu_mixin.py +361 -0
  63. setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
  64. setiastro/saspro/gui/mixins/toolbar_mixin.py +1324 -0
  65. setiastro/saspro/gui/mixins/update_mixin.py +309 -0
  66. setiastro/saspro/gui/mixins/view_mixin.py +435 -0
  67. setiastro/saspro/halobgon.py +462 -0
  68. setiastro/saspro/header_viewer.py +445 -0
  69. setiastro/saspro/headless_utils.py +88 -0
  70. setiastro/saspro/histogram.py +753 -0
  71. setiastro/saspro/history_explorer.py +939 -0
  72. setiastro/saspro/image_combine.py +414 -0
  73. setiastro/saspro/image_peeker_pro.py +1596 -0
  74. setiastro/saspro/imageops/__init__.py +37 -0
  75. setiastro/saspro/imageops/mdi_snap.py +292 -0
  76. setiastro/saspro/imageops/scnr.py +36 -0
  77. setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
  78. setiastro/saspro/imageops/stretch.py +244 -0
  79. setiastro/saspro/isophote.py +1179 -0
  80. setiastro/saspro/layers.py +208 -0
  81. setiastro/saspro/layers_dock.py +714 -0
  82. setiastro/saspro/lazy_imports.py +193 -0
  83. setiastro/saspro/legacy/__init__.py +2 -0
  84. setiastro/saspro/legacy/image_manager.py +2226 -0
  85. setiastro/saspro/legacy/numba_utils.py +3659 -0
  86. setiastro/saspro/legacy/xisf.py +1071 -0
  87. setiastro/saspro/linear_fit.py +534 -0
  88. setiastro/saspro/live_stacking.py +1830 -0
  89. setiastro/saspro/log_bus.py +5 -0
  90. setiastro/saspro/logging_config.py +460 -0
  91. setiastro/saspro/luminancerecombine.py +309 -0
  92. setiastro/saspro/main_helpers.py +201 -0
  93. setiastro/saspro/mask_creation.py +928 -0
  94. setiastro/saspro/masks_core.py +56 -0
  95. setiastro/saspro/mdi_widgets.py +353 -0
  96. setiastro/saspro/memory_utils.py +666 -0
  97. setiastro/saspro/metadata_patcher.py +75 -0
  98. setiastro/saspro/mfdeconv.py +3826 -0
  99. setiastro/saspro/mfdeconv_earlystop.py +71 -0
  100. setiastro/saspro/mfdeconvcudnn.py +3263 -0
  101. setiastro/saspro/mfdeconvsport.py +2382 -0
  102. setiastro/saspro/minorbodycatalog.py +567 -0
  103. setiastro/saspro/morphology.py +382 -0
  104. setiastro/saspro/multiscale_decomp.py +1290 -0
  105. setiastro/saspro/nbtorgb_stars.py +531 -0
  106. setiastro/saspro/numba_utils.py +3044 -0
  107. setiastro/saspro/numba_warmup.py +141 -0
  108. setiastro/saspro/ops/__init__.py +9 -0
  109. setiastro/saspro/ops/command_help_dialog.py +623 -0
  110. setiastro/saspro/ops/command_runner.py +217 -0
  111. setiastro/saspro/ops/commands.py +1594 -0
  112. setiastro/saspro/ops/script_editor.py +1102 -0
  113. setiastro/saspro/ops/scripts.py +1413 -0
  114. setiastro/saspro/ops/settings.py +560 -0
  115. setiastro/saspro/parallel_utils.py +554 -0
  116. setiastro/saspro/pedestal.py +121 -0
  117. setiastro/saspro/perfect_palette_picker.py +1053 -0
  118. setiastro/saspro/pipeline.py +110 -0
  119. setiastro/saspro/pixelmath.py +1600 -0
  120. setiastro/saspro/plate_solver.py +2435 -0
  121. setiastro/saspro/project_io.py +797 -0
  122. setiastro/saspro/psf_utils.py +136 -0
  123. setiastro/saspro/psf_viewer.py +549 -0
  124. setiastro/saspro/pyi_rthook_astroquery.py +95 -0
  125. setiastro/saspro/remove_green.py +314 -0
  126. setiastro/saspro/remove_stars.py +1625 -0
  127. setiastro/saspro/remove_stars_preset.py +404 -0
  128. setiastro/saspro/resources.py +472 -0
  129. setiastro/saspro/rgb_combination.py +207 -0
  130. setiastro/saspro/rgb_extract.py +19 -0
  131. setiastro/saspro/rgbalign.py +723 -0
  132. setiastro/saspro/runtime_imports.py +7 -0
  133. setiastro/saspro/runtime_torch.py +754 -0
  134. setiastro/saspro/save_options.py +72 -0
  135. setiastro/saspro/selective_color.py +1552 -0
  136. setiastro/saspro/sfcc.py +1425 -0
  137. setiastro/saspro/shortcuts.py +2807 -0
  138. setiastro/saspro/signature_insert.py +1099 -0
  139. setiastro/saspro/stacking_suite.py +17712 -0
  140. setiastro/saspro/star_alignment.py +7420 -0
  141. setiastro/saspro/star_alignment_preset.py +329 -0
  142. setiastro/saspro/star_metrics.py +49 -0
  143. setiastro/saspro/star_spikes.py +681 -0
  144. setiastro/saspro/star_stretch.py +470 -0
  145. setiastro/saspro/stat_stretch.py +502 -0
  146. setiastro/saspro/status_log_dock.py +78 -0
  147. setiastro/saspro/subwindow.py +3267 -0
  148. setiastro/saspro/supernovaasteroidhunter.py +1712 -0
  149. setiastro/saspro/swap_manager.py +99 -0
  150. setiastro/saspro/torch_backend.py +89 -0
  151. setiastro/saspro/torch_rejection.py +434 -0
  152. setiastro/saspro/view_bundle.py +1555 -0
  153. setiastro/saspro/wavescale_hdr.py +624 -0
  154. setiastro/saspro/wavescale_hdr_preset.py +100 -0
  155. setiastro/saspro/wavescalede.py +657 -0
  156. setiastro/saspro/wavescalede_preset.py +228 -0
  157. setiastro/saspro/wcs_update.py +374 -0
  158. setiastro/saspro/whitebalance.py +456 -0
  159. setiastro/saspro/widgets/__init__.py +48 -0
  160. setiastro/saspro/widgets/common_utilities.py +305 -0
  161. setiastro/saspro/widgets/graphics_views.py +122 -0
  162. setiastro/saspro/widgets/image_utils.py +518 -0
  163. setiastro/saspro/widgets/preview_dialogs.py +280 -0
  164. setiastro/saspro/widgets/spinboxes.py +275 -0
  165. setiastro/saspro/widgets/themed_buttons.py +13 -0
  166. setiastro/saspro/widgets/wavelet_utils.py +299 -0
  167. setiastro/saspro/window_shelf.py +185 -0
  168. setiastro/saspro/xisf.py +1123 -0
  169. setiastrosuitepro-1.6.0.dist-info/METADATA +266 -0
  170. setiastrosuitepro-1.6.0.dist-info/RECORD +174 -0
  171. setiastrosuitepro-1.6.0.dist-info/WHEEL +4 -0
  172. setiastrosuitepro-1.6.0.dist-info/entry_points.txt +6 -0
  173. setiastrosuitepro-1.6.0.dist-info/licenses/LICENSE +674 -0
  174. setiastrosuitepro-1.6.0.dist-info/licenses/license.txt +2580 -0
@@ -0,0 +1,244 @@
1
+ # imageops/stretch.py
2
+ from __future__ import annotations
3
+ import numpy as np
4
+
5
+ # ---- Try Numba kernels from legacy ----
6
+ try:
7
+ from setiastro.saspro.legacy.numba_utils import (
8
+ numba_mono_final_formula,
9
+ numba_color_final_formula_linked,
10
+ numba_color_final_formula_unlinked,
11
+ )
12
+ _HAS_NUMBA = True
13
+ except Exception:
14
+ _HAS_NUMBA = False
15
+
16
+ # Vectorized fallbacks (no Numba)
17
+ def numba_mono_final_formula(rescaled, median_rescaled, target_median):
18
+ r = rescaled
19
+ med = float(median_rescaled)
20
+ num = (med - 1.0) * target_median * r
21
+ den = med * (target_median + r - 1.0) - target_median * r
22
+ den = np.where(np.abs(den) < 1e-12, 1e-12, den)
23
+ return num / den
24
+
25
+ def numba_color_final_formula_linked(rescaled, median_rescaled, target_median):
26
+ r = rescaled
27
+ med = float(median_rescaled)
28
+ num = (med - 1.0) * target_median * r
29
+ den = med * (target_median + r - 1.0) - target_median * r
30
+ den = np.where(np.abs(den) < 1e-12, 1e-12, den)
31
+ return num / den
32
+
33
+ def numba_color_final_formula_unlinked(rescaled, medians_rescaled, target_median):
34
+ r = rescaled
35
+ med = np.asarray(medians_rescaled, dtype=np.float32).reshape((1, 1, 3))
36
+ num = (med - 1.0) * target_median * r
37
+ den = med * (target_median + r - 1.0) - target_median * r
38
+ den = np.where(np.abs(den) < 1e-12, 1e-12, den)
39
+ return num / den
40
+
41
+
42
+ # ---- Optional curves boost (gentle S-curve) ----
43
+ from functools import lru_cache
44
+
45
+ @lru_cache(maxsize=128)
46
+ def _calculate_curve_points(target_median: float, curves_boost: float):
47
+ """Calculate curve control points with caching."""
48
+ tm = float(target_median)
49
+ cb = float(curves_boost)
50
+
51
+ # These match your original formula
52
+ p3x = 0.25 * (1.0 - tm) + tm
53
+ p4x = 0.75 * (1.0 - tm) + tm
54
+ p3y = p3x ** (1.0 - cb)
55
+ p4y = (p4x ** (1.0 - cb)) ** (1.0 - cb)
56
+
57
+ # Original 6-point curve
58
+ xvals = np.array([
59
+ 0.0,
60
+ 0.5 * tm,
61
+ tm,
62
+ p3x,
63
+ p4x,
64
+ 1.0
65
+ ], dtype=np.float32)
66
+
67
+ yvals = np.array([
68
+ 0.0,
69
+ 0.5 * tm,
70
+ tm,
71
+ p3y,
72
+ p4y,
73
+ 1.0
74
+ ], dtype=np.float32)
75
+
76
+ return xvals, yvals
77
+
78
+ def apply_curves_adjustment(image: np.ndarray,
79
+ target_median: float,
80
+ curves_boost: float) -> np.ndarray:
81
+ """
82
+ curves_boost ∈ [0,1]. 0 = no change, 1 = strong S-curve.
83
+
84
+ This reproduces the original Statistical Stretch curves behavior:
85
+ we build a 1D curve from 6 control points and apply it as a
86
+ piecewise-linear LUT over [0,1].
87
+ """
88
+ # No curve? Just return as-is (but float32 / clipped)
89
+ if curves_boost <= 0.0:
90
+ return np.clip(image, 0.0, 1.0).astype(np.float32, copy=False)
91
+
92
+ img = np.clip(image.astype(np.float32, copy=False), 0.0, 1.0)
93
+
94
+ # Get cached curve points
95
+ xvals, yvals = _calculate_curve_points(target_median, curves_boost)
96
+
97
+ # Apply the 1D LUT per channel using np.interp (piecewise linear)
98
+ if img.ndim == 2:
99
+ flat = img.ravel()
100
+ out = np.interp(flat, xvals, yvals).reshape(img.shape).astype(np.float32)
101
+ elif img.ndim == 3 and img.shape[2] in (3, 4):
102
+ h, w, c = img.shape
103
+ out = np.empty_like(img, dtype=np.float32)
104
+ # Apply same curve to each color channel
105
+ for ch in range(c):
106
+ flat = img[..., ch].ravel()
107
+ out[..., ch] = np.interp(flat, xvals, yvals).reshape(h, w)
108
+ else:
109
+ # Fallback: just return clamped image
110
+ out = img
111
+
112
+ return np.clip(out, 0.0, 1.0)
113
+
114
+
115
+
116
+ # ---- Public API used by Pro ----
117
+ def stretch_mono_image(image: np.ndarray,
118
+ target_median: float,
119
+ normalize: bool = False,
120
+ apply_curves: bool = False,
121
+ curves_boost: float = 0.0) -> np.ndarray:
122
+ """
123
+ image: float32 preferred, ~[0..1]. Returns float32 in [0..1].
124
+ """
125
+ img = image.astype(np.float32, copy=False)
126
+
127
+ # Black point from SASv2 logic
128
+ med = float(np.median(img))
129
+ std = float(np.std(img))
130
+ bp = max(float(img.min()), med - 2.7 * std)
131
+ denom = 1.0 - bp
132
+ if abs(denom) < 1e-12:
133
+ denom = 1e-12
134
+
135
+ rescaled = (img - bp) / denom
136
+ med_rescaled = float(np.median(rescaled))
137
+
138
+ out = numba_mono_final_formula(rescaled, med_rescaled, float(target_median))
139
+
140
+ if apply_curves:
141
+ out = apply_curves_adjustment(out, float(target_median), float(curves_boost))
142
+ if normalize:
143
+ mx = float(out.max())
144
+ if mx > 0:
145
+ out = out / mx
146
+
147
+ return np.clip(out, 0.0, 1.0).astype(np.float32, copy=False)
148
+
149
+
150
+ def stretch_color_image(image: np.ndarray,
151
+ target_median: float,
152
+ linked: bool = True,
153
+ normalize: bool = False,
154
+ apply_curves: bool = False,
155
+ curves_boost: float = 0.0) -> np.ndarray:
156
+ """
157
+ image: float32 preferred, ~[0..1]. Returns float32 in [0..1].
158
+ """
159
+ img = image.astype(np.float32, copy=False)
160
+
161
+ # Mono/single-channel → reuse mono path and broadcast to 3-ch for display
162
+ if img.ndim == 2 or (img.ndim == 3 and img.shape[2] == 1):
163
+ mono = img.squeeze()
164
+ mono_out = stretch_mono_image(mono, target_median, normalize=normalize,
165
+ apply_curves=apply_curves, curves_boost=curves_boost)
166
+ return np.stack([mono_out] * 3, axis=-1)
167
+
168
+ # Color
169
+ if linked:
170
+ comb_med = float(np.median(img))
171
+ comb_std = float(np.std(img))
172
+ bp = max(float(img.min()), comb_med - 2.7 * comb_std)
173
+ denom = 1.0 - bp
174
+ if abs(denom) < 1e-12:
175
+ denom = 1e-12
176
+
177
+ rescaled = (img - bp) / denom
178
+ med_rescaled = float(np.median(rescaled))
179
+ out = numba_color_final_formula_linked(rescaled, med_rescaled, float(target_median))
180
+ else:
181
+ # Optimized: compute all channel statistics in single vectorized calls
182
+ # instead of per-channel loop (2-3x faster)
183
+ ch_meds = np.median(img, axis=(0, 1)) # Shape: (3,)
184
+ ch_stds = np.std(img, axis=(0, 1)) # Shape: (3,)
185
+ ch_mins = img.min(axis=(0, 1)) # Shape: (3,)
186
+
187
+ # Compute black points for all channels at once
188
+ bp = np.maximum(ch_mins, ch_meds - 2.7 * ch_stds)
189
+ denom = np.maximum(1.0 - bp, 1e-12) # Avoid divide by zero
190
+
191
+ # Rescale all channels at once using broadcasting
192
+ rescaled = (img - bp.reshape(1, 1, 3)) / denom.reshape(1, 1, 3)
193
+ rescaled = rescaled.astype(np.float32, copy=False)
194
+
195
+ # Compute rescaled medians
196
+ meds = np.median(rescaled, axis=(0, 1)).astype(np.float32)
197
+
198
+ out = numba_color_final_formula_unlinked(rescaled, meds, float(target_median))
199
+
200
+ if apply_curves:
201
+ out = apply_curves_adjustment(out, float(target_median), float(curves_boost))
202
+ if normalize:
203
+ mx = float(out.max())
204
+ if mx > 0:
205
+ out = out / mx
206
+
207
+ return np.clip(out, 0.0, 1.0).astype(np.float32, copy=False)
208
+
209
+
210
+ def siril_style_autostretch(image, sigma=3.0):
211
+ """
212
+ Perform a 'Siril-style histogram stretch' using MAD for robust contrast enhancement.
213
+
214
+ Parameters:
215
+ image (np.ndarray): Input image, assumed to be normalized to [0, 1] range.
216
+ sigma (float): How many MADs to stretch from the median.
217
+
218
+ Returns:
219
+ np.ndarray: Stretched image in [0, 1] range.
220
+ """
221
+ def stretch_channel(channel):
222
+ median = np.median(channel)
223
+ mad = np.median(np.abs(channel - median))
224
+ min_val = np.min(channel)
225
+ max_val = np.max(channel)
226
+
227
+ # Convert MAD to an equivalent of std (optional, keep raw MAD if preferred)
228
+ mad_std_equiv = mad * 1.4826
229
+
230
+ black_point = max(min_val, median - sigma * mad_std_equiv)
231
+ white_point = min(max_val, median + sigma * mad_std_equiv)
232
+
233
+ if white_point - black_point <= 1e-6:
234
+ return np.zeros_like(channel) # Avoid divide-by-zero
235
+
236
+ stretched = (channel - black_point) / (white_point - black_point)
237
+ return np.clip(stretched, 0, 1)
238
+
239
+ if image.ndim == 2:
240
+ return stretch_channel(image)
241
+ elif image.ndim == 3 and image.shape[2] == 3:
242
+ return np.stack([stretch_channel(image[..., c]) for c in range(3)], axis=-1)
243
+ else:
244
+ raise ValueError("Unsupported image format for histogram stretch.")