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
|
@@ -0,0 +1,741 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import tkinter as tk
|
|
4
|
+
from tkinter import messagebox
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from appdirs import user_config_dir
|
|
8
|
+
|
|
9
|
+
from graxpert.ai_model_handling import (
|
|
10
|
+
ai_model_path_from_version,
|
|
11
|
+
bge_ai_models_dir,
|
|
12
|
+
deconvolution_object_ai_models_dir,
|
|
13
|
+
deconvolution_stars_ai_models_dir,
|
|
14
|
+
denoise_ai_models_dir,
|
|
15
|
+
download_version,
|
|
16
|
+
validate_local_version,
|
|
17
|
+
)
|
|
18
|
+
from graxpert.app_state import INITIAL_STATE
|
|
19
|
+
from graxpert.application.app_events import AppEvents
|
|
20
|
+
from graxpert.application.eventbus import eventbus
|
|
21
|
+
from graxpert.astroimage import AstroImage
|
|
22
|
+
from graxpert.AstroImageRepository import AstroImageRepository, ImageTypes
|
|
23
|
+
from graxpert.background_extraction import extract_background
|
|
24
|
+
from graxpert.commands import INIT_HANDLER, RESET_POINTS_HANDLER, RM_POINT_HANDLER, SEL_POINTS_HANDLER, Command
|
|
25
|
+
from graxpert.deconvolution import deconvolve
|
|
26
|
+
from graxpert.denoising import denoise
|
|
27
|
+
from graxpert.localization import _
|
|
28
|
+
from graxpert.mp_logging import logfile_name
|
|
29
|
+
from graxpert.preferences import fitsheader_2_app_state, load_preferences, prefs_2_app_state
|
|
30
|
+
from graxpert.s3_secrets import bge_bucket_name, deconvolution_object_bucket_name, deconvolution_stars_bucket_name, denoise_bucket_name
|
|
31
|
+
from graxpert.stretch import StretchParameters, stretch_all
|
|
32
|
+
from graxpert.ui.loadingframe import DynamicProgressThread
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class GraXpert:
|
|
36
|
+
|
|
37
|
+
def __init__(self):
|
|
38
|
+
self.initialize()
|
|
39
|
+
|
|
40
|
+
def initialize(self):
|
|
41
|
+
# app preferences
|
|
42
|
+
prefs_filename = os.path.join(user_config_dir(appname="GraXpert"), "preferences.json")
|
|
43
|
+
self.prefs = load_preferences(prefs_filename)
|
|
44
|
+
|
|
45
|
+
self.filename = ""
|
|
46
|
+
self.data_type = ""
|
|
47
|
+
|
|
48
|
+
self.images = AstroImageRepository()
|
|
49
|
+
self.display_type = ImageTypes.Original
|
|
50
|
+
|
|
51
|
+
self.mat_affine = np.eye(3)
|
|
52
|
+
|
|
53
|
+
# state handling
|
|
54
|
+
tmp_state = prefs_2_app_state(self.prefs, INITIAL_STATE)
|
|
55
|
+
|
|
56
|
+
self.cmd: Command = Command(INIT_HANDLER, background_points=tmp_state.background_points)
|
|
57
|
+
self.cmd.execute()
|
|
58
|
+
|
|
59
|
+
# image loading
|
|
60
|
+
eventbus.add_listener(AppEvents.OPEN_FILE_DIALOG_REQUEST, self.on_open_file_dialog_request)
|
|
61
|
+
eventbus.add_listener(AppEvents.LOAD_IMAGE_REQUEST, self.on_load_image)
|
|
62
|
+
# image display
|
|
63
|
+
eventbus.add_listener(AppEvents.DISPLAY_TYPE_CHANGED, self.on_display_type_changed)
|
|
64
|
+
# stretch options
|
|
65
|
+
eventbus.add_listener(AppEvents.STRETCH_OPTION_CHANGED, self.on_stretch_option_changed)
|
|
66
|
+
eventbus.add_listener(AppEvents.CHANGE_SATURATION_REQUEST, self.on_change_saturation_request)
|
|
67
|
+
eventbus.add_listener(AppEvents.CHANNELS_LINKED_CHANGED, self.on_channels_linked_option_changed)
|
|
68
|
+
# sample selection
|
|
69
|
+
eventbus.add_listener(AppEvents.DISPLAY_PTS_CHANGED, self.on_display_pts_changed)
|
|
70
|
+
eventbus.add_listener(AppEvents.BG_FLOOD_SELECTION_CHANGED, self.on_bg_floot_selection_changed)
|
|
71
|
+
eventbus.add_listener(AppEvents.BG_PTS_CHANGED, self.on_bg_pts_changed)
|
|
72
|
+
eventbus.add_listener(AppEvents.BG_TOL_CHANGED, self.on_bg_tol_changed)
|
|
73
|
+
eventbus.add_listener(AppEvents.CREATE_GRID_REQUEST, self.on_create_grid_request)
|
|
74
|
+
eventbus.add_listener(AppEvents.RESET_POITS_REQUEST, self.on_reset_points_request)
|
|
75
|
+
# calculation
|
|
76
|
+
eventbus.add_listener(AppEvents.INTERPOL_TYPE_CHANGED, self.on_interpol_type_changed)
|
|
77
|
+
eventbus.add_listener(AppEvents.SMOTTHING_CHANGED, self.on_smoothing_changed)
|
|
78
|
+
eventbus.add_listener(AppEvents.CALCULATE_REQUEST, self.on_calculate_request)
|
|
79
|
+
# deconvolution
|
|
80
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_TYPE_CHANGED, self.on_deconvolution_type_changed)
|
|
81
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_STRENGTH_CHANGED, self.on_deconvolution_strength_changed)
|
|
82
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_PSFSIZE_CHANGED, self.on_deconvolution_psfsize_changed)
|
|
83
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_REQUEST, self.on_deconvolution_request)
|
|
84
|
+
# denoising
|
|
85
|
+
eventbus.add_listener(AppEvents.DENOISE_STRENGTH_CHANGED, self.on_denoise_strength_changed)
|
|
86
|
+
eventbus.add_listener(AppEvents.DENOISE_REQUEST, self.on_denoise_request)
|
|
87
|
+
# saving
|
|
88
|
+
eventbus.add_listener(AppEvents.SAVE_AS_CHANGED, self.on_save_as_changed)
|
|
89
|
+
eventbus.add_listener(AppEvents.SAVE_STRETCHED_CHANGED, self.on_save_stretched_changed)
|
|
90
|
+
eventbus.add_listener(AppEvents.SAVE_REQUEST, self.on_save_request)
|
|
91
|
+
# advanced settings
|
|
92
|
+
eventbus.add_listener(AppEvents.SAMPLE_SIZE_CHANGED, self.on_sample_size_changed)
|
|
93
|
+
eventbus.add_listener(AppEvents.SAMPLE_COLOR_CHANGED, self.on_sample_color_changed)
|
|
94
|
+
eventbus.add_listener(AppEvents.RBF_KERNEL_CHANGED, self.on_rbf_kernel_changed)
|
|
95
|
+
eventbus.add_listener(AppEvents.SPLINE_ORDER_CHANGED, self.on_spline_order_changed)
|
|
96
|
+
eventbus.add_listener(AppEvents.CORRECTION_TYPE_CHANGED, self.on_correction_type_changed)
|
|
97
|
+
eventbus.add_listener(AppEvents.LANGUAGE_CHANGED, self.on_language_selected)
|
|
98
|
+
eventbus.add_listener(AppEvents.BGE_AI_VERSION_CHANGED, self.on_bge_ai_version_changed)
|
|
99
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_OBJECT_AI_VERSION_CHANGED, self.on_deconvolution_object_ai_version_changed)
|
|
100
|
+
eventbus.add_listener(AppEvents.DECONVOLUTION_STARS_AI_VERSION_CHANGED, self.on_deconvolution_stars_ai_version_changed)
|
|
101
|
+
eventbus.add_listener(AppEvents.DENOISE_AI_VERSION_CHANGED, self.on_denoise_ai_version_changed)
|
|
102
|
+
eventbus.add_listener(AppEvents.SCALING_CHANGED, self.on_scaling_changed)
|
|
103
|
+
eventbus.add_listener(AppEvents.AI_BATCH_SIZE_CHANGED, self.on_ai_batch_size_changed)
|
|
104
|
+
eventbus.add_listener(AppEvents.AI_GPU_ACCELERATION_CHANGED, self.on_ai_gpu_acceleration_changed)
|
|
105
|
+
|
|
106
|
+
# event handling
|
|
107
|
+
def on_ai_batch_size_changed(self, event):
|
|
108
|
+
self.prefs.ai_batch_size = event["ai_batch_size"]
|
|
109
|
+
|
|
110
|
+
def on_ai_gpu_acceleration_changed(self, event):
|
|
111
|
+
self.prefs.ai_gpu_acceleration = event["ai_gpu_acceleration"]
|
|
112
|
+
|
|
113
|
+
def on_bge_ai_version_changed(self, event):
|
|
114
|
+
self.prefs.bge_ai_version = event["bge_ai_version"]
|
|
115
|
+
|
|
116
|
+
def on_bg_floot_selection_changed(self, event):
|
|
117
|
+
self.prefs.bg_flood_selection_option = event["bg_flood_selection_option"]
|
|
118
|
+
|
|
119
|
+
def on_bg_pts_changed(self, event):
|
|
120
|
+
self.prefs.bg_pts_option = event["bg_pts_option"]
|
|
121
|
+
|
|
122
|
+
def on_bg_tol_changed(self, event):
|
|
123
|
+
self.prefs.bg_tol_option = event["bg_tol_option"]
|
|
124
|
+
|
|
125
|
+
def on_calculate_request(self, event=None):
|
|
126
|
+
if self.images.get(ImageTypes.Original) is None:
|
|
127
|
+
messagebox.showerror("Error", _("Please load your picture first."))
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
background_points = self.cmd.app_state.background_points
|
|
131
|
+
|
|
132
|
+
# Error messages if not enough points
|
|
133
|
+
if len(background_points) == 0 and self.prefs.interpol_type_option != "AI":
|
|
134
|
+
messagebox.showerror("Error", _("Please select background points with left click."))
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
if len(background_points) < 2 and self.prefs.interpol_type_option == "Kriging":
|
|
138
|
+
messagebox.showerror("Error", _("Please select at least 2 background points with left click for the Kriging method."))
|
|
139
|
+
return
|
|
140
|
+
|
|
141
|
+
if len(background_points) < 16 and self.prefs.interpol_type_option == "Splines":
|
|
142
|
+
messagebox.showerror("Error", _("Please select at least 16 background points with left click for the Splines method."))
|
|
143
|
+
return
|
|
144
|
+
|
|
145
|
+
if self.prefs.interpol_type_option == "AI":
|
|
146
|
+
if not self.validate_bge_ai_installation():
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
eventbus.emit(AppEvents.CALCULATE_BEGIN)
|
|
150
|
+
|
|
151
|
+
progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p}))
|
|
152
|
+
|
|
153
|
+
downscale_factor = 1
|
|
154
|
+
|
|
155
|
+
if self.prefs.interpol_type_option == "Kriging" or self.prefs.interpol_type_option == "RBF":
|
|
156
|
+
downscale_factor = 4
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
self.prefs.images_linked_option = False
|
|
160
|
+
|
|
161
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Original).img_array)
|
|
162
|
+
|
|
163
|
+
background = AstroImage()
|
|
164
|
+
background.set_from_array(
|
|
165
|
+
extract_background(
|
|
166
|
+
img_array_to_be_processed,
|
|
167
|
+
np.array(background_points),
|
|
168
|
+
self.prefs.interpol_type_option,
|
|
169
|
+
self.prefs.smoothing_option,
|
|
170
|
+
downscale_factor,
|
|
171
|
+
self.prefs.sample_size,
|
|
172
|
+
self.prefs.RBF_kernel,
|
|
173
|
+
self.prefs.spline_order,
|
|
174
|
+
self.prefs.corr_type,
|
|
175
|
+
ai_model_path_from_version(bge_ai_models_dir, self.prefs.bge_ai_version),
|
|
176
|
+
progress,
|
|
177
|
+
self.prefs.ai_gpu_acceleration,
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
gradient_corrected = AstroImage()
|
|
182
|
+
gradient_corrected.set_from_array(img_array_to_be_processed)
|
|
183
|
+
|
|
184
|
+
# Update fits header and metadata
|
|
185
|
+
background_mean = np.mean(background.img_array)
|
|
186
|
+
gradient_corrected.update_fits_header(self.images.get(ImageTypes.Original).fits_header, background_mean, self.prefs, self.cmd.app_state)
|
|
187
|
+
gradient_corrected.update_fits_header(self.images.get(ImageTypes.Original).fits_header, background_mean, self.prefs, self.cmd.app_state)
|
|
188
|
+
|
|
189
|
+
gradient_corrected.copy_metadata(self.images.get(ImageTypes.Original))
|
|
190
|
+
background.copy_metadata(self.images.get(ImageTypes.Original))
|
|
191
|
+
|
|
192
|
+
self.images.set(ImageTypes.Gradient_Corrected, gradient_corrected)
|
|
193
|
+
self.images.set(ImageTypes.Background, background)
|
|
194
|
+
|
|
195
|
+
self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option), self.prefs.saturation)
|
|
196
|
+
|
|
197
|
+
eventbus.emit(AppEvents.CALCULATE_SUCCESS)
|
|
198
|
+
eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Gradient-Corrected"})
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
logging.exception(e)
|
|
202
|
+
eventbus.emit(AppEvents.CALCULATE_ERROR)
|
|
203
|
+
messagebox.showerror("Error", _("An error occured during background calculation. Please see the log at {}.".format(logfile_name)))
|
|
204
|
+
finally:
|
|
205
|
+
progress.done_progress()
|
|
206
|
+
eventbus.emit(AppEvents.CALCULATE_END)
|
|
207
|
+
|
|
208
|
+
def on_change_saturation_request(self, event):
|
|
209
|
+
if self.images.get(ImageTypes.Original) is None:
|
|
210
|
+
return
|
|
211
|
+
|
|
212
|
+
self.prefs.saturation = event["saturation"]
|
|
213
|
+
|
|
214
|
+
eventbus.emit(AppEvents.CHANGE_SATURATION_BEGIN)
|
|
215
|
+
|
|
216
|
+
self.images.update_saturation(self.prefs.saturation)
|
|
217
|
+
|
|
218
|
+
eventbus.emit(AppEvents.CHANGE_SATURATION_END)
|
|
219
|
+
|
|
220
|
+
def on_correction_type_changed(self, event):
|
|
221
|
+
self.prefs.corr_type = event["corr_type"]
|
|
222
|
+
|
|
223
|
+
def on_create_grid_request(self, event=None):
|
|
224
|
+
if self.images.get(ImageTypes.Original) is None:
|
|
225
|
+
messagebox.showerror("Error", _("Please load your picture first."))
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
eventbus.emit(AppEvents.CREATE_GRID_BEGIN)
|
|
229
|
+
|
|
230
|
+
self.cmd = Command(
|
|
231
|
+
SEL_POINTS_HANDLER, self.cmd, data=self.images.get(ImageTypes.Original).img_array, num_pts=self.prefs.bg_pts_option, tol=self.prefs.bg_tol_option, sample_size=self.prefs.sample_size
|
|
232
|
+
)
|
|
233
|
+
self.cmd.execute()
|
|
234
|
+
|
|
235
|
+
eventbus.emit(AppEvents.CREATE_GRID_END)
|
|
236
|
+
|
|
237
|
+
def on_deconvolution_type_changed(self, event):
|
|
238
|
+
self.prefs.deconvolution_type_option = event["deconvolution_type_option"]
|
|
239
|
+
|
|
240
|
+
def on_deconvolution_strength_changed(self, event):
|
|
241
|
+
self.prefs.deconvolution_strength = event["deconvolution_strength"]
|
|
242
|
+
|
|
243
|
+
def on_deconvolution_psfsize_changed(self, event):
|
|
244
|
+
self.prefs.deconvolution_psfsize = event["deconvolution_psfsize"]
|
|
245
|
+
|
|
246
|
+
def on_deconvolution_object_ai_version_changed(self, event):
|
|
247
|
+
self.prefs.deconvolution_object_ai_version = event["deconvolution_object_ai_version"]
|
|
248
|
+
|
|
249
|
+
def on_deconvolution_stars_ai_version_changed(self, event):
|
|
250
|
+
self.prefs.deconvolution_stars_ai_version = event["deconvolution_stars_ai_version"]
|
|
251
|
+
|
|
252
|
+
def on_deconvolution_request(self, event):
|
|
253
|
+
if self.images.get(ImageTypes.Original) is None:
|
|
254
|
+
messagebox.showerror("Error", _("Please load your picture first."))
|
|
255
|
+
return
|
|
256
|
+
|
|
257
|
+
if not self.validate_deconvolution_ai_installation():
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
eventbus.emit(AppEvents.DECONVOLUTION_BEGIN)
|
|
261
|
+
|
|
262
|
+
progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DECONVOLUTION_PROGRESS, {"progress": p}))
|
|
263
|
+
|
|
264
|
+
deconvolution_type_option = self.prefs.deconvolution_type_option
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Original).img_array)
|
|
268
|
+
if self.images.get(ImageTypes.Gradient_Corrected) is not None:
|
|
269
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Gradient_Corrected).img_array)
|
|
270
|
+
|
|
271
|
+
self.prefs.images_linked_option = True
|
|
272
|
+
|
|
273
|
+
if deconvolution_type_option == "Object-only":
|
|
274
|
+
ai_model_path = ai_model_path_from_version(deconvolution_object_ai_models_dir, self.prefs.deconvolution_object_ai_version)
|
|
275
|
+
else:
|
|
276
|
+
ai_model_path = ai_model_path_from_version(deconvolution_stars_ai_models_dir, self.prefs.deconvolution_stars_ai_version)
|
|
277
|
+
imarray = deconvolve(
|
|
278
|
+
img_array_to_be_processed,
|
|
279
|
+
ai_model_path,
|
|
280
|
+
self.prefs.deconvolution_strength,
|
|
281
|
+
self.prefs.deconvolution_psfsize,
|
|
282
|
+
batch_size=self.prefs.ai_batch_size,
|
|
283
|
+
progress=progress,
|
|
284
|
+
ai_gpu_acceleration=self.prefs.ai_gpu_acceleration,
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if imarray is not None:
|
|
288
|
+
|
|
289
|
+
deconvolved = AstroImage()
|
|
290
|
+
deconvolved.set_from_array(imarray)
|
|
291
|
+
|
|
292
|
+
# Update fits header and metadata
|
|
293
|
+
background_mean = np.mean(self.images.get(ImageTypes.Original).img_array)
|
|
294
|
+
deconvolved.update_fits_header(self.images.get(ImageTypes.Original).fits_header, background_mean, self.prefs, self.cmd.app_state)
|
|
295
|
+
|
|
296
|
+
deconvolved.copy_metadata(self.images.get(ImageTypes.Original))
|
|
297
|
+
|
|
298
|
+
self.images.set(f"Deconvolved {deconvolution_type_option}", deconvolved)
|
|
299
|
+
|
|
300
|
+
self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation)
|
|
301
|
+
|
|
302
|
+
eventbus.emit(AppEvents.DECONVOLUTION_SUCCESS, {"deconvolution_type_option": f"Deconvolved {deconvolution_type_option}"})
|
|
303
|
+
eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": f"Deconvolved {deconvolution_type_option}"})
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
logging.exception(e)
|
|
307
|
+
eventbus.emit(AppEvents.DECONVOLUTION_ERROR)
|
|
308
|
+
messagebox.showerror("Error", _("An error occured during deconvolution. Please see the log at {}.".format(logfile_name)))
|
|
309
|
+
finally:
|
|
310
|
+
progress.done_progress()
|
|
311
|
+
eventbus.emit(AppEvents.DECONVOLUTION_END)
|
|
312
|
+
|
|
313
|
+
def on_denoise_ai_version_changed(self, event):
|
|
314
|
+
self.prefs.denoise_ai_version = event["denoise_ai_version"]
|
|
315
|
+
|
|
316
|
+
def on_display_pts_changed(self, event):
|
|
317
|
+
self.prefs.display_pts = event["display_pts"]
|
|
318
|
+
eventbus.emit(AppEvents.REDRAW_POINTS_REQUEST)
|
|
319
|
+
|
|
320
|
+
def on_display_type_changed(self, event):
|
|
321
|
+
self.display_type = event["display_type"]
|
|
322
|
+
|
|
323
|
+
eventbus.emit(AppEvents.STRETCH_IMAGE_END)
|
|
324
|
+
|
|
325
|
+
def on_interpol_type_changed(self, event):
|
|
326
|
+
self.prefs.interpol_type_option = event["interpol_type_option"]
|
|
327
|
+
|
|
328
|
+
def on_language_selected(self, event):
|
|
329
|
+
self.prefs.lang = event["lang"]
|
|
330
|
+
messagebox.showerror("", _("Please restart the program to change the language."))
|
|
331
|
+
|
|
332
|
+
def on_load_image(self, event):
|
|
333
|
+
eventbus.emit(AppEvents.LOAD_IMAGE_BEGIN)
|
|
334
|
+
filename = event["filename"]
|
|
335
|
+
self.display_type = ImageTypes.Original
|
|
336
|
+
|
|
337
|
+
try:
|
|
338
|
+
image = AstroImage()
|
|
339
|
+
image.set_from_file(filename, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option), self.prefs.saturation)
|
|
340
|
+
|
|
341
|
+
except Exception as e:
|
|
342
|
+
eventbus.emit(AppEvents.LOAD_IMAGE_ERROR)
|
|
343
|
+
msg = _("An error occurred while loading your picture.")
|
|
344
|
+
logging.exception(msg)
|
|
345
|
+
messagebox.showerror("Error", _(msg))
|
|
346
|
+
return
|
|
347
|
+
|
|
348
|
+
self.filename = os.path.splitext(os.path.basename(filename))[0]
|
|
349
|
+
|
|
350
|
+
self.data_type = os.path.splitext(filename)[1]
|
|
351
|
+
self.images.reset()
|
|
352
|
+
self.images.set(ImageTypes.Original, image)
|
|
353
|
+
self.prefs.working_dir = os.path.dirname(filename)
|
|
354
|
+
|
|
355
|
+
os.chdir(os.path.dirname(filename))
|
|
356
|
+
|
|
357
|
+
width = self.images.get(ImageTypes.Original).img_display.width
|
|
358
|
+
height = self.images.get(ImageTypes.Original).img_display.height
|
|
359
|
+
|
|
360
|
+
if self.prefs.width != width or self.prefs.height != height:
|
|
361
|
+
self.reset_backgroundpts()
|
|
362
|
+
|
|
363
|
+
self.prefs.width = width
|
|
364
|
+
self.prefs.height = height
|
|
365
|
+
|
|
366
|
+
tmp_state = fitsheader_2_app_state(self, self.cmd.app_state, self.images.get(ImageTypes.Original).fits_header)
|
|
367
|
+
self.cmd: Command = Command(INIT_HANDLER, background_points=tmp_state.background_points)
|
|
368
|
+
self.cmd.execute()
|
|
369
|
+
|
|
370
|
+
eventbus.emit(AppEvents.LOAD_IMAGE_END, {"filename": filename})
|
|
371
|
+
|
|
372
|
+
def on_open_file_dialog_request(self, evet):
|
|
373
|
+
if self.prefs.working_dir != "" and os.path.exists(self.prefs.working_dir):
|
|
374
|
+
initialdir = self.prefs.working_dir
|
|
375
|
+
else:
|
|
376
|
+
initialdir = os.getcwd()
|
|
377
|
+
|
|
378
|
+
filename = tk.filedialog.askopenfilename(
|
|
379
|
+
filetypes=[
|
|
380
|
+
("Image file", ".bmp .png .jpg .jpeg .tif .tiff .fit .fits .fts .xisf"),
|
|
381
|
+
("Bitmap", ".bmp"),
|
|
382
|
+
("PNG", ".png"),
|
|
383
|
+
("JPEG", ".jpg .jpeg"),
|
|
384
|
+
("Tiff", ".tif .tiff"),
|
|
385
|
+
("Fits", ".fit .fits .fts"),
|
|
386
|
+
("XISF", ".xisf"),
|
|
387
|
+
],
|
|
388
|
+
initialdir=initialdir,
|
|
389
|
+
)
|
|
390
|
+
|
|
391
|
+
if filename == "":
|
|
392
|
+
return
|
|
393
|
+
|
|
394
|
+
eventbus.emit(AppEvents.LOAD_IMAGE_REQUEST, {"filename": filename})
|
|
395
|
+
|
|
396
|
+
def on_rbf_kernel_changed(self, event):
|
|
397
|
+
self.prefs.RBF_kernel = event["RBF_kernel"]
|
|
398
|
+
|
|
399
|
+
def on_reset_points_request(self, event):
|
|
400
|
+
eventbus.emit(AppEvents.RESET_POITS_BEGIN)
|
|
401
|
+
|
|
402
|
+
if len(self.cmd.app_state.background_points) > 0:
|
|
403
|
+
self.cmd = Command(RESET_POINTS_HANDLER, self.cmd)
|
|
404
|
+
self.cmd.execute()
|
|
405
|
+
|
|
406
|
+
eventbus.emit(AppEvents.RESET_POITS_END)
|
|
407
|
+
|
|
408
|
+
def on_sample_color_changed(self, event):
|
|
409
|
+
self.prefs.sample_color = event["sample_color"]
|
|
410
|
+
eventbus.emit(AppEvents.REDRAW_POINTS_REQUEST)
|
|
411
|
+
|
|
412
|
+
def on_sample_size_changed(self, event):
|
|
413
|
+
self.prefs.sample_size = event["sample_size"]
|
|
414
|
+
eventbus.emit(AppEvents.REDRAW_POINTS_REQUEST)
|
|
415
|
+
|
|
416
|
+
def on_save_as_changed(self, event):
|
|
417
|
+
self.prefs.saveas_option = event["saveas_option"]
|
|
418
|
+
|
|
419
|
+
def on_save_stretched_changed(self, event):
|
|
420
|
+
self.prefs.saveas_stretched = event["saveas_stretched"]
|
|
421
|
+
|
|
422
|
+
def on_smoothing_changed(self, event):
|
|
423
|
+
self.prefs.smoothing_option = event["smoothing_option"]
|
|
424
|
+
|
|
425
|
+
def on_denoise_strength_changed(self, event):
|
|
426
|
+
self.prefs.denoise_strength = event["denoise_strength"]
|
|
427
|
+
|
|
428
|
+
def on_denoise_request(self, event):
|
|
429
|
+
if self.images.get(ImageTypes.Original) is None:
|
|
430
|
+
messagebox.showerror("Error", _("Please load your picture first."))
|
|
431
|
+
return
|
|
432
|
+
|
|
433
|
+
if not self.validate_denoise_ai_installation():
|
|
434
|
+
return
|
|
435
|
+
|
|
436
|
+
eventbus.emit(AppEvents.DENOISE_BEGIN)
|
|
437
|
+
|
|
438
|
+
progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p}))
|
|
439
|
+
|
|
440
|
+
try:
|
|
441
|
+
|
|
442
|
+
if self.images.get(ImageTypes.Deconvolved_Object_only) is not None:
|
|
443
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Deconvolved_Object_only).img_array)
|
|
444
|
+
elif self.images.get(ImageTypes.Gradient_Corrected) is not None:
|
|
445
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Gradient_Corrected).img_array)
|
|
446
|
+
else:
|
|
447
|
+
img_array_to_be_processed = np.copy(self.images.get(ImageTypes.Original).img_array)
|
|
448
|
+
|
|
449
|
+
self.prefs.images_linked_option = True
|
|
450
|
+
ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version)
|
|
451
|
+
imarray = denoise(
|
|
452
|
+
img_array_to_be_processed,
|
|
453
|
+
ai_model_path,
|
|
454
|
+
self.prefs.denoise_strength,
|
|
455
|
+
batch_size=self.prefs.ai_batch_size,
|
|
456
|
+
progress=progress,
|
|
457
|
+
ai_gpu_acceleration=self.prefs.ai_gpu_acceleration,
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
if imarray is not None:
|
|
461
|
+
|
|
462
|
+
denoised = AstroImage()
|
|
463
|
+
denoised.set_from_array(imarray)
|
|
464
|
+
|
|
465
|
+
# Update fits header and metadata
|
|
466
|
+
background_mean = np.mean(self.images.get(ImageTypes.Original).img_array)
|
|
467
|
+
denoised.update_fits_header(self.images.get(ImageTypes.Original).fits_header, background_mean, self.prefs, self.cmd.app_state)
|
|
468
|
+
|
|
469
|
+
denoised.copy_metadata(self.images.get(ImageTypes.Original))
|
|
470
|
+
|
|
471
|
+
self.images.set(ImageTypes.Denoised, denoised)
|
|
472
|
+
|
|
473
|
+
self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation)
|
|
474
|
+
|
|
475
|
+
eventbus.emit(AppEvents.DENOISE_SUCCESS)
|
|
476
|
+
eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Denoised"})
|
|
477
|
+
|
|
478
|
+
except Exception as e:
|
|
479
|
+
logging.exception(e)
|
|
480
|
+
eventbus.emit(AppEvents.DENOISE_ERROR)
|
|
481
|
+
messagebox.showerror("Error", _("An error occured during denoising. Please see the log at {}.".format(logfile_name)))
|
|
482
|
+
finally:
|
|
483
|
+
progress.done_progress()
|
|
484
|
+
eventbus.emit(AppEvents.DENOISE_END)
|
|
485
|
+
|
|
486
|
+
def on_save_request(self, event):
|
|
487
|
+
|
|
488
|
+
suffix_1 = "_graxpert"
|
|
489
|
+
|
|
490
|
+
match self.display_type:
|
|
491
|
+
case ImageTypes.Gradient_Corrected:
|
|
492
|
+
suffix_2 = "_bge"
|
|
493
|
+
case ImageTypes.Background:
|
|
494
|
+
suffix_2 = "_background"
|
|
495
|
+
case ImageTypes.Deconvolved_Object_only:
|
|
496
|
+
suffix_2 = "_obj_decon"
|
|
497
|
+
case ImageTypes.Deconvolved_Stars_only:
|
|
498
|
+
suffix_2 = "_stars_decon"
|
|
499
|
+
case ImageTypes.Denoised:
|
|
500
|
+
suffix_2 = "_denoised"
|
|
501
|
+
case _:
|
|
502
|
+
suffix_2 = ""
|
|
503
|
+
|
|
504
|
+
match self.prefs.saveas_stretched:
|
|
505
|
+
case True:
|
|
506
|
+
suffix_3 = "_stretched"
|
|
507
|
+
case _:
|
|
508
|
+
suffix_3 = ""
|
|
509
|
+
|
|
510
|
+
if self.prefs.saveas_option == "16 bit Tiff" or self.prefs.saveas_option == "32 bit Tiff":
|
|
511
|
+
dir = tk.filedialog.asksaveasfilename(
|
|
512
|
+
initialfile=self.filename + f"{suffix_1}{suffix_2}{suffix_3}.tiff", filetypes=[("Tiff", ".tiff")], defaultextension=".tiff", initialdir=self.prefs.working_dir
|
|
513
|
+
)
|
|
514
|
+
elif self.prefs.saveas_option == "16 bit XISF" or self.prefs.saveas_option == "32 bit XISF":
|
|
515
|
+
dir = tk.filedialog.asksaveasfilename(
|
|
516
|
+
initialfile=self.filename + f"{suffix_1}{suffix_2}{suffix_3}.xisf", filetypes=[("XISF", ".xisf")], defaultextension=".xisf", initialdir=self.prefs.working_dir
|
|
517
|
+
)
|
|
518
|
+
else:
|
|
519
|
+
dir = tk.filedialog.asksaveasfilename(
|
|
520
|
+
initialfile=self.filename + f"{suffix_1}{suffix_2}{suffix_3}.fits", filetypes=[("Fits", ".fits")], defaultextension=".fits", initialdir=self.prefs.working_dir
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
if dir == "":
|
|
524
|
+
return
|
|
525
|
+
|
|
526
|
+
eventbus.emit(AppEvents.SAVE_BEGIN)
|
|
527
|
+
|
|
528
|
+
try:
|
|
529
|
+
if self.prefs.saveas_stretched:
|
|
530
|
+
self.images.get(self.display_type).save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option))
|
|
531
|
+
else:
|
|
532
|
+
self.images.get(self.display_type).save(dir, self.prefs.saveas_option)
|
|
533
|
+
|
|
534
|
+
except Exception as e:
|
|
535
|
+
logging.exception(e)
|
|
536
|
+
eventbus.emit(AppEvents.SAVE_ERROR)
|
|
537
|
+
messagebox.showerror("Error", _("Error occured when saving the image."))
|
|
538
|
+
|
|
539
|
+
eventbus.emit(AppEvents.SAVE_END)
|
|
540
|
+
|
|
541
|
+
def on_scaling_changed(self, event):
|
|
542
|
+
self.prefs.scaling = event["scaling"]
|
|
543
|
+
|
|
544
|
+
def on_spline_order_changed(self, event):
|
|
545
|
+
self.prefs.spline_order = event["spline_order"]
|
|
546
|
+
|
|
547
|
+
def on_stretch_option_changed(self, event):
|
|
548
|
+
self.prefs.stretch_option = event["stretch_option"]
|
|
549
|
+
self.do_stretch()
|
|
550
|
+
|
|
551
|
+
def on_channels_linked_option_changed(self, event):
|
|
552
|
+
self.prefs.channels_linked_option = event["channels_linked"]
|
|
553
|
+
self.do_stretch()
|
|
554
|
+
|
|
555
|
+
# application logic
|
|
556
|
+
def do_stretch(self):
|
|
557
|
+
eventbus.emit(AppEvents.STRETCH_IMAGE_BEGIN)
|
|
558
|
+
|
|
559
|
+
try:
|
|
560
|
+
self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation)
|
|
561
|
+
except Exception as e:
|
|
562
|
+
eventbus.emit(AppEvents.STRETCH_IMAGE_ERROR)
|
|
563
|
+
logging.exception(e)
|
|
564
|
+
|
|
565
|
+
eventbus.emit(AppEvents.STRETCH_IMAGE_END)
|
|
566
|
+
|
|
567
|
+
def remove_pt(self, event):
|
|
568
|
+
if len(self.cmd.app_state.background_points) == 0 or not self.prefs.display_pts:
|
|
569
|
+
return False
|
|
570
|
+
|
|
571
|
+
point_im = self.to_image_point(event.x, event.y)
|
|
572
|
+
if len(point_im) == 0:
|
|
573
|
+
return False
|
|
574
|
+
|
|
575
|
+
eventx_im = point_im[0]
|
|
576
|
+
eventy_im = point_im[1]
|
|
577
|
+
|
|
578
|
+
background_points = self.cmd.app_state.background_points
|
|
579
|
+
|
|
580
|
+
min_idx = -1
|
|
581
|
+
min_dist = -1
|
|
582
|
+
|
|
583
|
+
for i in range(len(background_points)):
|
|
584
|
+
x_im = background_points[i][0]
|
|
585
|
+
y_im = background_points[i][1]
|
|
586
|
+
|
|
587
|
+
dist = np.max(np.abs([x_im - eventx_im, y_im - eventy_im]))
|
|
588
|
+
|
|
589
|
+
if min_idx == -1 or dist < min_dist:
|
|
590
|
+
min_dist = dist
|
|
591
|
+
min_idx = i
|
|
592
|
+
|
|
593
|
+
if min_idx != -1 and min_dist <= self.prefs.sample_size:
|
|
594
|
+
point = background_points[min_idx]
|
|
595
|
+
self.cmd = Command(RM_POINT_HANDLER, self.cmd, idx=min_idx, point=point)
|
|
596
|
+
self.cmd.execute()
|
|
597
|
+
return True
|
|
598
|
+
else:
|
|
599
|
+
return False
|
|
600
|
+
|
|
601
|
+
def reset_backgroundpts(self):
|
|
602
|
+
if len(self.cmd.app_state.background_points) > 0:
|
|
603
|
+
self.cmd = Command(RESET_POINTS_HANDLER, self.cmd)
|
|
604
|
+
self.cmd.execute()
|
|
605
|
+
|
|
606
|
+
def reset_transform(self):
|
|
607
|
+
self.mat_affine = np.eye(3)
|
|
608
|
+
|
|
609
|
+
def scale_at(self, scale: float, cx: float, cy: float):
|
|
610
|
+
self.translate(-cx, -cy)
|
|
611
|
+
self.scale(scale)
|
|
612
|
+
self.translate(cx, cy)
|
|
613
|
+
|
|
614
|
+
def scale(self, scale: float):
|
|
615
|
+
mat = np.eye(3)
|
|
616
|
+
mat[0, 0] = scale
|
|
617
|
+
mat[1, 1] = scale
|
|
618
|
+
self.mat_affine = np.dot(mat, self.mat_affine)
|
|
619
|
+
|
|
620
|
+
def to_canvas_point(self, x, y):
|
|
621
|
+
return np.dot(self.mat_affine, (x, y, 1.0))
|
|
622
|
+
|
|
623
|
+
def to_image_point(self, x, y):
|
|
624
|
+
if self.images.get(self.display_type) is None:
|
|
625
|
+
return []
|
|
626
|
+
|
|
627
|
+
mat_inv = np.linalg.inv(self.mat_affine)
|
|
628
|
+
image_point = np.dot(mat_inv, (x, y, 1.0))
|
|
629
|
+
|
|
630
|
+
width = self.images.get(self.display_type).width
|
|
631
|
+
height = self.images.get(self.display_type).height
|
|
632
|
+
|
|
633
|
+
if image_point[0] < 0 or image_point[1] < 0 or image_point[0] > width or image_point[1] > height:
|
|
634
|
+
return []
|
|
635
|
+
|
|
636
|
+
return image_point
|
|
637
|
+
|
|
638
|
+
def to_image_point_pinned(self, x, y):
|
|
639
|
+
if self.images.get(self.display_type) is None:
|
|
640
|
+
return []
|
|
641
|
+
|
|
642
|
+
mat_inv = np.linalg.inv(self.mat_affine)
|
|
643
|
+
image_point = np.dot(mat_inv, (x, y, 1.0))
|
|
644
|
+
|
|
645
|
+
width = self.images.get(self.display_type).width
|
|
646
|
+
height = self.images.get(self.display_type).height
|
|
647
|
+
|
|
648
|
+
if image_point[0] < 0:
|
|
649
|
+
image_point[0] = 0
|
|
650
|
+
if image_point[1] < 0:
|
|
651
|
+
image_point[1] = 0
|
|
652
|
+
if image_point[0] > width:
|
|
653
|
+
image_point[0] = width
|
|
654
|
+
if image_point[1] > height:
|
|
655
|
+
image_point[1] = height
|
|
656
|
+
|
|
657
|
+
return image_point
|
|
658
|
+
|
|
659
|
+
def translate(self, offset_x, offset_y):
|
|
660
|
+
mat = np.eye(3)
|
|
661
|
+
mat[0, 2] = float(offset_x)
|
|
662
|
+
mat[1, 2] = float(offset_y)
|
|
663
|
+
|
|
664
|
+
self.mat_affine = np.dot(mat, self.mat_affine)
|
|
665
|
+
|
|
666
|
+
def validate_bge_ai_installation(self):
|
|
667
|
+
if self.prefs.bge_ai_version is None or self.prefs.bge_ai_version == "None":
|
|
668
|
+
messagebox.showerror("Error", _("No Background Extraction AI-Model selected. Please select one from the Advanced panel on the right."))
|
|
669
|
+
return False
|
|
670
|
+
|
|
671
|
+
if not validate_local_version(bge_ai_models_dir, self.prefs.bge_ai_version):
|
|
672
|
+
if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Background Extraction AI-Model is not installed. Should I download it now?")):
|
|
673
|
+
return False
|
|
674
|
+
else:
|
|
675
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
676
|
+
|
|
677
|
+
def callback(p):
|
|
678
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
679
|
+
|
|
680
|
+
download_version(bge_ai_models_dir, bge_bucket_name, self.prefs.bge_ai_version, progress=callback)
|
|
681
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
682
|
+
return True
|
|
683
|
+
|
|
684
|
+
def validate_deconvolution_ai_installation(self):
|
|
685
|
+
|
|
686
|
+
if self.prefs.deconvolution_type_option == "Object-only":
|
|
687
|
+
|
|
688
|
+
if self.prefs.deconvolution_object_ai_version is None or self.prefs.deconvolution_object_ai_version == "None":
|
|
689
|
+
messagebox.showerror("Error", _("No Object-only Deconvolution AI-Model selected. Please select one from the Advanced panel on the right."))
|
|
690
|
+
return False
|
|
691
|
+
|
|
692
|
+
if not validate_local_version(deconvolution_object_ai_models_dir, self.prefs.deconvolution_object_ai_version):
|
|
693
|
+
if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Object-only Deconvolution AI-Model is not installed. Should I download it now?")):
|
|
694
|
+
return False
|
|
695
|
+
else:
|
|
696
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
697
|
+
|
|
698
|
+
def callback(p):
|
|
699
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
700
|
+
|
|
701
|
+
download_version(deconvolution_object_ai_models_dir, deconvolution_object_bucket_name, self.prefs.deconvolution_object_ai_version, progress=callback)
|
|
702
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
703
|
+
return True
|
|
704
|
+
else:
|
|
705
|
+
if self.prefs.deconvolution_stars_ai_version is None or self.prefs.deconvolution_stars_ai_version == "None":
|
|
706
|
+
messagebox.showerror("Error", _("No Stars-only Denoising AI-Model selected. Please select one from the Advanced panel on the right."))
|
|
707
|
+
return False
|
|
708
|
+
|
|
709
|
+
if not validate_local_version(deconvolution_stars_ai_models_dir, self.prefs.deconvolution_stars_ai_version):
|
|
710
|
+
if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Stars-only Deconvolution AI-Model is not installed. Should I download it now?")):
|
|
711
|
+
return False
|
|
712
|
+
else:
|
|
713
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
714
|
+
|
|
715
|
+
def callback(p):
|
|
716
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
717
|
+
|
|
718
|
+
download_version(deconvolution_stars_ai_models_dir, deconvolution_stars_bucket_name, self.prefs.deconvolution_stars_ai_version, progress=callback)
|
|
719
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
720
|
+
return True
|
|
721
|
+
|
|
722
|
+
def validate_denoise_ai_installation(self):
|
|
723
|
+
if self.prefs.denoise_ai_version is None or self.prefs.denoise_ai_version == "None":
|
|
724
|
+
messagebox.showerror("Error", _("No Denoising AI-Model selected. Please select one from the Advanced panel on the right."))
|
|
725
|
+
return False
|
|
726
|
+
|
|
727
|
+
if not validate_local_version(denoise_ai_models_dir, self.prefs.denoise_ai_version):
|
|
728
|
+
if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Denoising AI-Model is not installed. Should I download it now?")):
|
|
729
|
+
return False
|
|
730
|
+
else:
|
|
731
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN)
|
|
732
|
+
|
|
733
|
+
def callback(p):
|
|
734
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p})
|
|
735
|
+
|
|
736
|
+
download_version(denoise_ai_models_dir, denoise_bucket_name, self.prefs.denoise_ai_version, progress=callback)
|
|
737
|
+
eventbus.emit(AppEvents.AI_DOWNLOAD_END)
|
|
738
|
+
return True
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
graxpert = GraXpert()
|