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,196 @@
1
+ # pro/autostretch.py
2
+ import numpy as np
3
+
4
+ _MAX_STATS_PIXELS = 1_000_000
5
+ _DEFAULT_SIGMA = 3
6
+ _U8_MAX = 4095 # 12-bit output for better gradations than 255
7
+ _U16_MAX = 65535
8
+
9
+ # ---------- helpers (generic N-level pipeline) ----------
10
+ def _to_uN(a: np.ndarray, maxv: int) -> np.ndarray:
11
+ """Convert to uint8/uint16 [0..maxv] for cheap hist/LUT work."""
12
+ tgt_dtype = np.uint16 if maxv > _U8_MAX else np.uint8
13
+ if a.dtype == tgt_dtype:
14
+ return a
15
+ if np.issubdtype(a.dtype, np.integer):
16
+ info = np.iinfo(a.dtype)
17
+ if info.max <= 0:
18
+ return np.zeros_like(a, dtype=tgt_dtype)
19
+ scaled = np.clip(a.astype(np.float32), 0, info.max) * (maxv / float(info.max))
20
+ return (scaled + 0.5).astype(tgt_dtype)
21
+ # float-ish
22
+ af = np.clip(a.astype(np.float32), 0.0, 1.0)
23
+ return (af * maxv + 0.5).astype(tgt_dtype)
24
+
25
+ def _choose_stride(h: int, w: int, max_pixels: int) -> tuple[int, int]:
26
+ n = h * w
27
+ if n <= max_pixels:
28
+ return 1, 1
29
+ s = max(1, int(np.sqrt(n / float(max_pixels))))
30
+ return s, s
31
+
32
+ def _compute_lut_from_sample(sample_uN: np.ndarray, target: float, sigma: float, maxv: int,
33
+ qfloor: float = 0.001) -> np.ndarray:
34
+ """Return a 0..maxv -> [0..1] LUT using the same math as _fast_channel_autostretch_uN."""
35
+ hist = np.bincount(sample_uN.ravel(), minlength=maxv + 1)
36
+ total = int(hist.sum()) or 1
37
+
38
+ cdf = np.cumsum(hist)
39
+ med = int(np.searchsorted(cdf, (total + 1) // 2))
40
+
41
+ bins = np.arange(maxv + 1, dtype=np.float64)
42
+ hist_low = hist[:med + 1]
43
+ total_low = int(hist_low.sum()) or 1
44
+ mean_low = float((hist_low * bins[:med + 1]).sum() / total_low)
45
+ var_low = float((hist_low * (bins[:med + 1] - mean_low)**2).sum() / total_low)
46
+ std_low = float(np.sqrt(max(1e-12, var_low)))
47
+
48
+ floor_idx = int(np.searchsorted(cdf, int(qfloor * total)))
49
+ bp = int(max(floor_idx, med - sigma * std_low))
50
+ bp = int(np.clip(bp, 0, maxv - 1))
51
+
52
+ return _build_lut_generic(bp, target, med, maxv)
53
+
54
+ def _stats_from_hist_generic(uN: np.ndarray, maxv: int) -> tuple[float, float, int, int]:
55
+ """(median, std, minv, maxv) using a histogram of levels [0..maxv]."""
56
+ hist = np.bincount(uN.ravel(), minlength=maxv + 1)
57
+ total = int(hist.sum())
58
+ if total == 0:
59
+ return 0.0, 1.0, 0, 0
60
+
61
+ # min / max (first/last nonzero bin)
62
+ minv = int(np.argmax(hist > 0))
63
+ maxv_found = int(maxv - np.argmax(hist[::-1] > 0))
64
+
65
+ cdf = np.cumsum(hist)
66
+ med_idx = int(np.searchsorted(cdf, (total + 1) // 2))
67
+
68
+ bins = np.arange(hist.size, dtype=np.float64)
69
+ s1 = float((hist * bins).sum())
70
+ s2 = float((hist * (bins * bins)).sum())
71
+ mean = s1 / total
72
+ var = max(0.0, s2 / total - mean * mean)
73
+ std = float(np.sqrt(var))
74
+ return float(med_idx), std, minv, maxv_found
75
+
76
+ def _build_lut_generic(bp: int, target_median: float, med_uN: float, maxv: int) -> np.ndarray:
77
+ denom_bp = max(1, maxv - int(bp))
78
+ median_rescaled = (med_uN - bp) / float(denom_bp)
79
+ median_rescaled = float(np.clip(median_rescaled, 1e-9, 1.0))
80
+
81
+ x = np.arange(maxv + 1, dtype=np.float32)
82
+
83
+ # ✅ KEY FIX: clamp r to [0,1] so x<=bp -> r=0 (maps to 0), x>=max -> r=1
84
+ r = np.clip((x - bp) / float(denom_bp), 0.0, 1.0)
85
+
86
+ denom = median_rescaled * (target_median + r - 1.0) - target_median * r
87
+ denom = np.where(np.abs(denom) < 1e-12, 1e-12, denom)
88
+ out = ((median_rescaled - 1.0) * target_median * r) / denom
89
+ return np.clip(out, 0.0, 1.0).astype(np.float32)
90
+
91
+ def _fast_channel_autostretch_uN(ch_uN: np.ndarray, target: float, sigma: float, maxv: int,
92
+ qfloor: float = 0.001) -> np.ndarray:
93
+ """
94
+ qfloor: low-percentile floor (e.g. 0.1%) so BP doesn't peg to minv=0.
95
+ """
96
+ # Subsample
97
+ h, w = ch_uN.shape
98
+ sy, sx = _choose_stride(h, w, _MAX_STATS_PIXELS)
99
+ sample = ch_uN[::sy, ::sx]
100
+
101
+ # Histogram on the sample
102
+ hist = np.bincount(sample.ravel(), minlength=maxv + 1)
103
+ total = int(hist.sum()) or 1
104
+
105
+ # CDF + median index
106
+ cdf = np.cumsum(hist)
107
+ med = int(np.searchsorted(cdf, (total + 1)//2))
108
+
109
+ # Robust std: only use bins <= median (avoids bright-tail inflation)
110
+ bins = np.arange(maxv + 1, dtype=np.float64)
111
+ hist_low = hist[:med + 1]
112
+ total_low = int(hist_low.sum()) or 1
113
+ mean_low = float((hist_low * bins[:med + 1]).sum() / total_low)
114
+ var_low = float((hist_low * (bins[:med + 1] - mean_low)**2).sum() / total_low)
115
+ std_low = float(np.sqrt(max(1e-12, var_low)))
116
+
117
+ # Percentile floor (avoid pegging to 0)
118
+ floor_idx = int(np.searchsorted(cdf, int(qfloor * total)))
119
+
120
+ # Black point driven by sigma, but never below the floor
121
+ bp = int(max(floor_idx, med - sigma * std_low))
122
+ bp = int(np.clip(bp, 0, maxv - 1))
123
+
124
+ # Build LUT and map
125
+ lut = _build_lut_generic(bp, target, med, maxv)
126
+ return lut[ch_uN]
127
+
128
+ # ---------- public API ----------
129
+ def autostretch(
130
+ img: np.ndarray,
131
+ target_median: float = 0.25,
132
+ linked: bool = False,
133
+ sigma: float = _DEFAULT_SIGMA,
134
+ *,
135
+ use_16bit: bool | None = None,
136
+ ) -> np.ndarray:
137
+ """
138
+ High-quality autostretch that can operate in 16-bit (HQ, default) or 8-bit (fast) mode.
139
+
140
+ • 16-bit mode: smooth gradients, minimal posterization (recommended).
141
+ • 8-bit mode: slightly faster on very large images, lower fidelity.
142
+
143
+ If use_16bit is None, we try to read QSettings("display/autostretch_16bit") and
144
+ default to True on failure (no Qt in context).
145
+ """
146
+ if img is None:
147
+ return None
148
+
149
+ # Optional auto-read from QSettings if caller didn’t pass a flag.
150
+ if use_16bit is None:
151
+ try:
152
+ from PyQt6.QtCore import QSettings
153
+ use_16bit = QSettings().value("display/autostretch_16bit", True, type=bool)
154
+ except Exception:
155
+ use_16bit = True
156
+
157
+ maxv = _U16_MAX if use_16bit else _U8_MAX
158
+ a = np.asarray(img)
159
+
160
+ # MONO (or pseudo-mono)
161
+ if a.ndim == 2 or (a.ndim == 3 and a.shape[2] == 1):
162
+ u = _to_uN(a.squeeze(), maxv)
163
+ out = _fast_channel_autostretch_uN(u, target_median, sigma, maxv)
164
+ return out.astype(np.float32, copy=False)
165
+
166
+ # color
167
+ u = _to_uN(a, maxv)
168
+ C = u.shape[2]
169
+
170
+ if linked:
171
+ # sample fewer pixels for stats
172
+ h, w, _ = u.shape
173
+ sy, sx = _choose_stride(h, w, max(1, _MAX_STATS_PIXELS // 3))
174
+ sample = u[::sy, ::sx]
175
+
176
+ # Rec.709-ish luminance, integer dtype preserved
177
+ # (weights sum to 1; cast back to u.dtype for the LUT builder)
178
+ lum = (0.2126 * sample[..., 0] + 0.7152 * sample[..., 1] + 0.0722 * sample[..., 2]).astype(u.dtype)
179
+
180
+ lut = _compute_lut_from_sample(lum, target_median, sigma, maxv)
181
+
182
+ out = np.empty_like(u, dtype=np.float32)
183
+ for c in range(min(3, C)):
184
+ out[..., c] = lut[u[..., c]]
185
+ if C > 3: # pass-through non-RGB channels
186
+ out[..., 3:] = u[..., 3:] / float(maxv)
187
+ return out
188
+ else:
189
+ out = np.empty_like(u, dtype=np.float32)
190
+ for c in range(min(3, C)):
191
+ out[..., c] = _fast_channel_autostretch_uN(u[..., c], target_median, sigma, maxv)
192
+ if C > 3:
193
+ out[..., 3:] = u[..., 3:] / float(maxv)
194
+ return out
195
+
196
+ print(f"med={med} std_low={std_low:.2f} floor={floor_idx} σ={sigma} → bp={bp}")