graxpert 3.2.0a0.dev4__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.
- graxpert/AstroImageRepository.py +114 -0
- graxpert/__init__.py +1 -0
- graxpert/ai_model_handling.py +215 -0
- graxpert/app_state.py +10 -0
- graxpert/application/__init__.py +0 -0
- graxpert/application/app.py +741 -0
- graxpert/application/app_events.py +96 -0
- graxpert/application/eventbus.py +24 -0
- graxpert/astroimage.py +308 -0
- graxpert/background_extraction.py +290 -0
- graxpert/background_flood_selection.py +240 -0
- graxpert/background_grid_selection.py +64 -0
- graxpert/cmdline_tools.py +547 -0
- graxpert/commands.py +200 -0
- graxpert/deconvolution.py +176 -0
- graxpert/denoising.py +178 -0
- graxpert/grid_utils.py +38 -0
- graxpert/img/GraXpert_LOGO_Hauptvariante.png +0 -0
- graxpert/img/Icon.png +0 -0
- graxpert/img/LDN1235_original.jpg +0 -0
- graxpert/img/LDN1235_processed.jpg +0 -0
- graxpert/img/__init__.py +0 -0
- graxpert/img/gfx_numbers.png +0 -0
- graxpert/img/gfx_numbers.svg +737 -0
- graxpert/img/graXpert_Startbadge_Umbriel.png +0 -0
- graxpert/img/hourglass.png +0 -0
- graxpert/locales/__init__.py +0 -0
- graxpert/locales/de_DE/LC_MESSAGES/base.mo +0 -0
- graxpert/localization.py +39 -0
- graxpert/main.py +441 -0
- graxpert/mp_logging.py +97 -0
- graxpert/parallel_processing.py +3 -0
- graxpert/preferences.py +139 -0
- graxpert/radialbasisinterpolation.py +215 -0
- graxpert/resource_utils.py +35 -0
- graxpert/s3_secrets.py +16 -0
- graxpert/skyall.py +152 -0
- graxpert/stretch.py +151 -0
- graxpert/theme/__init__.py +0 -0
- graxpert/theme/graxpert-dark-blue.json +367 -0
- graxpert/ui/__init__.py +1 -0
- graxpert/ui/application_frame.py +115 -0
- graxpert/ui/canvas.py +558 -0
- graxpert/ui/left_menu.py +437 -0
- graxpert/ui/loadingframe.py +142 -0
- graxpert/ui/right_menu.py +315 -0
- graxpert/ui/statusbar.py +102 -0
- graxpert/ui/styling.py +23 -0
- graxpert/ui/tooltip.py +194 -0
- graxpert/ui/ui_events.py +19 -0
- graxpert/ui/widgets.py +297 -0
- graxpert/ui_scaling.py +13 -0
- graxpert/version.py +2 -0
- graxpert-3.2.0a0.dev4.dist-info/METADATA +219 -0
- graxpert-3.2.0a0.dev4.dist-info/RECORD +58 -0
- graxpert-3.2.0a0.dev4.dist-info/WHEEL +5 -0
- graxpert-3.2.0a0.dev4.dist-info/entry_points.txt +2 -0
- graxpert-3.2.0a0.dev4.dist-info/top_level.txt +1 -0
graxpert/preferences.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from dataclasses import asdict, dataclass, field, fields
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import AnyStr, List
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from graxpert.app_state import AppState
|
|
12
|
+
from graxpert.version import version as graxpert_version
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class Prefs:
|
|
17
|
+
working_dir: AnyStr = os.getcwd()
|
|
18
|
+
width: int = None
|
|
19
|
+
height: int = None
|
|
20
|
+
background_points: List = field(default_factory=list)
|
|
21
|
+
bg_flood_selection_option: bool = False
|
|
22
|
+
bg_pts_option: int = 15
|
|
23
|
+
stretch_option: AnyStr = "No Stretch"
|
|
24
|
+
saturation: float = 1.0
|
|
25
|
+
channels_linked_option: bool = False
|
|
26
|
+
images_linked_option: bool = False
|
|
27
|
+
display_pts: bool = True
|
|
28
|
+
bg_tol_option: float = 1.0
|
|
29
|
+
interpol_type_option: AnyStr = "RBF"
|
|
30
|
+
smoothing_option: float = 0.0
|
|
31
|
+
saveas_option: AnyStr = "32 bit Tiff"
|
|
32
|
+
saveas_stretched: bool = False
|
|
33
|
+
sample_size: int = 25
|
|
34
|
+
sample_color: int = 55
|
|
35
|
+
RBF_kernel: AnyStr = "thin_plate"
|
|
36
|
+
spline_order: int = 3
|
|
37
|
+
lang: AnyStr = None
|
|
38
|
+
corr_type: AnyStr = "Subtraction"
|
|
39
|
+
scaling: float = 1.0
|
|
40
|
+
bge_ai_version: AnyStr = None
|
|
41
|
+
deconvolution_type_option: AnyStr = "Object-only"
|
|
42
|
+
deconvolution_object_ai_version: AnyStr = None
|
|
43
|
+
deconvolution_stars_ai_version: AnyStr = None
|
|
44
|
+
denoise_ai_version: AnyStr = None
|
|
45
|
+
graxpert_version: AnyStr = graxpert_version
|
|
46
|
+
deconvolution_strength: float = 0.5
|
|
47
|
+
deconvolution_psfsize: float = 5.0
|
|
48
|
+
denoise_strength: float = 0.5
|
|
49
|
+
ai_batch_size: int = 4
|
|
50
|
+
ai_gpu_acceleration: bool = True
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def app_state_2_prefs(prefs: Prefs, app_state: AppState) -> Prefs:
|
|
54
|
+
prefs.background_points = [p.tolist() for p in app_state.background_points]
|
|
55
|
+
return prefs
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def prefs_2_app_state(prefs: Prefs, app_state: AppState) -> AppState:
|
|
59
|
+
app_state.background_points = [np.array(p) for p in prefs.background_points]
|
|
60
|
+
return app_state
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def merge_json(prefs: Prefs, json) -> Prefs:
|
|
64
|
+
for f in fields(prefs):
|
|
65
|
+
if f.name in json:
|
|
66
|
+
setattr(prefs, f.name, json[f.name])
|
|
67
|
+
return prefs
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def load_preferences(prefs_filename) -> Prefs:
|
|
71
|
+
prefs = Prefs()
|
|
72
|
+
try:
|
|
73
|
+
if os.path.isfile(prefs_filename):
|
|
74
|
+
with open(prefs_filename) as f:
|
|
75
|
+
json_prefs = json.load(f)
|
|
76
|
+
|
|
77
|
+
if "ai_version" in json_prefs:
|
|
78
|
+
logging.warning(f"Obsolete key 'ai_version' found in {prefs_filename}. Renaming it to 'bge_ai_version.")
|
|
79
|
+
json_prefs = {"bge_ai_version" if k == "ai_version" else k: v for k, v in json_prefs.items()}
|
|
80
|
+
|
|
81
|
+
prefs = merge_json(prefs, json_prefs)
|
|
82
|
+
|
|
83
|
+
if not "graxpert_version" in json_prefs: # reset scaling in case we start from GraXpert < 2.1.0
|
|
84
|
+
prefs.scaling = 1.0
|
|
85
|
+
else:
|
|
86
|
+
logging.info("{} appears to be missing. it will be created after program shutdown".format(prefs_filename))
|
|
87
|
+
except:
|
|
88
|
+
logging.exception("could not load preferences.json from {}".format(prefs_filename))
|
|
89
|
+
if os.path.isfile(prefs_filename):
|
|
90
|
+
# make a backup of the old preferences file so we don't loose it
|
|
91
|
+
backup_filename = os.path.join(os.path.dirname(prefs_filename), datetime.now().strftime("%m-%d-%Y_%H-%M-%S_{}".format(os.path.basename(prefs_filename))))
|
|
92
|
+
shutil.copyfile(prefs_filename, backup_filename)
|
|
93
|
+
return prefs
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def save_preferences(prefs_filename, prefs):
|
|
97
|
+
try:
|
|
98
|
+
os.makedirs(os.path.dirname(prefs_filename), exist_ok=True)
|
|
99
|
+
with open(prefs_filename, "w") as f:
|
|
100
|
+
json.dump(asdict(prefs), f)
|
|
101
|
+
except OSError as err:
|
|
102
|
+
logging.exception("error serializing preferences")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def app_state_2_fitsheader(prefs: Prefs, app_state: AppState, fits_header):
|
|
106
|
+
fits_header["INTP-OPT"] = prefs.interpol_type_option
|
|
107
|
+
fits_header["SMOOTH"] = prefs.smoothing_option
|
|
108
|
+
fits_header["CORRTYPE"] = prefs.corr_type
|
|
109
|
+
|
|
110
|
+
if prefs.interpol_type_option == "AI":
|
|
111
|
+
fits_header["BGAI_VER"] = prefs.bge_ai_version
|
|
112
|
+
|
|
113
|
+
if prefs.interpol_type_option != "AI":
|
|
114
|
+
fits_header["SAMPSIZE"] = prefs.sample_size
|
|
115
|
+
fits_header["RBFKRNL"] = prefs.RBF_kernel
|
|
116
|
+
fits_header["SPLNORDR"] = prefs.spline_order
|
|
117
|
+
fits_header["BG-PTS"] = str(list(map(lambda e: e.tolist(), app_state.background_points)))
|
|
118
|
+
|
|
119
|
+
return fits_header
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def fitsheader_2_app_state(prefs: Prefs, app_state: AppState, fits_header):
|
|
123
|
+
if "BG-PTS" in fits_header.keys():
|
|
124
|
+
try:
|
|
125
|
+
app_state.background_points = [np.array(p) for p in json.loads(fits_header["BG-PTS"])]
|
|
126
|
+
except:
|
|
127
|
+
logging.warning("Could not transfer background points from fits header to application state", stack_info=True)
|
|
128
|
+
|
|
129
|
+
if "INTP-OPT" in fits_header.keys():
|
|
130
|
+
prefs.interpol_type_option = fits_header["INTP-OPT"]
|
|
131
|
+
prefs.smoothing_option = fits_header["SMOOTH"]
|
|
132
|
+
prefs.corr_type = fits_header["CORRTYPE"]
|
|
133
|
+
|
|
134
|
+
if fits_header["INTP-OPT"] != "AI":
|
|
135
|
+
prefs.sample_size = fits_header["SAMPSIZE"]
|
|
136
|
+
prefs.RBF_kernel = fits_header["RBFKRNL"]
|
|
137
|
+
prefs.spline_order = fits_header["SPLNORDR"]
|
|
138
|
+
|
|
139
|
+
return app_state
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
if sys.version_info[0] >2:
|
|
3
|
+
unicode = str
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import scipy.spatial
|
|
7
|
+
from scipy.special import xlogy
|
|
8
|
+
import scipy.linalg
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RadialBasisInterpolation:
|
|
12
|
+
"""
|
|
13
|
+
Augmented Radial Basis function interpolation with (optional) polynomial
|
|
14
|
+
augmentation. The construction follows [1] with code borrowed from [2]
|
|
15
|
+
for the kernel (which they call the "function")
|
|
16
|
+
|
|
17
|
+
Inputs
|
|
18
|
+
------
|
|
19
|
+
X (array like)
|
|
20
|
+
(N,ndim) array or (N,) vector of build points
|
|
21
|
+
|
|
22
|
+
f (array like)
|
|
23
|
+
(N,) vector of function values
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--------
|
|
27
|
+
degree [0]
|
|
28
|
+
Use an augmented RBF. Specify the *total* degree fit if given as an
|
|
29
|
+
integer. If given as a matrix, must be (P+1,ndim) shape. This is the
|
|
30
|
+
degree of the augmenting polynomial.
|
|
31
|
+
|
|
32
|
+
kernel : ['gaussian']
|
|
33
|
+
The radial basis kernel, based on the radius, r
|
|
34
|
+
If string:
|
|
35
|
+
'multiquadric': sqrt((r/epsilon)**2 + 1)
|
|
36
|
+
'inverse': 1.0/sqrt((r/epsilon)**2 + 1)
|
|
37
|
+
'gaussian': exp(-(r/epsilon)**2)
|
|
38
|
+
'linear': r
|
|
39
|
+
'cubic': r**3
|
|
40
|
+
'quintic': r**5
|
|
41
|
+
'thin_plate': r**2 * log(r)
|
|
42
|
+
If callable
|
|
43
|
+
must take the arguments (r,epsilon) and ignore epsilon if
|
|
44
|
+
not needed. Tip: If epsilon is not needed, set it to
|
|
45
|
+
0 to avoid trying to optimize it
|
|
46
|
+
If integer:
|
|
47
|
+
Spline of the form: r**kernel if kernel is odd else r**kernel*log(r)
|
|
48
|
+
|
|
49
|
+
epsilon [None]
|
|
50
|
+
Adjustable parameter for some kernels.
|
|
51
|
+
|
|
52
|
+
smooth : float, optional
|
|
53
|
+
Values greater than zero increase the smoothness of the
|
|
54
|
+
approximation. 0 is for interpolation (default). Actually set to
|
|
55
|
+
max(smooth,1e-10 * ||f||) for numerical precision
|
|
56
|
+
|
|
57
|
+
Theory:
|
|
58
|
+
------
|
|
59
|
+
The RBF is based on a radial distance
|
|
60
|
+
|
|
61
|
+
r_j = ||x - x_j|| (1)
|
|
62
|
+
|
|
63
|
+
with the kernel phi(r) and an optional "Agumenting" polynomial of set
|
|
64
|
+
degree. The interpolant is of the form: [1]
|
|
65
|
+
|
|
66
|
+
s(x) = sum_{j=1}^N c_j * phi(r_j) + sum_{k \in P} g_k * p_k (2)
|
|
67
|
+
|
|
68
|
+
where `P` is a polynomial index and `p_k` is the corresponding
|
|
69
|
+
polynomial (e.g. k = {1,2,0} then p_k = x*y^2*z^0).
|
|
70
|
+
|
|
71
|
+
In order to solve for c_j and g_k we enforce
|
|
72
|
+
(a) s(x_j) = f_j for all j (i.e. exact interpolation)
|
|
73
|
+
(b) sum_{j=1}^N c_j*p_k(x_j) = 0 for all k=1,...,N
|
|
74
|
+
|
|
75
|
+
That results in a matrix system:
|
|
76
|
+
____________________________________________________ ___ ___
|
|
77
|
+
| | | | | | |
|
|
78
|
+
| phi(||x_i - x_j||) (N,N) | p_k(x_j) (N,len(K)) | | c | | f |
|
|
79
|
+
| | | | | = | | (3)
|
|
80
|
+
|----------------------------|-----------------------| |---| |---|
|
|
81
|
+
| p_k(x_j).T | 0 | | g | | 0 |
|
|
82
|
+
---------------------------------------------------- --- ---
|
|
83
|
+
|
|
84
|
+
which is then solved. Given c and g, (2) can be used to solve for
|
|
85
|
+
any given x
|
|
86
|
+
|
|
87
|
+
References:
|
|
88
|
+
----------
|
|
89
|
+
[1] G. B. Wright. Radial Basis Function Interpolation: Numerical and
|
|
90
|
+
Analytical Developments. PhD thesis, University of Colorado, 2003.
|
|
91
|
+
|
|
92
|
+
[2] SciPy version 1.1.0
|
|
93
|
+
https://github.com/scipy/scipy/blob/v1.1.0/scipy/interpolate/rbf.py
|
|
94
|
+
|
|
95
|
+
[3] S. Rippa. An algorithm for selecting a good value for the parameter
|
|
96
|
+
c in radial basis function interpolation. Advances in Computational
|
|
97
|
+
Mathematics, 11(2-3):193–210, 1999.
|
|
98
|
+
|
|
99
|
+
[4] J. D. Martin and T. W. Simpson. Use of Kriging Models to Approximate
|
|
100
|
+
Deterministic Computer Models. AIAA journal, 43(4):853–863, 2005.
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
def __init__(self,X,f,degree=0,
|
|
104
|
+
epsilon=1,smooth=0,
|
|
105
|
+
kernel='gaussian',_solve=True):
|
|
106
|
+
self.X = X = np.atleast_2d(X)
|
|
107
|
+
self.N,self.ndim = X.shape
|
|
108
|
+
self.f = f = np.ravel(f)
|
|
109
|
+
self.degree = degree
|
|
110
|
+
self.kernel = kernel
|
|
111
|
+
self.epsilon = epsilon
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
r = scipy.spatial.distance.cdist(X,X)
|
|
115
|
+
|
|
116
|
+
self.smooth = max(float(smooth),1e-10)
|
|
117
|
+
|
|
118
|
+
K = self._kernel(r) + np.eye(self.N)*self.smooth*np.mean(self._kernel(r))
|
|
119
|
+
P = RadialBasisInterpolation.vandermond(X,degree=self.degree)
|
|
120
|
+
|
|
121
|
+
# Build the matrix
|
|
122
|
+
Z = np.zeros([P.shape[1]]*2)
|
|
123
|
+
z = np.zeros(P.shape[1])
|
|
124
|
+
KP = np.block([[K , P],
|
|
125
|
+
[P.T , Z]])
|
|
126
|
+
b = np.hstack([f,z])
|
|
127
|
+
coef = scipy.linalg.solve(KP,b)
|
|
128
|
+
self.rbf_coef = coef[:self.N]
|
|
129
|
+
self.poly_coef = coef[self.N:]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def __call__(self,X):
|
|
133
|
+
X = np.atleast_2d(X)
|
|
134
|
+
step_size = int(10*X.shape[0]/self.X.size + 1)
|
|
135
|
+
i = 0
|
|
136
|
+
|
|
137
|
+
result = np.empty(X.shape[0])
|
|
138
|
+
|
|
139
|
+
while(i < X.shape[0]):
|
|
140
|
+
start = i
|
|
141
|
+
end = np.minimum(i+step_size,X.shape[0])
|
|
142
|
+
K = self._kernel( scipy.spatial.distance.cdist(X[start:end],self.X) )
|
|
143
|
+
P = RadialBasisInterpolation.vandermond(X[start:end],degree=self.degree)
|
|
144
|
+
|
|
145
|
+
result[start:end] = K.dot(self.rbf_coef) + P.dot(self.poly_coef)
|
|
146
|
+
i = i + step_size
|
|
147
|
+
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
def _kernel(self,r):
|
|
151
|
+
r = np.asarray(r)
|
|
152
|
+
if callable(self.kernel):
|
|
153
|
+
return self.kernel(r,self.epsilon)
|
|
154
|
+
elif isinstance(self.kernel,(int,np.integer)):
|
|
155
|
+
if np.mod(self.kernel,2) == 0:
|
|
156
|
+
return xlogy(r**self.kernel,r)
|
|
157
|
+
else:
|
|
158
|
+
return r**self.kernel
|
|
159
|
+
elif not isinstance(self.kernel,(str,unicode)):
|
|
160
|
+
raise ValueError('Kernel must be a callable with signature (r,epsilon), an integer (spline) or a valid string')
|
|
161
|
+
|
|
162
|
+
kernel = self.kernel.lower().replace(' ','_').replace('-','_')
|
|
163
|
+
|
|
164
|
+
if kernel in ['multiquadric']:
|
|
165
|
+
return np.sqrt((r/self.epsilon)**2 + 1)
|
|
166
|
+
elif kernel in ['inverse_multiquadric','inverse']:
|
|
167
|
+
return 1.0/np.sqrt((1.0/self.epsilon*r)**2 + 1)
|
|
168
|
+
elif kernel in ['gaussian','squared_exponential']:
|
|
169
|
+
return np.exp(-(1.0/self.epsilon*r)**2)
|
|
170
|
+
elif kernel in ['linear']:
|
|
171
|
+
return r
|
|
172
|
+
elif kernel in ['cubic']:
|
|
173
|
+
return r**3
|
|
174
|
+
elif kernel in ['quintic']:
|
|
175
|
+
return r**5
|
|
176
|
+
elif kernel in ['thin_plate']:
|
|
177
|
+
return xlogy(r**2, r)
|
|
178
|
+
else:
|
|
179
|
+
raise ValueError('Not valid kernel name')
|
|
180
|
+
|
|
181
|
+
@staticmethod
|
|
182
|
+
def vandermond(X,degree):
|
|
183
|
+
"""
|
|
184
|
+
Return a Vandermond matrix of X up to the
|
|
185
|
+
*total* order degree
|
|
186
|
+
"""
|
|
187
|
+
X = np.atleast_2d(X)
|
|
188
|
+
ndim = X.shape[1]
|
|
189
|
+
index = np.asarray(RadialBasisInterpolation.total_index(degree,ndim),dtype=int)
|
|
190
|
+
V = np.ones([X.shape[0],len(index)])
|
|
191
|
+
for d in range(ndim):
|
|
192
|
+
v = np.fliplr(np.vander(X[:,d],N=degree+1))
|
|
193
|
+
V *= v[:,index[:,d]]
|
|
194
|
+
return V
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def total_index(P,ndim,sort=True):
|
|
199
|
+
P = tuple([P]*ndim)
|
|
200
|
+
curr = [0]*ndim
|
|
201
|
+
ind = []
|
|
202
|
+
ind.append(tuple(curr))
|
|
203
|
+
while True:
|
|
204
|
+
for d in range(ndim):
|
|
205
|
+
if sum(curr) < P[0]:
|
|
206
|
+
curr[d] += 1
|
|
207
|
+
break
|
|
208
|
+
else:
|
|
209
|
+
curr[d] = 0
|
|
210
|
+
else:
|
|
211
|
+
break
|
|
212
|
+
ind.append(tuple(curr))
|
|
213
|
+
if sort:
|
|
214
|
+
ind.sort(key=lambda a:(sum(a),(np.array(a)**2).sum(),a[::-1]))
|
|
215
|
+
return ind
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# from appdirs import
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from tempfile import TemporaryDirectory
|
|
5
|
+
from importlib import resources
|
|
6
|
+
|
|
7
|
+
temp_resource_dir = TemporaryDirectory()
|
|
8
|
+
|
|
9
|
+
def temp_cleanup():
|
|
10
|
+
temp_resource_dir.cleanup()
|
|
11
|
+
|
|
12
|
+
def resource_path(relative_path):
|
|
13
|
+
base_path = os.path.join(os.path.dirname(os.path.dirname(__file__)))
|
|
14
|
+
return os.path.join(base_path, relative_path)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def temp_resource_path(relative_path):
|
|
18
|
+
return os.path.join(temp_resource_dir.name, relative_path)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def resource_bytestream(name, dir = 'img'):
|
|
22
|
+
return resources.files(f'graxpert.{dir}').joinpath(name).open('rb')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def resource_image(name):
|
|
26
|
+
from PIL import Image
|
|
27
|
+
with resources.as_file(resources.files('graxpert.img').joinpath(name)) as file_path:
|
|
28
|
+
return Image.open(file_path)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Unfortunately tk.PhotoImage doesn't accept file-like objects, so we need to use a temporary file
|
|
32
|
+
def resource_photoimage(resource_name):
|
|
33
|
+
import tkinter as tk
|
|
34
|
+
with resources.as_file(resources.files('graxpert.img').joinpath(resource_name)) as file_path:
|
|
35
|
+
return tk.PhotoImage(file=file_path)
|
graxpert/s3_secrets.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Decompiled with PyLingual (https://pylingual.io)
|
|
2
|
+
# Internal filename: /home/runner/work/GraXpert/GraXpert/graxpert/s3_secrets.py
|
|
3
|
+
# Bytecode version: 3.10.0rc2 (3439)
|
|
4
|
+
# Source timestamp: 2024-05-03 17:20:08 UTC (1714756808)
|
|
5
|
+
|
|
6
|
+
endpoint = 'minio.schmelly.de'
|
|
7
|
+
ro_access_key = 'IynFklnoqVLigqvqkBR5'
|
|
8
|
+
ro_secret_key = '1250a0FYS2WlUF78aZk0yoeT5daJQkRsNiIjLlhQ'
|
|
9
|
+
bucket_name = 'graxpert-ai'
|
|
10
|
+
bge_bucket_name = 'graxpert-bge-ai-onnx'
|
|
11
|
+
denoise_bucket_name = 'graxpert-denoise-ai-onnx'
|
|
12
|
+
|
|
13
|
+
deconvolution_object_bucket_name = 'graxpert-deconv-object'
|
|
14
|
+
deconvolution_stars_bucket_name = 'graxpert-deconvolution-stars'
|
|
15
|
+
deconvolution_object_bucket_name = "graxpert-deconvolution-object-ai-onnx"
|
|
16
|
+
deconvolution_stars_bucket_name = "graxpert-deconvolution-stars-ai-onnx"
|
graxpert/skyall.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
Find the mode of a distribution using a route based on the SKYALL as described in
|
|
7
|
+
https://articles.adsabs.harvard.edu//full/1993MNRAS.265..641A/0000643.000.html
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def mode(distribution):
|
|
11
|
+
|
|
12
|
+
# Find appropriate intensity range
|
|
13
|
+
|
|
14
|
+
clip = np.logical_and(distribution > 0.0, distribution < 1.0)
|
|
15
|
+
|
|
16
|
+
median = np.median(distribution[clip])
|
|
17
|
+
|
|
18
|
+
left_of_median = np.where(distribution < median)
|
|
19
|
+
right_of_median = np.where(distribution > median)
|
|
20
|
+
|
|
21
|
+
rms_left = np.sqrt(np.sum((distribution[left_of_median] - median)**2)/distribution.size)
|
|
22
|
+
rms_right= np.sqrt(np.sum((distribution[right_of_median] - median)**2)/distribution.size)
|
|
23
|
+
|
|
24
|
+
rms = np.min([rms_left,rms_right])
|
|
25
|
+
|
|
26
|
+
lower_bound = np.max([0.0, median - 2*rms])
|
|
27
|
+
upper_bound = np.min([1.0, median + 2*rms])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Set initial number of bins
|
|
31
|
+
|
|
32
|
+
num_bins = 8
|
|
33
|
+
histo, bin_edges = np.histogram(distribution, bins=num_bins, range=(lower_bound,upper_bound), density=True)
|
|
34
|
+
|
|
35
|
+
found = False
|
|
36
|
+
iterations = 0
|
|
37
|
+
|
|
38
|
+
while(not found and iterations <= 20):
|
|
39
|
+
|
|
40
|
+
max_bin = np.argmax(histo)
|
|
41
|
+
max_value = histo[max_bin]
|
|
42
|
+
|
|
43
|
+
left_pointer = max_bin
|
|
44
|
+
right_pointer = max_bin
|
|
45
|
+
|
|
46
|
+
while(histo[left_pointer] > max_value/1.75):
|
|
47
|
+
left_pointer = left_pointer - 1
|
|
48
|
+
if(left_pointer < 0):
|
|
49
|
+
left_pointer = 0
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
while(histo[right_pointer] > max_value/1.75):
|
|
53
|
+
right_pointer = right_pointer + 1
|
|
54
|
+
if(right_pointer >= bin_edges.size - 1):
|
|
55
|
+
right_pointer = bin_edges.size - 2
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
if(right_pointer - left_pointer > 5):
|
|
59
|
+
found = True
|
|
60
|
+
|
|
61
|
+
else:
|
|
62
|
+
found = False
|
|
63
|
+
num_bins = int(num_bins * 1.5)
|
|
64
|
+
histo, bin_edges = np.histogram(distribution, bins=num_bins, range=(lower_bound,upper_bound), density=True)
|
|
65
|
+
|
|
66
|
+
iterations = iterations + 1
|
|
67
|
+
|
|
68
|
+
if(iterations > 20):
|
|
69
|
+
logging.debug("More than 20 iterations in second step of SKYALL. Return median instead.")
|
|
70
|
+
return median
|
|
71
|
+
|
|
72
|
+
#print(bin_edges[left_pointer])
|
|
73
|
+
#print(bin_edges[right_pointer])
|
|
74
|
+
lower_bound = (bin_edges[left_pointer] + bin_edges[left_pointer+1])/2
|
|
75
|
+
upper_bound = (bin_edges[right_pointer] + bin_edges[right_pointer+1])/2
|
|
76
|
+
histo, bin_edges = np.histogram(distribution, bins=num_bins, range=(lower_bound,upper_bound), density=True)
|
|
77
|
+
|
|
78
|
+
# Find best fit
|
|
79
|
+
|
|
80
|
+
best_coeff = np.array([0,0,0])
|
|
81
|
+
best_err = -1
|
|
82
|
+
|
|
83
|
+
iterations = 0
|
|
84
|
+
|
|
85
|
+
while(iterations < 20):
|
|
86
|
+
|
|
87
|
+
x = averaged_histo(distribution, bin_edges)
|
|
88
|
+
coeff, err, misc1, misc2, misc3 = np.polyfit(x, histo, deg=2, full=True)
|
|
89
|
+
err = err/x.size
|
|
90
|
+
|
|
91
|
+
if(err < best_err or best_err == -1):
|
|
92
|
+
best_err = err
|
|
93
|
+
best_coeff = coeff
|
|
94
|
+
|
|
95
|
+
if(err > 1.3*best_err and best_err != -1):
|
|
96
|
+
break
|
|
97
|
+
|
|
98
|
+
iterations = iterations + 1
|
|
99
|
+
|
|
100
|
+
if(iterations >= 20):
|
|
101
|
+
|
|
102
|
+
logging.debug("More than 20 iterations in third step of SKYAL. Return median instead.")
|
|
103
|
+
return median
|
|
104
|
+
|
|
105
|
+
num_bins = int(num_bins*1.5)
|
|
106
|
+
histo, bin_edges = np.histogram(distribution, bins=num_bins, range=(lower_bound,upper_bound), density=True)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
mode = -best_coeff[1]/2/best_coeff[0]
|
|
111
|
+
|
|
112
|
+
# Testing
|
|
113
|
+
#plt.hist(distribution.ravel(),50,range=(0.1,0.5), density=True)
|
|
114
|
+
#plt.hist(distribution.ravel(),10,range=(bin_edges[0],bin_edges[-1]), density=True)
|
|
115
|
+
#plt.plot(np.arange(bin_edges[0],bin_edges[-1],0.01), f(np.arange(bin_edges[0],bin_edges[-1],0.01),best_coeff), color="g")
|
|
116
|
+
#plt.axvline(np.mean(distribution), color='r', label="Mean")
|
|
117
|
+
#plt.axvline(np.median(distribution), color='k', label="Median")
|
|
118
|
+
#plt.axvline(mode, color='g', label="Mode")
|
|
119
|
+
#plt.legend()
|
|
120
|
+
#plt.savefig("vergleich.jpg")
|
|
121
|
+
return mode
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def averaged_histo(distribution, bin_edges):
|
|
127
|
+
|
|
128
|
+
x = np.zeros(bin_edges.shape[0]-1)
|
|
129
|
+
|
|
130
|
+
for i in range(x.shape[0]):
|
|
131
|
+
idx = np.logical_and(distribution >= bin_edges[i], distribution < bin_edges[i+1])
|
|
132
|
+
|
|
133
|
+
if(distribution[idx].shape[0] == 0):
|
|
134
|
+
x[i] = (bin_edges[i] + bin_edges[i+1])/2.0
|
|
135
|
+
else:
|
|
136
|
+
x[i] = np.mean(distribution[idx])
|
|
137
|
+
|
|
138
|
+
return x
|
|
139
|
+
|
|
140
|
+
def f(x, coeff):
|
|
141
|
+
return coeff[0]*x**2 + coeff[1]*x + coeff[2]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Testing
|
|
146
|
+
# from skimage import img_as_float32, io
|
|
147
|
+
#y=3100
|
|
148
|
+
#x=483
|
|
149
|
+
#size=25
|
|
150
|
+
#im = img_as_float32(io.imread("../../milchstr.tif")[x-size:x+size,y-size:y+size,0])
|
|
151
|
+
|
|
152
|
+
#mode(im)
|