setiastrosuitepro 1.6.4__py3-none-any.whl → 1.7.1.post2__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 (132) hide show
  1. setiastro/images/TextureClarity.svg +56 -0
  2. setiastro/images/abeicon.svg +16 -0
  3. setiastro/images/acv_icon.png +0 -0
  4. setiastro/images/colorwheel.svg +97 -0
  5. setiastro/images/cosmic.svg +40 -0
  6. setiastro/images/cosmicsat.svg +24 -0
  7. setiastro/images/first_quarter.png +0 -0
  8. setiastro/images/full_moon.png +0 -0
  9. setiastro/images/graxpert.svg +19 -0
  10. setiastro/images/last_quarter.png +0 -0
  11. setiastro/images/linearfit.svg +32 -0
  12. setiastro/images/narrowbandnormalization.png +0 -0
  13. setiastro/images/new_moon.png +0 -0
  14. setiastro/images/pixelmath.svg +42 -0
  15. setiastro/images/planetarystacker.png +0 -0
  16. setiastro/images/waning_crescent_1.png +0 -0
  17. setiastro/images/waning_crescent_2.png +0 -0
  18. setiastro/images/waning_crescent_3.png +0 -0
  19. setiastro/images/waning_crescent_4.png +0 -0
  20. setiastro/images/waning_crescent_5.png +0 -0
  21. setiastro/images/waning_gibbous_1.png +0 -0
  22. setiastro/images/waning_gibbous_2.png +0 -0
  23. setiastro/images/waning_gibbous_3.png +0 -0
  24. setiastro/images/waning_gibbous_4.png +0 -0
  25. setiastro/images/waning_gibbous_5.png +0 -0
  26. setiastro/images/waxing_crescent_1.png +0 -0
  27. setiastro/images/waxing_crescent_2.png +0 -0
  28. setiastro/images/waxing_crescent_3.png +0 -0
  29. setiastro/images/waxing_crescent_4.png +0 -0
  30. setiastro/images/waxing_crescent_5.png +0 -0
  31. setiastro/images/waxing_gibbous_1.png +0 -0
  32. setiastro/images/waxing_gibbous_2.png +0 -0
  33. setiastro/images/waxing_gibbous_3.png +0 -0
  34. setiastro/images/waxing_gibbous_4.png +0 -0
  35. setiastro/images/waxing_gibbous_5.png +0 -0
  36. setiastro/qml/ResourceMonitor.qml +84 -82
  37. setiastro/saspro/__main__.py +20 -1
  38. setiastro/saspro/_generated/build_info.py +2 -2
  39. setiastro/saspro/abe.py +37 -4
  40. setiastro/saspro/aberration_ai.py +364 -33
  41. setiastro/saspro/aberration_ai_preset.py +29 -3
  42. setiastro/saspro/acv_exporter.py +379 -0
  43. setiastro/saspro/add_stars.py +33 -6
  44. setiastro/saspro/astrospike_python.py +45 -3
  45. setiastro/saspro/backgroundneutral.py +108 -40
  46. setiastro/saspro/blemish_blaster.py +4 -1
  47. setiastro/saspro/blink_comparator_pro.py +150 -55
  48. setiastro/saspro/clahe.py +4 -1
  49. setiastro/saspro/continuum_subtract.py +4 -1
  50. setiastro/saspro/convo.py +13 -7
  51. setiastro/saspro/cosmicclarity.py +129 -18
  52. setiastro/saspro/crop_dialog_pro.py +123 -7
  53. setiastro/saspro/curve_editor_pro.py +181 -64
  54. setiastro/saspro/curves_preset.py +249 -47
  55. setiastro/saspro/doc_manager.py +245 -15
  56. setiastro/saspro/exoplanet_detector.py +120 -28
  57. setiastro/saspro/frequency_separation.py +1158 -204
  58. setiastro/saspro/ghs_dialog_pro.py +81 -16
  59. setiastro/saspro/graxpert.py +1 -0
  60. setiastro/saspro/gui/main_window.py +706 -264
  61. setiastro/saspro/gui/mixins/dock_mixin.py +245 -24
  62. setiastro/saspro/gui/mixins/file_mixin.py +35 -16
  63. setiastro/saspro/gui/mixins/menu_mixin.py +35 -1
  64. setiastro/saspro/gui/mixins/theme_mixin.py +160 -14
  65. setiastro/saspro/gui/mixins/toolbar_mixin.py +499 -24
  66. setiastro/saspro/gui/mixins/update_mixin.py +138 -36
  67. setiastro/saspro/gui/mixins/view_mixin.py +42 -0
  68. setiastro/saspro/halobgon.py +4 -0
  69. setiastro/saspro/histogram.py +184 -8
  70. setiastro/saspro/image_combine.py +4 -0
  71. setiastro/saspro/image_peeker_pro.py +4 -0
  72. setiastro/saspro/imageops/narrowband_normalization.py +816 -0
  73. setiastro/saspro/imageops/serloader.py +1345 -0
  74. setiastro/saspro/imageops/starbasedwhitebalance.py +23 -52
  75. setiastro/saspro/imageops/stretch.py +582 -62
  76. setiastro/saspro/isophote.py +4 -0
  77. setiastro/saspro/layers.py +13 -9
  78. setiastro/saspro/layers_dock.py +183 -3
  79. setiastro/saspro/legacy/image_manager.py +154 -20
  80. setiastro/saspro/legacy/numba_utils.py +68 -48
  81. setiastro/saspro/legacy/xisf.py +240 -98
  82. setiastro/saspro/live_stacking.py +203 -82
  83. setiastro/saspro/luminancerecombine.py +228 -27
  84. setiastro/saspro/mask_creation.py +174 -15
  85. setiastro/saspro/mfdeconv.py +113 -35
  86. setiastro/saspro/mfdeconvcudnn.py +119 -70
  87. setiastro/saspro/mfdeconvsport.py +112 -35
  88. setiastro/saspro/morphology.py +4 -0
  89. setiastro/saspro/multiscale_decomp.py +81 -29
  90. setiastro/saspro/narrowband_normalization.py +1618 -0
  91. setiastro/saspro/numba_utils.py +72 -57
  92. setiastro/saspro/ops/commands.py +18 -18
  93. setiastro/saspro/ops/script_editor.py +10 -2
  94. setiastro/saspro/ops/scripts.py +122 -0
  95. setiastro/saspro/perfect_palette_picker.py +37 -3
  96. setiastro/saspro/plate_solver.py +84 -49
  97. setiastro/saspro/psf_viewer.py +119 -37
  98. setiastro/saspro/remove_green.py +1 -1
  99. setiastro/saspro/resources.py +73 -0
  100. setiastro/saspro/rgbalign.py +460 -12
  101. setiastro/saspro/selective_color.py +4 -1
  102. setiastro/saspro/ser_stack_config.py +82 -0
  103. setiastro/saspro/ser_stacker.py +2321 -0
  104. setiastro/saspro/ser_stacker_dialog.py +1838 -0
  105. setiastro/saspro/ser_tracking.py +206 -0
  106. setiastro/saspro/serviewer.py +1625 -0
  107. setiastro/saspro/sfcc.py +662 -216
  108. setiastro/saspro/shortcuts.py +171 -33
  109. setiastro/saspro/signature_insert.py +692 -33
  110. setiastro/saspro/stacking_suite.py +1347 -485
  111. setiastro/saspro/star_alignment.py +247 -123
  112. setiastro/saspro/star_spikes.py +4 -0
  113. setiastro/saspro/star_stretch.py +38 -3
  114. setiastro/saspro/stat_stretch.py +892 -129
  115. setiastro/saspro/subwindow.py +787 -363
  116. setiastro/saspro/supernovaasteroidhunter.py +1 -1
  117. setiastro/saspro/texture_clarity.py +593 -0
  118. setiastro/saspro/wavescale_hdr.py +4 -1
  119. setiastro/saspro/wavescalede.py +4 -1
  120. setiastro/saspro/whitebalance.py +84 -12
  121. setiastro/saspro/widgets/common_utilities.py +28 -21
  122. setiastro/saspro/widgets/resource_monitor.py +209 -111
  123. setiastro/saspro/widgets/spinboxes.py +10 -13
  124. setiastro/saspro/wimi.py +27 -656
  125. setiastro/saspro/wims.py +13 -3
  126. setiastro/saspro/xisf.py +101 -11
  127. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/METADATA +4 -2
  128. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/RECORD +132 -87
  129. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/WHEEL +0 -0
  130. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/entry_points.txt +0 -0
  131. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/licenses/LICENSE +0 -0
  132. {setiastrosuitepro-1.6.4.dist-info → setiastrosuitepro-1.7.1.post2.dist-info}/licenses/license.txt +0 -0
@@ -0,0 +1,206 @@
1
+ # src/setiastro/saspro/ser_tracking.py
2
+ from __future__ import annotations
3
+ import numpy as np
4
+
5
+ try:
6
+ import cv2
7
+ except Exception:
8
+ cv2 = None
9
+
10
+
11
+ def _to_mono01(img: np.ndarray) -> np.ndarray:
12
+ """Convert frame float [0..1] mono/RGB -> mono float32 [0..1]."""
13
+ if img.ndim == 2:
14
+ m = img
15
+ else:
16
+ # simple luma; keep fast
17
+ m = 0.2126 * img[..., 0] + 0.7152 * img[..., 1] + 0.0722 * img[..., 2]
18
+ return np.asarray(m, dtype=np.float32)
19
+
20
+
21
+ class PlanetaryTracker:
22
+ """
23
+ Tracks by centroid of the brightest connected component inside ROI.
24
+ Good for: planets, full disk objects.
25
+ """
26
+ def __init__(self, smooth_sigma: float = 1.5, thresh_pct: float = 92.0):
27
+ self.smooth_sigma = float(smooth_sigma)
28
+ self.thresh_pct = float(thresh_pct)
29
+ self._ref_center = None # (cx, cy)
30
+
31
+ def reset(self):
32
+ self._ref_center = None
33
+
34
+ def _blur(self, m: np.ndarray) -> np.ndarray:
35
+ if cv2 is None:
36
+ return m
37
+ # sigma->ksize
38
+ sigma = max(0.0, self.smooth_sigma)
39
+ if sigma <= 0:
40
+ return m
41
+ k = int(max(3, (sigma * 6) // 2 * 2 + 1))
42
+ return cv2.GaussianBlur(m, (k, k), sigmaX=sigma, sigmaY=sigma)
43
+
44
+ def _largest_component_mask(self, mask: np.ndarray) -> np.ndarray:
45
+ if cv2 is None:
46
+ return mask
47
+ # mask uint8 0/255
48
+ num, labels, stats, _ = cv2.connectedComponentsWithStats(mask, connectivity=8)
49
+ if num <= 1:
50
+ return mask
51
+ # skip background 0
52
+ areas = stats[1:, cv2.CC_STAT_AREA]
53
+ k = 1 + int(np.argmax(areas))
54
+ out = (labels == k).astype(np.uint8) * 255
55
+ return out
56
+
57
+ def _centroid(self, m: np.ndarray, mask: np.ndarray) -> tuple[float, float, float]:
58
+ if cv2 is None:
59
+ # fallback: simple average of mask pixels
60
+ ys, xs = np.nonzero(mask > 0)
61
+ if len(xs) < 10:
62
+ return (0.0, 0.0, 0.0)
63
+ return (float(xs.mean()), float(ys.mean()), 1.0)
64
+
65
+ mm = cv2.moments((mask > 0).astype(np.uint8), binaryImage=True)
66
+ if mm["m00"] <= 0:
67
+ return (0.0, 0.0, 0.0)
68
+ cx = float(mm["m10"] / mm["m00"])
69
+ cy = float(mm["m01"] / mm["m00"])
70
+ # confidence: area fraction
71
+ conf = float(np.clip(mm["m00"] / float(mask.size), 0.0, 1.0))
72
+ return (cx, cy, conf)
73
+
74
+
75
+ def step(self, img01: np.ndarray) -> tuple[float, float, float]:
76
+ """
77
+ Returns (dx, dy, conf) where dx/dy shifts FROM current frame TO reference.
78
+ """
79
+ m = _to_mono01(img01)
80
+ m2 = self._blur(m)
81
+
82
+ # adaptive threshold by percentile
83
+ t = float(np.percentile(m2, self.thresh_pct))
84
+ if not np.isfinite(t):
85
+ return 0.0, 0.0, 0.0
86
+
87
+ mask = (m2 >= t).astype(np.uint8) * 255
88
+ mask = self._largest_component_mask(mask)
89
+
90
+ cx, cy, conf = self._centroid(m2, mask)
91
+ if conf <= 0.0:
92
+ return 0.0, 0.0, 0.0
93
+
94
+ if self._ref_center is None:
95
+ self._ref_center = (cx, cy)
96
+ return 0.0, 0.0, conf
97
+
98
+ rx, ry = self._ref_center
99
+ dx = rx - cx
100
+ dy = ry - cy
101
+ return float(dx), float(dy), conf
102
+
103
+ def compute_center(self, img01: np.ndarray) -> tuple[float, float, float]:
104
+ """
105
+ Compute (cx, cy, conf) in pixels in the provided image coordinate system.
106
+ Uses the same pipeline as step(): blur -> percentile thresh -> largest CC -> centroid.
107
+ """
108
+ m = _to_mono01(img01)
109
+ m2 = self._blur(m)
110
+
111
+ t = float(np.percentile(m2, self.thresh_pct))
112
+ if not np.isfinite(t):
113
+ return 0.0, 0.0, 0.0
114
+
115
+ mask = (m2 >= t).astype(np.uint8) * 255
116
+ mask = self._largest_component_mask(mask)
117
+
118
+ cx, cy, conf = self._centroid(m2, mask)
119
+ return float(cx), float(cy), float(conf)
120
+
121
+ def shift_to_ref(self, img01: np.ndarray, ref_center: tuple[float, float]) -> tuple[float, float, float]:
122
+ """
123
+ Returns (dx, dy, conf) shifting FROM current frame TO the provided reference center.
124
+ """
125
+ cx, cy, conf = self.compute_center(img01)
126
+ if conf <= 0.0:
127
+ return 0.0, 0.0, 0.0
128
+ rx, ry = ref_center
129
+ return float(rx - cx), float(ry - cy), float(conf)
130
+
131
+ class SurfaceTracker:
132
+ """
133
+ Tracks by translation using phase correlation between anchor patch and current patch.
134
+ Good for: lunar/solar/planetary surface close-ups.
135
+ """
136
+ def __init__(self, anchor_patch: np.ndarray, hann_window: bool = True):
137
+ self.ref = np.asarray(anchor_patch, dtype=np.float32)
138
+ self.ref = _to_mono01(self.ref)
139
+ self.hann_window = bool(hann_window)
140
+ self._ref_fft = None
141
+ self._win = None
142
+ self._prep()
143
+
144
+ def _prep(self):
145
+ h, w = self.ref.shape
146
+ if self.hann_window:
147
+ wy = np.hanning(h).astype(np.float32)
148
+ wx = np.hanning(w).astype(np.float32)
149
+ self._win = (wy[:, None] * wx[None, :]).astype(np.float32)
150
+ else:
151
+ self._win = None
152
+
153
+ a = self.ref.copy()
154
+ a -= float(np.mean(a))
155
+ if self._win is not None:
156
+ a *= self._win
157
+ self._ref_fft = np.fft.rfft2(a)
158
+
159
+ def _phase_corr_shift(ref_m: np.ndarray, cur_m: np.ndarray) -> tuple[float, float, float]:
160
+ """
161
+ Returns (dx, dy, response) such that shifting cur by (dx,dy) aligns to ref.
162
+ Uses cv2.phaseCorrelate with mean subtraction + Hann window.
163
+ """
164
+ if cv2 is None:
165
+ return 0.0, 0.0, 0.0
166
+
167
+ ref = ref_m.astype(np.float32, copy=False)
168
+ cur = cur_m.astype(np.float32, copy=False)
169
+
170
+ # stabilize
171
+ ref = ref - float(ref.mean())
172
+ cur = cur - float(cur.mean())
173
+
174
+ # hann window (OpenCV expects float32)
175
+ try:
176
+ win = cv2.createHanningWindow((ref.shape[1], ref.shape[0]), cv2.CV_32F)
177
+ (dx, dy), resp = cv2.phaseCorrelate(ref, cur, win)
178
+ except Exception:
179
+ (dx, dy), resp = cv2.phaseCorrelate(ref, cur)
180
+
181
+ return float(dx), float(dy), float(resp)
182
+
183
+
184
+ @staticmethod
185
+ def _phase_corr(ref_m: np.ndarray, cur_m: np.ndarray) -> tuple[float, float, float]:
186
+ if cv2 is None:
187
+ return 0.0, 0.0, 0.0
188
+
189
+ ref = ref_m.astype(np.float32, copy=False)
190
+ cur = cur_m.astype(np.float32, copy=False)
191
+
192
+ ref = ref - float(ref.mean())
193
+ cur = cur - float(cur.mean())
194
+
195
+ try:
196
+ win = cv2.createHanningWindow((ref.shape[1], ref.shape[0]), cv2.CV_32F)
197
+ (dx, dy), resp = cv2.phaseCorrelate(ref, cur, win)
198
+ except Exception:
199
+ (dx, dy), resp = cv2.phaseCorrelate(ref, cur)
200
+
201
+ return float(dx), float(dy), float(resp)
202
+
203
+ def step(self, cur_patch: np.ndarray) -> tuple[float, float, float]:
204
+ cur = _to_mono01(np.asarray(cur_patch, dtype=np.float32))
205
+ ref = self.ref
206
+ return self._phase_corr(ref, cur)