From 1e8e7bfa7b3f0674693ca0860b5117e4ba9a0e41 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 5 Nov 2023 17:49:26 +0100 Subject: [PATCH 01/59] Added menu for denoising --- graxpert/denoising.py | 56 +++++++++++++++++++++++++++++++++++++++++++ graxpert/gui.py | 34 +++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 graxpert/denoising.py diff --git a/graxpert/denoising.py b/graxpert/denoising.py new file mode 100644 index 0000000..0e9506a --- /dev/null +++ b/graxpert/denoising.py @@ -0,0 +1,56 @@ +import numpy as np +import copy +import tensorflow as tf + +def denoise(image, window_size, stride, AI_dir = "", strength=1.0): + input = copy.deepcopy(image) + + H, W, _ = image.shape + offset = int((window_size - stride) / 2) + + h, w, _ = image.shape + + ith = int(h / stride) + 1 + itw = int(w / stride) + 1 + + dh = ith * stride - h + dw = itw * stride - w + + image = np.concatenate((image, image[(h - dh) :, :, :]), axis = 0) + image = np.concatenate((image, image[:, (w - dw) :, :]), axis = 1) + + h, w, _ = image.shape + image = np.concatenate((image, image[(h - offset) :, :, :]), axis = 0) + image = np.concatenate((image[: offset, :, :], image), axis = 0) + image = np.concatenate((image, image[:, (w - offset) :, :]), axis = 1) + image = np.concatenate((image[:, : offset, :], image), axis = 1) + + median = np.median(image[::4,::4,:], axis=[0,1]) + mad = np.median(np.abs(image[::4,::4,:]-median), axis=[0,1]) + + output = copy.deepcopy(image) + model = tf.keras.models.load_model(AI_dir) + + for i in range(ith): + print(str(i) + " of " + str(ith)) + for j in range(itw): + x = stride * i + y = stride * j + + tile = image[x:x+window_size, y:y+window_size, :] + tile = (tile - median) / mad * 0.04 + tile_copy = tile.copy() + tile = np.clip(tile, -1.0, 1.0) + + tile = np.expand_dims(tile, axis = 0) + tile = np.array(model(tile)[0]) + + tile = np.where(tile_copy < 0.95, tile, tile_copy) + tile = tile / 0.04 * mad + median + tile = tile[offset:offset+stride, offset:offset+stride, :] + output[x+offset:stride*(i+1)+offset, y+offset:stride*(j+1)+offset, :] = tile + + output = np.clip(output, 0, 1) + output = output[offset:H+offset,offset:W+offset,:] + + return output * strength + input * (strength - 1) \ No newline at end of file diff --git a/graxpert/gui.py b/graxpert/gui.py index f9c942e..83e73f4 100644 --- a/graxpert/gui.py +++ b/graxpert/gui.py @@ -16,6 +16,7 @@ from skimage.transform import resize import graxpert.background_extraction as background_extraction +import graxpert.denoising as denoising import graxpert.tooltip as tooltip from graxpert.app_state import INITIAL_STATE from graxpert.astroimage import AstroImage @@ -190,7 +191,7 @@ def create_widget(self): #Background extraction menu self.bgextr_menu = CollapsibleFrame(self.side_menu, text=_("Background Extraction") + " ") - self.bgextr_menu.grid(column=0, row=1, pady=(5*scal,20*scal), padx=15*scal, sticky="news") + self.bgextr_menu.grid(column=0, row=1, pady=(5*scal,5*scal), padx=15*scal, sticky="news") self.bgextr_menu.sub_frame.grid_columnconfigure(0, weight=1) for i in range(21): @@ -352,7 +353,24 @@ def create_widget(self): self.save_stretched_button.grid(column=0, row=21, pady=(5*scal,10*scal), padx=15*scal, sticky="news") tt_save_pic= tooltip.Tooltip(self.save_stretched_button, text=tooltip.save_stretched_pic_text) + + # Denoising Menu + + self.denoising_menu = CollapsibleFrame(self.side_menu, text=_("Denoising") + " ") + self.denoising_menu.grid(column=0, row=2, pady=(5*scal,20*scal), padx=15*scal, sticky="news") + self.denoising_menu.sub_frame.grid_columnconfigure(0, weight=1) + + for i in range(1): + self.denoising_menu.sub_frame.grid_rowconfigure(i, weight=1) + + self.denoising_button = ttk.Button(self.denoising_menu.sub_frame, + text=_("Denoise"), + command=self.denoising_callback, + ) + self.denoising_button.grid(column=0, row=0, pady=(20*scal,5*scal), padx=15*scal, sticky="news") + + # Configure Scrollbar self.side_canvas.create_window((0,0), window=self.side_menu) self.side_canvas.configure(yscrollcommand=self.scrollbar.set) self.side_canvas.bind('', lambda e: self.side_canvas.configure(scrollregion=self.side_canvas.bbox("all"))) @@ -704,6 +722,20 @@ def enter_key(self,enter): self.calculate() + def denoising_callback(self, event=None): + denoised_image = denoising.denoise(self.images["Original"].img_array, 256, 128, "C:/Users/steff/Desktop/background/Background_extraction/GraXpert/denoise_model", strength=1.0) + + self.images["Processed"] = AstroImage(self.stretch_option_current, self.saturation) + self.images["Processed"].set_from_array(denoised_image) + self.images["Processed"].copy_metadata(self.images["Original"]) + + all_images = [self.images["Original"].img_array, self.images["Processed"].img_array] + stretches = stretch_all(all_images, self.images["Original"].get_stretch()) + self.images["Original"].update_display_from_array(stretches[0]) + self.images["Processed"].update_display_from_array(stretches[1]) + + self.display_type.set("Processed") + self.redraw_image() def mouse_down_left(self,event): From 69cbf1c4b7fd90543bbb63444d04c20833ae7ef4 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Dec 2023 12:19:32 +0100 Subject: [PATCH 02/59] fix progressbar when no ai model has been selected --- graxpert/application/app.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index b5e6e33..0df8ba9 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -35,10 +35,6 @@ def initialize(self): self.images = {"Original": None, "Background": None, "Processed": None} self.display_type = "Original" - self.ai_version = None - if self.prefs.ai_version is not None: - self.ai_version = self.prefs.ai_version - self.mat_affine = np.eye(3) # state handling @@ -95,10 +91,8 @@ def on_bg_tol_changed(self, event): self.prefs.bg_tol_option = event["bg_tol_option"] def on_calculate_request(self, event=None): - eventbus.emit(AppEvents.CALCULATE_BEGIN) if self.images["Original"] is None: - eventbus.emit(AppEvents.CALCULATE_END) messagebox.showerror("Error", _("Please load your picture first.")) return @@ -106,28 +100,24 @@ def on_calculate_request(self, event=None): # Error messages if not enough points if len(background_points) == 0 and self.prefs.interpol_type_option != "AI": - eventbus.emit(AppEvents.CALCULATE_END) messagebox.showerror("Error", _("Please select background points with left click.")) return if len(background_points) < 2 and self.prefs.interpol_type_option == "Kriging": - eventbus.emit(AppEvents.CALCULATE_END) messagebox.showerror("Error", _("Please select at least 2 background points with left click for the Kriging method.")) return if len(background_points) < 16 and self.prefs.interpol_type_option == "Splines": - eventbus.emit(AppEvents.CALCULATE_END) messagebox.showerror("Error", _("Please select at least 16 background points with left click for the Splines method.")) return if self.prefs.interpol_type_option == "AI": if not self.validate_ai_installation(): return + + eventbus.emit(AppEvents.CALCULATE_BEGIN) - def callback(p): - eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p}) - - progress = DynamicProgressThread(callback=callback) + progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p})) imarray = np.copy(self.images["Original"].img_array) @@ -512,7 +502,7 @@ def translate(self, offset_x, offset_y): self.mat_affine = np.dot(mat, self.mat_affine) def validate_ai_installation(self): - if self.ai_version is None or self.prefs.ai_version == "None": + if self.prefs.ai_version is None or self.prefs.ai_version == "None": messagebox.showerror("Error", _("No AI-Model selected. Please select one from the Advanced panel on the right.")) return False @@ -525,7 +515,7 @@ def validate_ai_installation(self): def callback(p): eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p}) - download_version(self.ai_version, progress=callback) + download_version(self.prefs.ai_version, progress=callback) eventbus.emit(AppEvents.AI_DOWNLOAD_END) return True From dfdaca33e9d3e4a6904c0a02ff035b0471463115 Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Fri, 29 Dec 2023 23:14:09 +0100 Subject: [PATCH 03/59] Implemented onnxruntime --- graxpert/background_extraction.py | 131 ++++++++++++++++-------------- requirements.txt | 27 +++--- 2 files changed, 83 insertions(+), 75 deletions(-) diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index 3b3fa0c..89ffb5f 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -16,30 +16,32 @@ import sys import os -import tensorflow as tf -os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # Run tensorflow on CPU -tf.compat.v1.logging.set_verbosity(40) # Only show errors +import onnxruntime as ort +# import tensorflow as tf +# os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # Run tensorflow on CPU +# tf.compat.v1.logging.set_verbosity(40) # Only show errors from graxpert.mp_logging import get_logging_queue, worker_configurer from graxpert.parallel_processing import executor from graxpert.radialbasisinterpolation import RadialBasisInterpolation -def extract_background(in_imarray, background_points, interpolation_type, smoothing, +def extract_background(in_imarray, background_points, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, AI_dir, progress=None): - + shm_imarray = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) shm_background = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) imarray = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_imarray.buf) background = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_background.buf) np.copyto(imarray, in_imarray) - + num_colors = imarray.shape[-1] - + if interpolation_type == 'AI': # Shrink and pad to avoid artifacts on borders padding = 8 - imarray_shrink = tf.image.resize(imarray,size=(256 - 2*padding,256 - 2*padding)) + # imarray_shrink = tf.image.resize(imarray,size=(256 - 2*padding,256 - 2*padding)) + imarray_shrink = resize(imarray, output_shape=(256 - 2*padding,256 - 2*padding)) imarray_shrink = np.pad(imarray_shrink, ((padding,padding),(padding,padding),(0,0)), mode='edge') median = [] @@ -47,78 +49,83 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if progress is not None: progress.update(8) - + for c in range(num_colors): median.append(np.median(imarray_shrink[:,:,c])) mad.append(np.median(np.abs(imarray_shrink[:,:,c] - median[c]))) if progress is not None: progress.update(8) - + imarray_shrink = (imarray_shrink - median) / mad * 0.04 imarray_shrink = np.clip(imarray_shrink, -1.0, 1.0) - + if progress is not None: progress.update(8) - + if num_colors == 1: imarray_shrink = np.array([imarray_shrink[:,:,0],imarray_shrink[:,:,0],imarray_shrink[:,:,0]]) imarray_shrink = np.moveaxis(imarray_shrink, 0, -1) - + if progress is not None: progress.update(8) - - model = tf.saved_model.load(AI_dir) - background = np.array(model(np.expand_dims(imarray_shrink, axis=0))[0]) + # model = tf.saved_model.load(AI_dir) + session = ort.InferenceSession(os.path.join(AI_dir, "model.onnx"), providers=ort.get_available_providers()) + + # background = np.array(model(np.expand_dims(imarray_shrink, axis=0))[0]) + background = session.run(None, {"gen_input_image": np.expand_dims(imarray_shrink, axis=0)})[0][0] + background = background / 0.04 * mad + median - + if progress is not None: progress.update(8) - + if smoothing != 0: sigma = smoothing * 20 background = gaussian(image=background, sigma=sigma, channel_axis=-1) - + if progress is not None: progress.update(8) - + if num_colors == 1: background = np.array([background[:,:,0]]) background = np.moveaxis(background, 0, -1) - + if progress is not None: progress.update(8) - + # Slice to unpadded size of shrinked image, then resize to original size if padding != 0: background = background[padding:-padding,padding:-padding,:] - + if progress is not None: progress.update(8) - - background = tf.image.resize(background,size=(in_imarray.shape[0],in_imarray.shape[1]),method='gaussian') - + + # background = tf.image.resize(background,size=(in_imarray.shape[0],in_imarray.shape[1]),method='gaussian') + background = gaussian(background, sigma=3.0) # To simulate method='gaussian + background = resize(background, output_shape=(in_imarray.shape[0],in_imarray.shape[1])) + if progress is not None: progress.update(8) - - - else: + + + else: x_sub = np.array(background_points[:,0],dtype=int) y_sub = np.array(background_points[:,1],dtype=int) - + if progress is not None: progress.update(24) - + futures = [] logging_queue = get_logging_queue() for c in range(num_colors): futures.insert(c, executor.submit(interpol, shm_imarray.name, shm_background.name, c, x_sub, y_sub, in_imarray.shape, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, imarray.dtype, logging_queue, worker_configurer)) wait(futures) - + if progress is not None: progress.update(48) - + #Correction if(corr_type == "Subtraction"): mean = np.mean(background) @@ -127,7 +134,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth for c in range(num_colors): mean = np.mean(imarray[:,:,c]) imarray[:,:,c] = imarray[:,:,c] / background[:,:,c] * mean - + if progress is not None: progress.update(8) @@ -136,28 +143,28 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth in_imarray[:] = imarray[:] background = np.copy(background) - + if progress is not None: progress.update(8) - + shm_imarray.close() shm_background.close() shm_imarray.unlink() shm_background.unlink() - + return background def calc_mode_dataset(data, x_sub, y_sub, halfsize): - + n = x_sub.shape[0] data_padded = np.pad(array=data, pad_width=(halfsize,), mode="reflect") subsample = np.zeros(n) - + for i in range(n): data_footprint = data_padded[y_sub[i]:y_sub[i]+2*halfsize,x_sub[i]:x_sub[i]+2*halfsize] subsample[i] = sigma_clipped_stats(data=data_footprint, cenfunc="median", stdfunc="std", grow=4)[1] - + return subsample @@ -174,42 +181,42 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind background = np.ndarray(shape, dtype, buffer=existing_shm_background.buf) # background = background[:,:,c] shape = imarray.shape - + subsample = calc_mode_dataset(imarray, x_sub, y_sub, sample_size) - + if(downscale_factor != 1): x_sub = x_sub / shape[1] y_sub = y_sub / shape[0] - + shape_scaled = (shape[0] // downscale_factor, shape[1] // downscale_factor) - + x_sub = x_sub * shape_scaled[1] y_sub = y_sub * shape_scaled[0] - + else: shape_scaled = shape - + if(kind=='RBF'): points_stacked = np.stack([x_sub,y_sub],-1) - interp = RadialBasisInterpolation(points_stacked,subsample,kernel=RBF_kernel,smooth=smoothing*linalg.norm(subsample)/np.sqrt(len(subsample))) - + interp = RadialBasisInterpolation(points_stacked,subsample,kernel=RBF_kernel,smooth=smoothing*linalg.norm(subsample)/np.sqrt(len(subsample))) + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1) y_new = np.arange(0,shape_scaled[0],1) - + xx, yy = np.meshgrid(x_new,y_new) points_new_stacked = np.stack([xx.ravel(),yy.ravel()],-1) - + result = interp(points_new_stacked).reshape(shape_scaled) - + elif(kind=='Splines'): interp = interpolate.bisplrep(y_sub,x_sub,subsample,w=np.ones(len(x_sub))/np.std(subsample), s=smoothing*len(x_sub), kx=spline_order, ky=spline_order) - + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1) y_new = np.arange(0,shape_scaled[0],1) result = interpolate.bisplev(y_new,x_new,interp) - + elif(kind=='Kriging'): OK = OrdinaryKriging( x=x_sub, @@ -219,23 +226,23 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind verbose=False, enable_plotting=False, ) - + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1).astype("float64") y_new = np.arange(0,shape_scaled[0],1).astype("float64") result = np.zeros(shape_scaled, dtype=np.float32) - + num_it = shape_scaled[0]//50 - + for i in range(num_it): result_i, var = OK.execute("grid", xpoints=x_new, ypoints=y_new[i*50:(i+1)*50], backend="vectorized") result[i*50:(i+1)*50,:] = result_i - + result_i, var = OK.execute("grid", xpoints=x_new, ypoints=y_new[num_it*50:], backend="vectorized") result[num_it*50:,:] = result_i - + # if(kind=='GPR_CUDA'): # # A likelihood in GPyTorch specifies the mapping from latent function values f(X) to observed labels y. # gpr = GPRegression( @@ -246,18 +253,18 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind # ) # result = gpr.run() # del gpr - + else: logging.warning("Interpolation method not recognized") return - + if(downscale_factor != 1): result = resize(result, shape, preserve_range=True) - + background[:,:,c] = result except Exception as e: logging.exception("Error occured during background_extraction.interpol") - + existing_shm_imarray.close() existing_shm_background.close() diff --git a/requirements.txt b/requirements.txt index 3ca5dc3..3a2489e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,14 @@ -appdirs -astropy -customtkinter -minio -ml_dtypes -numpy<=1.24.3,>=1.22 -Pillow -pykrige -requests -scikit-image == 0.21.0 -scipy -tensorflow == 2.13.1 -xisf \ No newline at end of file +appdirs +astropy +customtkinter +minio +ml_dtypes +numpy<=1.24.3,>=1.22 +Pillow +pykrige +requests +scikit-image == 0.21.0 +scipy +xisf +onnxruntime-silicon; sys_platform == "darwin" +onnxruntime-gpu; sys_platform != "darwin" From fbff05462e3bca247ee1b2b61806bceba8e92967 Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Sat, 30 Dec 2023 13:53:15 +0100 Subject: [PATCH 04/59] Changed .onnx model dir and implemented methid='gaussian' --- graxpert/background_extraction.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index 89ffb5f..04134e2 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -71,7 +71,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth progress.update(8) # model = tf.saved_model.load(AI_dir) - session = ort.InferenceSession(os.path.join(AI_dir, "model.onnx"), providers=ort.get_available_providers()) + session = ort.InferenceSession(os.path.join(os.path.split(AI_dir)[0], "bg_model.onnx"), providers=ort.get_available_providers()) # background = np.array(model(np.expand_dims(imarray_shrink, axis=0))[0]) background = session.run(None, {"gen_input_image": np.expand_dims(imarray_shrink, axis=0)})[0][0] @@ -103,7 +103,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth progress.update(8) # background = tf.image.resize(background,size=(in_imarray.shape[0],in_imarray.shape[1]),method='gaussian') - background = gaussian(background, sigma=3.0) # To simulate method='gaussian + background = gaussian(background, sigma=3.0) # To simulate method='gaussian' background = resize(background, output_shape=(in_imarray.shape[0],in_imarray.shape[1])) if progress is not None: From 89b85e0f06a1b06a907657fa4544e415ed2c8e69 Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Sun, 31 Dec 2023 12:16:28 +0000 Subject: [PATCH 05/59] reformatted background_extraction --- graxpert/background_extraction.py | 112 +++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index 04134e2..fdcf8cc 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -26,17 +26,17 @@ from graxpert.radialbasisinterpolation import RadialBasisInterpolation -def extract_background(in_imarray, background_points, interpolation_type, smoothing, +def extract_background(in_imarray, background_points, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, AI_dir, progress=None): - + shm_imarray = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) shm_background = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) imarray = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_imarray.buf) background = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_background.buf) np.copyto(imarray, in_imarray) - + num_colors = imarray.shape[-1] - + if interpolation_type == 'AI': # Shrink and pad to avoid artifacts on borders padding = 8 @@ -49,83 +49,83 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if progress is not None: progress.update(8) - + for c in range(num_colors): median.append(np.median(imarray_shrink[:,:,c])) mad.append(np.median(np.abs(imarray_shrink[:,:,c] - median[c]))) if progress is not None: progress.update(8) - + imarray_shrink = (imarray_shrink - median) / mad * 0.04 imarray_shrink = np.clip(imarray_shrink, -1.0, 1.0) - + if progress is not None: progress.update(8) - + if num_colors == 1: imarray_shrink = np.array([imarray_shrink[:,:,0],imarray_shrink[:,:,0],imarray_shrink[:,:,0]]) imarray_shrink = np.moveaxis(imarray_shrink, 0, -1) - + if progress is not None: progress.update(8) - + # model = tf.saved_model.load(AI_dir) session = ort.InferenceSession(os.path.join(os.path.split(AI_dir)[0], "bg_model.onnx"), providers=ort.get_available_providers()) # background = np.array(model(np.expand_dims(imarray_shrink, axis=0))[0]) background = session.run(None, {"gen_input_image": np.expand_dims(imarray_shrink, axis=0)})[0][0] - + background = background / 0.04 * mad + median - + if progress is not None: progress.update(8) - + if smoothing != 0: sigma = smoothing * 20 background = gaussian(image=background, sigma=sigma, channel_axis=-1) - + if progress is not None: progress.update(8) - + if num_colors == 1: background = np.array([background[:,:,0]]) background = np.moveaxis(background, 0, -1) - + if progress is not None: progress.update(8) - + # Slice to unpadded size of shrinked image, then resize to original size if padding != 0: background = background[padding:-padding,padding:-padding,:] - + if progress is not None: progress.update(8) - + # background = tf.image.resize(background,size=(in_imarray.shape[0],in_imarray.shape[1]),method='gaussian') background = gaussian(background, sigma=3.0) # To simulate method='gaussian' background = resize(background, output_shape=(in_imarray.shape[0],in_imarray.shape[1])) - + if progress is not None: progress.update(8) - - - else: + + + else: x_sub = np.array(background_points[:,0],dtype=int) y_sub = np.array(background_points[:,1],dtype=int) - + if progress is not None: progress.update(24) - + futures = [] logging_queue = get_logging_queue() for c in range(num_colors): futures.insert(c, executor.submit(interpol, shm_imarray.name, shm_background.name, c, x_sub, y_sub, in_imarray.shape, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, imarray.dtype, logging_queue, worker_configurer)) wait(futures) - + if progress is not None: progress.update(48) - + #Correction if(corr_type == "Subtraction"): mean = np.mean(background) @@ -134,7 +134,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth for c in range(num_colors): mean = np.mean(imarray[:,:,c]) imarray[:,:,c] = imarray[:,:,c] / background[:,:,c] * mean - + if progress is not None: progress.update(8) @@ -143,28 +143,28 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth in_imarray[:] = imarray[:] background = np.copy(background) - + if progress is not None: progress.update(8) - + shm_imarray.close() shm_background.close() shm_imarray.unlink() shm_background.unlink() - + return background def calc_mode_dataset(data, x_sub, y_sub, halfsize): - + n = x_sub.shape[0] data_padded = np.pad(array=data, pad_width=(halfsize,), mode="reflect") subsample = np.zeros(n) - + for i in range(n): data_footprint = data_padded[y_sub[i]:y_sub[i]+2*halfsize,x_sub[i]:x_sub[i]+2*halfsize] subsample[i] = sigma_clipped_stats(data=data_footprint, cenfunc="median", stdfunc="std", grow=4)[1] - + return subsample @@ -181,42 +181,42 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind background = np.ndarray(shape, dtype, buffer=existing_shm_background.buf) # background = background[:,:,c] shape = imarray.shape - + subsample = calc_mode_dataset(imarray, x_sub, y_sub, sample_size) - + if(downscale_factor != 1): x_sub = x_sub / shape[1] y_sub = y_sub / shape[0] - + shape_scaled = (shape[0] // downscale_factor, shape[1] // downscale_factor) - + x_sub = x_sub * shape_scaled[1] y_sub = y_sub * shape_scaled[0] - + else: shape_scaled = shape - + if(kind=='RBF'): points_stacked = np.stack([x_sub,y_sub],-1) - interp = RadialBasisInterpolation(points_stacked,subsample,kernel=RBF_kernel,smooth=smoothing*linalg.norm(subsample)/np.sqrt(len(subsample))) - + interp = RadialBasisInterpolation(points_stacked,subsample,kernel=RBF_kernel,smooth=smoothing*linalg.norm(subsample)/np.sqrt(len(subsample))) + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1) y_new = np.arange(0,shape_scaled[0],1) - + xx, yy = np.meshgrid(x_new,y_new) points_new_stacked = np.stack([xx.ravel(),yy.ravel()],-1) - + result = interp(points_new_stacked).reshape(shape_scaled) - + elif(kind=='Splines'): interp = interpolate.bisplrep(y_sub,x_sub,subsample,w=np.ones(len(x_sub))/np.std(subsample), s=smoothing*len(x_sub), kx=spline_order, ky=spline_order) - + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1) y_new = np.arange(0,shape_scaled[0],1) result = interpolate.bisplev(y_new,x_new,interp) - + elif(kind=='Kriging'): OK = OrdinaryKriging( x=x_sub, @@ -226,23 +226,23 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind verbose=False, enable_plotting=False, ) - + # Create background from interpolation x_new = np.arange(0,shape_scaled[1],1).astype("float64") y_new = np.arange(0,shape_scaled[0],1).astype("float64") result = np.zeros(shape_scaled, dtype=np.float32) - + num_it = shape_scaled[0]//50 - + for i in range(num_it): result_i, var = OK.execute("grid", xpoints=x_new, ypoints=y_new[i*50:(i+1)*50], backend="vectorized") result[i*50:(i+1)*50,:] = result_i - + result_i, var = OK.execute("grid", xpoints=x_new, ypoints=y_new[num_it*50:], backend="vectorized") result[num_it*50:,:] = result_i - + # if(kind=='GPR_CUDA'): # # A likelihood in GPyTorch specifies the mapping from latent function values f(X) to observed labels y. # gpr = GPRegression( @@ -253,18 +253,18 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind # ) # result = gpr.run() # del gpr - + else: logging.warning("Interpolation method not recognized") return - + if(downscale_factor != 1): result = resize(result, shape, preserve_range=True) - + background[:,:,c] = result except Exception as e: logging.exception("Error occured during background_extraction.interpol") - + existing_shm_imarray.close() existing_shm_background.close() From b3b42ddadbe36131a4f40ccc5c99f39c881f8dc5 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 21 Jan 2024 13:19:42 +0100 Subject: [PATCH 06/59] stretch refactoring --- graxpert/application/app.py | 13 +++--- graxpert/astroimage.py | 48 ++++--------------- graxpert/stretch.py | 91 +++++++++++++++---------------------- tests/test_AstroImage.py | 19 ++++---- 4 files changed, 63 insertions(+), 108 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 550d43f..1d1cfff 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -16,7 +16,7 @@ from graxpert.localization import _ from graxpert.mp_logging import logfile_name from graxpert.preferences import fitsheader_2_app_state, load_preferences, prefs_2_app_state -from graxpert.stretch import stretch_all +from graxpert.stretch import stretch_all, StretchParameters from graxpert.ui.loadingframe import DynamicProgressThread @@ -155,7 +155,7 @@ def on_calculate_request(self, event=None): self.images["Background"].copy_metadata(self.images["Original"]) all_images = [self.images["Original"].img_array, self.images["Processed"].img_array, self.images["Background"].img_array] - stretches = stretch_all(all_images, self.images["Original"].get_stretch(self.prefs.stretch_option)) + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option)) self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) self.images["Background"].update_display_from_array(stretches[2], self.prefs.saturation) @@ -220,7 +220,7 @@ def on_load_image(self, event): try: image = AstroImage() - image.set_from_file(filename, self.prefs.stretch_option, self.prefs.saturation) + image.set_from_file(filename, StretchParameters(self.prefs.stretch_option), self.prefs.saturation) except Exception as e: eventbus.emit(AppEvents.LOAD_IMAGE_ERROR) @@ -363,9 +363,9 @@ def on_save_stretched_request(self, event): try: if self.images["Processed"] is None: - self.images["Original"].save_stretched(dir, self.prefs.saveas_option, self.prefs.stretch_option) + self.images["Original"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option)) else: - self.images["Processed"].save_stretched(dir, self.prefs.saveas_option, self.prefs.stretch_option) + self.images["Processed"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option)) except Exception as e: eventbus.emit(AppEvents.SAVE_ERROR) logging.exception(e) @@ -391,8 +391,7 @@ def on_stretch_option_changed(self, event): if img is not None: all_images.append(img.img_array) if len(all_images) > 0: - stretch_params = self.images["Original"].get_stretch(self.prefs.stretch_option) - stretches = stretch_all(all_images, stretch_params) + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option)) for idx, img in enumerate(self.images.values()): if img is not None: img.update_display_from_array(stretches[idx], self.prefs.saturation) diff --git a/graxpert/astroimage.py b/graxpert/astroimage.py index 388f25e..edc6911 100644 --- a/graxpert/astroimage.py +++ b/graxpert/astroimage.py @@ -12,7 +12,7 @@ from graxpert.app_state import AppState from graxpert.preferences import Prefs, app_state_2_fitsheader -from graxpert.stretch import stretch +from graxpert.stretch import stretch, StretchParameters class AstroImage: @@ -29,7 +29,7 @@ def __init__(self, do_update_display=True): self.height = 0 self.roworder = "BOTTOM-UP" - def set_from_file(self, directory, stretch_option, saturation): + def set_from_file(self, directory: str, stretch_params: StretchParameters, saturation: float): self.img_format = os.path.splitext(directory)[1].lower() img_array = None @@ -76,7 +76,7 @@ def set_from_file(self, directory, stretch_option, saturation): self.height = self.img_array.shape[0] if self.do_update_display: - self.update_display(stretch_option, saturation) + self.update_display(stretch_params, saturation) return @@ -86,8 +86,8 @@ def set_from_array(self, array): self.height = self.img_array.shape[0] return - def update_display(self, stretch_option, saturation): - img_display = self.stretch(stretch_option) + def update_display(self, stretch_params: StretchParameters, saturation: float): + img_display = self.stretch(stretch_params) img_display = img_display * 255 # if self.roworder == "TOP-DOWN": @@ -117,36 +117,8 @@ def update_display_from_array(self, img_display, saturation): return - def stretch(self, stretch_option): - bg, sigma = (0.2, 3) - if stretch_option == "No Stretch": - return self.img_array - - elif stretch_option == "10% Bg, 3 sigma": - bg, sigma = (0.1, 3) - - elif stretch_option == "15% Bg, 3 sigma": - bg, sigma = (0.15, 3) - - elif stretch_option == "20% Bg, 3 sigma": - bg, sigma = (0.2, 3) - - elif stretch_option == "30% Bg, 2 sigma": - bg, sigma = (0.3, 2) - - return np.clip(stretch(self.img_array, bg, sigma), 0.0, 1.0) - - def get_stretch(self, stretch_option): - if stretch_option == "No Stretch": - return None - elif stretch_option == "10% Bg, 3 sigma": - return (0.1, 3) - elif stretch_option == "15% Bg, 3 sigma": - return (0.15, 3) - elif stretch_option == "20% Bg, 3 sigma": - return (0.2, 3) - elif stretch_option == "30% Bg, 2 sigma": - return (0.3, 2) + def stretch(self, stretch_params: StretchParameters): + return np.clip(stretch(self.img_array, stretch_params), 0.0, 1.0) def crop(self, startx, endx, starty, endy): self.img_array = self.img_array[starty:endy, startx:endx, :] @@ -201,13 +173,13 @@ def save(self, dir, saveas_type): return - def save_stretched(self, dir, saveas_type, stretch_option): + def save_stretched(self, dir, saveas_type, stretch_params): if self.img_array is None: return - self.fits_header["STRETCH"] = stretch_option + self.fits_header["STRETCH"] = stretch_params.stretch_option - stretched_img = self.stretch(stretch_option) + stretched_img = self.stretch(stretch_params) if saveas_type == "16 bit Tiff" or saveas_type == "16 bit Fits" or saveas_type == "16 bit XISF": image_converted = img_as_uint(stretched_img) diff --git a/graxpert/stretch.py b/graxpert/stretch.py index 2f224de..77aac71 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -6,13 +6,42 @@ from multiprocessing import shared_memory import numpy as np -from astropy.visualization import AsinhStretch -from scipy.optimize import root from graxpert.mp_logging import get_logging_queue, worker_configurer from graxpert.parallel_processing import executor +class StretchParameters: + stretch_option: str + bg: float + sigma: float + do_stretch: bool = True + channels_linked: bool = False + images_linked: bool = False + + def __init__(self, stretch_option: str): + self.stretch_option = stretch_option + + if stretch_option == "No Stretch": + self.do_stretch = False + + elif stretch_option == "10% Bg, 3 sigma": + self.bg = 0.1 + self.sigma = 3.0 + + elif stretch_option == "15% Bg, 3 sigma": + self.bg = 0.15 + self.sigma = 3.0 + + elif stretch_option == "20% Bg, 3 sigma": + self.bg = 0.2 + self.sigma = 3.0 + + elif stretch_option == "30% Bg, 2 sigma": + self.bg = 0.3 + self.sigma = 2.0 + + def stretch_channel(shm_name, c, bg, sigma, shape, dtype, logging_queue, logging_configurer): logging_configurer(logging_queue) @@ -48,33 +77,17 @@ def stretch_channel(shm_name, c, bg, sigma, shape, dtype, logging_queue, logging logging.info("stretch.stretch_channel finished") -def stretch(data, bg, sigma): - - shm = shared_memory.SharedMemory(create=True, size=data.nbytes) - copy = np.ndarray(data.shape, dtype=data.dtype, buffer=shm.buf) - np.copyto(copy, data) +def stretch(data, stretch_params: StretchParameters): + return stretch_all([data], stretch_params)[0] - futures = [] - logging_queue = get_logging_queue() - for c in range(copy.shape[-1]): - futures.insert(c, executor.submit(stretch_channel, shm.name, c, bg, sigma, copy.shape, copy.dtype, logging_queue, worker_configurer)) - wait(futures) - - copy = np.copy(copy) - - shm.close() - shm.unlink() - - return copy - -def stretch_all(datas, stretch_params): +def stretch_all(datas, stretch_params: StretchParameters): - if stretch_params is None: + if not stretch_params.do_stretch: datas = [data.clip(min=0, max=1) for data in datas] return datas - bg = stretch_params[0] - sigma = stretch_params[1] + bg = stretch_params.bg + sigma = stretch_params.sigma futures = [] shms = [] copies = [] @@ -111,34 +124,4 @@ def MTF(data, midtone): return data - -def asinh_stretch(data, bg, sigma): - - data = data/np.max(data) - median = np.median(data) - deviation_from_median = np.mean(np.abs(data-median)) - - shadow_clipping = np.clip(median - sigma*deviation_from_median, 0, 1.0) - highlight_clipping = 1.0 - - # Use rootfinding to find correct factor a - a = root(asinhfunc_root, 0.5, ((median-shadow_clipping)/(highlight_clipping - shadow_clipping),bg), method='lm') - a = np.abs(a.x) - - data[data <= shadow_clipping] = 0.0 - data[data >= highlight_clipping] = 1.0 - - indx_inside = data > shadow_clipping - - data[indx_inside] = (data[indx_inside]-shadow_clipping)/(highlight_clipping - shadow_clipping) - - asinh = AsinhStretch(a) - data = asinh(data) - - return data - - -def asinhfunc_root(a,x,y): - - return np.arcsinh(x/a)/np.arcsinh(1/a) - y diff --git a/tests/test_AstroImage.py b/tests/test_AstroImage.py index 1d5a72b..7d73615 100644 --- a/tests/test_AstroImage.py +++ b/tests/test_AstroImage.py @@ -1,4 +1,5 @@ from graxpert.astroimage import AstroImage +from graxpert.stretch import StretchParameters from numpy.testing import assert_array_almost_equal import os import numpy as np @@ -29,7 +30,7 @@ file_types = ["16 bit Fits", "32 bit Fits", "16 bit Tiff", "32 bit Tiff", "16 bit XISF", "32 bit XISF"] saturation = 2.0 -stretch = "30% Bg, 2 sigma" +stretch_params = StretchParameters("30% Bg, 2 sigma") @@ -75,7 +76,7 @@ def test_update_display_mono(): a = AstroImage(do_update_display=False) a.set_from_array(array_mono) - a.update_display(stretch, saturation) + a.update_display(stretch_params, saturation) assert np.asarray(a.img_display).shape == (5,6) assert np.asarray(a.img_display_saturated).shape == (5,6) @@ -83,7 +84,7 @@ def test_update_display_color(): a = AstroImage(do_update_display=False) a.set_from_array(array_color) - a.update_display(stretch, saturation) + a.update_display(stretch_params, saturation) assert np.asarray(a.img_display).shape == (5,6,3) assert np.asarray(a.img_display_saturated).shape == (5,6,3) @@ -92,7 +93,7 @@ def test_update_display_color(): def test_save_mono(tmp_path, file_type): a = AstroImage() - a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) + a.set_from_file("./tests/test_images/mono_32bit.fits", stretch_params, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save(file_dir, file_type) @@ -121,7 +122,7 @@ def test_save_mono(tmp_path, file_type): def test_save_color(tmp_path, file_type): a = AstroImage() - a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) + a.set_from_file("./tests/test_images/color_32bit.fits", stretch_params, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) a.save(file_dir, file_type) @@ -149,10 +150,10 @@ def test_save_color(tmp_path, file_type): def test_save_stretched_mono(tmp_path, file_type): a = AstroImage() - a.set_from_file("./tests/test_images/mono_32bit.fits", stretch, saturation) + a.set_from_file("./tests/test_images/mono_32bit.fits", stretch_params, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) - a.save_stretched(file_dir, file_type, stretch) + a.save_stretched(file_dir, file_type, stretch_params) if file_ending == "fits": hdul = fits.open(file_dir) @@ -178,10 +179,10 @@ def test_save_stretched_mono(tmp_path, file_type): def test_save_stretched_color(tmp_path, file_type): a = AstroImage() - a.set_from_file("./tests/test_images/color_32bit.fits", stretch, saturation) + a.set_from_file("./tests/test_images/color_32bit.fits", stretch_params, saturation) file_ending = file_type[-4::].lower() file_dir = os.path.join(tmp_path, file_type + "." + file_ending) - a.save_stretched(file_dir, file_type, stretch) + a.save_stretched(file_dir, file_type, stretch_params) if file_ending == "fits": hdul = fits.open(file_dir) From 0c5944303d217bbcaae7b623f4932d19c5a1b0bf Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 21 Jan 2024 14:05:26 +0100 Subject: [PATCH 07/59] Images can now be stretched with linked channels --- graxpert/stretch.py | 56 ++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/graxpert/stretch.py b/graxpert/stretch.py index 77aac71..cb91cb8 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -10,6 +10,13 @@ from graxpert.mp_logging import get_logging_queue, worker_configurer from graxpert.parallel_processing import executor +from dataclasses import dataclass + +@dataclass +class MTFStretchParameters: + midtone: float + shadow_clipping: float + highlight_clipping: float = 1.0 class StretchParameters: stretch_option: str @@ -19,8 +26,10 @@ class StretchParameters: channels_linked: bool = False images_linked: bool = False - def __init__(self, stretch_option: str): + def __init__(self, stretch_option: str, channels_linked: bool = False, images_linked: bool = False): self.stretch_option = stretch_option + self.channels_linked = channels_linked + self. images_linked = images_linked if stretch_option == "No Stretch": self.do_stretch = False @@ -42,7 +51,7 @@ def __init__(self, stretch_option: str): self.sigma = 2.0 -def stretch_channel(shm_name, c, bg, sigma, shape, dtype, logging_queue, logging_configurer): +def stretch_channel(shm_name, c, stretch_params, mtf_stretch_params, shape, dtype, logging_queue, logging_configurer): logging_configurer(logging_queue) logging.info("stretch.stretch_channel started") @@ -52,23 +61,17 @@ def stretch_channel(shm_name, c, bg, sigma, shape, dtype, logging_queue, logging channel = channels[:,:,c] try: - indx_clip = np.logical_and(channel < 1.0, channel > 0.0) - median = np.median(channel[indx_clip]) - mad = np.median(np.abs(channel[indx_clip]-median)) - - shadow_clipping = np.clip(median - sigma*mad, 0, 1.0) - highlight_clipping = 1.0 - - midtone = MTF((median-shadow_clipping)/(highlight_clipping - shadow_clipping), bg) + if not mtf_stretch_params: + mtf_stretch_params = calculate_mtf_stretch_parameters(stretch_params, channel) - channel[channel <= shadow_clipping] = 0.0 - channel[channel >= highlight_clipping] = 1.0 + channel[channel <= mtf_stretch_params.shadow_clipping] = 0.0 + channel[channel >= mtf_stretch_params.highlight_clipping] = 1.0 - indx_inside = np.logical_and(channel > shadow_clipping, channel < highlight_clipping) + indx_inside = np.logical_and(channel > mtf_stretch_params.shadow_clipping, channel < mtf_stretch_params.highlight_clipping) - channel[indx_inside] = (channel[indx_inside]-shadow_clipping)/(highlight_clipping - shadow_clipping) + channel[indx_inside] = (channel[indx_inside]-mtf_stretch_params.shadow_clipping)/(mtf_stretch_params.highlight_clipping - mtf_stretch_params.shadow_clipping) - channel = MTF(channel, midtone) + channel = MTF(channel, mtf_stretch_params.midtone) except: logging.exception("An error occured while stretching a color channel") @@ -76,6 +79,20 @@ def stretch_channel(shm_name, c, bg, sigma, shape, dtype, logging_queue, logging existing_shm.close() logging.info("stretch.stretch_channel finished") + +def calculate_mtf_stretch_parameters(stretch_params, channel): + channel = channel.flatten() + + indx_clip = np.logical_and(channel < 1.0, channel > 0.0) + median = np.median(channel[indx_clip]) + mad = np.median(np.abs(channel[indx_clip]-median)) + + shadow_clipping = np.clip(median - stretch_params.sigma*mad, 0, 1.0) + highlight_clipping = 1.0 + midtone = MTF((median-shadow_clipping)/(highlight_clipping - shadow_clipping), stretch_params.bg) + + return MTFStretchParameters(midtone, shadow_clipping) + def stretch(data, stretch_params: StretchParameters): return stretch_all([data], stretch_params)[0] @@ -86,8 +103,6 @@ def stretch_all(datas, stretch_params: StretchParameters): datas = [data.clip(min=0, max=1) for data in datas] return datas - bg = stretch_params.bg - sigma = stretch_params.sigma futures = [] shms = [] copies = [] @@ -100,8 +115,13 @@ def stretch_all(datas, stretch_params: StretchParameters): np.copyto(copy, data) shms.append(shm) copies.append(copy) + + mtf_stretch_params = None + if stretch_params.channels_linked: + mtf_stretch_params = calculate_mtf_stretch_parameters(stretch_params, copy) + for c in range(copy.shape[-1]): - futures.insert(c, executor.submit(stretch_channel, shm.name, c, bg, sigma, copy.shape, copy.dtype, logging_queue, worker_configurer)) + futures.insert(c, executor.submit(stretch_channel, shm.name, c, stretch_params, mtf_stretch_params, copy.shape, copy.dtype, logging_queue, worker_configurer)) wait(futures) for copy in copies: From 94f52041036c110d682310a6f8c87d4152d4fc77 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 21 Jan 2024 14:36:34 +0100 Subject: [PATCH 08/59] Added checkbox for linked channels stretch option --- graxpert/application/app.py | 23 +++++++++++------ graxpert/application/app_events.py | 1 + graxpert/preferences.py | 1 + graxpert/ui/left_menu.py | 40 +++++++++++++++++------------- 4 files changed, 40 insertions(+), 25 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 1d1cfff..199a859 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -51,6 +51,7 @@ def initialize(self): # stretch options eventbus.add_listener(AppEvents.STRETCH_OPTION_CHANGED, self.on_stretch_option_changed) eventbus.add_listener(AppEvents.CHANGE_SATURATION_REQUEST, self.on_change_saturation_request) + eventbus.add_listener(AppEvents.CHANNELS_LINKED_CHANGED, self.on_channels_linked_option_changed) # sample selection eventbus.add_listener(AppEvents.DISPLAY_PTS_CHANGED, self.on_display_pts_changed) eventbus.add_listener(AppEvents.BG_FLOOD_SELECTION_CHANGED, self.on_bg_floot_selection_changed) @@ -155,7 +156,7 @@ def on_calculate_request(self, event=None): self.images["Background"].copy_metadata(self.images["Original"]) all_images = [self.images["Original"].img_array, self.images["Processed"].img_array, self.images["Background"].img_array] - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option)) + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) self.images["Background"].update_display_from_array(stretches[2], self.prefs.saturation) @@ -220,7 +221,7 @@ def on_load_image(self, event): try: image = AstroImage() - image.set_from_file(filename, StretchParameters(self.prefs.stretch_option), self.prefs.saturation) + image.set_from_file(filename, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option), self.prefs.saturation) except Exception as e: eventbus.emit(AppEvents.LOAD_IMAGE_ERROR) @@ -363,9 +364,9 @@ def on_save_stretched_request(self, event): try: if self.images["Processed"] is None: - self.images["Original"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option)) + self.images["Original"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) else: - self.images["Processed"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option)) + self.images["Processed"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) except Exception as e: eventbus.emit(AppEvents.SAVE_ERROR) logging.exception(e) @@ -381,7 +382,15 @@ def on_spline_order_changed(self, event): def on_stretch_option_changed(self, event): self.prefs.stretch_option = event["stretch_option"] + self.do_stretch() + + def on_channels_linked_option_changed(self, event): + self.prefs.channels_linked_option = event["channels_linked"] + self.do_stretch() + + # application logic + def do_stretch(self): eventbus.emit(AppEvents.STRETCH_IMAGE_BEGIN) try: @@ -391,7 +400,7 @@ def on_stretch_option_changed(self, event): if img is not None: all_images.append(img.img_array) if len(all_images) > 0: - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option)) + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) for idx, img in enumerate(self.images.values()): if img is not None: img.update_display_from_array(stretches[idx], self.prefs.saturation) @@ -400,8 +409,7 @@ def on_stretch_option_changed(self, event): logging.exception(e) eventbus.emit(AppEvents.STRETCH_IMAGE_END) - - # application logic + def remove_pt(self, event): if len(self.cmd.app_state.background_points) == 0 or not self.prefs.display_pts: return False @@ -436,7 +444,6 @@ def remove_pt(self, event): else: return False - # application logic def reset_backgroundpts(self): if len(self.cmd.app_state.background_points) > 0: self.cmd = Command(RESET_POINTS_HANDLER, self.cmd) diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index fb0c77f..cbba78a 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -22,6 +22,7 @@ class AppEvents(Enum): REDRAW_POINTS_REQUEST = auto() # stretch options STRETCH_OPTION_CHANGED = auto() + CHANNELS_LINKED_CHANGED = auto() # sample selection DISPLAY_PTS_CHANGED = auto() BG_FLOOD_SELECTION_CHANGED = auto() diff --git a/graxpert/preferences.py b/graxpert/preferences.py index a8a1ae4..62aa145 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -22,6 +22,7 @@ class Prefs: bg_pts_option: int = 15 stretch_option: AnyStr = "No Stretch" saturation: float = 1.0 + channels_linked_option: bool = False display_pts: bool = True bg_tol_option: float = 1.0 interpol_type_option: AnyStr = "RBF" diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index 78d5a2f..a176014 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -57,6 +57,10 @@ def __init__(self, parent, **kwargs): self.saturation = tk.DoubleVar() self.saturation.set(graxpert.prefs.saturation) self.saturation.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANGE_SATURATION_REQUEST, {"saturation": self.saturation.get()})) + + self.channels_linked = tk.BooleanVar() + self.channels_linked.set(graxpert.prefs.channels_linked_option) + self.channels_linked.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANNELS_LINKED_CHANGED, {"channels_linked": self.channels_linked.get()})) # sample selection self.display_pts = tk.BooleanVar() @@ -126,6 +130,7 @@ def create_children(self): max_value=3, precision=1, ) + self.channels_linked_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Channels linked"), variable=self.channels_linked) # sample selection self.sample_selection_title = ExtractionStep(self.sub_frame, 3, _(" Sample Selection")) @@ -188,29 +193,30 @@ def place_children(self): self.stretch_options_title.grid(column=0, row=2, columnspan=2, pady=pady, sticky=tk.EW) self.stretch_menu.grid(column=1, row=3, pady=pady, sticky=tk.EW) self.saturation_slider.grid(column=1, row=4, pady=pady, sticky=tk.EW) + self.channels_linked_switch.grid(column=1, row=5, pady=pady, sticky=tk.EW) # sample selection - self.sample_selection_title.grid(column=0, row=5, columnspan=2, pady=pady, sticky=tk.EW) - self.display_pts_switch.grid(column=1, row=6, pady=pady, sticky=tk.EW) - self.flood_select_pts_switch.grid(column=1, row=7, pady=pady, sticky=tk.EW) - self.bg_pts_slider.grid(column=1, row=8, pady=pady, sticky=tk.EW) - self.bg_tol_slider.grid(column=1, row=9, pady=pady, sticky=tk.EW) - self.bg_selection_button.grid(column=1, row=10, pady=pady, sticky=tk.EW) - self.reset_button.grid(column=1, row=11, pady=pady, sticky=tk.EW) + self.sample_selection_title.grid(column=0, row=6, columnspan=2, pady=pady, sticky=tk.EW) + self.display_pts_switch.grid(column=1, row=7, pady=pady, sticky=tk.EW) + self.flood_select_pts_switch.grid(column=1, row=8, pady=pady, sticky=tk.EW) + self.bg_pts_slider.grid(column=1, row=9, pady=pady, sticky=tk.EW) + self.bg_tol_slider.grid(column=1, row=10, pady=pady, sticky=tk.EW) + self.bg_selection_button.grid(column=1, row=11, pady=pady, sticky=tk.EW) + self.reset_button.grid(column=1, row=12, pady=pady, sticky=tk.EW) # calculation - self.calculation_title.grid(column=0, row=12, pady=pady, columnspan=2, sticky=tk.EW) - self.intp_type_text.grid(column=1, row=13, pady=pady, sticky=tk.EW) - self.interpol_menu.grid(column=1, row=14, pady=pady, sticky=tk.EW) - self.smoothing_slider.grid(column=1, row=15, pady=pady, sticky=tk.EW) - self.calculate_button.grid(column=1, row=16, pady=pady, sticky=tk.EW) + self.calculation_title.grid(column=0, row=13, pady=pady, columnspan=2, sticky=tk.EW) + self.intp_type_text.grid(column=1, row=14, pady=pady, sticky=tk.EW) + self.interpol_menu.grid(column=1, row=15, pady=pady, sticky=tk.EW) + self.smoothing_slider.grid(column=1, row=16, pady=pady, sticky=tk.EW) + self.calculate_button.grid(column=1, row=17, pady=pady, sticky=tk.EW) # saving - self.saving_title.grid(column=0, row=17, pady=pady, columnspan=2, sticky=tk.EW) - self.saveas_menu.grid(column=1, row=18, pady=pady, sticky=tk.EW) - self.save_button.grid(column=1, row=19, pady=pady, sticky=tk.EW) - self.save_background_button.grid(column=1, row=20, pady=pady, sticky=tk.EW) - self.save_stretched_button.grid(column=1, row=21, pady=pady, sticky=tk.EW) + self.saving_title.grid(column=0, row=18, pady=pady, columnspan=2, sticky=tk.EW) + self.saveas_menu.grid(column=1, row=19, pady=pady, sticky=tk.EW) + self.save_button.grid(column=1, row=20, pady=pady, sticky=tk.EW) + self.save_background_button.grid(column=1, row=21, pady=pady, sticky=tk.EW) + self.save_stretched_button.grid(column=1, row=22, pady=pady, sticky=tk.EW) def menu_open_clicked(self, event=None): eventbus.emit(AppEvents.OPEN_FILE_DIALOG_REQUEST) From eb6e4eabfbdd4fa3b52b1047dfaaa0d0b492a1ee Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 21 Jan 2024 20:00:22 +0100 Subject: [PATCH 09/59] Implemented option for stretch with linked images --- graxpert/stretch.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/graxpert/stretch.py b/graxpert/stretch.py index cb91cb8..6474922 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -107,8 +107,18 @@ def stretch_all(datas, stretch_params: StretchParameters): shms = [] copies = [] result = [] - logging_queue = get_logging_queue() + + common_mtf_stretch_params_per_channel = [] + if stretch_params.images_linked: + if stretch_params.channels_linked: + mtf_stretch_params_for_all_channel = calculate_mtf_stretch_parameters(stretch_params, datas[0]) + common_mtf_stretch_params_per_channel = [mtf_stretch_params_for_all_channel] * datas[0].shape[-1] + else: + for c in range(datas[0].shape[-1]): + common_mtf_stretch_params_per_channel.append(calculate_mtf_stretch_parameters(stretch_params, datas[0][:,:,c])) + + for data in datas: shm = shared_memory.SharedMemory(create=True, size=data.nbytes) copy = np.ndarray(data.shape, dtype=data.dtype, buffer=shm.buf) @@ -116,12 +126,16 @@ def stretch_all(datas, stretch_params: StretchParameters): shms.append(shm) copies.append(copy) - mtf_stretch_params = None - if stretch_params.channels_linked: + mtf_stretch_params = [None] * data.shape[-1] + + if stretch_params.images_linked: + mtf_stretch_params = common_mtf_stretch_params_per_channel + elif stretch_params.channels_linked: mtf_stretch_params = calculate_mtf_stretch_parameters(stretch_params, copy) + mtf_stretch_params = [mtf_stretch_params] * data.shape[-1] for c in range(copy.shape[-1]): - futures.insert(c, executor.submit(stretch_channel, shm.name, c, stretch_params, mtf_stretch_params, copy.shape, copy.dtype, logging_queue, worker_configurer)) + futures.insert(c, executor.submit(stretch_channel, shm.name, c, stretch_params, mtf_stretch_params[c], copy.shape, copy.dtype, logging_queue, worker_configurer)) wait(futures) for copy in copies: From 3c94e9e896eb71198e5d068ea92d6aa1c40b1058 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Mon, 22 Jan 2024 19:18:32 +0100 Subject: [PATCH 10/59] The astrometric solution of xisf files is now preserved --- graxpert/astroimage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graxpert/astroimage.py b/graxpert/astroimage.py index edc6911..243a570 100644 --- a/graxpert/astroimage.py +++ b/graxpert/astroimage.py @@ -53,8 +53,8 @@ def set_from_file(self, directory: str, stretch_params: StretchParameters, satur self.xisf_imagedata_2_fitsheader() img_array = np.copy(xisf.read_image(0)) - entry = {"id": "BackgroundExtraction", "type": "String", "value": "GraXpert"} - self.image_metadata["XISFProperties"] = {"ProcessingHistory": entry} + entry = {"id": "GraXpert:ProcessingHistory", "type": "String", "value": "BackgroundExtraction"} + self.image_metadata["XISFProperties"]["GraXpert:ProcessingHistory"] = entry else: img_array = np.copy(io.imread(directory)) From aecb6d0ceb0287bbae9dcd1683c073e48a239ed7 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Tue, 12 Mar 2024 12:51:38 +0100 Subject: [PATCH 11/59] rework ui to prepare integration of denoising ai --- graxpert/application/app.py | 34 +- graxpert/application/app_events.py | 6 + graxpert/denoising.py | 2 + graxpert/ui/left_menu.py | 349 +++++++++----- graxpert/ui/right_menu.py | 12 +- graxpert/ui/tooltip.py | 2 + graxpert/ui/ui_events.py | 2 + graxpert/ui/widgets.py | 55 ++- img/HELP.png | Bin 1422 -> 0 bytes img/HELP_trapez.png | Bin 1828 -> 0 bytes img/advanced.png | Bin 2173 -> 0 bytes img/advanced_trapez.png | Bin 2786 -> 0 bytes img/gfx_number_1.png | Bin 4226 -> 0 bytes img/gfx_number_2.png | Bin 6276 -> 0 bytes img/gfx_number_3.png | Bin 6198 -> 0 bytes img/gfx_number_4.png | Bin 5461 -> 0 bytes img/gfx_number_5.png | Bin 6082 -> 0 bytes img/gfx_numbers.png | Bin 0 -> 44855 bytes img/gfx_numbers.svg | 737 +++++++++++++++++++++++++++++ 19 files changed, 1067 insertions(+), 132 deletions(-) create mode 100644 graxpert/denoising.py delete mode 100644 img/HELP.png delete mode 100644 img/HELP_trapez.png delete mode 100644 img/advanced.png delete mode 100644 img/advanced_trapez.png delete mode 100644 img/gfx_number_1.png delete mode 100644 img/gfx_number_2.png delete mode 100644 img/gfx_number_3.png delete mode 100644 img/gfx_number_4.png delete mode 100644 img/gfx_number_5.png create mode 100644 img/gfx_numbers.png create mode 100644 img/gfx_numbers.svg diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 199a859..3c79ffa 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -13,10 +13,11 @@ from graxpert.astroimage import AstroImage from graxpert.background_extraction import extract_background from graxpert.commands import INIT_HANDLER, RESET_POINTS_HANDLER, RM_POINT_HANDLER, SEL_POINTS_HANDLER, Command +from graxpert.denoising import denoise from graxpert.localization import _ from graxpert.mp_logging import logfile_name from graxpert.preferences import fitsheader_2_app_state, load_preferences, prefs_2_app_state -from graxpert.stretch import stretch_all, StretchParameters +from graxpert.stretch import StretchParameters, stretch_all from graxpert.ui.loadingframe import DynamicProgressThread @@ -63,6 +64,8 @@ def initialize(self): eventbus.add_listener(AppEvents.INTERPOL_TYPE_CHANGED, self.on_interpol_type_changed) eventbus.add_listener(AppEvents.SMOTTHING_CHANGED, self.on_smoothing_changed) eventbus.add_listener(AppEvents.CALCULATE_REQUEST, self.on_calculate_request) + # denoising + eventbus.add_listener(AppEvents.DENOISE_REQUEST, self.on_denoise_request) # saving eventbus.add_listener(AppEvents.SAVE_AS_CHANGED, self.on_save_as_changed) eventbus.add_listener(AppEvents.SAVE_REQUEST, self.on_save_request) @@ -305,6 +308,30 @@ def on_save_as_changed(self, event): def on_smoothing_changed(self, event): self.prefs.smoothing_option = event["smoothing_option"] + def on_denoise_request(self, event): + if self.images["Original"] is None: + messagebox.showerror("Error", _("Please load your picture first.")) + return + + eventbus.emit(AppEvents.CALCULATE_BEGIN) + + progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p})) + + try: + imarray = np.copy(self.images["Original"].img_array) + + denoise(imarray, ai_model_path_from_version(self.prefs.ai_version), progress=progress) + + eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) + + except Exception as e: + logging.exception(e) + eventbus.emit(AppEvents.DENOISE_ERROR) + messagebox.showerror("Error", _("An error occured during denoising. Please see the log at {}.".format(logfile_name))) + finally: + progress.done_progress() + eventbus.emit(AppEvents.DENOISE_END) + def on_save_request(self, event): if self.prefs.saveas_option == "16 bit Tiff" or self.prefs.saveas_option == "32 bit Tiff": dir = tk.filedialog.asksaveasfilename(initialfile=self.filename + "_GraXpert.tiff", filetypes=[("Tiff", ".tiff")], defaultextension=".tiff", initialdir=self.prefs.working_dir) @@ -383,11 +410,10 @@ def on_spline_order_changed(self, event): def on_stretch_option_changed(self, event): self.prefs.stretch_option = event["stretch_option"] self.do_stretch() - + def on_channels_linked_option_changed(self, event): self.prefs.channels_linked_option = event["channels_linked"] self.do_stretch() - # application logic def do_stretch(self): @@ -409,7 +435,7 @@ def do_stretch(self): logging.exception(e) eventbus.emit(AppEvents.STRETCH_IMAGE_END) - + def remove_pt(self, event): if len(self.cmd.app_state.background_points) == 0 or not self.prefs.display_pts: return False diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index cbba78a..ec61484 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -42,6 +42,12 @@ class AppEvents(Enum): CALCULATE_PROGRESS = auto() CALCULATE_END = auto() CALCULATE_ERROR = auto() + # denoising + DENOISE_REQUEST = auto() + DENOISE_BEGIN = auto() + DENOISE_PROGRESS = auto() + DENOISE_END = auto() + DENOISE_ERROR = auto() # saving SAVE_AS_CHANGED = auto() SAVE_REQUEST = auto() diff --git a/graxpert/denoising.py b/graxpert/denoising.py new file mode 100644 index 0000000..8988b31 --- /dev/null +++ b/graxpert/denoising.py @@ -0,0 +1,2 @@ +def denoise(image, AI_dir, window_size=256, stride=128, strength=1.0, progress=None): + raise NotImplementedError("Denoising has not been implemented yet") diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index a176014..21c72fc 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -8,28 +8,105 @@ from graxpert.application.eventbus import eventbus from graxpert.localization import _ from graxpert.ui.ui_events import UiEvents -from graxpert.ui.widgets import ( - CollapsibleMenuFrame, - ExtractionStep, - GraXpertButton, - GraXpertCheckbox, - GraXpertLabel, - GraXpertOptionMenu, - GraXpertScrollableFrame, - ValueSlider, - default_label_width, - padx, - pady, -) +from graxpert.ui.widgets import CollapsibleMenuFrame, GraXpertButton, GraXpertCheckbox, GraXpertOptionMenu, GraXpertScrollableFrame, ProcessingStep, ValueSlider, default_label_width, padx, pady + + +class LoadMenu(CollapsibleMenuFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, title=_("Loading"), show=True, number=1, **kwargs) + + # stretch options + self.stretch_options = ["No Stretch", "10% Bg, 3 sigma", "15% Bg, 3 sigma", "20% Bg, 3 sigma", "30% Bg, 2 sigma"] + self.stretch_option_current = StringVar() + self.stretch_option_current.set(graxpert.prefs.stretch_option) + self.stretch_option_current.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.STRETCH_OPTION_CHANGED, {"stretch_option": self.stretch_option_current.get()})) + + self.saturation = tk.DoubleVar() + self.saturation.set(graxpert.prefs.saturation) + self.saturation.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANGE_SATURATION_REQUEST, {"saturation": self.saturation.get()})) + + self.channels_linked = tk.BooleanVar() + self.channels_linked.set(graxpert.prefs.channels_linked_option) + self.channels_linked.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANNELS_LINKED_CHANGED, {"channels_linked": self.channels_linked.get()})) + + self.create_children() + self.setup_layout() + self.place_children() + + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "LOAD" else None) + + def create_children(self): + super().create_children() + + # image loading + self.load_image_button = GraXpertButton( + self.sub_frame, + text=_("Load Image"), + fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], + hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], + command=self.menu_open_clicked, + ) + self.tt_load = tooltip.Tooltip(self.load_image_button, text=tooltip.load_text) + + # stretch options + self.stretch_options_title = ProcessingStep(self.sub_frame, number=0, indent=2, title=_(" Stretch Options")) + self.stretch_menu = GraXpertOptionMenu( + self.sub_frame, + variable=self.stretch_option_current, + values=self.stretch_options, + ) + tooltip.Tooltip(self.stretch_menu, text=tooltip.stretch_text) + self.saturation_slider = ValueSlider( + self.sub_frame, + width=default_label_width, + variable_name=_("Saturation"), + variable=self.saturation, + min_value=0, + max_value=3, + precision=1, + ) + self.channels_linked_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Channels linked"), variable=self.channels_linked) + + def setup_layout(self): + super().setup_layout() + + def place_children(self): + super().place_children() + + row = -1 + + def next_row(): + nonlocal row + row += 1 + return row + + # image loading + self.load_image_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + + # stretch options + self.stretch_options_title.grid(column=0, row=next_row(), columnspan=2, pady=pady, sticky=tk.EW) + self.stretch_menu.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.saturation_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.channels_linked_switch.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + + def toggle(self): + super().toggle() + if self.show: + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "LOAD") + + def menu_open_clicked(self, event=None): + eventbus.emit(AppEvents.OPEN_FILE_DIALOG_REQUEST) class CropMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Crop"), show=False, **kwargs) + super().__init__(parent, title=_("Crop"), show=False, number=2, **kwargs) self.create_children() self.setup_layout() self.place_children() + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "CROP" else None) + def create_children(self): super().create_children() self.cropmode_button = GraXpertButton(self.sub_frame, text=_("Crop mode on/off"), command=lambda: eventbus.emit(UiEvents.TOGGLE_CROP_REQUEST)) @@ -43,24 +120,21 @@ def place_children(self): self.cropmode_button.grid(column=1, row=0, pady=pady, sticky=tk.NSEW) self.cropapply_button.grid(column=1, row=1, pady=pady, sticky=tk.NSEW) + def toggle(self): + super().toggle() + if self.show: + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "CROP") + class ExtractionMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Background Extraction"), **kwargs) - - # stretch options - self.stretch_options = ["No Stretch", "10% Bg, 3 sigma", "15% Bg, 3 sigma", "20% Bg, 3 sigma", "30% Bg, 2 sigma"] - self.stretch_option_current = StringVar() - self.stretch_option_current.set(graxpert.prefs.stretch_option) - self.stretch_option_current.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.STRETCH_OPTION_CHANGED, {"stretch_option": self.stretch_option_current.get()})) + super().__init__(parent, title=_("Background Extraction"), show=False, number=3, **kwargs) - self.saturation = tk.DoubleVar() - self.saturation.set(graxpert.prefs.saturation) - self.saturation.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANGE_SATURATION_REQUEST, {"saturation": self.saturation.get()})) - - self.channels_linked = tk.BooleanVar() - self.channels_linked.set(graxpert.prefs.channels_linked_option) - self.channels_linked.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANNELS_LINKED_CHANGED, {"channels_linked": self.channels_linked.get()})) + # method selection + self.interpol_options = ["RBF", "Splines", "Kriging", "AI"] + self.interpol_type = tk.StringVar() + self.interpol_type.set(graxpert.prefs.interpol_type_option) + self.interpol_type.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.INTERPOL_TYPE_CHANGED, {"interpol_type_option": self.interpol_type.get()})) # sample selection self.display_pts = tk.BooleanVar() @@ -80,60 +154,27 @@ def __init__(self, parent, **kwargs): self.bg_tol.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.BG_TOL_CHANGED, {"bg_tol_option": self.bg_tol.get()})) # calculation - self.interpol_options = ["RBF", "Splines", "Kriging", "AI"] - self.interpol_type = tk.StringVar() - self.interpol_type.set(graxpert.prefs.interpol_type_option) - self.interpol_type.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.INTERPOL_TYPE_CHANGED, {"interpol_type_option": self.interpol_type.get()})) - self.smoothing = tk.DoubleVar() self.smoothing.set(graxpert.prefs.smoothing_option) self.smoothing.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.SMOTTHING_CHANGED, {"smoothing_option": self.smoothing.get()})) - # saving - self.saveas_options = ["16 bit Tiff", "32 bit Tiff", "16 bit Fits", "32 bit Fits", "16 bit XISF", "32 bit XISF"] - self.saveas_type = tk.StringVar() - self.saveas_type.set(graxpert.prefs.saveas_option) - self.saveas_type.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.SAVE_AS_CHANGED, {"saveas_option": self.saveas_type.get()})) - self.create_children() self.setup_layout() self.place_children() + eventbus.add_listener(AppEvents.INTERPOL_TYPE_CHANGED, self.place_children) + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "BGE" else None) + def create_children(self): super().create_children() - # image loading - self.loading_title = ExtractionStep(self.sub_frame, 1, _(" Loading")) - self.load_image_button = GraXpertButton( - self.sub_frame, - text=_("Load Image"), - fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], - hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], - command=self.menu_open_clicked, - ) - self.tt_load = tooltip.Tooltip(self.load_image_button, text=tooltip.load_text) - - # stretch options - self.stretch_options_title = ExtractionStep(self.sub_frame, 2, _(" Stretch Options")) - self.stretch_menu = GraXpertOptionMenu( - self.sub_frame, - variable=self.stretch_option_current, - values=self.stretch_options, - ) - tooltip.Tooltip(self.stretch_menu, text=tooltip.stretch_text) - self.saturation_slider = ValueSlider( - self.sub_frame, - width=default_label_width, - variable_name=_("Saturation"), - variable=self.saturation, - min_value=0, - max_value=3, - precision=1, - ) - self.channels_linked_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Channels linked"), variable=self.channels_linked) + # method selection + self.intp_type_title = ProcessingStep(self.sub_frame, number=0, title=_("Interpolation Method:")) + self.interpol_menu = GraXpertOptionMenu(self.sub_frame, variable=self.interpol_type, values=self.interpol_options) + tooltip.Tooltip(self.interpol_menu, text=tooltip.interpol_type_text) # sample selection - self.sample_selection_title = ExtractionStep(self.sub_frame, 3, _(" Sample Selection")) + self.sample_selection_title = ProcessingStep(self.sub_frame, number=0, title=_(" Sample Selection")) self.display_pts_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Display points"), variable=self.display_pts) self.flood_select_pts_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Flooded generation"), variable=self.flood_select_pts) tooltip.Tooltip(self.flood_select_pts_switch, text=tooltip.bg_flood_text) @@ -147,10 +188,7 @@ def create_children(self): tooltip.Tooltip(self.reset_button, text=tooltip.reset_text) # calculation - self.calculation_title = ExtractionStep(self.sub_frame, 4, _(" Calculation")) - self.intp_type_text = GraXpertLabel(self.sub_frame, text=_("Interpolation Method:")) - self.interpol_menu = GraXpertOptionMenu(self.sub_frame, variable=self.interpol_type, values=self.interpol_options) - tooltip.Tooltip(self.interpol_menu, text=tooltip.interpol_type_text) + self.calculation_title = ProcessingStep(self.sub_frame, number=0, title=_(" Calculation")) self.smoothing_slider = ValueSlider(self.sub_frame, width=default_label_width, variable_name=_("Smoothing"), variable=self.smoothing, min_value=0, max_value=1, precision=1) tooltip.Tooltip(self.smoothing_slider, text=tooltip.smoothing_text) self.calculate_button = GraXpertButton( @@ -162,8 +200,109 @@ def create_children(self): ) tooltip.Tooltip(self.calculate_button, text=tooltip.calculate_text) + def setup_layout(self): + super().setup_layout() + + def place_children(self, event=None): + super().place_children() + + row = -1 + + def next_row(): + nonlocal row + row += 1 + return row + + # method selection + self.intp_type_title.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.interpol_menu.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + + # sample selection + self.sample_selection_title.grid_forget() + self.display_pts_switch.grid_forget() + self.flood_select_pts_switch.grid_forget() + self.bg_pts_slider.grid_forget() + self.bg_tol_slider.grid_forget() + self.bg_selection_button.grid_forget() + self.reset_button.grid_forget() + if not self.interpol_type.get() == "AI": + self.sample_selection_title.grid(column=0, row=next_row(), columnspan=2, pady=pady, sticky=tk.EW) + self.display_pts_switch.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.flood_select_pts_switch.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.bg_pts_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.bg_tol_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.bg_selection_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.reset_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + + # calculation + self.calculation_title.grid_forget() + self.smoothing_slider.grid_forget() + self.calculate_button.grid_forget() + self.calculation_title.grid(column=0, row=next_row(), pady=pady, columnspan=2, sticky=tk.EW) + self.smoothing_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.calculate_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + + def toggle(self): + super().toggle() + if self.show: + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "BGE") + + +class DenoiseMenu(CollapsibleMenuFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, title=_("Denoising"), show=False, number=4, **kwargs) + self.create_children() + self.setup_layout() + self.place_children() + + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "DENOISE" else None) + + def create_children(self): + super().create_children() + + self.denoise_button = GraXpertButton( + self.sub_frame, + text=_("Denoise Image"), + fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], + hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], + command=lambda: eventbus.emit(AppEvents.DENOISE_REQUEST), + ) + self.tt_load = tooltip.Tooltip(self.denoise_button, text=tooltip.denoise_text) + + def setup_layout(self): + super().setup_layout() + + def place_children(self): + super().place_children() + + self.denoise_button.grid(column=1, row=0, pady=pady, sticky=tk.EW) + + def toggle(self): + super().toggle() + if self.show: + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "DENOISE") + + +class SaveMenu(CollapsibleMenuFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, title=_("Saving"), show=False, number=5, **kwargs) + + # saving + self.saveas_options = ["16 bit Tiff", "32 bit Tiff", "16 bit Fits", "32 bit Fits", "16 bit XISF", "32 bit XISF"] + self.saveas_type = tk.StringVar() + self.saveas_type.set(graxpert.prefs.saveas_option) + self.saveas_type.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.SAVE_AS_CHANGED, {"saveas_option": self.saveas_type.get()})) + + self.create_children() + self.setup_layout() + self.place_children() + + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "SAVE" else None) + + def create_children(self): + super().create_children() + # saving - self.saving_title = ExtractionStep(self.sub_frame, 5, _(" Saving")) self.saveas_menu = GraXpertOptionMenu(self.sub_frame, variable=self.saveas_type, values=self.saveas_options) tooltip.Tooltip(self.saveas_menu, text=tooltip.saveas_text) self.save_button = GraXpertButton( @@ -185,41 +324,23 @@ def setup_layout(self): def place_children(self): super().place_children() - # image loading - self.loading_title.grid(column=0, row=0, columnspan=2, pady=pady, sticky=tk.EW) - self.load_image_button.grid(column=1, row=1, pady=pady, sticky=tk.EW) - - # stretch options - self.stretch_options_title.grid(column=0, row=2, columnspan=2, pady=pady, sticky=tk.EW) - self.stretch_menu.grid(column=1, row=3, pady=pady, sticky=tk.EW) - self.saturation_slider.grid(column=1, row=4, pady=pady, sticky=tk.EW) - self.channels_linked_switch.grid(column=1, row=5, pady=pady, sticky=tk.EW) - - # sample selection - self.sample_selection_title.grid(column=0, row=6, columnspan=2, pady=pady, sticky=tk.EW) - self.display_pts_switch.grid(column=1, row=7, pady=pady, sticky=tk.EW) - self.flood_select_pts_switch.grid(column=1, row=8, pady=pady, sticky=tk.EW) - self.bg_pts_slider.grid(column=1, row=9, pady=pady, sticky=tk.EW) - self.bg_tol_slider.grid(column=1, row=10, pady=pady, sticky=tk.EW) - self.bg_selection_button.grid(column=1, row=11, pady=pady, sticky=tk.EW) - self.reset_button.grid(column=1, row=12, pady=pady, sticky=tk.EW) + row = -1 - # calculation - self.calculation_title.grid(column=0, row=13, pady=pady, columnspan=2, sticky=tk.EW) - self.intp_type_text.grid(column=1, row=14, pady=pady, sticky=tk.EW) - self.interpol_menu.grid(column=1, row=15, pady=pady, sticky=tk.EW) - self.smoothing_slider.grid(column=1, row=16, pady=pady, sticky=tk.EW) - self.calculate_button.grid(column=1, row=17, pady=pady, sticky=tk.EW) + def next_row(): + nonlocal row + row += 1 + return row # saving - self.saving_title.grid(column=0, row=18, pady=pady, columnspan=2, sticky=tk.EW) - self.saveas_menu.grid(column=1, row=19, pady=pady, sticky=tk.EW) - self.save_button.grid(column=1, row=20, pady=pady, sticky=tk.EW) - self.save_background_button.grid(column=1, row=21, pady=pady, sticky=tk.EW) - self.save_stretched_button.grid(column=1, row=22, pady=pady, sticky=tk.EW) + self.saveas_menu.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.save_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.save_background_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + self.save_stretched_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) - def menu_open_clicked(self, event=None): - eventbus.emit(AppEvents.OPEN_FILE_DIALOG_REQUEST) + def toggle(self): + super().toggle() + if self.show: + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "SAVE") class LeftMenu(GraXpertScrollableFrame): @@ -230,13 +351,27 @@ def __init__(self, parent, **kwargs): self.place_children() def create_children(self): + self.load_menu = LoadMenu(self, fg_color="transparent") self.crop_menu = CropMenu(self, fg_color="transparent") self.extraction_menu = ExtractionMenu(self, fg_color="transparent") + self.denoise_menu = DenoiseMenu(self, fg_color="transparent") + self.save_menu = SaveMenu(self, fg_color="transparent") def setup_layout(self): self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) def place_children(self): - self.crop_menu.grid(column=0, row=0, ipadx=padx, sticky=tk.N) - self.extraction_menu.grid(column=0, row=1, ipadx=padx, sticky=tk.N) + + row = -1 + + def next_row(): + nonlocal row + row += 1 + return row + + self.load_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) + self.crop_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) + self.extraction_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) + self.denoise_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) + self.save_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) diff --git a/graxpert/ui/right_menu.py b/graxpert/ui/right_menu.py index a70495c..dc0a29d 100644 --- a/graxpert/ui/right_menu.py +++ b/graxpert/ui/right_menu.py @@ -12,7 +12,7 @@ from graxpert.application.eventbus import eventbus from graxpert.localization import _, lang from graxpert.resource_utils import resource_path -from graxpert.ui.widgets import ExtractionStep, GraXpertOptionMenu, GraXpertScrollableFrame, ValueSlider, padx, pady +from graxpert.ui.widgets import GraXpertOptionMenu, GraXpertScrollableFrame, ProcessingStep, ValueSlider, padx, pady class HelpText(CTkTextbox): @@ -54,23 +54,23 @@ def create_and_place_children(self): CTkLabel(self, image=logo, text="").grid(column=0, row=self.nrow(), padx=padx, pady=pady, sticky=tk.NSEW) CTkLabel(self, text=_("Instructions"), font=self.heading_font).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) - ExtractionStep(self, number=1, title=_(" Loading")).grid(**self.default_grid()) + ProcessingStep(self, number=1, indent=0, title=_(" Loading")).grid(**self.default_grid()) HelpText(self, text=_("Load your image.")).grid(**self.default_grid()) - ExtractionStep(self, number=2, title=_(" Stretch Options")).grid(**self.default_grid()) + ProcessingStep(self, number=2, indent=0, title=_(" Stretch Options")).grid(**self.default_grid()) HelpText(self, rows=2, text=_("Stretch your image if necessary to reveal gradients.")).grid(**self.default_grid()) - ExtractionStep(self, number=3, title=_(" Sample Selection")).grid(**self.default_grid()) + ProcessingStep(self, number=3, indent=0, title=_(" Sample Selection")).grid(**self.default_grid()) HelpText( self, rows=5, text=_("Select background points\n a) manually with left click\n b) automatically via grid (grid selection)" "\nYou can remove already set points by right clicking on them."), ).grid(**self.default_grid()) - ExtractionStep(self, number=4, title=_(" Calculation")).grid(**self.default_grid()) + ProcessingStep(self, number=4, indent=0, title=_(" Calculation")).grid(**self.default_grid()) HelpText(self, rows=2, text=_("Click on Calculate Background to get the processed image.")).grid(**self.default_grid()) - ExtractionStep(self, number=5, title=_(" Saving")).grid(**self.default_grid()) + ProcessingStep(self, number=5, indent=0, title=_(" Saving")).grid(**self.default_grid()) HelpText(self, text=_("Save the processed image.")).grid(**self.default_grid()) CTkLabel(self, text=_("Keybindings"), font=self.heading_font).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) diff --git a/graxpert/ui/tooltip.py b/graxpert/ui/tooltip.py index aca67dd..9ed789f 100644 --- a/graxpert/ui/tooltip.py +++ b/graxpert/ui/tooltip.py @@ -163,6 +163,8 @@ def hide(self): calculate_text = _("Use the specified interpolation method to calculate a background model " "and subtract it from the picture. This may take a while.") +denoise_text = _("Use GraXpert's denoising AI model to reduce the noise in your image. This may take a while") + saveas_text = _("Choose the bitdepth of the saved pictures and the file format. " "If you are working with a .fits image the fits header will " "be preserved.") save_bg_text = _("Save the background model") save_pic_text = _("Save the processed picture") diff --git a/graxpert/ui/ui_events.py b/graxpert/ui/ui_events.py index 1fe0a1c..07de140 100644 --- a/graxpert/ui/ui_events.py +++ b/graxpert/ui/ui_events.py @@ -4,6 +4,8 @@ class UiEvents(Enum): # main ui requests RESET_ZOOM_REQUEST = auto() + # menu requests + SHOW_MENU_REQUEST = auto() # crop TOGGLE_CROP_REQUEST = auto() APPLY_CROP_REQUEST = auto() diff --git a/graxpert/ui/widgets.py b/graxpert/ui/widgets.py index ac1dc7c..4b9bd17 100644 --- a/graxpert/ui/widgets.py +++ b/graxpert/ui/widgets.py @@ -1,6 +1,7 @@ import tkinter as tk +from tkinter import ttk -from customtkinter import CTkButton, CTkCheckBox, CTkEntry, CTkFrame, CTkImage, CTkLabel, CTkOptionMenu, CTkScrollableFrame, CTkSlider, DoubleVar, StringVar, ThemeManager +from customtkinter import CTkButton, CTkCheckBox, CTkEntry, CTkFont, CTkFrame, CTkImage, CTkLabel, CTkOptionMenu, CTkScrollableFrame, CTkSlider, DoubleVar, StringVar, ThemeManager from PIL import Image from graxpert.localization import _ @@ -14,6 +15,11 @@ pady = 5 * get_scaling_factor() +def gfx_image(number, indent=1): + img = Image.open(resource_path(f"img/gfx_numbers.png")).crop((number * 100, indent * 100, number * 100 + 100, indent * 100 + 100)) + return img + + class GraXpertButton(CTkButton): def __init__(self, parent, width=default_button_width, **kwargs): super().__init__(parent, width=width, **kwargs) @@ -57,10 +63,12 @@ def on_mouse_wheel(self, event=None): self._parent_canvas.yview_scroll(1, "units") -class ExtractionStep(CTkFrame): - def __init__(self, parent, number=0, title="", **kwargs): +class ProcessingStep(CTkFrame): + def __init__(self, parent, number=0, indent=2, title="", **kwargs): super().__init__(parent, **kwargs) + self.bold = CTkFont(weight="bold") self.number = number + self.indent = indent self.title = title self.create_children() self.setup_layout() @@ -68,11 +76,11 @@ def __init__(self, parent, number=0, title="", **kwargs): def create_children(self): num_pic = CTkImage( - light_image=Image.open(resource_path(f"img/gfx_number_{self.number}.png")), - dark_image=Image.open(resource_path(f"img/gfx_number_{self.number}.png")), + light_image=gfx_image(self.number, self.indent), + dark_image=gfx_image(self.number, self.indent), size=(20, 20), ) - self.title = GraXpertLabel(self, text=self.title, image=num_pic, anchor=tk.W, compound=tk.LEFT) + self.title = GraXpertLabel(self, text=self.title, image=num_pic, font=self.bold, anchor=tk.W, compound=tk.LEFT) def setup_layout(self): self.columnconfigure(0, weight=0) @@ -228,25 +236,36 @@ def down(self, event): class CollapsibleMenuFrame(CTkFrame): - def __init__(self, parent, title="", show=True, **kwargs): + def __init__(self, parent, title="", number=0, show=True, **kwargs): super().__init__(parent, **kwargs) - + self.bold = CTkFont(weight="bold") + self.number = number self.title = title self.show = show def create_children(self): - self.title_label = GraXpertLabel( + num_pic = CTkImage( + light_image=gfx_image(self.number, 0), + dark_image=gfx_image(self.number, 0), + size=(20, 20), + ) + self.number_label = GraXpertLabel( self, - width=default_button_width + padx, - text=self.title, + width=20 + padx, + text="", + image=num_pic, pady=pady, ) + self.title_label = GraXpertLabel(self, width=default_button_width + padx, text=self.title, pady=pady, font=self.bold) self.toggle_button = GraXpertButton(self, width=25, text="+", command=self.toggle) + self.separator = CTkFrame(self, height=2, fg_color=ThemeManager.theme["CTkButton"]["fg_color"]) self.sub_frame = CTkFrame(self, fg_color="transparent") def setup_layout(self): - self.columnconfigure(0, weight=1) + self.columnconfigure(0, weight=0) + self.columnconfigure(1, weight=1) + self.columnconfigure(2, weight=0) self.rowconfigure(0, weight=1) self.sub_frame.columnconfigure(0, minsize=padx, weight=0) @@ -254,13 +273,15 @@ def setup_layout(self): self.sub_frame.rowconfigure(0, weight=0) def place_children(self): - self.title_label.grid(column=0, row=0, pady=pady, sticky=tk.W) - self.toggle_button.grid(column=0, row=0, pady=pady, sticky=tk.E) + self.number_label.grid(column=0, row=0, pady=pady, sticky=tk.W) + self.title_label.grid(column=1, row=0, pady=pady, sticky=tk.EW) + self.toggle_button.grid(column=3, row=0, pady=pady, sticky=tk.E) + self.separator.grid(column=0, row=1, columnspan=3, sticky=tk.EW) self.place_sub_frame(self.show) def place_sub_frame(self, show): if show: - self.sub_frame.grid(column=0, row=1, sticky=tk.NS) + self.sub_frame.grid(column=0, row=2, columnspan=3, sticky=tk.NS) self.toggle_button.configure(text="-") else: self.sub_frame.grid_forget() @@ -270,3 +291,7 @@ def toggle(self): self.show = not self.show self.place_sub_frame(self.show) self.sub_frame.update() + + def hide(self, event=None): + if self.show: + self.toggle() diff --git a/img/HELP.png b/img/HELP.png deleted file mode 100644 index 9439e37bc48b2972893ceb90cd0c8f64579561cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1422 zcmeAS@N?(olHy`uVBq!ia0vp^58U}fi7AzZCsS=07?@QvLn2Bde0{8v^K z^~=l4^~#O)@{7{-4J|D#^$m>ljf`}GDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7_p zOiaozEwNPsx)tJy+yc06!V z;*iRMRQ;gT;{4L0WMI^#DTAykuyQU+O)SYT3dzsUfrVp0Mt(_taYlZDf|0SFk%C5e zW?o8ud9fx~gRifZXI^nhVqS8pr;Du;&43= zHxn}h7biC-7iVLbUYGpj(%jU%5}4i;gkE!;dO@inw*Y9fOKMSOS!#+~QGTuh*w0p( zxZPrc(>$o&6x?nx#i>^x=oo!a%p%1!ObD2KKumbb1#;kNKQ#}S;ERAMd*|oEI0gpB z|DG<6Ar-fhY$oX+b>Ka4#6i^{>%t1h#caJ&CfFDcOgdOsujnbCJ;z&SLSd%Ysp-3| zA3REXyFJ2U$Guql!sIZHOueLsVlEGh3K%`p{N^o`b}KlbyxLo~S;5h6#-48(=NIYs z>mS}3)p<8XipAvV;iXSKnC>1{TmSdxFS+0k@4xHMXzE$K*tA(W)w#>i#Bt41DMse;p1es;Djy=k$MZqLeX{ty6L* zgW#Rn;p*=sE;R9S#Ld0^`Pm~so5~px&2@XK+oHBj%of<+CD>dpedx~i{`+%g_)T-< zvT|sdvu1;oOHo3y?p2N*FCrG6$*44W!t*Hb+lE*5OfE(qoReglFWjnK+-RF6z^bYe zrO3HPA^y#4h3g7SoP;8rl1w|Y;-qtb@g7=sf4=;EySw|pJUS8;bJcvKuf0OF$7QA) z)=%zZF1vt~2qlCcdnO{h&7GgnQ_z0=Iam`YJgTB<$L zQXNrIibBzGHdG#|Y&y|HDrgl4c%bjcvCR0Sa{SfA98qe%4su1e*ww}ukqU-kYc zu|^W3!XYuPAtTi?x^-c*^`TT;ff|=mq*_9f5kqxcx}Ky+&3aM=pw285unSZWaxz-8 zU;rQzafO72k`gjpi19$0f~8Q%x!#xyn}e}E`5b2qLA(T>0@%wFK?R^Mc7z~TEAZnkg>Fd0>YSy;~-9T!r(m#jB?VyZEXslDKl z37^>;UT^+{*<&h{S?rx`Y%~_}IRO}(J*|;=>`u3@OUT>tOnNfAGJSkq_3OgZJzQYY zDWHAckvyZFwF%atJ7;}kdd-VMve%Z**fjaXi8UK4cDGhu_U?y@9`w0Tw%Nb8m@ohQ z@p-q!wAY-A?(ZEDC#+1vf4Z#q0r-6-qZr+)BU`CGu@Ia65d=-J@_iTb!E%w z7VFOaGuAl%J+UhG_}2DQwU-(XqDRdCu1~=qau|M}_cYb`OJrpN9JE_$Njrujso4rfC-|q4D-X;6q@Qcct73`{X2)EoC zC%NM|zpc*iN54b9`z$Q z@lz3x8p^|-Yyq$Jhg8|6_T?0oWgLTvW4eC|TKey2F+F z<^KMKlMtOx3VfaUQ{dW7fwdVC?mY)qRpoCC^-VymSLH^%$tQ@pbM7m9b7Qw0R~i`A zd?;_TOmC^Eyl~~5WHxl5p?rRutLywpNDu!;X;Y%Xy#D8@;mHE8qGbWktedu)Z0uqp z)%x7NHEs*NJ6LmsT5r?R!@UfXT^cKPKKe9sW4BFsAoGTU#qF$usVm}l z=bT~I_aDk*n10`MGfQP0XPA@gV7F99>|g|os$= z8@h;U24UNh%M7WMYZuAdaMI!|ah6+^fwR9|m5 zT^&;$2n3=_btlnP>lW2Jrmd#>T6w@UREvq294OuchKVH%Apjw=z)%26>l)93x=R z4-jz#9`;vIfiz#JD<}k@4setW6NyAZ9Wd}vWZ3Rd0E4uK+9GXH2$U@XWp87P!rIzn zQTEW)2d45TWQAerB+9Bc)ea8}7mEd01VSQ_z$IunC}bm07z_r1v_;t3+NcmVqFBC| z5o5y_nXM_101;Ej5r{b;AG)H*2nD0Wc$g~IzmnhyKFab%tA$dP3=zW+AW(4RN>Xb; z8twl>dAyHkk(dsAiuZpCi~M5+0D=yPz$hV8)w(dV6;}eRs}Nv_L7_hga@XqU8xD#= zQ8*}o+M?mMP|E-gp9M-pJ3kO;G%S@b5;OQrfJ(x{R1$CwhlNGCAW1H}U0sPJ3KE4P zyY431QHU5al1#R9q1d?+*SI8*8N~zm;x#Vo6PL6ucV!xQ0+nYHAml^?EQ%21K|kb- z<*XkIab3MtE^GZ*T-N0xRKXxtI{ROpUOQ5a&x-kRa#fp;vk&l9120rf_M?1dFa)AL zP9+ijW4cGrM|k-M=r?yZQyBlKfEHu z!=nau=oyKrXl$588*O}Es2Npkm~_i;SEDv1wN6WBp-4k;L#gx4oKp_JmB&4;u4!s$ zStPXHDRmxdSzx!e^z;tr$qxQfH8+*k-U!u1r4T<0)lb~guxk2N5a4Y3*!Z*`< z&3Jup@7t?n^#n}yK=XH~_@T@c0`do=Y)aBb3q7eL+dsQ1cQpFBy3ORvrlzU-{uV@S zKYO3F`*x~XB@xL!xWuwH%{g$p=8@y2#iXd;M{&HigklV<^~(02CU7yqk#k>~Xv}&p z-<1?e%-TNxl6y3RXT6C%5}Yf+-kAm z$i-amp?iogDr-&RH8k$gD73)&lvjRJ#5b?a1VG<4LuDJ$^F_~G;ZV;K+P6BHoT%Ag z0-oNLBE9lW{DiXc-S%ij^6}j-ozpL6R{9hWtEHB)N5}Vh zW*eQ$`gw#~HS~B)>jAvD%wDEx6zmO0PmD+Xp}jA^!2Gmn3#<)tzu6z1IGx_@m-8)O z+&S-h^PJN|T4h0v`>Y2Wn@D=_F#sb z92A>n75-up(t)gSXKkK2QI_7=m|U3LS!3E-n5;dVK}jt;n-{RJYnZIdAyclP4er?7 zQf}iV*=s*EDXQ^Wymo_SfhWy|xw-w|^DL$JoDRWKWK9s1pxR-X(U~?dU6H=WJamhO z)`1K1%m@LpZnpj@(Xq$<)XD0O&TS=iBS5YHqu?E}g@fm_+57W2CgxgM)^9F9M(Y97 zZi?Qbsjsa6afM-U3wN>(ADDS0@+L}p;7l2J&OH|xteHcg@( z*!eHAsLFG5$Qx9*9A!VcDOq;7HhQwI`qw^BFMXfV)~(K8PxnaF&R#FxfBev{gB=7% z$@t>=i~2rnZpZt_B?l7eI{5d?QSl+5V_anrZaeOBZB?b_lf3>y4NCk#b6tz!n<9pB zh4#0>rz{s12SR0XdCt$giU*PDzUmL_mrDoy?w=g@wqpjC$X~^l4lBZQ+mjoVioO7i zN(t^*AmP508{On)*6t+!8j*8Gxo{?^?LSY3jL^ICp*t{#^PZ(#dTvtB=~3R0|MUth zht}_`DH}4J8T6u_oUa{ab~^b+w%7E5<)u+i4TI_v)0K5z3Xh2$HCt!eCZJW*Cn!lI zIooN%&)hhBZp!+{Xx;X^K06n-ER5tF%+7E2!SWIaljCpQq-nmVH_5H{Z{XzaRr_6A z|0+Zg8{L!LB_*^6ZLSiKy9fU`CXfY%T{8^#55s=$8Tn#netVox=kpDWl!C51b$#@I zD#|ZKJN?>w;k`Z9SP^iUyHwYeQU3n#Aq6LDUk^&xu8&VQiB23QbRM^?mB>=po_klT b_8BB&EN-W1;+?B2KLk{=H|e^|cL{$2K=77W diff --git a/img/advanced_trapez.png b/img/advanced_trapez.png deleted file mode 100644 index c5616a81b1c2f1784758734e2be28435904733b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2786 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 GNc=C>NUi1o diff --git a/img/gfx_number_1.png b/img/gfx_number_1.png deleted file mode 100644 index b6f398dead52eb88a9601df0ddfc5bc91d6e79fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4226 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%0Ar^LZI6ij!DXP*bu;1*&(3 zCmbH&JLUKCdF z&ZaQ#b6FKjXq(k)DME^7lknlo#4PDeo>0Vp|0umhadKgj6}nD#@GWFx$ymkkr7M}E zwPVKyyTy?E(NTfpm;E>p+3?OQ8cl8R!C|=rUT3Fv9Pm3_nIcPhQ)r12DxNqwLh0?L zKu4DP!>>rCPg-x;ya*K(w|x6_#AJ@LKoMc_$N6$)c+gOB1k4xd{N@f3A#AKvMWl&~ z$G}&?5x*|Gc7hdy-O{pcZMEBsom9p}P=TA?p@RdhNSH{~O+jPAg3p=R1ol38N?-sV ztrn5poOX_QslF1w*D?~ex=r5F>0|2>D@k)}^Wc!~ROyPbqZi~1YG(wnrHToboi1Ld zU@$<)LyK;SncvRq0%{clo0@u1y}a4aiYLg?j?`DfWA5xkN8@5tlwHwuEqE#@B6{nk ze@3{k`I*02wmdy*xLPIs^WL8wowK)5iVA+|DkQs-8v_#`%5-!r!Jah2W7BZ{q|AY# zsNf@~-?FFS0cFcjN`f2!wtel!_=0SXGIrX^=c zM@U3&Q}MrjG&$N_B8HV9LG&9Kp)rGCEag>0it@doCuC1Kezh7 zgkXzk2sfrjcm6MyWWb6LTklv&*h%4OR zEwG2A;V(-VUvCy*m@rSUT#Elz*!;s?^wZU4;Pma9{?@k-Q!{5~iIWdQ{!T2u`{n2k zPEuMSC28dvk~w=q0kQMX0dI+n(e_%W+`C*WkSMMUi@IIOa_8GOIulYW^!mK@H20)C zJ#Szmx7(b%vJ0toyYkO)xNX?yzn2c9zu1bj`5vJ*<2uHcg5Z(sdUB-!d%|`1a0-MG z(4;SYJr&Bh`HCbJl4ac9xMREZ?d$vOSRBo%wNuj2WwrV0HWzsZpO)z4>6@NG21l+n ztJqk+=%J(LKi_0lEe88w8J_m+>_+!`U=KY@Wq>+E%36q{#dQ9&2uk3~Nr~ybf z*w&+UbI08j$nD|3{bEU#i>lmc5dX<><+mX&7E`0q?!>f_LzkATR>j9XISE<5XwOEH zAD#QrP;KTd<@S<0}4>F^|>}bz_$pqmuLm^`vFA>V>gaa9ExsHw|jetP756_+)Y zWju*xDzf`@!zs`Atl;v>@x@Xp1P3}o-R~4sMUk)DNK6qM7o$IJe#)f43}thvSj?(g*d%C(}4fRF`6WFlI*@~cP&>e!j=T#LYSg6XT)UYLp^5~Q>Ejkvp>x`-5kgMYy6c5 z9ip_MPn}QBSLMMIcQBx+HcuLrn)u3W;aeS5*Z8;@P`)jv_Sv=1PgF%YjXxDKy;R4y z8&@-{Jn-%Dd6!Lt2hZ2Flmh#@qqi+0@5`E*b#_~sSXkEdLp|RLdPG-Gt<7c^$SWC< zmT3CCGx%<=B`wEJ<3P~Q?UyZ||1BY~Wm-!HjcmQiYDbj*~W3PfZVxoD<4tUHTG(eS9fnzY&)^Y6T;xRqSUGxz>`LQ^xQ z>oP3qB~N2x>}pV~*+No3x`IURmi~EQj6j99dMXQxSKD-;kF~$Z;O6ly`flgq}&(HAiho z$FIRLR8>S7Y$cCaL_@E9%cFrXqdB4q)4?iO!BNfk`HqCs>@fHC_KcUSok#-~FWh}w zhE(UJiGjooLrnGGLhY2-$eT6bXbI3_xni?*W;GK}yaX?PGWFzSLOS>#9Z%{d$dPGa zYgJYw#y$~2tu*7cMSGh@~8ad>D(PiRrs(0E6;5y_FLpqp8ap^#j)S{rgOOxPP zE?liEaK2jtVtMY}V;m9&rAY-JpNp@5Pq3C+EhVj#&6>fhnw(y4gEsmnT-;=co2^p_ zdAliQBNIQ({5I`(SWs1@iYU&cY8+WYJ}Xnx`9}KXo$5)gZpyz+U}@`fFD;20-}x&c z_#1d-^)A}Wv}5TjN`2S(o*FyIGvloOmaV%r9JupZ5$M|R+5kJ=G;);-JGReYRz1+Ykm(Fhb5wv-U5Uoyt8JmVgK?TwRv_B9P0?O4F zx>wTF((-XeU1@TU`q#a;|;3yYS`SkU?FA!DK>5l6Lupp9mw#XbFE$B z>O7;ETWKL_KFR)et&Mp-=v(D$HaL#lkKzB=tU4ar3GMNTdvPjf9v)pY2c0&erE8ubE@L}3 zC4{>hj0;Sop2$t#Z2s7&R8fR_?CsPx|MLjfzFcKeW4TM6{O8g}r{Cyw3#)xvUDasX zz^ij7!0o9ykP$FynfS>NISze=c2xA0dA-R_RaRJUB8k6Z zGg;-Ychz_9={+@hvbc0hcflwafSP~`%Dzd85VvM`=`jk@_22Dcoq!B8_Kxm;3E&;N zrU}u@X5Od5S4T_}g89pcdS==8UY`WTw#;ArdR`M zZ7pC}m&}Wz*{P;G63b&>5dP#oqzH(`8TTUuXf@)x`jyOlK(^uEaIySHb?2rSunj!?r~cFrytLe?wI9hs&u z?kNN?Vsi|0M!w_oKAF;XT`C5ZJTEcy8` zdf5NiqCFz$PSE2#TG3rF z#xynId-eo3F`}}R#bGCHh>lLLy*%XiGSZ+oG0fEE$k2L`qh|2r;P1`DcF?rv9H#m- ze4*V-5FyNn)+@w2mgmiKt|t!dB9|(}&nat`>miC&nBkV;^*u#fafK=~JB5;B zehFh)tsH^gff<9daMZ-eSCdzPe1oxfEPMtu8KgZ{OP7ntlrw0H; zMMOn~M8t)_(l8MTh?pb<3>FZPf{2K;e)*O6Uxt^Sj&9CD|JyK_Z_f5$0BEY}s?;gj GMg1Sp`lZtV diff --git a/img/gfx_number_4.png b/img/gfx_number_4.png deleted file mode 100644 index 13081a5585459248952b6399b5f4fea8a2a24f95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5461 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 Cc`sD} diff --git a/img/gfx_number_5.png b/img/gfx_number_5.png deleted file mode 100644 index a2bb65ad4ef4441bce2e1bf5719f40e24e377690..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6082 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 G?tcJ5*=-yE diff --git a/img/gfx_numbers.png b/img/gfx_numbers.png new file mode 100644 index 0000000000000000000000000000000000000000..03e34f644c0bbff84c81c6377a54054f065bb36f GIT binary patch literal 44855 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%0Dh@{9&p2#aT>@^y;l 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 ju3yx+_4fbEOLr7(%=rx-$Y+b + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + + From 44371af522b8860e5acb962b3a21857972ae93a5 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Tue, 12 Mar 2024 17:07:45 +0100 Subject: [PATCH 12/59] prepare denoising integration: ui and cli changes --- graxpert/ai_model_handling.py | 44 +++++--- graxpert/application/app.py | 56 +++++++--- graxpert/application/app_events.py | 5 +- graxpert/background_extraction.py | 4 +- .../{CommandLineTool.py => cmdline_tools.py} | 23 ++-- graxpert/denoising.py | 2 +- graxpert/main.py | 101 +++++++++++------- graxpert/preferences.py | 11 +- graxpert/ui/right_menu.py | 57 ++++++---- 9 files changed, 206 insertions(+), 97 deletions(-) rename graxpert/{CommandLineTool.py => cmdline_tools.py} (91%) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index 6475e00..1e677d3 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -9,7 +9,7 @@ from packaging import version try: - from graxpert.s3_secrets import bucket_name, endpoint, ro_access_key, ro_secret_key + from graxpert.s3_secrets import endpoint, ro_access_key, ro_secret_key client = Minio(endpoint, ro_access_key, ro_secret_key) except Exception as e: @@ -19,11 +19,24 @@ from graxpert.ui.loadingframe import DynamicProgressThread ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "ai-models") -os.makedirs(ai_models_dir, exist_ok=True) +bge_ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "bge-ai-models") + +# old ai-models folder exists, rename to 'bge-ai-models' +if os.path.exists(ai_models_dir): + logging.warning(f"Older 'ai_models_dir' {ai_models_dir} exists. Renaming to {bge_ai_models_dir} due to introduction of new denoising models in GraXpert 3.") + try: + os.rename(ai_models_dir, bge_ai_models_dir) + except Exception as e: + logging.error(f"Renaming {ai_models_dir} to {bge_ai_models_dir} failed. {bge_ai_models_dir} will be newly created. Consider deleting obsolete {ai_models_dir}.") + +os.makedirs(bge_ai_models_dir, exist_ok=True) + +denoise_ai_models_dir = os.path.join(user_data_dir(appname="GraXpert"), "denoise-ai-models") +os.makedirs(denoise_ai_models_dir, exist_ok=True) # ui operations -def list_remote_versions(): +def list_remote_versions(bucket_name): if client is None: return [] try: @@ -48,7 +61,7 @@ def list_remote_versions(): return versions -def list_local_versions(): +def list_local_versions(ai_models_dir): try: model_dirs = [{"path": os.path.join(ai_models_dir, f), "version": f} for f in os.listdir(ai_models_dir) if re.search(r"\d\.\d\.\d", f)] # match semantic version return model_dirs @@ -57,14 +70,14 @@ def list_local_versions(): return None -def latest_version(): +def latest_version(ai_models_dir, bucket_name): try: - remote_versions = list_remote_versions() + remote_versions = list_remote_versions(bucket_name) except Exception as e: remote_versions = [] logging.exception(e) try: - local_versions = list_local_versions() + local_versions = list_local_versions(ai_models_dir) except Exception as e: local_versions = [] logging.exception(e) @@ -75,15 +88,16 @@ def latest_version(): return ai_options[0] -def ai_model_path_from_version(local_version): +def ai_model_path_from_version(ai_models_dir, local_version): if local_version is None: return None - return os.path.join(ai_models_dir, local_version, "bg_model") + # TODO migrate to onnx + return os.path.join(ai_models_dir, local_version, "model.onnx") -def compute_orphaned_local_versions(): - remote_versions = list_remote_versions() +def compute_orphaned_local_versions(ai_models_dir): + remote_versions = list_remote_versions(ai_models_dir) if remote_versions is None: logging.warning("Could not fetch remote versions. Thus, aborting cleaning of local versions in {}. Consider manual cleaning".format(ai_models_dir)) @@ -108,9 +122,9 @@ def cleanup_orphaned_local_versions(orphaned_local_versions): logging.exception(e) -def download_version(remote_version, progress=None): +def download_version(ai_models_dir, bucket_name, remote_version, progress=None): try: - remote_versions = list_remote_versions() + remote_versions = list_remote_versions(bucket_name) for r in remote_versions: if remote_version == r["version"]: remote_version = r @@ -140,5 +154,5 @@ def download_version(remote_version, progress=None): logging.exception(e2) -def validate_local_version(local_version): - return os.path.isdir(os.path.join(ai_models_dir, local_version, "bg_model")) +def validate_local_version(ai_models_dir, local_version): + return os.path.isfile(os.path.join(ai_models_dir, local_version, "model.onnx")) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 3c79ffa..eb0d71b 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -6,7 +6,7 @@ import numpy as np from appdirs import user_config_dir -from graxpert.ai_model_handling import ai_model_path_from_version, download_version, validate_local_version +from graxpert.ai_model_handling import ai_model_path_from_version, bge_ai_models_dir, denoise_ai_models_dir, download_version, validate_local_version from graxpert.app_state import INITIAL_STATE from graxpert.application.app_events import AppEvents from graxpert.application.eventbus import eventbus @@ -17,6 +17,7 @@ from graxpert.localization import _ from graxpert.mp_logging import logfile_name from graxpert.preferences import fitsheader_2_app_state, load_preferences, prefs_2_app_state +from graxpert.s3_secrets import bge_bucket_name, denoise_bucket_name from graxpert.stretch import StretchParameters, stretch_all from graxpert.ui.loadingframe import DynamicProgressThread @@ -78,12 +79,13 @@ def initialize(self): eventbus.add_listener(AppEvents.SPLINE_ORDER_CHANGED, self.on_spline_order_changed) eventbus.add_listener(AppEvents.CORRECTION_TYPE_CHANGED, self.on_correction_type_changed) eventbus.add_listener(AppEvents.LANGUAGE_CHANGED, self.on_language_selected) - eventbus.add_listener(AppEvents.AI_VERSION_CHANGED, self.on_ai_version_changed) + eventbus.add_listener(AppEvents.BGE_AI_VERSION_CHANGED, self.on_bge_ai_version_changed) + eventbus.add_listener(AppEvents.DENOISE_AI_VERSION_CHANGED, self.on_denoise_ai_version_changed) eventbus.add_listener(AppEvents.SCALING_CHANGED, self.on_scaling_changed) # event handling - def on_ai_version_changed(self, event): - self.prefs.ai_version = event["ai_version"] + def on_bge_ai_version_changed(self, event): + self.prefs.bge_ai_version = event["bge_ai_version"] def on_bg_floot_selection_changed(self, event): self.prefs.bg_flood_selection_option = event["bg_flood_selection_option"] @@ -115,7 +117,7 @@ def on_calculate_request(self, event=None): return if self.prefs.interpol_type_option == "AI": - if not self.validate_ai_installation(): + if not self.validate_bge_ai_installation(): return eventbus.emit(AppEvents.CALCULATE_BEGIN) @@ -142,7 +144,7 @@ def on_calculate_request(self, event=None): self.prefs.RBF_kernel, self.prefs.spline_order, self.prefs.corr_type, - ai_model_path_from_version(self.prefs.ai_version), + ai_model_path_from_version(bge_ai_models_dir, self.prefs.bge_ai_version), progress, ) ) @@ -201,6 +203,9 @@ def on_create_grid_request(self, event=None): eventbus.emit(AppEvents.CREATE_GRID_END) + def on_denoise_ai_version_changed(self, event): + self.prefs.denoise_ai_version = event["denoise_ai_version"] + def on_display_pts_changed(self, event): self.prefs.display_pts = event["display_pts"] eventbus.emit(AppEvents.REDRAW_POINTS_REQUEST) @@ -313,14 +318,17 @@ def on_denoise_request(self, event): messagebox.showerror("Error", _("Please load your picture first.")) return - eventbus.emit(AppEvents.CALCULATE_BEGIN) + if not self.validate_denoise_ai_installation(): + return - progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p})) + eventbus.emit(AppEvents.DENOISE_BEGIN) + + progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p})) try: imarray = np.copy(self.images["Original"].img_array) - denoise(imarray, ai_model_path_from_version(self.prefs.ai_version), progress=progress) + denoise(imarray, ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version), progress=progress) eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) @@ -535,13 +543,31 @@ def translate(self, offset_x, offset_y): self.mat_affine = np.dot(mat, self.mat_affine) - def validate_ai_installation(self): - if self.prefs.ai_version is None or self.prefs.ai_version == "None": - messagebox.showerror("Error", _("No AI-Model selected. Please select one from the Advanced panel on the right.")) + def validate_bge_ai_installation(self): + if self.prefs.bge_ai_version is None or self.prefs.bge_ai_version == "None": + messagebox.showerror("Error", _("No Background Extraction AI-Model selected. Please select one from the Advanced panel on the right.")) + return False + + if not validate_local_version(bge_ai_models_dir, self.prefs.bge_ai_version): + if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Background Extraction AI-Model is not installed. Should I download it now?")): + return False + else: + eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN) + + def callback(p): + eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p}) + + download_version(bge_ai_models_dir, bge_bucket_name, self.prefs.bge_ai_version, progress=callback) + eventbus.emit(AppEvents.AI_DOWNLOAD_END) + return True + + def validate_denoise_ai_installation(self): + if self.prefs.denoise_ai_version is None or self.prefs.denoise_ai_version == "None": + messagebox.showerror("Error", _("No Denoising AI-Model selected. Please select one from the Advanced panel on the right.")) return False - if not validate_local_version(self.prefs.ai_version): - if not messagebox.askyesno(_("Install AI-Model?"), _("Selected AI-Model is not installed. Should I download it now?")): + if not validate_local_version(denoise_ai_models_dir, self.prefs.denoise_ai_version): + if not messagebox.askyesno(_("Install AI-Model?"), _("Selected Denoising AI-Model is not installed. Should I download it now?")): return False else: eventbus.emit(AppEvents.AI_DOWNLOAD_BEGIN) @@ -549,7 +575,7 @@ def validate_ai_installation(self): def callback(p): eventbus.emit(AppEvents.AI_DOWNLOAD_PROGRESS, {"progress": p}) - download_version(self.prefs.ai_version, progress=callback) + download_version(denoise_ai_models_dir, denoise_bucket_name, self.prefs.denoise_ai_version, progress=callback) eventbus.emit(AppEvents.AI_DOWNLOAD_END) return True diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index ec61484..3089e20 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -57,11 +57,14 @@ class AppEvents(Enum): SAVE_END = auto() SAVE_ERROR = auto() # ai model handling - AI_VERSION_CHANGED = auto() AI_DOWNLOAD_BEGIN = auto() AI_DOWNLOAD_PROGRESS = auto() AI_DOWNLOAD_END = auto() AI_DOWNLOAD_ERROR = auto() + # bge ai model handling + BGE_AI_VERSION_CHANGED = auto() + # bge ai model handling + DENOISE_AI_VERSION_CHANGED = auto() # advanced settings SAMPLE_SIZE_CHANGED = auto() SAMPLE_COLOR_CHANGED = auto() diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index 3b3fa0c..94f0da0 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -26,7 +26,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smoothing, - downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, AI_dir, progress=None): + downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, ai_path, progress=None): shm_imarray = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) shm_background = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) @@ -68,7 +68,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if progress is not None: progress.update(8) - model = tf.saved_model.load(AI_dir) + model = tf.saved_model.load(ai_path) background = np.array(model(np.expand_dims(imarray_shrink, axis=0))[0]) background = background / 0.04 * mad + median diff --git a/graxpert/CommandLineTool.py b/graxpert/cmdline_tools.py similarity index 91% rename from graxpert/CommandLineTool.py rename to graxpert/cmdline_tools.py index 233141f..a734e0a 100644 --- a/graxpert/CommandLineTool.py +++ b/graxpert/cmdline_tools.py @@ -7,15 +7,16 @@ import numpy as np from appdirs import user_config_dir -from graxpert.ai_model_handling import ai_model_path_from_version, download_version, latest_version, list_local_versions +from graxpert.ai_model_handling import ai_model_path_from_version, bge_ai_models_dir, download_version, latest_version, list_local_versions from graxpert.astroimage import AstroImage from graxpert.background_extraction import extract_background from graxpert.preferences import Prefs, load_preferences, save_preferences +from graxpert.s3_secrets import bge_bucket_name, denoise_bucket_name user_preferences_filename = os.path.join(user_config_dir(appname="GraXpert"), "preferences.json") -class CommandLineTool: +class BGECmdlineTool: def __init__(self, args): self.args = args @@ -80,7 +81,7 @@ def execute(self): logging.info(f"Using stored correction type {preferences.corr_type}.") if preferences.interpol_type_option == "AI": - ai_model_path = ai_model_path_from_version(self.get_ai_version(preferences)) + ai_model_path = ai_model_path_from_version(bge_ai_models_dir, self.get_ai_version(preferences)) else: ai_model_path = None @@ -140,16 +141,16 @@ def get_ai_version(self, prefs): ai_version = self.args.ai_version logging.info(f"Using user-supplied AI version {ai_version}.") else: - ai_version = prefs.ai_version + ai_version = prefs.bge_ai_version if ai_version is None: - ai_version = latest_version() + ai_version = latest_version(bge_ai_models_dir, bge_bucket_name) logging.info(f"Using AI version {ai_version}. You can overwrite this by providing the argument '-ai_version'") - if not ai_version in [v["version"] for v in list_local_versions()]: + if not ai_version in [v["version"] for v in list_local_versions(bge_ai_models_dir)]: try: logging.info(f"AI version {ai_version} not found locally, downloading...") - download_version(ai_version) + download_version(bge_ai_models_dir, bge_bucket_name, ai_version) logging.info("download successful") except Exception as e: logging.exception(e) @@ -188,3 +189,11 @@ def get_save_path(self): def get_background_save_path(self): save_path = self.get_save_path() return os.path.splitext(save_path)[0] + "_background" + self.get_output_file_ending() + + +class DenoiseCmdlineTool: + def __init__(self, args): + self.args = args + + def execute(self): + raise NotImplementedError("Denoising CLI has not been implemented yet.") diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 8988b31..37ae634 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -1,2 +1,2 @@ -def denoise(image, AI_dir, window_size=256, stride=128, strength=1.0, progress=None): +def denoise(image, ai_path, window_size=256, stride=128, strength=1.0, progress=None): raise NotImplementedError("Denoising has not been implemented yet") diff --git a/graxpert/main.py b/graxpert/main.py index 9712044..00b9ff1 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -15,22 +15,18 @@ from packaging import version -from graxpert.ai_model_handling import list_local_versions, list_remote_versions +from graxpert.ai_model_handling import bge_ai_models_dir, denoise_ai_models_dir, list_local_versions, list_remote_versions from graxpert.mp_logging import configure_logging +from graxpert.s3_secrets import bge_bucket_name, denoise_bucket_name from graxpert.version import release as graxpert_release from graxpert.version import version as graxpert_version -available_local_versions = [] -available_remote_versions = [] - -def collect_available_version(): - global available_local_versions - global available_remote_versions +def collect_available_versions(ai_models_dir, bucket_name): try: available_local_versions = sorted( - [v["version"] for v in list_local_versions()], + [v["version"] for v in list_local_versions(ai_models_dir)], key=lambda k: version.parse(k), reverse=True, ) @@ -39,7 +35,7 @@ def collect_available_version(): logging.exception(e) try: available_remote_versions = sorted( - [v["version"] for v in list_remote_versions()], + [v["version"] for v in list_remote_versions(bucket_name)], key=lambda k: version.parse(k), reverse=True, ) @@ -47,10 +43,18 @@ def collect_available_version(): available_remote_versions = "" logging.exception(e) + return (available_local_versions, available_remote_versions) + + +def bge_version_type(arg_value, pat=re.compile(r"^\d+\.\d+\.\d+$")): + return version_type(bge_ai_models_dir, bge_bucket_name, arg_value, pat=re.compile(r"^\d+\.\d+\.\d+$")) + + +def version_type(ai_models_dir, bucket_name, arg_value, pat=re.compile(r"^\d+\.\d+\.\d+$")): -def version_type(arg_value, pat=re.compile(r"^\d+\.\d+\.\d+$")): - global available_local_versions - global available_remote_versions + available_versions = collect_available_versions(ai_models_dir, bucket_name) + available_local_versions = available_versions[0] + available_remote_versions = available_versions[1] if not pat.match(arg_value): raise argparse.ArgumentTypeError("invalid version, expected format: n.n.n") @@ -66,7 +70,7 @@ def version_type(arg_value, pat=re.compile(r"^\d+\.\d+\.\d+$")): return arg_value -def ui_main(open_with_file = None): +def ui_main(open_with_file=None): import logging import tkinter as tk from concurrent.futures import ProcessPoolExecutor @@ -79,8 +83,8 @@ def ui_main(open_with_file = None): from customtkinter import CTk from graxpert.application.app import graxpert - from graxpert.application.eventbus import eventbus from graxpert.application.app_events import AppEvents + from graxpert.application.eventbus import eventbus from graxpert.localization import _ from graxpert.mp_logging import initialize_logging, shutdown_logging from graxpert.parallel_processing import executor @@ -161,56 +165,81 @@ def check_for_new_version(): app.grid(column=0, row=0, sticky=tk.NSEW) root.update() check_for_new_version() - + if open_with_file and len(open_with_file) > 0: eventbus.emit(AppEvents.LOAD_IMAGE_REQUEST, {"filename": open_with_file}) else: eventbus.emit(UiEvents.DISPLAY_START_BADGE_REQUEST) - + root.mainloop() def main(): if len(sys.argv) > 1: - global available_local_versions - global available_remote_versions - collect_available_version() + available_bge_versions = collect_available_versions(bge_ai_models_dir, bge_bucket_name) + available_denoise_versions = collect_available_versions(denoise_ai_models_dir, denoise_bucket_name) parser = argparse.ArgumentParser(description="GraXpert,the astronomical background extraction tool") + parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") parser.add_argument("filename", type=str, help="Path of the unprocessed image") + parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") parser.add_argument( + "-preferences_file", + "--preferences_file", + nargs="?", + required=False, + default=None, + type=str, + help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points", + ) + parser.add_argument("-v", "--version", action="version", version=f"GraXpert version: {graxpert_version} release: {graxpert_release}") + + subparsers = parser.add_subparsers(dest="command") + bge_parser = subparsers.add_parser("background-extraction") + bge_parser.add_argument( "-ai_version", "--ai_version", nargs="?", required=False, default=None, - type=version_type, - help='Version of the AI model, default: "latest"; available locally: [{}], available remotely: [{}]'.format(", ".join(available_local_versions), ", ".join(available_remote_versions)), + type=bge_version_type, + help='Version of the Background Extraction AI model, default: "latest"; available locally: [{}], available remotely: [{}]'.format( + ", ".join(available_bge_versions[0]), ", ".join(available_bge_versions[1]) + ), ) - parser.add_argument("-correction", "--correction", nargs="?", required=False, default=None, choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") - parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=None, type=float, help="Strength of smoothing between 0 and 1") - parser.add_argument( - "-preferences_file", - "--preferences_file", + bge_parser.add_argument("-correction", "--correction", nargs="?", required=False, default=None, choices=["Subtraction", "Division"], type=str, help="Subtraction or Division") + bge_parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=None, type=float, help="Strength of smoothing between 0 and 1") + bge_parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") + + denoise_parser = subparsers.add_parser("denoising") + denoise_parser.add_argument( + "-ai_version", + "--ai_version", nargs="?", required=False, default=None, - type=str, - help="Allows GraXpert commandline to run all extraction methods based on a preferences file that contains background grid points", + type=bge_version_type, + help='Version of the Denoising AI model, default: "latest"; available locally: [{}], available remotely: [{}]'.format( + ", ".join(available_denoise_versions[0]), ", ".join(available_denoise_versions[1]) + ), ) - parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") - parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") - parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") - parser.add_argument("-v", "--version", action="version", version=f"GraXpert version: {graxpert_version} release: {graxpert_release}") args = parser.parse_args() - if args.cli: - from graxpert.CommandLineTool import CommandLineTool + print(args) + if args.cli and args.command == "background-extraction": + from graxpert.cmdline_tools import BGECmdlineTool + + logging.info(f"Starting GraXpert CLI, Background-Extraction, version: {graxpert_version} release: {graxpert_release}") + clt = BGECmdlineTool(args) + clt.execute() + logging.shutdown() + elif args.cli and args.command == "denoising": + from graxpert.cmdline_tools import DenoiseCmdlineTool - logging.info(f"Starting GraXpert CLI, version: {graxpert_version} release: {graxpert_release}") - clt = CommandLineTool(args) + logging.info(f"Starting GraXpert CLI, Denoising, version: {graxpert_version} release: {graxpert_release}") + clt = DenoiseCmdlineTool(args) clt.execute() logging.shutdown() else: diff --git a/graxpert/preferences.py b/graxpert/preferences.py index 62aa145..ebc9653 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -35,7 +35,8 @@ class Prefs: lang: AnyStr = None corr_type: AnyStr = "Subtraction" scaling: float = 1.0 - ai_version: AnyStr = None + bge_ai_version: AnyStr = None + denoise_ai_version: AnyStr = None graxpert_version: AnyStr = graxpert_version @@ -62,7 +63,13 @@ def load_preferences(prefs_filename) -> Prefs: if os.path.isfile(prefs_filename): with open(prefs_filename) as f: json_prefs = json.load(f) + + if "ai_version" in json_prefs: + logging.warning(f"Obsolete key 'ai_version' found in {prefs_filename}. Renaming it to 'bge_ai_version.") + json_prefs = {"bge_ai_version" if k == "ai_version" else k:v for k,v in json_prefs.items()} + prefs = merge_json(prefs, json_prefs) + if not "graxpert_version" in json_prefs: # reset scaling in case we start from GraXpert < 2.1.0 prefs.scaling = 1.0 else: @@ -91,7 +98,7 @@ def app_state_2_fitsheader(prefs: Prefs, app_state: AppState, fits_header): fits_header["CORR-TYPE"] = prefs.corr_type if prefs.interpol_type_option == "AI": - fits_header["AI-VER"] = prefs.ai_version + fits_header["BGE-AI-VER"] = prefs.bge_ai_version if prefs.interpol_type_option != "AI": fits_header["SAMPLE-SIZE"] = prefs.sample_size diff --git a/graxpert/ui/right_menu.py b/graxpert/ui/right_menu.py index dc0a29d..2b516db 100644 --- a/graxpert/ui/right_menu.py +++ b/graxpert/ui/right_menu.py @@ -6,12 +6,13 @@ from packaging import version from PIL import Image -from graxpert.ai_model_handling import list_local_versions, list_remote_versions +from graxpert.ai_model_handling import bge_ai_models_dir, denoise_ai_models_dir, list_local_versions, list_remote_versions from graxpert.application.app import graxpert from graxpert.application.app_events import AppEvents from graxpert.application.eventbus import eventbus from graxpert.localization import _, lang from graxpert.resource_utils import resource_path +from graxpert.s3_secrets import bge_bucket_name, denoise_bucket_name from graxpert.ui.widgets import GraXpertOptionMenu, GraXpertScrollableFrame, ProcessingStep, ValueSlider, padx, pady @@ -126,21 +127,37 @@ def __init__(self, master, **kwargs): self.scaling.set(graxpert.prefs.scaling) self.scaling.trace_add("write", self.on_scaling_change) - # ai model - remote_versions = list_remote_versions() - local_versions = list_local_versions() - self.ai_options = set([]) - self.ai_options.update([rv["version"] for rv in remote_versions]) - self.ai_options.update([lv["version"] for lv in local_versions]) - self.ai_options = sorted(self.ai_options, key=lambda k: version.parse(k), reverse=True) - - self.ai_version = tk.StringVar(master) - self.ai_version.set("None") # default value - if graxpert.prefs.ai_version is not None: - self.ai_version.set(graxpert.prefs.ai_version) + # bge ai model + bge_remote_versions = list_remote_versions(bge_bucket_name) + bge_local_versions = list_local_versions(bge_ai_models_dir) + self.bge_ai_options = set([]) + self.bge_ai_options.update([rv["version"] for rv in bge_remote_versions]) + self.bge_ai_options.update([lv["version"] for lv in bge_local_versions]) + self.bge_ai_options = sorted(self.bge_ai_options, key=lambda k: version.parse(k), reverse=True) + + self.bge_ai_version = tk.StringVar(master) + self.bge_ai_version.set("None") # default value + if graxpert.prefs.bge_ai_version is not None: + self.bge_ai_version.set(graxpert.prefs.bge_ai_version) else: - self.ai_options.insert(0, "None") - self.ai_version.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.AI_VERSION_CHANGED, {"ai_version": self.ai_version.get()})) + self.bge_ai_options.insert(0, "None") + self.bge_ai_version.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.BGE_AI_VERSION_CHANGED, {"bge_ai_version": self.bge_ai_version.get()})) + + # denoise ai model + denoise_remote_versions = list_remote_versions(denoise_bucket_name) + denoise_local_versions = list_local_versions(denoise_ai_models_dir) + self.denoise_ai_options = set([]) + self.denoise_ai_options.update([rv["version"] for rv in denoise_remote_versions]) + self.denoise_ai_options.update([lv["version"] for lv in denoise_local_versions]) + self.denoise_ai_options = sorted(self.denoise_ai_options, key=lambda k: version.parse(k), reverse=True) + + self.denoise_ai_version = tk.StringVar(master) + self.denoise_ai_version.set("None") # default value + if graxpert.prefs.denoise_ai_version is not None: + self.denoise_ai_version.set(graxpert.prefs.denoise_ai_version) + else: + self.denoise_ai_options.insert(0, "None") + self.denoise_ai_version.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.DENOISE_AI_VERSION_CHANGED, {"denoise_ai_version": self.denoise_ai_version.get()})) self.create_and_place_children() self.setup_layout() @@ -181,9 +198,13 @@ def lang_change(lang): ValueSlider(self, variable=self.scaling, variable_name=_("Scaling"), min_value=1, max_value=2, precision=1).grid(**self.default_grid()) - # ai model - CTkLabel(self, text=_("AI-Model"), font=self.heading_font2).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) - GraXpertOptionMenu(self, variable=self.ai_version, values=self.ai_options).grid(**self.default_grid()) + # bge ai model + CTkLabel(self, text=_("Background Extraction AI-Model"), font=self.heading_font2).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) + GraXpertOptionMenu(self, variable=self.bge_ai_version, values=self.bge_ai_options).grid(**self.default_grid()) + + # denoise ai model + CTkLabel(self, text=_("Denoising AI-Model"), font=self.heading_font2).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) + GraXpertOptionMenu(self, variable=self.denoise_ai_version, values=self.denoise_ai_options).grid(**self.default_grid()) def setup_layout(self): self.columnconfigure(0, weight=1) From 8d0703423135fac703357a2fd273e460de17abe2 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Tue, 12 Mar 2024 20:14:20 +0100 Subject: [PATCH 13/59] implement denoising cmd line tool --- graxpert/ai_model_handling.py | 8 +-- graxpert/cmdline_tools.py | 127 ++++++++++++++++++++++++++-------- 2 files changed, 101 insertions(+), 34 deletions(-) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index 1e677d3..e9fd95a 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -92,7 +92,6 @@ def ai_model_path_from_version(ai_models_dir, local_version): if local_version is None: return None - # TODO migrate to onnx return os.path.join(ai_models_dir, local_version, "model.onnx") @@ -133,18 +132,13 @@ def download_version(ai_models_dir, bucket_name, remote_version, progress=None): ai_model_dir = os.path.join(ai_models_dir, "{}".format(remote_version["version"])) os.makedirs(ai_model_dir, exist_ok=True) - ai_model_file = os.path.join(ai_model_dir, "{}.zip".format(remote_version["version"])) + ai_model_file = os.path.join(ai_model_dir, "model.onnx") client.fget_object( remote_version["bucket"], remote_version["object"], ai_model_file, progress=DynamicProgressThread(callback=progress), ) - - with zipfile.ZipFile(ai_model_file, "r") as zip_ref: - zip_ref.extractall(ai_model_dir) - - os.remove(ai_model_file) except Exception as e: # try to delete (rollback) ai_model_dir in case of errors logging.exception(e) diff --git a/graxpert/cmdline_tools.py b/graxpert/cmdline_tools.py index a734e0a..74b76a6 100644 --- a/graxpert/cmdline_tools.py +++ b/graxpert/cmdline_tools.py @@ -7,19 +7,48 @@ import numpy as np from appdirs import user_config_dir -from graxpert.ai_model_handling import ai_model_path_from_version, bge_ai_models_dir, download_version, latest_version, list_local_versions +from graxpert.ai_model_handling import ai_model_path_from_version, bge_ai_models_dir, denoise_ai_models_dir, download_version, latest_version, list_local_versions from graxpert.astroimage import AstroImage from graxpert.background_extraction import extract_background from graxpert.preferences import Prefs, load_preferences, save_preferences from graxpert.s3_secrets import bge_bucket_name, denoise_bucket_name +from graxpert.denoising import denoise user_preferences_filename = os.path.join(user_config_dir(appname="GraXpert"), "preferences.json") -class BGECmdlineTool: +class CmdlineToolBase: def __init__(self, args): self.args = args + def get_output_file_ending(self): + file_ending = os.path.splitext(self.args.filename)[-1] + + if file_ending.lower() == ".xisf": + return ".xisf" + else: + return ".fits" + + def get_output_file_format(self): + output_file_ending = self.get_output_file_ending() + if (output_file_ending) == ".xisf": + return "32 bit XISF" + else: + return "32 bit Fits" + + def get_save_path(self): + if self.args.output is not None: + base_path = os.path.dirname(self.args.filename) + output_file_name = self.args.output + self.get_output_file_ending() + return os.path.join(base_path, output_file_name) + else: + return os.path.splitext(self.args.filename)[0] + "_GraXpert" + self.get_output_file_ending() + + +class BGECmdlineTool(CmdlineToolBase): + def __init__(self, args): + super().__init__(args) + def execute(self): astro_Image = AstroImage(do_update_display=False) astro_Image.set_from_file(self.args.filename, None, None) @@ -162,38 +191,82 @@ def get_ai_version(self, prefs): return ai_version - def get_output_file_ending(self): - file_ending = os.path.splitext(self.args.filename)[-1] + def get_background_save_path(self): + save_path = self.get_save_path() + return os.path.splitext(save_path)[0] + "_background" + self.get_output_file_ending() - if file_ending.lower() == ".xisf": - return ".xisf" - else: - return ".fits" - def get_output_file_format(self): - output_file_ending = self.get_output_file_ending() - if (output_file_ending) == ".xisf": - return "32 bit XISF" +class DenoiseCmdlineTool(CmdlineToolBase): + def __init__(self, args): + super().__init__(args) + + def execute(self): + astro_Image = AstroImage(do_update_display=False) + astro_Image.set_from_file(self.args.filename, None, None) + + processed_Astro_Image = AstroImage(do_update_display=False) + + processed_Astro_Image.fits_header = astro_Image.fits_header + + if self.args.preferences_file is not None: + preferences = Prefs() + try: + preferences_file = os.path.abspath(self.args.preferences_file) + if os.path.isfile(preferences_file): + with open(preferences_file, "r") as f: + json_prefs = json.load(f) + if "ai_version" in json_prefs: + preferences.ai_version = json_prefs["ai_version"] + + except Exception as e: + logging.exception(e) + logging.shutdown() + sys.exit(1) else: - return "32 bit Fits" + preferences = Prefs() - def get_save_path(self): - if self.args.output is not None: - base_path = os.path.dirname(self.args.filename) - output_file_name = self.args.output + self.get_output_file_ending() - return os.path.join(base_path, output_file_name) + ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.get_ai_version(preferences)) + logging.info( + dedent( + f"""\ + Excecuting denoising with the following parameters: + AI model path - {ai_model_path}""" + ) + ) + + processed_Astro_Image.set_from_array( + denoise( + astro_Image.img_array, + ai_model_path + )) + processed_Astro_Image.save(self.get_save_path(), self.get_output_file_format()) + + def get_ai_version(self, prefs): + user_preferences = load_preferences(user_preferences_filename) + + ai_version = None + if self.args.ai_version: + ai_version = self.args.ai_version + logging.info(f"Using user-supplied AI version {ai_version}.") else: - return os.path.splitext(self.args.filename)[0] + "_GraXpert" + self.get_output_file_ending() + ai_version = prefs.denoise_ai_version - def get_background_save_path(self): - save_path = self.get_save_path() - return os.path.splitext(save_path)[0] + "_background" + self.get_output_file_ending() + if ai_version is None: + ai_version = latest_version(denoise_ai_models_dir, denoise_bucket_name) + logging.info(f"Using AI version {ai_version}. You can overwrite this by providing the argument '-ai_version'") + if not ai_version in [v["version"] for v in list_local_versions(denoise_ai_models_dir)]: + try: + logging.info(f"AI version {ai_version} not found locally, downloading...") + download_version(denoise_ai_models_dir, denoise_bucket_name, ai_version) + logging.info("download successful") + except Exception as e: + logging.exception(e) + logging.shutdown() + sys.exit(1) -class DenoiseCmdlineTool: - def __init__(self, args): - self.args = args + user_preferences.ai_version = ai_version + save_preferences(user_preferences_filename, user_preferences) - def execute(self): - raise NotImplementedError("Denoising CLI has not been implemented yet.") + return ai_version From ab9311f6b55c834fc207e5b9c2945c52eb2d8eeb Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Tue, 12 Mar 2024 21:45:44 +0100 Subject: [PATCH 14/59] migrate denoise logic to onnx, fix progress bar during denoising --- graxpert/application/app.py | 28 ++++++++++++----- graxpert/denoising.py | 61 ++++++++++++++++++++++++++++++++++++- graxpert/ui/canvas.py | 17 +++++++++++ graxpert/ui/loadingframe.py | 4 +-- 4 files changed, 99 insertions(+), 11 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index eb0d71b..a593754 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -166,7 +166,6 @@ def on_calculate_request(self, event=None): self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) self.images["Background"].update_display_from_array(stretches[2], self.prefs.saturation) - # self.display_type = "Processed" eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) except Exception as e: @@ -326,9 +325,21 @@ def on_denoise_request(self, event): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p})) try: - imarray = np.copy(self.images["Original"].img_array) + imarray = denoise(self.images["Original"].img_array, ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version), progress=progress) - denoise(imarray, ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version), progress=progress) + self.images["Processed"] = AstroImage() + self.images["Processed"].set_from_array(imarray) + + # Update fits header and metadata + background_mean = np.mean(self.images["Original"].img_array) + self.images["Processed"].update_fits_header(self.images["Original"].fits_header, background_mean, self.prefs, self.cmd.app_state) + + self.images["Processed"].copy_metadata(self.images["Original"]) + + all_images = [self.images["Original"].img_array, self.images["Processed"].img_array] + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) + self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) @@ -429,15 +440,16 @@ def do_stretch(self): try: all_images = [] + all_image_arrays = [] stretches = [] for img in self.images.values(): if img is not None: - all_images.append(img.img_array) + all_images.append(img) + all_image_arrays.append(img.img_array) if len(all_images) > 0: - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) - for idx, img in enumerate(self.images.values()): - if img is not None: - img.update_display_from_array(stretches[idx], self.prefs.saturation) + stretches = stretch_all(all_image_arrays, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + for idx, img in enumerate(all_images): + all_images[idx].update_display_from_array(stretches[idx], self.prefs.saturation) except Exception as e: eventbus.emit(AppEvents.STRETCH_IMAGE_ERROR) logging.exception(e) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 37ae634..8fcde68 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -1,2 +1,61 @@ +import copy + +import numpy as np +import onnxruntime as ort + + def denoise(image, ai_path, window_size=256, stride=128, strength=1.0, progress=None): - raise NotImplementedError("Denoising has not been implemented yet") + + input = copy.deepcopy(image) + + H, W, _ = image.shape + offset = int((window_size - stride) / 2) + + h, w, _ = image.shape + + ith = int(h / stride) + 1 + itw = int(w / stride) + 1 + + dh = ith * stride - h + dw = itw * stride - w + + image = np.concatenate((image, image[(h - dh) :, :, :]), axis=0) + image = np.concatenate((image, image[:, (w - dw) :, :]), axis=1) + + h, w, _ = image.shape + image = np.concatenate((image, image[(h - offset) :, :, :]), axis=0) + image = np.concatenate((image[:offset, :, :], image), axis=0) + image = np.concatenate((image, image[:, (w - offset) :, :]), axis=1) + image = np.concatenate((image[:, :offset, :], image), axis=1) + + median = np.median(image[::4, ::4, :], axis=[0, 1]) + mad = np.median(np.abs(image[::4, ::4, :] - median), axis=[0, 1]) + + output = copy.deepcopy(image) + + session = ort.InferenceSession(ai_path, providers=ort.get_available_providers()) + + for i in range(ith): + for j in range(itw): + x = stride * i + y = stride * j + + tile = image[x : x + window_size, y : y + window_size, :] + tile = (tile - median) / mad * 0.04 + tile_copy = tile.copy() + tile = np.clip(tile, -1.0, 1.0) + + tile = np.expand_dims(tile, axis=0) + tile = np.array(session.run(None, {"gen_input_image": tile})[0][0]) + + tile = np.where(tile_copy < 0.95, tile, tile_copy) + tile = tile / 0.04 * mad + median + tile = tile[offset : offset + stride, offset : offset + stride, :] + output[x + offset : stride * (i + 1) + offset, y + offset : stride * (j + 1) + offset, :] = tile + + progress.update(int(100/ith)) + + output = np.clip(output, 0, 1) + output = output[offset : H + offset, offset : W + offset, :] + + return output * strength + input * (strength - 1) diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index 37f0975..6ae5385 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -100,6 +100,10 @@ def register_events(self): eventbus.add_listener(AppEvents.CALCULATE_PROGRESS, self.on_calculate_progress) eventbus.add_listener(AppEvents.CALCULATE_END, self.on_calculate_end) eventbus.add_listener(AppEvents.CALCULATE_ERROR, self.on_calculate_end) + eventbus.add_listener(AppEvents.DENOISE_BEGIN, self.on_denoise_begin) + eventbus.add_listener(AppEvents.DENOISE_PROGRESS, self.on_denoise_progress) + eventbus.add_listener(AppEvents.DENOISE_END, self.on_denoise_end) + eventbus.add_listener(AppEvents.DENOISE_ERROR, self.on_denoise_end) eventbus.add_listener(AppEvents.SAVE_BEGIN, self.on_save_begin) eventbus.add_listener(AppEvents.SAVE_END, self.on_save_end) eventbus.add_listener(AppEvents.SAVE_ERROR, self.on_save_end) @@ -158,6 +162,19 @@ def on_calculate_end(self, event=None): self.show_progress_frame(False) self.redraw_image() + def on_denoise_begin(self, event=None): + self.dynamic_progress_frame.text.set(_("Denoising")) + self.show_progress_frame(True) + + def on_denoise_progress(self, event=None): + self.dynamic_progress_frame.update_progress(event["progress"]) + + def on_denoise_end(self, event=None): + self.dynamic_progress_frame.text.set("") + self.dynamic_progress_frame.variable.set(0.0) + self.show_progress_frame(False) + self.redraw_image() + def on_change_saturation_begin(self, event=None): self.show_loading_frame(True) diff --git a/graxpert/ui/loadingframe.py b/graxpert/ui/loadingframe.py index f067d3a..bfc7772 100644 --- a/graxpert/ui/loadingframe.py +++ b/graxpert/ui/loadingframe.py @@ -71,7 +71,7 @@ def close(self): def update_progress(self, progress): self.variable.set(progress) # * 100 - logging.info("Progress: {}%".format(int(self.variable.get()))) + logging.info("Progress: {}%".format(int(self.variable.get() * 100))) self.pb.update() @@ -107,7 +107,7 @@ def set_meta(self, total_length, object_name=None): def update(self, size): if not isinstance(size, int): - raise ValueError("{} type can not be displayed. " "Please change it to Int.".format(type(size))) + raise ValueError(f"{type(size)} type can not be displayed. Please change it to Int.") self.current_progress += size self.update_queue.put((self.current_progress, self.total)) From 4cd12ec842509479385312084281fe6a27b945d7 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Tue, 12 Mar 2024 21:56:26 +0100 Subject: [PATCH 15/59] fix denoise progress logging in cli mode --- graxpert/denoising.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 8fcde68..1dac0ca 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -1,4 +1,5 @@ import copy +import logging import numpy as np import onnxruntime as ort @@ -34,7 +35,7 @@ def denoise(image, ai_path, window_size=256, stride=128, strength=1.0, progress= output = copy.deepcopy(image) session = ort.InferenceSession(ai_path, providers=ort.get_available_providers()) - + for i in range(ith): for j in range(itw): x = stride * i @@ -52,8 +53,11 @@ def denoise(image, ai_path, window_size=256, stride=128, strength=1.0, progress= tile = tile / 0.04 * mad + median tile = tile[offset : offset + stride, offset : offset + stride, :] output[x + offset : stride * (i + 1) + offset, y + offset : stride * (j + 1) + offset, :] = tile - - progress.update(int(100/ith)) + + if progress is not None: + progress.update(int(100 / ith)) + else: + logging.info(f"Progress: {int(i/ith*100)}%") output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] From b4af58ea3473bc5d072cef6d4832d2e0df1ba560 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 15 Mar 2024 16:12:49 +0100 Subject: [PATCH 16/59] render "display_menu" dynamically based on available image types "original", "processed", and "background" --- graxpert/application/app.py | 2 ++ graxpert/application/app_events.py | 2 ++ graxpert/ui/canvas.py | 38 +++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index a593754..4778dad 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -166,6 +166,7 @@ def on_calculate_request(self, event=None): self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) self.images["Background"].update_display_from_array(stretches[2], self.prefs.saturation) + eventbus.emit(AppEvents.CALCULATE_SUCCESS) eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) except Exception as e: @@ -341,6 +342,7 @@ def on_denoise_request(self, event): self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) + eventbus.emit(AppEvents.DENOISE_SUCCESS) eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) except Exception as e: diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index 3089e20..004ae1d 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -41,12 +41,14 @@ class AppEvents(Enum): CALCULATE_BEGIN = auto() CALCULATE_PROGRESS = auto() CALCULATE_END = auto() + CALCULATE_SUCCESS = auto() CALCULATE_ERROR = auto() # denoising DENOISE_REQUEST = auto() DENOISE_BEGIN = auto() DENOISE_PROGRESS = auto() DENOISE_END = auto() + DENOISE_SUCCESS = auto() DENOISE_ERROR = auto() # saving SAVE_AS_CHANGED = auto() diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index 6ae5385..e8bf8d5 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -20,10 +20,11 @@ class Canvas(CTkFrame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) - self.display_options = ["Original", "Processed", "Background"] + self.display_options = [] self.display_type = StringVar() - self.display_type.set(self.display_options[0]) + self.display_type.set(None) self.display_type.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.DISPLAY_TYPE_CHANGED, {"display_type": self.display_type.get()})) + self.display_menu = None self.startx = 0 self.starty = 0 @@ -41,7 +42,6 @@ def __init__(self, master, **kwargs): # widget setup def create_children(self): self.canvas = CTkCanvas(self, background="black", bd=0, highlightthickness=0) - self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) self.help_button = CTkButton( self.canvas, text=_("H\nE\nL\nP"), @@ -65,7 +65,6 @@ def setup_layout(self): def place_children(self): self.canvas.grid(column=0, row=1, sticky=tk.NSEW) - self.display_menu.grid(column=0, row=0, sticky=tk.N) self.help_button.grid(column=0, row=0, sticky=tk.SE) self.advanced_button.grid(column=0, row=1, sticky=tk.NE) self.static_loading_frame.grid_forget() @@ -99,10 +98,12 @@ def register_events(self): eventbus.add_listener(AppEvents.CALCULATE_BEGIN, self.on_calculate_begin) eventbus.add_listener(AppEvents.CALCULATE_PROGRESS, self.on_calculate_progress) eventbus.add_listener(AppEvents.CALCULATE_END, self.on_calculate_end) + eventbus.add_listener(AppEvents.CALCULATE_SUCCESS, self.on_calculate_success) eventbus.add_listener(AppEvents.CALCULATE_ERROR, self.on_calculate_end) eventbus.add_listener(AppEvents.DENOISE_BEGIN, self.on_denoise_begin) eventbus.add_listener(AppEvents.DENOISE_PROGRESS, self.on_denoise_progress) eventbus.add_listener(AppEvents.DENOISE_END, self.on_denoise_end) + eventbus.add_listener(AppEvents.DENOISE_SUCCESS, self.on_denoise_success) eventbus.add_listener(AppEvents.DENOISE_ERROR, self.on_denoise_end) eventbus.add_listener(AppEvents.SAVE_BEGIN, self.on_save_begin) eventbus.add_listener(AppEvents.SAVE_END, self.on_save_end) @@ -155,6 +156,18 @@ def on_calculate_begin(self, event=None): def on_calculate_progress(self, event=None): self.dynamic_progress_frame.update_progress(event["progress"]) + + def on_calculate_success(self, event=None): + if not "Processed" in self.display_options: + self.display_options.append("Processed") + self.display_menu.grid_forget() + self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) + self.display_menu.grid(column=0, row=0, sticky=tk.N) + if not "Background" in self.display_options: + self.display_menu._values.append("Background") + self.display_menu.grid_forget() + self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) + self.display_menu.grid(column=0, row=0, sticky=tk.N) def on_calculate_end(self, event=None): self.dynamic_progress_frame.text.set("") @@ -168,6 +181,13 @@ def on_denoise_begin(self, event=None): def on_denoise_progress(self, event=None): self.dynamic_progress_frame.update_progress(event["progress"]) + + def on_denoise_success(self, event=None): + if not "Processed" in self.display_options: + self.display_options.append("Processed") + self.display_menu.grid_forget() + self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) + self.display_menu.grid(column=0, row=0, sticky=tk.N) def on_denoise_end(self, event=None): self.dynamic_progress_frame.text.set("") @@ -199,14 +219,20 @@ def on_load_image_begin(self, event=None): self.show_loading_frame(True) def on_load_image_end(self, event=None): + + if self.display_menu is not None: + self.display_menu.grid_forget() + self.display_options = ["Original"] + self.display_type.set(self.display_options[0]) + self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) + self.display_menu.grid(column=0, row=0, sticky=tk.N) + width = graxpert.images["Original"].img_display.width height = graxpert.images["Original"].img_display.height self.zoom_fit(width, height) self.redraw_image() - self.display_type.set("Original") - self.show_loading_frame(False) def on_load_image_error(self, event=None): From e3874fc4c3953ca57be265075f0f21cb40f7fe3a Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 15 Mar 2024 16:13:34 +0100 Subject: [PATCH 17/59] hide tooltips during denoise --- graxpert/ui/tooltip.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graxpert/ui/tooltip.py b/graxpert/ui/tooltip.py index 9ed789f..16f032a 100644 --- a/graxpert/ui/tooltip.py +++ b/graxpert/ui/tooltip.py @@ -52,6 +52,7 @@ def __init__(self, widget, *, pad=(5, 3, 5, 3), text="widget info", waittime=500 self.id = None self.tw = None eventbus.add_listener(AppEvents.CALCULATE_BEGIN, lambda e: self.hide()) + eventbus.add_listener(AppEvents.DENOISE_BEGIN, lambda e: self.hide()) def onEnter(self, event=None): self.schedule() From 00359a2fdf86cc362f07d4d3b039887d379e0c8f Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 15 Mar 2024 18:50:52 +0100 Subject: [PATCH 18/59] Added slider for denoise strength --- graxpert/application/app.py | 3 ++- graxpert/application/app_events.py | 1 + graxpert/denoising.py | 2 +- graxpert/preferences.py | 1 + graxpert/ui/left_menu.py | 13 +++++++++++-- graxpert/ui/tooltip.py | 1 + 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 4778dad..daecf9b 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -326,7 +326,8 @@ def on_denoise_request(self, event): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p})) try: - imarray = denoise(self.images["Original"].img_array, ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version), progress=progress) + ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version) + imarray = denoise(self.images["Original"].img_array, ai_model_path, self.prefs.denoise_strength, progress=progress) self.images["Processed"] = AstroImage() self.images["Processed"].set_from_array(imarray) diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index 004ae1d..843cd65 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -44,6 +44,7 @@ class AppEvents(Enum): CALCULATE_SUCCESS = auto() CALCULATE_ERROR = auto() # denoising + DENOISE_STRENGTH_CHANGED = auto() DENOISE_REQUEST = auto() DENOISE_BEGIN = auto() DENOISE_PROGRESS = auto() diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 1dac0ca..fbe6611 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -5,7 +5,7 @@ import onnxruntime as ort -def denoise(image, ai_path, window_size=256, stride=128, strength=1.0, progress=None): +def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None): input = copy.deepcopy(image) diff --git a/graxpert/preferences.py b/graxpert/preferences.py index ebc9653..ea7bd7f 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -38,6 +38,7 @@ class Prefs: bge_ai_version: AnyStr = None denoise_ai_version: AnyStr = None graxpert_version: AnyStr = graxpert_version + denoise_strength: float = 1.0 def app_state_2_prefs(prefs: Prefs, app_state: AppState) -> Prefs: diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index 21c72fc..f166255 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -251,6 +251,11 @@ def toggle(self): class DenoiseMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): super().__init__(parent, title=_("Denoising"), show=False, number=4, **kwargs) + + self.denoise_strength = tk.DoubleVar() + self.denoise_strength.set(graxpert.prefs.denoise_strength) + self.denoise_strength.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.DENOISE_STRENGTH_CHANGED, {"denoise_strength": self.denoise_strength.get()})) + self.create_children() self.setup_layout() self.place_children() @@ -268,14 +273,18 @@ def create_children(self): command=lambda: eventbus.emit(AppEvents.DENOISE_REQUEST), ) self.tt_load = tooltip.Tooltip(self.denoise_button, text=tooltip.denoise_text) + + self.denoise_strength_slider = ValueSlider(self.sub_frame, width=default_label_width, variable_name=_("Denoise Strength"), variable=self.denoise_strength, min_value=0.0, max_value=1.0, precision=2) + tooltip.Tooltip(self.denoise_strength_slider, text=tooltip.bg_tol_text) def setup_layout(self): super().setup_layout() def place_children(self): super().place_children() - - self.denoise_button.grid(column=1, row=0, pady=pady, sticky=tk.EW) + + self.denoise_strength_slider.grid(column=1, row=0, pady=pady, sticky=tk.EW) + self.denoise_button.grid(column=1, row=1, pady=pady, sticky=tk.EW) def toggle(self): super().toggle() diff --git a/graxpert/ui/tooltip.py b/graxpert/ui/tooltip.py index 16f032a..0867014 100644 --- a/graxpert/ui/tooltip.py +++ b/graxpert/ui/tooltip.py @@ -165,6 +165,7 @@ def hide(self): calculate_text = _("Use the specified interpolation method to calculate a background model " "and subtract it from the picture. This may take a while.") denoise_text = _("Use GraXpert's denoising AI model to reduce the noise in your image. This may take a while") +denoise_strength_text = _("Determines strength of denoising.") saveas_text = _("Choose the bitdepth of the saved pictures and the file format. " "If you are working with a .fits image the fits header will " "be preserved.") save_bg_text = _("Save the background model") From a6488295af16d992595e480e0c5f3962e142b191 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 15 Mar 2024 19:02:46 +0100 Subject: [PATCH 19/59] Stretch with images_linked_option=True after denoising --- graxpert/application/app.py | 6 ++++-- graxpert/preferences.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index daecf9b..1595549 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -132,6 +132,7 @@ def on_calculate_request(self, event=None): downscale_factor = 4 try: + self.prefs.images_linked_option = False self.images["Background"] = AstroImage() self.images["Background"].set_from_array( extract_background( @@ -326,6 +327,7 @@ def on_denoise_request(self, event): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p})) try: + self.prefs.images_linked_option = True ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version) imarray = denoise(self.images["Original"].img_array, ai_model_path, self.prefs.denoise_strength, progress=progress) @@ -339,7 +341,7 @@ def on_denoise_request(self, event): self.images["Processed"].copy_metadata(self.images["Original"]) all_images = [self.images["Original"].img_array, self.images["Processed"].img_array] - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option)) self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) @@ -450,7 +452,7 @@ def do_stretch(self): all_images.append(img) all_image_arrays.append(img.img_array) if len(all_images) > 0: - stretches = stretch_all(all_image_arrays, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + stretches = stretch_all(all_image_arrays, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option)) for idx, img in enumerate(all_images): all_images[idx].update_display_from_array(stretches[idx], self.prefs.saturation) except Exception as e: diff --git a/graxpert/preferences.py b/graxpert/preferences.py index ea7bd7f..0f7414f 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -23,6 +23,7 @@ class Prefs: stretch_option: AnyStr = "No Stretch" saturation: float = 1.0 channels_linked_option: bool = False + images_linked_option: bool = False display_pts: bool = True bg_tol_option: float = 1.0 interpol_type_option: AnyStr = "RBF" From 1ed95c377940ea989dbf2ebc4f447b9d05e88e50 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 15 Mar 2024 19:23:13 +0100 Subject: [PATCH 20/59] Insert new secrets for denoise AI --- .github/workflows/build-release.yml | 6 +++++- graxpert/application/app_events.py | 2 +- graxpert/preferences.py | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 0876a58..4fedd3a 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -5,6 +5,8 @@ env: ai_s3_access_key: ${{ secrets.AI_S3_ACCESS_KEY }} ai_s3_secret_key: ${{ secrets.AI_S3_SECRET_KEY }} ai_s3_bucket_name: ${{ secrets.AI_S3_BUCKET_NAME }} + ai_s3_bge_bucket_name: ${{ secrets.AI_S3_BGE_BUCKET_NAME }} + ai_s3_denoise_bucket_name: ${{ secrets.AI_S3_DENOISE_BUCKET_NAME }} on: push: @@ -27,7 +29,9 @@ jobs: echo "endpoint = \"$ai_s3_endpoint\"" >> ./graxpert/s3_secrets.py && \ echo "ro_access_key = \"$ai_s3_access_key\"" >> ./graxpert/s3_secrets.py && \ echo "ro_secret_key = \"$ai_s3_secret_key\"" >> ./graxpert/s3_secrets.py && \ - echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py + echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + echo "bge_bucket_name = \"$ai_s3_bge_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + echo "denoise_bucket_name = \"$ai_s3_denoise_bucket_name\"" >> ./graxpert/s3_secrets.py - name: install dependencies run: | sudo apt install alien -y && \ diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index 843cd65..ad5a1b1 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -66,7 +66,7 @@ class AppEvents(Enum): AI_DOWNLOAD_ERROR = auto() # bge ai model handling BGE_AI_VERSION_CHANGED = auto() - # bge ai model handling + # denoise ai model handling DENOISE_AI_VERSION_CHANGED = auto() # advanced settings SAMPLE_SIZE_CHANGED = auto() diff --git a/graxpert/preferences.py b/graxpert/preferences.py index 0f7414f..bc25e93 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -39,7 +39,7 @@ class Prefs: bge_ai_version: AnyStr = None denoise_ai_version: AnyStr = None graxpert_version: AnyStr = graxpert_version - denoise_strength: float = 1.0 + denoise_strength: float = 0.5 def app_state_2_prefs(prefs: Prefs, app_state: AppState) -> Prefs: From db374a0e745fd554ea7725a8412c35e8d77cc7a7 Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Sat, 16 Mar 2024 10:59:44 +0100 Subject: [PATCH 21/59] Added hardware acceleration to bkg extraction and denoise --- graxpert/ai_model_handling.py | 8 ++++++++ graxpert/background_extraction.py | 7 ++++++- graxpert/denoising.py | 8 +++++++- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index e9fd95a..d2fc19d 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -7,6 +7,7 @@ from appdirs import user_data_dir from minio import Minio from packaging import version +import onnxruntime as ort try: from graxpert.s3_secrets import endpoint, ro_access_key, ro_secret_key @@ -150,3 +151,10 @@ def download_version(ai_models_dir, bucket_name, remote_version, progress=None): def validate_local_version(ai_models_dir, local_version): return os.path.isfile(os.path.join(ai_models_dir, local_version, "model.onnx")) + + +def get_execution_providers_ordered(): + supported_providers = ["DmlExecutionProvider", "CoreMLExecutionProvider", "CUDAExecutionProvider", + "CPUExecutionProvider"] + + return [provider for provider in supported_providers if provider in ort.get_available_providers()] diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index 3b3da31..e4d43ad 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -17,6 +17,7 @@ from graxpert.mp_logging import get_logging_queue, worker_configurer from graxpert.parallel_processing import executor from graxpert.radialbasisinterpolation import RadialBasisInterpolation +from graxpert.ai_model_handling import get_execution_providers_ordered def extract_background(in_imarray, background_points, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, ai_path, progress=None): @@ -61,7 +62,11 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if progress is not None: progress.update(8) - session = ort.InferenceSession(ai_path, providers=ort.get_available_providers()) + providers = get_execution_providers_ordered() + session = ort.InferenceSession(ai_path, providers=providers) + + logging.info(f"Providers : {providers}") + logging.info(f"Used providers : {session.get_providers()}") background = session.run(None, {"gen_input_image": np.expand_dims(imarray_shrink, axis=0)})[0][0] diff --git a/graxpert/denoising.py b/graxpert/denoising.py index fbe6611..6ada9eb 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -4,6 +4,8 @@ import numpy as np import onnxruntime as ort +from graxpert.ai_model_handling import get_execution_providers_ordered + def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None): @@ -34,7 +36,11 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None output = copy.deepcopy(image) - session = ort.InferenceSession(ai_path, providers=ort.get_available_providers()) + providers = get_execution_providers_ordered() + session = ort.InferenceSession(ai_path, providers=providers) + + logging.info(f"Providers : {providers}") + logging.info(f"Used providers : {session.get_providers()}") for i in range(ith): for j in range(itw): From f020b7a878153b87218e36fb55e351802678071b Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Sat, 16 Mar 2024 11:05:11 +0100 Subject: [PATCH 22/59] Changed onnxruntime installation from requirements.txt to build-release.yml --- .github/workflows/build-release.yml | 4 ++++ requirements.txt | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 4fedd3a..4e558ba 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -36,6 +36,7 @@ jobs: run: | sudo apt install alien -y && \ pip install "cx_freeze>=6.16.0.dev" && \ + pip install onnxruntime-gpu && \ pip install -r requirements.txt - name: patch version run: | @@ -68,6 +69,7 @@ jobs: - name: install dependencies run: | pip install setuptools wheel cx_freeze && \ + pip install onnxruntime-gpu && \ pip install -r requirements.txt - name: patch version run: | @@ -105,6 +107,7 @@ jobs: - name: install dependencies run: | pip install setuptools wheel cx_freeze; ` + pip install onnxruntime-directml; ` pip install -r requirements.txt - name: patch version run: ./releng/patch_version.ps1 @@ -138,6 +141,7 @@ jobs: run: | brew install python-tk && \ pip3 install setuptools wheel pyinstaller && \ + pip3 install onnxruntime && \ pip3 install -r requirements.txt - name: patch version run: | diff --git a/requirements.txt b/requirements.txt index 5687b1b..a9c5f27 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,5 +10,3 @@ requests scikit-image == 0.21.0 scipy xisf -onnxruntime-silicon; sys_platform == "darwin" -onnxruntime-directml; sys_platform != "darwin" From 104b70ccaa9faa0997baa213203053bddbc5ece7 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 16 Mar 2024 11:06:44 +0100 Subject: [PATCH 23/59] Fixed denoise strength slider and error when denoise strength is not 1 --- graxpert/application/app.py | 6 +++++- graxpert/denoising.py | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 1595549..477ce85 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -66,6 +66,7 @@ def initialize(self): eventbus.add_listener(AppEvents.SMOTTHING_CHANGED, self.on_smoothing_changed) eventbus.add_listener(AppEvents.CALCULATE_REQUEST, self.on_calculate_request) # denoising + eventbus.add_listener(AppEvents.DENOISE_STRENGTH_CHANGED, self.on_denoise_strength_changed) eventbus.add_listener(AppEvents.DENOISE_REQUEST, self.on_denoise_request) # saving eventbus.add_listener(AppEvents.SAVE_AS_CHANGED, self.on_save_as_changed) @@ -313,7 +314,10 @@ def on_save_as_changed(self, event): def on_smoothing_changed(self, event): self.prefs.smoothing_option = event["smoothing_option"] - + + def on_denoise_strength_changed(self, event): + self.prefs.denoise_strength = event["denoise_strength"] + def on_denoise_request(self, event): if self.images["Original"] is None: messagebox.showerror("Error", _("Please load your picture first.")) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index fbe6611..defa855 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -62,4 +62,4 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] - return output * strength + input * (strength - 1) + return output * strength + input * (1 - strength) From 3fe3a6db47d9f2dbeb874ee5aaef38768b458445 Mon Sep 17 00:00:00 2001 From: Riccardo Alberghi Date: Sat, 16 Mar 2024 11:11:48 +0100 Subject: [PATCH 24/59] Fixed recursion error of cx_freeze --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 166ca25..ab60703 100644 --- a/setup.py +++ b/setup.py @@ -6,6 +6,8 @@ from graxpert.version import release, version +sys.setrecursionlimit(15_000) + astropy_path = os.path.dirname(os.path.abspath(astropy.__file__)) directory_table = [("ProgramMenuFolder", "TARGETDIR", "."), ("GraXpert", "ProgramMenuFolder", "GraXpert")] From 55a49f1014e58032c640f11daf4c2da2a1300a73 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 16 Mar 2024 11:53:53 +0100 Subject: [PATCH 25/59] Use newest version of cx_freeze for linux debian build --- .github/workflows/build-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 4e558ba..345dca5 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -35,7 +35,7 @@ jobs: - name: install dependencies run: | sudo apt install alien -y && \ - pip install "cx_freeze>=6.16.0.dev" && \ + pip install "cx_freeze" && \ pip install onnxruntime-gpu && \ pip install -r requirements.txt - name: patch version From ee066d5bbce5a4024b439e1929ff33c0b2af921e Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Mon, 18 Mar 2024 19:54:21 +0100 Subject: [PATCH 26/59] prepare release --- .github/workflows/build-release.yml | 91 +++++++++++++++-------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 345dca5..09792fb 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -15,7 +15,43 @@ on: jobs: - build-linux-deb: + # build-linux-deb: + # runs-on: ubuntu-20.04 + # steps: + # - name: setup python + # uses: actions/setup-python@v2 + # with: + # python-version: '3.10' + # - name: checkout repository + # uses: actions/checkout@v3 + # - name: configure ai s3 secrets + # run: | + # echo "endpoint = \"$ai_s3_endpoint\"" >> ./graxpert/s3_secrets.py && \ + # echo "ro_access_key = \"$ai_s3_access_key\"" >> ./graxpert/s3_secrets.py && \ + # echo "ro_secret_key = \"$ai_s3_secret_key\"" >> ./graxpert/s3_secrets.py && \ + # echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + # echo "bge_bucket_name = \"$ai_s3_bge_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + # echo "denoise_bucket_name = \"$ai_s3_denoise_bucket_name\"" >> ./graxpert/s3_secrets.py + # - name: install dependencies + # run: | + # sudo apt install alien -y && \ + # pip install "cx_freeze" && \ + # pip install onnxruntime-gpu && \ + # pip install -r requirements.txt + # - name: patch version + # run: | + # chmod u+x ./releng/patch_version.sh && \ + # ./releng/patch_version.sh + # - name: create GraXpert-linux bundle + # run: python ./setup.py bdist_deb + # - name: store artifacts + # uses: actions/upload-artifact@v2 + # with: + # name: graxpert_${{github.ref_name}}-1_amd64.deb + # path: ./dist/graxpert_${{github.ref_name}}-1_amd64.deb + # retention-days: 5 + + build-linux-zip: runs-on: ubuntu-20.04 steps: - name: setup python @@ -32,44 +68,10 @@ jobs: echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py && \ echo "bge_bucket_name = \"$ai_s3_bge_bucket_name\"" >> ./graxpert/s3_secrets.py && \ echo "denoise_bucket_name = \"$ai_s3_denoise_bucket_name\"" >> ./graxpert/s3_secrets.py - - name: install dependencies - run: | - sudo apt install alien -y && \ - pip install "cx_freeze" && \ - pip install onnxruntime-gpu && \ - pip install -r requirements.txt - - name: patch version - run: | - chmod u+x ./releng/patch_version.sh && \ - ./releng/patch_version.sh - - name: create GraXpert-linux bundle - run: python ./setup.py bdist_deb - - name: store artifacts - uses: actions/upload-artifact@v2 - with: - name: graxpert_${{github.ref_name}}-1_amd64.deb - path: ./dist/graxpert_${{github.ref_name}}-1_amd64.deb - retention-days: 5 - - build-linux-zip: - runs-on: ubuntu-20.04 - steps: - - name: setup python - uses: actions/setup-python@v2 - with: - python-version: '3.10' - - name: checkout repository - uses: actions/checkout@v3 - - name: configure ai s3 secrets - run: | - echo "endpoint = \"$ai_s3_endpoint\"" >> ./graxpert/s3_secrets.py && \ - echo "ro_access_key = \"$ai_s3_access_key\"" >> ./graxpert/s3_secrets.py && \ - echo "ro_secret_key = \"$ai_s3_secret_key\"" >> ./graxpert/s3_secrets.py && \ - echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py - name: install dependencies run: | pip install setuptools wheel cx_freeze && \ - pip install onnxruntime-gpu && \ + pip install onnxruntime-gpu --extra-index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/onnxruntime-cuda-12/pypi/simple/ && \ pip install -r requirements.txt - name: patch version run: | @@ -103,7 +105,9 @@ jobs: "endpoint = `"$env:ai_s3_endpoint`"" | Out-File -Append .\graxpert\s3_secrets.py ; ` "ro_access_key = `"$env:ai_s3_access_key`"" | Out-File -Append .\graxpert\s3_secrets.py ; ` "ro_secret_key = `"$env:ai_s3_secret_key`"" | Out-File -Append .\graxpert\s3_secrets.py ; ` - "bucket_name = `"$env:ai_s3_bucket_name`"" | Out-File -Append .\graxpert\s3_secrets.py + "bucket_name = `"$env:ai_s3_bucket_name`"" | Out-File -Append .\graxpert\s3_secrets.py ; ` + "bge_bucket_name = `"$env:ai_s3_bge_bucket_name`"" | Out-File -Append .\graxpert\s3_secrets.py ; ` + "denoise_bucket_name = `"$env:ai_s3_denoise_bucket_name`"" | Out-File -Append .\graxpert\s3_secrets.py - name: install dependencies run: | pip install setuptools wheel cx_freeze; ` @@ -174,12 +178,13 @@ jobs: release: runs-on: ubuntu-latest - needs: [build-linux-deb, build-linux-zip, build-windows, build-macos-x86_64] + # needs: [build-linux-deb, build-linux-zip, build-windows, build-macos-x86_64] + needs: [build-linux-zip, build-windows, build-macos-x86_64] steps: - - name: download linux deb - uses: actions/download-artifact@v2 - with: - name: graxpert_${{github.ref_name}}-1_amd64.deb + # - name: download linux deb + # uses: actions/download-artifact@v2 + # with: + # name: graxpert_${{github.ref_name}}-1_amd64.deb - name: download linux zip uses: actions/download-artifact@v2 with: @@ -196,7 +201,7 @@ jobs: uses: softprops/action-gh-release@v1 with: files: | - graxpert_${{github.ref_name}}-1_amd64.deb GraXpert-linux.zip GraXpert-${{github.ref_name}}-win64.msi GraXpert-macos-x86_64.dmg + # graxpert_${{github.ref_name}}-1_amd64.deb From a504e36fb1c4433949d6fb98f148f51511d0a730 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 23 Mar 2024 10:34:42 +0100 Subject: [PATCH 27/59] Management of all images is now done in AstroImageRepository class --- graxpert/AstroImageRepository.py | 54 +++++++++++++++ graxpert/application/app.py | 114 ++++++++++++++----------------- graxpert/ui/canvas.py | 48 +++++++------ graxpert/ui/statusbar.py | 12 ++-- 4 files changed, 133 insertions(+), 95 deletions(-) create mode 100644 graxpert/AstroImageRepository.py diff --git a/graxpert/AstroImageRepository.py b/graxpert/AstroImageRepository.py new file mode 100644 index 0000000..9488619 --- /dev/null +++ b/graxpert/AstroImageRepository.py @@ -0,0 +1,54 @@ +from graxpert.astroimage import AstroImage +from graxpert.stretch import StretchParameters, stretch_all +from typing import Dict + +class AstroImageRepository: + images: Dict = {"Original": None, "Gradient-Corrected": None, "Background": None, "Denoised": None} + + def set(self, type:str, image:AstroImage): + self.images[type] = image + + def get(self, type:str): + return self.images[type] + + def stretch_all(self, stretch_params:StretchParameters, saturation:float): + all_image_arrays = [] + + for key, value in self.images.items(): + if (value is not None): + all_image_arrays.append(value.img_array) + + + stretches = stretch_all(all_image_arrays, stretch_params) + + i = 0 + for key, value in self.images.items(): + if (value is not None): + value.update_display_from_array(stretches[i], saturation) + i = i + 1 + + def crop_all(self, start_x:float, end_x:float, start_y:float, end_y:float): + for key, astroimg in self.images.items(): + if astroimg is not None: + astroimg.crop(start_x, end_x, start_y, end_y) + + def update_saturation(self, saturation): + for key, value in self.images.items(): + if (value is not None): + value.update_saturation(saturation) + + def reset(self): + for key, value in self.images.items(): + self.images[key] = None + + def display_options(self): + display_options = [] + + for key, value in self.images.items(): + if (self.images[key] is not None): + display_options.append(key) + + return display_options + + + \ No newline at end of file diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 477ce85..8c99929 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -11,6 +11,7 @@ from graxpert.application.app_events import AppEvents from graxpert.application.eventbus import eventbus from graxpert.astroimage import AstroImage +from graxpert.AstroImageRepository import AstroImageRepository from graxpert.background_extraction import extract_background from graxpert.commands import INIT_HANDLER, RESET_POINTS_HANDLER, RM_POINT_HANDLER, SEL_POINTS_HANDLER, Command from graxpert.denoising import denoise @@ -34,7 +35,7 @@ def initialize(self): self.filename = "" self.data_type = "" - self.images = {"Original": None, "Background": None, "Processed": None} + self.images = AstroImageRepository() self.display_type = "Original" self.mat_affine = np.eye(3) @@ -98,7 +99,7 @@ def on_bg_tol_changed(self, event): self.prefs.bg_tol_option = event["bg_tol_option"] def on_calculate_request(self, event=None): - if self.images["Original"] is None: + if self.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) return @@ -125,7 +126,7 @@ def on_calculate_request(self, event=None): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p})) - imarray = np.copy(self.images["Original"].img_array) + imarray = np.copy(self.images.get("Original").img_array) downscale_factor = 1 @@ -134,8 +135,8 @@ def on_calculate_request(self, event=None): try: self.prefs.images_linked_option = False - self.images["Background"] = AstroImage() - self.images["Background"].set_from_array( + background = AstroImage() + background.set_from_array( extract_background( imarray, np.array(background_points), @@ -151,25 +152,24 @@ def on_calculate_request(self, event=None): ) ) - self.images["Processed"] = AstroImage() - self.images["Processed"].set_from_array(imarray) + gradient_corrected = AstroImage() + gradient_corrected.set_from_array(imarray) # Update fits header and metadata - background_mean = np.mean(self.images["Background"].img_array) - self.images["Processed"].update_fits_header(self.images["Original"].fits_header, background_mean, self.prefs, self.cmd.app_state) - self.images["Background"].update_fits_header(self.images["Original"].fits_header, background_mean, self.prefs, self.cmd.app_state) + background_mean = np.mean(background.img_array) + gradient_corrected.update_fits_header(self.images.get("Original").fits_header, background_mean, self.prefs, self.cmd.app_state) + gradient_corrected.update_fits_header(self.images.get("Original").fits_header, background_mean, self.prefs, self.cmd.app_state) - self.images["Processed"].copy_metadata(self.images["Original"]) - self.images["Background"].copy_metadata(self.images["Original"]) + gradient_corrected.copy_metadata(self.images.get("Original")) + background.copy_metadata(self.images.get("Original")) - all_images = [self.images["Original"].img_array, self.images["Processed"].img_array, self.images["Background"].img_array] - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) - self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) - self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) - self.images["Background"].update_display_from_array(stretches[2], self.prefs.saturation) + self.images.set("Gradient-Corrected", gradient_corrected) + self.images.set("Background", background) + + self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option), self.prefs.saturation) eventbus.emit(AppEvents.CALCULATE_SUCCESS) - eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) + eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Gradient-Corrected"}) except Exception as e: logging.exception(e) @@ -184,9 +184,7 @@ def on_change_saturation_request(self, event): eventbus.emit(AppEvents.CHANGE_SATURATION_BEGIN) - for img in self.images.values(): - if img is not None: - img.update_saturation(self.prefs.saturation) + self.images.update_saturation(self.prefs.saturation) eventbus.emit(AppEvents.CHANGE_SATURATION_END) @@ -194,13 +192,13 @@ def on_correction_type_changed(self, event): self.prefs.corr_type = event["corr_type"] def on_create_grid_request(self, event=None): - if self.images["Original"] is None: + if self.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) return eventbus.emit(AppEvents.CREATE_GRID_BEGIN) - self.cmd = Command(SEL_POINTS_HANDLER, self.cmd, data=self.images["Original"].img_array, num_pts=self.prefs.bg_pts_option, tol=self.prefs.bg_tol_option, sample_size=self.prefs.sample_size) + self.cmd = Command(SEL_POINTS_HANDLER, self.cmd, data=self.images.get("Original").img_array, num_pts=self.prefs.bg_pts_option, tol=self.prefs.bg_tol_option, sample_size=self.prefs.sample_size) self.cmd.execute() eventbus.emit(AppEvents.CREATE_GRID_END) @@ -243,15 +241,14 @@ def on_load_image(self, event): self.filename = os.path.splitext(os.path.basename(filename))[0] self.data_type = os.path.splitext(filename)[1] - self.images["Original"] = image - self.images["Processed"] = None - self.images["Background"] = None + self.images.reset() + self.images.set("Original", image) self.prefs.working_dir = os.path.dirname(filename) os.chdir(os.path.dirname(filename)) - width = self.images["Original"].img_display.width - height = self.images["Original"].img_display.height + width = self.images.get("Original").img_display.width + height = self.images.get("Original").img_display.height if self.prefs.width != width or self.prefs.height != height: self.reset_backgroundpts() @@ -259,7 +256,7 @@ def on_load_image(self, event): self.prefs.width = width self.prefs.height = height - tmp_state = fitsheader_2_app_state(self, self.cmd.app_state, self.images["Original"].fits_header) + tmp_state = fitsheader_2_app_state(self, self.cmd.app_state, self.images.get("Original").fits_header) self.cmd: Command = Command(INIT_HANDLER, background_points=tmp_state.background_points) self.cmd.execute() @@ -319,7 +316,7 @@ def on_denoise_strength_changed(self, event): self.prefs.denoise_strength = event["denoise_strength"] def on_denoise_request(self, event): - if self.images["Original"] is None: + if self.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) return @@ -333,24 +330,23 @@ def on_denoise_request(self, event): try: self.prefs.images_linked_option = True ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version) - imarray = denoise(self.images["Original"].img_array, ai_model_path, self.prefs.denoise_strength, progress=progress) + imarray = denoise(self.images.get("Original").img_array, ai_model_path, self.prefs.denoise_strength, progress=progress) - self.images["Processed"] = AstroImage() - self.images["Processed"].set_from_array(imarray) + denoised = AstroImage() + denoised.set_from_array(imarray) # Update fits header and metadata - background_mean = np.mean(self.images["Original"].img_array) - self.images["Processed"].update_fits_header(self.images["Original"].fits_header, background_mean, self.prefs, self.cmd.app_state) + background_mean = np.mean(self.images.get("Original").img_array) + denoised.update_fits_header(self.images.get("Original").fits_header, background_mean, self.prefs, self.cmd.app_state) - self.images["Processed"].copy_metadata(self.images["Original"]) - - all_images = [self.images["Original"].img_array, self.images["Processed"].img_array] - stretches = stretch_all(all_images, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option)) - self.images["Original"].update_display_from_array(stretches[0], self.prefs.saturation) - self.images["Processed"].update_display_from_array(stretches[1], self.prefs.saturation) + denoised.copy_metadata(self.images.get("Original")) + + self.images.set("Denoised", denoised) + + self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation) eventbus.emit(AppEvents.DENOISE_SUCCESS) - eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Processed"}) + eventbus.emit(AppEvents.UPDATE_DISPLAY_TYPE_REEQUEST, {"display_type": "Denoised"}) except Exception as e: logging.exception(e) @@ -374,7 +370,7 @@ def on_save_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - self.images["Processed"].save(dir, self.prefs.saveas_option) + self.images.get("Gradient-Corrected").save(dir, self.prefs.saveas_option) except Exception as e: logging.exception(e) eventbus.emit(AppEvents.SAVE_ERROR) @@ -396,7 +392,7 @@ def on_save_background_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - self.images["Background"].save(dir, self.prefs.saveas_option) + self.images.get("Background").save(dir, self.prefs.saveas_option) except Exception as e: logging.exception(e) eventbus.emit(AppEvents.SAVE_ERROR) @@ -418,10 +414,10 @@ def on_save_stretched_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - if self.images["Processed"] is None: - self.images["Original"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + if self.images.get("Gradient-Corrected") is None: + self.images.get("Original").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) else: - self.images["Processed"].save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + self.images.get("Gradient-Corrected").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) except Exception as e: eventbus.emit(AppEvents.SAVE_ERROR) logging.exception(e) @@ -448,17 +444,7 @@ def do_stretch(self): eventbus.emit(AppEvents.STRETCH_IMAGE_BEGIN) try: - all_images = [] - all_image_arrays = [] - stretches = [] - for img in self.images.values(): - if img is not None: - all_images.append(img) - all_image_arrays.append(img.img_array) - if len(all_images) > 0: - stretches = stretch_all(all_image_arrays, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option)) - for idx, img in enumerate(all_images): - all_images[idx].update_display_from_array(stretches[idx], self.prefs.saturation) + self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation) except Exception as e: eventbus.emit(AppEvents.STRETCH_IMAGE_ERROR) logging.exception(e) @@ -522,14 +508,14 @@ def to_canvas_point(self, x, y): return np.dot(self.mat_affine, (x, y, 1.0)) def to_image_point(self, x, y): - if self.images[self.display_type] is None: + if self.images.get(self.display_type) is None: return [] mat_inv = np.linalg.inv(self.mat_affine) image_point = np.dot(mat_inv, (x, y, 1.0)) - width = self.images[self.display_type].width - height = self.images[self.display_type].height + width = self.images.get(self.display_type).width + height = self.images.get(self.display_type).height if image_point[0] < 0 or image_point[1] < 0 or image_point[0] > width or image_point[1] > height: return [] @@ -537,14 +523,14 @@ def to_image_point(self, x, y): return image_point def to_image_point_pinned(self, x, y): - if self.images[self.display_type] is None: + if self.images.get(self.display_type) is None: return [] mat_inv = np.linalg.inv(self.mat_affine) image_point = np.dot(mat_inv, (x, y, 1.0)) - width = self.images[self.display_type].width - height = self.images[self.display_type].height + width = self.images.get(self.display_type).width + height = self.images.get(self.display_type).height if image_point[0] < 0: image_point[0] = 0 diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index e8bf8d5..fe1b2b2 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -138,13 +138,11 @@ def on_apply_crop_request(self, event=None): if not self.crop_mode: return - for astroimg in graxpert.images.values(): - if astroimg is not None: - astroimg.crop(self.startx, self.endx, self.starty, self.endy) + graxpert.images.crop_all(self.startx, self.endx, self.starty, self.endy) eventbus.emit(AppEvents.RESET_POITS_REQUEST) self.crop_mode = False - self.zoom_fit(graxpert.images[self.display_type.get()].width, graxpert.images[self.display_type.get()].height) + self.zoom_fit(graxpert.images.get(self.display_type.get()).width, graxpert.images.get(self.display_type.get()).height) self.redraw_points() self.redraw_image() @@ -158,8 +156,8 @@ def on_calculate_progress(self, event=None): self.dynamic_progress_frame.update_progress(event["progress"]) def on_calculate_success(self, event=None): - if not "Processed" in self.display_options: - self.display_options.append("Processed") + if not "Gradient-Corrected" in self.display_options: + self.display_options.append("Gradient-Corrected") self.display_menu.grid_forget() self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) self.display_menu.grid(column=0, row=0, sticky=tk.N) @@ -183,8 +181,8 @@ def on_denoise_progress(self, event=None): self.dynamic_progress_frame.update_progress(event["progress"]) def on_denoise_success(self, event=None): - if not "Processed" in self.display_options: - self.display_options.append("Processed") + if not "Denoised" in self.display_options: + self.display_options.append("Denoised") self.display_menu.grid_forget() self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) self.display_menu.grid(column=0, row=0, sticky=tk.N) @@ -227,8 +225,8 @@ def on_load_image_end(self, event=None): self.display_menu = CTkOptionMenu(self, variable=self.display_type, values=self.display_options) self.display_menu.grid(column=0, row=0, sticky=tk.N) - width = graxpert.images["Original"].img_display.width - height = graxpert.images["Original"].img_display.height + width = graxpert.images.get("Original").img_display.width + height = graxpert.images.get("Original").img_display.height self.zoom_fit(width, height) self.redraw_image() @@ -240,7 +238,7 @@ def on_load_image_error(self, event=None): def on_mouse_down_left(self, event=None): self.left_drag_timer = -1 - if graxpert.images["Original"] is None: + if graxpert.images.get("Original") is None: return self.clicked_inside_pt = False @@ -280,7 +278,7 @@ def on_mouse_down_left(self, event=None): self.__old_event = event def on_mouse_down_right(self, event=None): - if graxpert.images["Original"] is None or not graxpert.prefs.display_pts: + if graxpert.images.get("Original") is None or not graxpert.prefs.display_pts: return graxpert.remove_pt(event) @@ -291,10 +289,10 @@ def on_mouse_move(self, event=None): eventbus.emit(UiEvents.MOUSE_MOVED, {"mouse_event": event}) def on_mouse_move_left(self, event=None): - if graxpert.images["Original"] is None: + if graxpert.images.get("Original") is None: return - if graxpert.images[graxpert.display_type] is None: + if graxpert.images.get(graxpert.display_type) is None: return if self.left_drag_timer == -1: @@ -333,7 +331,7 @@ def on_mouse_move_left(self, event=None): return def on_mouse_release_left(self, event=None): - if graxpert.images["Original"] is None or not graxpert.prefs.display_pts: + if graxpert.images.get("Original") is None or not graxpert.prefs.display_pts: return if self.clicked_inside_pt and not self.crop_mode: @@ -355,7 +353,7 @@ def on_mouse_release_left(self, event=None): tol=graxpert.prefs.bg_tol_option, bg_pts=graxpert.prefs.bg_pts_option, sample_size=graxpert.prefs.sample_size, - image=graxpert.images["Original"], + image=graxpert.images.get("Original"), ) graxpert.cmd.execute() @@ -364,7 +362,7 @@ def on_mouse_release_left(self, event=None): self.left_drag_timer = -1 def on_mouse_wheel(self, event=None): - if graxpert.images[self.display_type.get()] is None: + if graxpert.images.get(self.display_type.get()) is None: return if event.delta > 0 or event.num == 4: graxpert.scale_at(6 / 5, event.x, event.y) @@ -396,14 +394,14 @@ def on_stretch_image_error(self, event=None): self.show_loading_frame(False) def on_toggle_crop_request(self, event=None): - if graxpert.images["Original"] is None: + if graxpert.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) return self.startx = 0 self.starty = 0 - self.endx = graxpert.images["Original"].width - self.endy = graxpert.images["Original"].height + self.endx = graxpert.images.get("Original").width + self.endy = graxpert.images.get("Original").height if self.crop_mode: self.crop_mode = False @@ -434,12 +432,12 @@ def draw_image(self, pil_image, tags=None): return def redraw_image(self, event=None): - if graxpert.images[self.display_type.get()] is None: + if graxpert.images.get(self.display_type.get()) is None: return - self.draw_image(graxpert.images[self.display_type.get()].img_display_saturated) + self.draw_image(graxpert.images.get(self.display_type.get()).img_display_saturated) def redraw_points(self, event=None): - if graxpert.images["Original"] is None: + if graxpert.images.get("Original") is None: return color = hls_to_rgb(graxpert.prefs.sample_color / 360, 0.5, 1.0) @@ -465,9 +463,9 @@ def redraw_points(self, event=None): self.canvas.create_oval(corner2[0] - 15, corner2[1] - 15, corner2[0] + 15, corner2[1] + 15, outline=color, width=2, tags="crop") def reset_zoom(self, event=None): - if graxpert.images[self.display_type.get()] is None: + if graxpert.images.get(self.display_type.get()) is None: return - self.zoom_fit(graxpert.images[self.display_type.get()].width, graxpert.images[self.display_type.get()].height) + self.zoom_fit(graxpert.images.get(self.display_type.get()).width, graxpert.images.get(self.display_type.get()).height) self.redraw_image() def show_loading_frame(self, show): diff --git a/graxpert/ui/statusbar.py b/graxpert/ui/statusbar.py index 32b4c84..e4f6520 100644 --- a/graxpert/ui/statusbar.py +++ b/graxpert/ui/statusbar.py @@ -36,22 +36,22 @@ def register_events(self): # event handling def on_load_image_end(self, event): self.label_image_info.configure( - text=f'{graxpert.data_type} : {graxpert.images["Original"].img_display.width} x {graxpert.images["Original"].img_display.height} {graxpert.images["Original"].img_display.mode}' + text=f'{graxpert.data_type} : {graxpert.images.get("Original").img_display.width} x {graxpert.images.get("Original").img_display.height} {graxpert.images.get("Original").img_display.mode}' ) def on_mouse_move(self, event): - if graxpert.images[graxpert.display_type] is None: + if graxpert.images.get(graxpert.display_type) is None: return image_point = graxpert.to_image_point(event["mouse_event"].x, event["mouse_event"].y) if len(image_point) != 0: text = "x=" + f"{image_point[0]:.2f}" + ",y=" + f"{image_point[1]:.2f} " - if graxpert.images[graxpert.display_type].img_array.shape[2] == 3: - R, G, B = graxpert.images[graxpert.display_type].get_local_median(image_point) + if graxpert.images.get(graxpert.display_type).img_array.shape[2] == 3: + R, G, B = graxpert.images.get(graxpert.display_type).get_local_median(image_point) text = text + "RGB = (" + f"{R:.4f}," + f"{G:.4f}," + f"{B:.4f})" - if graxpert.images[graxpert.display_type].img_array.shape[2] == 1: - L = graxpert.images[graxpert.display_type].get_local_median(image_point) + if graxpert.images.get(graxpert.display_type).img_array.shape[2] == 1: + L = graxpert.images.get(graxpert.display_type).get_local_median(image_point) text = text + "L= " + f"{L:.4f}" self.label_image_pixel.configure(text=text) From 6d0a1bb5147c3527f523c44d7c81ea2c0bb92d83 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 23 Mar 2024 10:49:05 +0100 Subject: [PATCH 28/59] Denoising is now performed on gradient-corrected image if available --- graxpert/application/app.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 8c99929..42bad7f 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -126,8 +126,6 @@ def on_calculate_request(self, event=None): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.CALCULATE_PROGRESS, {"progress": p})) - imarray = np.copy(self.images.get("Original").img_array) - downscale_factor = 1 if self.prefs.interpol_type_option == "Kriging" or self.prefs.interpol_type_option == "RBF": @@ -135,10 +133,15 @@ def on_calculate_request(self, event=None): try: self.prefs.images_linked_option = False + + img_array_to_be_processed = np.copy(self.images.get("Original").img_array) + if (self.images.get("Denoised") is not None): + img_array_to_be_processed = np.copy(self.images.get("Denoised").img_array) + background = AstroImage() background.set_from_array( extract_background( - imarray, + img_array_to_be_processed, np.array(background_points), self.prefs.interpol_type_option, self.prefs.smoothing_option, @@ -153,7 +156,7 @@ def on_calculate_request(self, event=None): ) gradient_corrected = AstroImage() - gradient_corrected.set_from_array(imarray) + gradient_corrected.set_from_array(img_array_to_be_processed) # Update fits header and metadata background_mean = np.mean(background.img_array) @@ -328,9 +331,13 @@ def on_denoise_request(self, event): progress = DynamicProgressThread(callback=lambda p: eventbus.emit(AppEvents.DENOISE_PROGRESS, {"progress": p})) try: + img_array_to_be_processed = np.copy(self.images.get("Original").img_array) + if (self.images.get("Gradient-Corrected") is not None): + img_array_to_be_processed = np.copy(self.images.get("Gradient-Corrected").img_array) + self.prefs.images_linked_option = True ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version) - imarray = denoise(self.images.get("Original").img_array, ai_model_path, self.prefs.denoise_strength, progress=progress) + imarray = denoise(img_array_to_be_processed, ai_model_path, self.prefs.denoise_strength, progress=progress) denoised = AstroImage() denoised.set_from_array(imarray) From a2a4a87e704ac404bbb127b123e89ca226d858ca Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 23 Mar 2024 10:59:19 +0100 Subject: [PATCH 29/59] Priority for saving is now Denoised > Gradient-Corrected > Original --- graxpert/application/app.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 42bad7f..3514757 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -135,8 +135,6 @@ def on_calculate_request(self, event=None): self.prefs.images_linked_option = False img_array_to_be_processed = np.copy(self.images.get("Original").img_array) - if (self.images.get("Denoised") is not None): - img_array_to_be_processed = np.copy(self.images.get("Denoised").img_array) background = AstroImage() background.set_from_array( @@ -377,7 +375,13 @@ def on_save_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - self.images.get("Gradient-Corrected").save(dir, self.prefs.saveas_option) + if (self.images.get("Denoised") is not None): + self.images.get("Denoised").save(dir, self.prefs.saveas_option) + elif (self.images.get("Gradient-Corrected") is not None): + self.images.get("Gradient-Corrected").save(dir, self.prefs.saveas_option) + else: + self.images.get("Original").save(dir, self.prefs.saveas_option) + except Exception as e: logging.exception(e) eventbus.emit(AppEvents.SAVE_ERROR) @@ -421,10 +425,13 @@ def on_save_stretched_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - if self.images.get("Gradient-Corrected") is None: - self.images.get("Original").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) - else: + if (self.images.get("Denoised") is not None): + self.images.get("Denoised").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + elif (self.images.get("Gradient-Corrected") is not None): self.images.get("Gradient-Corrected").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + else: + self.images.get("Original").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) + except Exception as e: eventbus.emit(AppEvents.SAVE_ERROR) logging.exception(e) From 388a945d3f9c9672a4406f8a1fd55f7947fc4866 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 23 Mar 2024 11:16:05 +0100 Subject: [PATCH 30/59] Mono images can now be denoised --- graxpert/denoising.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index cf01c89..f3fbcfd 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -10,6 +10,11 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None): input = copy.deepcopy(image) + num_colors = image.shape[-1] + + if num_colors == 1: + image = np.array([image[:, :, 0], image[:, :, 0], image[:, :, 0]]) + image = np.moveaxis(image, 0, -1) H, W, _ = image.shape offset = int((window_size - stride) / 2) @@ -67,5 +72,10 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] + output = output * strength + input * (1 - strength) + + if num_colors == 1: + output = np.array([output[:, :, 0]]) + output = np.moveaxis(output, 0, -1) - return output * strength + input * (1 - strength) + return output From 6fda664dcca297126a6d6ae524a611b93e9fde2c Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 23 Mar 2024 16:23:55 +0100 Subject: [PATCH 31/59] support license information along with ai model files --- graxpert/ai_model_handling.py | 13 +++++++++++-- graxpert/ui/canvas.py | 3 +++ graxpert/ui/widgets.py | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/graxpert/ai_model_handling.py b/graxpert/ai_model_handling.py index d2fc19d..fd515e8 100644 --- a/graxpert/ai_model_handling.py +++ b/graxpert/ai_model_handling.py @@ -46,7 +46,7 @@ def list_remote_versions(bucket_name): for o in objects: tags = client.get_object_tags(o.bucket_name, o.object_name) - if "ai-version" in tags: + if tags is not None and "ai-version" in tags: versions.append( { "bucket": o.bucket_name, @@ -134,12 +134,21 @@ def download_version(ai_models_dir, bucket_name, remote_version, progress=None): os.makedirs(ai_model_dir, exist_ok=True) ai_model_file = os.path.join(ai_model_dir, "model.onnx") + ai_model_zip = os.path.join(ai_model_dir, "model.zip") client.fget_object( remote_version["bucket"], remote_version["object"], - ai_model_file, + ai_model_zip, progress=DynamicProgressThread(callback=progress), ) + + with zipfile.ZipFile(ai_model_zip, "r") as zip_ref: + zip_ref.extractall(ai_model_dir) + + if not os.path.isfile(ai_model_file): + raise ValueError(f"Could not find ai 'model.onnx' file after extracting {ai_model_zip}") + os.remove(ai_model_zip) + except Exception as e: # try to delete (rollback) ai_model_dir in case of errors logging.exception(e) diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index fe1b2b2..a019d92 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -14,6 +14,7 @@ from graxpert.resource_utils import resource_path from graxpert.ui.loadingframe import DynamicProgressFrame, LoadingFrame from graxpert.ui.ui_events import UiEvents +from graxpert.ui.widgets import default_option_menu_height class Canvas(CTkFrame): @@ -41,6 +42,7 @@ def __init__(self, master, **kwargs): # widget setup def create_children(self): + self.topbar = CTkFrame(self, height=default_option_menu_height) self.canvas = CTkCanvas(self, background="black", bd=0, highlightthickness=0) self.help_button = CTkButton( self.canvas, @@ -64,6 +66,7 @@ def setup_layout(self): self.canvas.rowconfigure(1, weight=1) def place_children(self): + self.topbar.grid(column=0, row=0, sticky=tk.NSEW) self.canvas.grid(column=0, row=1, sticky=tk.NSEW) self.help_button.grid(column=0, row=0, sticky=tk.SE) self.advanced_button.grid(column=0, row=1, sticky=tk.NE) diff --git a/graxpert/ui/widgets.py b/graxpert/ui/widgets.py index 4b9bd17..4e8f7b0 100644 --- a/graxpert/ui/widgets.py +++ b/graxpert/ui/widgets.py @@ -10,6 +10,7 @@ default_button_width = 200 default_label_width = 200 +default_option_menu_height = 28 padx = 5 * get_scaling_factor() pady = 5 * get_scaling_factor() From 378dbeb526db41f56f6d4d62502be5618db50d3a Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 23 Mar 2024 16:46:15 +0100 Subject: [PATCH 32/59] add "strength" parameter to denoise cli; make "background-extraction" the default cli subcommand --- graxpert/cmdline_tools.py | 3 ++- graxpert/main.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/graxpert/cmdline_tools.py b/graxpert/cmdline_tools.py index 74b76a6..4749b97 100644 --- a/graxpert/cmdline_tools.py +++ b/graxpert/cmdline_tools.py @@ -238,7 +238,8 @@ def execute(self): processed_Astro_Image.set_from_array( denoise( astro_Image.img_array, - ai_model_path + ai_model_path, + self.args.denoise_strength )) processed_Astro_Image.save(self.get_save_path(), self.get_output_file_format()) diff --git a/graxpert/main.py b/graxpert/main.py index 00b9ff1..cd0a910 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -224,7 +224,20 @@ def main(): ", ".join(available_denoise_versions[0]), ", ".join(available_denoise_versions[1]) ), ) + denoise_parser.add_argument( + "-strength", + "--denoise_strength", + nargs="?", + required=False, + default=1.0, + type=float, + help='Strength of the desired denoising effect, default: "1.0"', + ) + # assume "background-extraction" as default sub-command + if not "background-extraction" in sys.argv and not "denoising" in sys.argv: + sys.argv.append("background-extraction") + args = parser.parse_args() print(args) From fe5aded46993e59c3c1668bfa2cc15a7bc35b869 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 23 Mar 2024 17:10:27 +0100 Subject: [PATCH 33/59] make tooltips more robust during long running tasks --- graxpert/application/eventbus.py | 5 +++-- graxpert/ui/tooltip.py | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/graxpert/application/eventbus.py b/graxpert/application/eventbus.py index 6a55c6d..9a3b5d2 100644 --- a/graxpert/application/eventbus.py +++ b/graxpert/application/eventbus.py @@ -5,9 +5,10 @@ def __init__(self): def add_listener(self, event_name, listener): if not self.listeners.get(event_name, None): - self.listeners[event_name] = {listener} + self.listeners[event_name] = [listener] else: - self.listeners[event_name].add(listener) + if not listener in self.listeners[event_name]: + self.listeners[event_name].insert(0, listener) def remove_listener(self, event_name, listener): self.listeners[event_name].remove(listener) diff --git a/graxpert/ui/tooltip.py b/graxpert/ui/tooltip.py index 0867014..e28e792 100644 --- a/graxpert/ui/tooltip.py +++ b/graxpert/ui/tooltip.py @@ -51,8 +51,11 @@ def __init__(self, widget, *, pad=(5, 3, 5, 3), text="widget info", waittime=500 self.pad = pad self.id = None self.tw = None - eventbus.add_listener(AppEvents.CALCULATE_BEGIN, lambda e: self.hide()) - eventbus.add_listener(AppEvents.DENOISE_BEGIN, lambda e: self.hide()) + self.enable_tt = True + eventbus.add_listener(AppEvents.CALCULATE_REQUEST, lambda e: self.disable()) + eventbus.add_listener(AppEvents.DENOISE_REQUEST, lambda e: self.disable()) + eventbus.add_listener(AppEvents.CALCULATE_END, lambda e: self.enable()) + eventbus.add_listener(AppEvents.DENOISE_END, lambda e: self.enable()) def onEnter(self, event=None): self.schedule() @@ -72,6 +75,10 @@ def unschedule(self): self.widget.after_cancel(id_) def show(self): + + if not self.enable_tt: + return + def tip_pos_calculator(widget, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)): w = widget @@ -137,6 +144,13 @@ def hide(self): if tw: tw.destroy() self.tw = None + + def enable(self): + self.enable_tt = True + + def disable(self): + self.enable_tt = False + self.hide() load_text = _("Load your image you would like to correct. \n" "\n" "Supported formats: .tiff, .fits, .png, .jpg \n" "Supported bitdepths: 16 bit integer, 32 bit float") From 262f0b9d514ef360835373befbb12480e383fcc5 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 23 Mar 2024 17:22:59 +0100 Subject: [PATCH 34/59] update start badge for release 'Umbriel' --- graxpert/ui/canvas.py | 2 +- img/graXpert_Startbadge_Umbriel.png | Bin 0 -> 435524 bytes img/graXpert_Startbadge_Umbriel.svg | 72 ++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 img/graXpert_Startbadge_Umbriel.png create mode 100644 img/graXpert_Startbadge_Umbriel.svg diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index e8bf8d5..79018e0 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -210,7 +210,7 @@ def on_create_grid_end(self, event=None): self.show_loading_frame(False) def on_display_start_badge_request(self, event=None): - self.start_badge = ImageTk.PhotoImage(file=resource_path("img/graXpert_Startbadge_Ariel.png")) + self.start_badge = ImageTk.PhotoImage(file=resource_path("img/graXpert_Startbadge_Umbriel.png")) self.canvas.create_image(self.canvas.winfo_width() / 2, self.canvas.winfo_height() / 2, anchor=tk.CENTER, image=self.start_badge, tags="start_badge") self.canvas.after(5000, lambda: self.canvas.delete("start_badge")) diff --git a/img/graXpert_Startbadge_Umbriel.png b/img/graXpert_Startbadge_Umbriel.png new file mode 100644 index 0000000000000000000000000000000000000000..a547638be212922b60b47fa4748ac6f2140ddcda GIT binary patch literal 435524 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

B}(IIF4W;wPQsp0?IJcRN`UNKwvDR^ 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�maYm_r4m7*Epd{*TX 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 U%!4tL z5tHU|IHvM6D{D+tQUG@jrvn?xnTj!}lG6&Y6#mhJ)5zMYdr&NxT{v*wg%Go|E@>+E zd9am@Aj<(Ng3m}HoWN3oIbn&)h?$c%D%=HcRnC}n7N6XP^HV?ZNq+Vx{u00YPrkzR z!K+f4vvQ3NAJ;ft33a9{yo{ajpcbJ=0@YAqj-7}=it*Ar#VQx8csO00OLSH`+cb;? z_lIKoglxOqeD%p#LE4V?$mvc{}I!W%I>4kRY~wu2b^IGB+^Sr_1A zG*F~t&mJBgzJwH}Oh(N6*fK{iqLFLB7`%Tflu(}7I2>M=1@p;SQ{miYWf`eHZww-W zDaNT3OeTj+s!yga94x3_Gyfn?gdih(%~A6tFFk0MFG8R9`s2*~-1~3e(C3Y(=Vz<} zGeI$;li9aCk(ZP)Q95U9*a)gM4pQ;(x@P_E7K7^W=45>G;mqyWF%peC;y`r4&503I zFZ7Y2v5*_3PZkE#8oOofuv%r;Ge!Ho9;;jsKAHv91bi)k`iZcDj~D8MqRPwMaVeZz zz`U{@J0Xu~IU{TkolOgba_hpw`a+}dG6S`p;+;9tvzW%@4oB|M)-uuYB{H-{$={CpI^#tu%)|ccyhNRNlqlp;U?wOq{D& z+Cb@CY~>b0sX>d}=Od~4z705OW0_Z?R9YOUH$se?I2)6CM~yGKa`lwkJ=V$tulUHb zzwjy!`V2NIB9(32K}8{SaY`I4O;YE8vPa$o*4mjpcqJ3O^Sx*k88mHlZxjwrB7F0^ zAM#hf_&Hiz?(n^weEi@5!u?E=8=U;R|sBFY&2n%MNLt*-rrm#x3_DqfG2emd9KX5gUI0$j%DEQ0^)uM$P zgQ0>HL85Tcz++JmDc||dJAUgQ{{c6Ji&^U71Ntbq4Ti-1U>uyAQq4Hun+{s${rx^OysZsJPVk7} zWlt%jm{8}$BT26dJBL=TSK$<$DS7a{&W#dD=@cdkY{!vsP0y7A=2UHrx&MGj+dm%D z#||Pa2wf({)AGGYHWqtkfA8<{ z*)RMx{^+Z}$CtnI4Z@5%Zd|8uibC&MROnXelEKiSnPJg6s46(8G$@M_Ba$jj77#)v zjZUTGRybQ>r(~vte&2j>83XlXB;w&zYo&da06Y zqN!Ol@Z_~rZHVN-vrS7mm<7V})wsBDj6szP9+Ru((0U0&HM1n!*su_M=EPwk zt4P=5g~f~}@X7}7To^-HrL&Ym^@-HUoAu1aEAM8@PJ47NYJ8vtk%OX>ZFWxe%%vJ1 z+%`r8ry|r$;$V^?zCNG0Aw0SB3CR~qS9ldE-}=bmrp76rc#q09oU6cAMz%E=smd;m zeQ{2GXE7M$!K9W#HKEIrZaiC9E$Oc54_Hx8!)e-!1^Uh&HG@-B>QsnA5oaGHURfr$ z#W0IZ?{FL(r^yk2TW(DVY-7sE00+Zjc0!7oRP4n?VyJ9 zc&cnOcz5i)r!B3{B)@6s&|UdLeQ!mfoOw?tcaBTQLM8CsyHTPN7r zZwJ5qPk)=A{h3d*p3XlwfI!?=H+jf_`2UTmS$d07*naRM!}^sXXM<-=18BAsNWRRp6%XSlKy zihU9(;(GWen5^hh{hk%1Hl9yqb##{rR? zpQ4Q_6|<79EIU}5Aqu`5XPbnP*^`;Po3+7GR_4gof&QRn0&@-)jIB?G4Bopm+Wdd1 zdbeiFw(KhJ>%EUL=3HyK9Trm~&)4?<@+dR-Bs>BpEXvbK+XL?1Smf+E(6s=bqQwLChO-N7E3l;@G-Ae6f^l z1I0DXuA!icYoSJ#^SpR?U?_}!Q0j@0!RDQn;E+j=gA0X9&3$c5&NC6d*Ex6)XKL~c z?g^NdrF%=RUaTqgw4%P?ej#i!hGFCZ!nk53dvp%Zrc*)~#S%s)ovKNN^w_yrVKGB? z=c7Fs<)DS~I{1aun7wdU0$L$v#m$K7G@m@h zax0RO^$z3#VWe!?WQ}BrkJ-> z1<;gzM&29^#k^vsOv!HHE-R%5>r5l*@B8d08GE36$C^+)%~eHt8=F3rg*tbp=lbDv z+ewBBQx*n|kVmE`yyx8#h-VV1w3Qv_PA1=cna1E}s;oMgA`De(Iam<_!}rNMYM3d9 zDTl7Kc%+K*;e@?A&)S*k&KT)e65TPJg*$v?AIH6>Vd^r4kP}zmkhZW&12%?qt`R)< zjarP&mAeSerJ^SEp*#gF4BlC9wcg~05DF4+hm=3^g)i{+uY8qPAHNR-Z5Xx~ zQ#brj3Ja$y?9$PGMVAxZlsdEN`)om&@zHhTM?d#nJe(W9^K#2xr?}9`PMB*K9@$Yn zxNxF`JjI-0{j$oX$A|aG| zWIvD}+?8M(#-n#k3u?;h7sOW_VOp+Dik?AA!V0x>oePid7>?Kju~n8+=lSy!W8b;> zfsd637sMt=;lmkRJj?oCEN33-9hYsRX(zg~YhzJk_@ox+t`r)Bs+Il7Sa9#1*%O&Q zEm#%G)PyC5vjerlGb;=~=pLNNV#cc{UjIEa>fM>`a?R9^O!lJmnIvkh6(wjz7^R_l z(B?r6Wt#=9nan6Nc|uCTG;leRry>mr$$N?@#e_Nv8yi3IBcJEf@80nnU;R4RiOxcB zaI%U|IAUXwN~wa4i6OjMhF0H}pij#)Z+6s5)6%}D^D_d#Y zpH|pj^3C7+O@84Qex85y|Nb(U;n}_&*|^?S@R8T?F1fPrJy(csPHipM(>|%w5i_*f zt<_g(M|wCeW=YhIgJTTLCt5)DoP9M6W&}qBhX>1TZO$}YE;yPBr5be#G15!iUSNO)a zKH&24M@%ma-&k}>jQh+%L~SA=Tw{lF;#7<+gqVs@8PvqsQd!r9F|Leh3|W~0kCG9p zJ1mjP^MLid9?lO$M+A!DbSa<;-# zB&xVkDQbkB5G!;Q!iD>}Av1T_V;-5{u*!8@fkx$uGijPlxz!iclUuM2Pk%{)$3wED zYdP^MHmn7UYD)Q$-5l+F&&8cjR2Y{luPHofqUXrfFSm+kcp%RIPvuu9NH>Bq<(Bod$B=m}>l3k?We(U`X^e8#-%ae!5X6CWL( zCN%G8@ubJZMCU+hXmL0Om$9T7uJ7zGKjOoW-bXp8^&ZuOD?8UITqTRyObQy4K6l)+ z;Lc^T`$5eO1{Z74p$VMp%JTdc9K0!F$zr&Y);UDu%4vq=0ZoM%t)F>@@8G{p(8Y>5d zBM$l$-l@jMit$9X!lys+45`MqKHh2bkuhP>#_O@+vZ0p6l~vDKC$MKn$tuQZ&v>+g z^;9Jqxf+bfL1MV&y0bv|!Np3h+q!eii5I6V4>Wbk+)b&qrzMNbv`-M_BAv%$5M=x6xDD7J2TW>8{cgF|P#Cjw zXwTnUghip~q)n&Wf|c}hbx)J)RVyVRT$!cd7=8qgVK@hi<)Dl!ogKztm4fSvc&eH) zop;uSPdq>K!SzZmInG2V;gCDbt#nL2$O3REQF<1 zRxt>p6(^XuD7_#2@E`m!5tn97MXwQeD4o=12ZJ6)VA zNmm}?bPZIp&SQ&%T2E9ru92%CmmSfG3#{T0%5fw?7c*)o!zZD_V!`W?&Brxzt?i*$ z1k}dIFL%EBwXbnGHjb!-!zRw02BR@^ACDkxB%<07uxyA<-;yz7(#4q(Y430ESMWxxwrj@k>&)bUF%5}Rial~PjOewh;=99;(Ga?9gaA>CaXXt_nIFnGt&M#hk zarz{rp);_e47p7~elRmy&8MHOoQeUJh=EAw8A8zu*O^@%=O*-dWo4kUa>Y5MbJy;f zHwo@u8@*J@F(~0!t$ghpU#A=g`{>l>j9BSJI*WM%3WqBDAfLQlSoFjmoyx&VFeK~O z5A9qfFk5NIK;j9j!by~($F0KNP*xThoYw`_$&qc`oJwW2Y@!_6iFwU_#bORPC zmbmN~WN zs*<^7xgtBdI8S{h(RQg^FxFLgj_~nyu+3b9`FNrsNFAJd=i}EK!;c&mk$evju2HC~ zBLeS?LRz?1o@rpZp_2TS;X)Zs)yixQlgU{I7Q$shxxC`(^=m%Zf`?Yvrt*qO>la28 zs>2ZF8j~?AtG0yr+*BK%2TK@36r{4pNQoGsnXExweY2{$4I+NiO;qCMF_E{wmQPmSQCEKZYhU4?|I$CF&ulv? z99S$o`oXG-%u2!79DF!0)-ziv`I-cjQdzC?uYT`CzWuoKuqqa?QE|J$ylU{GRCZZd zaNKsfUl9t2C?*APYGl*yXoER-G%S54W?5<$9W~3p{TLh(Y;~b+1M@4C;7JTMa%tcvbQapWsrYYxdBNIew!Hf=JbPlE#K7Rd##{enpS}8uM zwQ!YSUY{uIk`)W2>C(k`XKl>kJgRcCM6GW#xYLS=FmL485tENZSV{iR)80`wni;?L zTi@Wf{`K#1cV3wo1#%daLDj*#_wVquKe0z};l!$wnR|UopUevn_2WL}6l&d%o zS{TK+?42?v8iUaXy=Tkw$tG@-F((m~Qci3`QQwm^?&)VzYg}XiK?z|pImN(5Ifj8{ zeAZR6W!RN7L3q#u4hKkxC(A7s8a21WhZKF~IHS{TNK0 zI6D@>;Vp&WHdUNEMPZY)SWF%F}5*Ttfdkrg3r!24qok(MbgB-sZnD^ zZ(goS8sA+9g=_yPfgiP#wTE3{Fxa2-|=$ecT_bk=npt$p?hj-9O zlHH6>cs5psm6Rr!N163AuPNJo;tLaKB3(^)wd_sS(?rWv@!Q<>HO_r6rc26PQ>AjvgF;P|aAsBw6h6d-D^vH|rJTuL-tjd#5EF2p` zL6Takov{~w?{Xl#CL%c_YZw|%l)>%`iwL_+PPX7(&>~!GBSWvndUs*sEsoYh6noyW(gkJN-G(C8(uh$jk6l}r7@0!_Ut*QMR`0n zj^QkJ2HgpSu8Mnbu9c7t_24dyU6tOmaau4+6Yfmequs9Q>@K><6=TV`~@~3|K%@lGQK+^FVH~l1)lYhf#a+_LG zL3yK=@oImTphxm_nWIANKvlQ%>a zJPz*6XtRJ-ycUj`a`o&I58e@m!W?bW7pTR4iJg=2io#{#=&BzDBeOy60B9kbEIVL`xM&W9~ zgXXHXdvYH(JR_Y{cF&U0VU;sV*O^L71ZoTKEO)pZfbl2|xKQPWv-e7((F|u#Lvkrx z{mM(bN0@{dYfpme&{VYMyhAO`s;jmPDZF{W6X)KP77J`obSdYV4WGw-TTg|8R98Zngl_H7xsYW!iYd9 zw;G1zMhRI<(udGA6`p+xwXP6>YoMBn!oZnK-jO?YooJuvG|Va{xlxGTnK)BGhU0cn z#j~?VD*N2ihvG9+n0A9F&K!&<=~pvN8n}kAO3BYD`S7Zil!Cb70k1#5Kaj6NCrhA~*%8IOdX1(Ci+_55BuIZ<=cMCdni zZnHF4OI3)LyfVq5=hdyD{pJo&bFBF7cOL2Hcf*#uhcCV<`Lbff?96#!CJeF6#;a3S zBgN0bIpCxZ?Ai!{>rD8~vn6SN`+VTy8Re@IxJ~9z)PuF8Y3?GO-3sgS4k~GEBNil} zYp~2jj~|>l)!a#4=D{4sT`7!tCA5Gh$xf)O=FHitT9D(QYh&ty_!TXc*#QQ=3bIYc zJeVygM}y+Lj#PTA3HMrn%9z2~GfGt~_u^F>)lNjfz3#MV+^Molmheq4L`e|QValrs zL}$2hWI&k7}74A=sS9{03 zAPy%{E>U>wPb?A?Svcf1$I+<@&)t{^SVg6B9S7r@uqbakLeMZ~T~VAL{OtGevJ1!4 zQ&I@+04vNarr>N>Y#tmv55vtWt4gN-Zu7~BCb zYj!%F=7ng&C^-nM)svPSjbQTHPu%H(227b;o?h~eZ+@E}`QaZyZfl%3WE0`d3=%iZ zM`2Y=zGeuyuA@r(TQPyGz7Exa+@ zycyRVd$lTC``+G3lA52!jB7HC-+;>@vAzP8Dvi~II+bfE7jB#&pHvy_B3u-fS@GN2)wFQ7${0ad zr7?JYs}^W=!N3lQb`v6H*qe4~k_0ty-pL4wO1lmB5U{)AK0`V;q<-oQrVyVBnN+P9jWC zBdutf(&YB@rk=5KDQODE*`p9e85D*qJ_mh!MCO(M;eYy@{LG*G5BSpm`M0@_L5+pQ zghLEG(oP_T#!Qt=Gi6jg=p=AeMVKY1GkHs!2#?o{kYmESHhTBl?P`D|G26wlyN6GH zQOZaQwvgr*(OaPrEIL6eez)?Vr-a>z5K*|8(LDH}&wq|T{nLMpr#|`c8^6mgca&x< z6m*ak=$?|+V_06S-kBks&I=#Be8u(YCC^&rB+iC2WK!n571v#G89dYM{1`rY$0W-$ z*>HpCN?0RUC^9iEIFmjmAuDUGc=UV`hjaLaLmMS3_>SqCsCyAcROmZXb}m+L(Z-el zojG86V5ehoaEy)JbKu!!QtF`5*k|rZg+d)!%(g5KG~4MmDO35x{WG3s@cO#(P#O`F z!v}p7S~JENtX{c#=jxvR3Kd)zj020p5GeIT@4^Q!ue@k0XDNst;2G0aSE?kM{-dF+ zMS$d39C~ZZY))yg0$W%fnjopEHuvx(uu85CMTyYV50!kqSAY%A8MVWYQz%LMw%rWKT|4 z<>-~OW%8ryB=b<683%{LxhmV`U>rM9vTD0T7RD_lZ?G{V(cE^yXt%YtI z`_!lT%y)n0t^V;HPYG#){*Jrkw$jP3iQB*DkNLg7|8w8R&;R@{^3gUp)yjP>i0sVB zgOI~%W#Q3o>$*_-^1xLNCI@T1qv=76Af)qf4kVKPIMvy;vdW2S2R?#k3(so~3K0rx zRw(o#ynopVo7Ck6MZmZsEQqbt(s_9u+`qVIaiu>#(L<@RqqlCaYDQIM4?qj=SrU?~ zD(`&i1^?|||L^$j@BRI66{LLm^5@0$Rwnixwdvg#FZi=R`?GxM|M{mpeega-;Od2# zBVXScOgh~Us-zz)Wq!{{DZ-tes6J2?tQ6>-wLQ?9rt&s-_MX%ukA(2AdN9*jfs3P| zoNhi1bfv~4qGv*b8E}l6q-ROy%Je|BabGppPd($_QW~NQAH4iJ*XxnZ=b;=DH;;vJ z?E_b*aw}78g?$RzgVltAB@4rxW=cQcwd5cbF|v?u9zesSQeqO4X}ZjOq{80A2~pP4 zFwF?_S&b5dOH9TQAjWxFXrYYx$fC}x0Es{~J!-3ro5!OkI8CzeX$ejq9oS4tGNNUxC6(ue1RDhpxBe2S=G&e5UJ2<>e2 zJbxTu$)<3GW{nx0sg)SFS`!JvuL-v7&Xvwmlx7Q)gQ`m94&*?`l{q`bCTBY{CA}F> zE}W!bVr&BQc8ymwRT7dtV*(=zBF@&cd#zXw1M@hL0?+U6DJmR&<1hb(Kf_}1xBl)w zNSj1e?rLMqWXy=%1{qJ)3vrg{95FyE)hZ&vAPW_7Ct`BhCq=ob*%0I)TBQ&sOb1iJ zo{|~B5BYPNr0A$^XcU|wInEO8;bD676X?vU-;fxTk^WEF>2G zRFPO%MR6&4)A!C2O4Z7JZEQ2Bwy|2lrKV&)gS%E(fD7qLzn8{qoD%n(Lea8=>sz@m zSXtIH%c-Hgb1f@6vqjN0*rPD#K?`B`!i)z2g0s z9}_yDr2Kw~gT+>!X#vURhSy!Wza@HRU8(yMOC9W%xb7E`-6qWoGx7$lVN9F64(DBi zMJrbg#IHP*%BBZbO{1G2yd-heDo}OjA`6Qv=93R^DG$@akb^NhQkEM*aWdV|fEb+v zWkFHPr^9VJXH#frP69{S&{5e&I=b&$Fo!cFz?3kNoSM{~vKgCQ$o#;Sv-V`44A zKf6y#xe*Bs_IZUEJZNM3poLMK+>NeEjRU{M{7$Ea={@^Cd1%2k4$dMh-q`F+(Swsu z{N@5tiCj;N$qNYv4Mb?Qvr{=E{Ih@lEBwiy{8QAn+_p9OtUqrz2qkW8gk0_1>?pSs zkKPX6#9^0GdGYQi`11evPdRg7MY#9`IrDf7-mMG4#Ev8gy9F{{(;X_#YCCf{E)_HI z{a{AnvG1&s$p;Celwgg9&w~$qa*hfZDidSj<0r@aHqm+yLwkkdL^h;5h?p$Y~?m@Fckd4b#NHAnO;XWyBbRt*AN9UlTzEfkT$3m5b zvpKCwl6n2Ym<2pRaB4x(g2|o`Lm5%e!amBr+K5w>2Dv9XFL>x4mw zQfIKMvumf!l4$nZs_?atq*+P!QkTIZNee!TW~(=6p6CdPr0C*o3|tC~$;FN435eXM zC!|hK1X(>$+_{cGi?h2?bRaRA(^5gvY$#rA!F;etXY2W%PcdXVt1Nkd`$5%uL$+(K z!6j0qonWq9)15_er`82wA~QK7CP%i_7tqouZXi1cZ)*G;<4Dwfl-vlYAy&AIK*b4% z@CpLEI)|rH*yKbwG@aa?RzCHq2bRS+mk0j--~L_SOD?wrSAY`!5o9R|2RlzH4+kr)@kP(qXr%cisoPq@I*y+A~(S60S zY@!WijC9AUDZymS;Cmhxf&$WM^Y$i-a97}8f9nH&>7V{9E>BlfvU!&Pl}0g7`KLB6 zePhwdsT!p}u?^wn(-Z&AfBska!Owj!|Lgzuci0sg!lz0leCOk}p{&G6!lsua@$bhC zsZL}87wjxD3|DH2q(K^ zSlo7=m7_zLQX-f=xgU21EsWqyYe@|>dydVGJ{N{eYMs37K`?10;dqmZdCRF=Hb&{l zTqxG?n5<#h1wb~x+t!v+@*U#?aZAi zWu(%v+2DjTbZ7QTAA>2A(g$-K9F_woGkpUvsJ60?$rOiLnOhnP*COjp_?UHL+JScqYL{`nGI3$Jmjgv?_>S z!JX}xeBUSU`M&RakH?q!5aXQa5zLq%fyTmpTiM27^vT&0TvtsoQx@w)7(FbFvuwD) z4}Aak^K*aW=XiK{cx%mxxBi^BB$({!__r2g-}!NAjUW5tKgQqtzy3aYePR<~lR>Dm z80@o=ebBH=V$M|(ckjoA5W5YGomy6ylQ9NWCPNEmNqc@mSYz-^(_G#q59T)tWvLAt z2d0VEzi&pZ#%13rB&*2v7DFE^a|uSI5!_kWN6>XrBHPou08)@Kag3!+YK8p(Zuk1? zlUvO#Hk>6CmC6>`&RdG`2?iG*c^2rBs*_BvQgR?02N0BIm`Og2RN;tVbz{g*pH7`K z%lm9)R-yI_5fvwg`Cb-QacT$>N+~d0xJTGY<_Hp8dS1grPPh!J9~>&2v~!(~7Ug8{ zeQ>rjwKguZ^JIlOk0cTLAQP%-!Z{d} zD#Q>*TsgFGXU2U@Hs4sr!q8w5OAydLUokTri{;;a>y7D+uq#?78-|Y^?E@8I zc%Zc*lJ)S_CLw7S6`5QPqj5#+8FQykXeIH>W(P-i7I(}}Je5K#=~emGp^O{i_)7Y3 zOf+S2uQV;h+?moi*YdX8qna_tPP2xW!t`y=Yis#r?2m{Ut(;Jdt8_*wv@t+dhJuB08qg$@ zKU)N9N~5#6WPG|v;?*O#bWcB!3texH>=*={7iB^FLaaedC&~>pv~R37;e1cuF3jkt zr*V5Sh$8gsYff5O7p41w(dgw&l**zVox<)xEejTx97?2e4tN$>V?Rt8?5v?Ia>^T* zDMbsx!4<*ug1XRSVZ&I9F%C!Lfa=UKiLs*gjJqCb{MaA)L4N69{0`Ttgn`D+u!W+*g9%>KI~C(#_(t)G>nRD( zqcdI5lTfu&r||us{~SN}H~vQ+?jPO`8gER%Z(k{St0nzgU-Nb>xxG|(cW3_HFMNT& z`@jD^M9DScNQr)x;2?MnR6W7maW^g<9$KL{XkPPPAea2JB2}gd>~Y0sr*T56Cc{Jr zO@msDz?rcjo=FBH(dT1q_*m#MFb}Le!$_aky;W)rVq6fvM~cEcFin(!S>Z8~ay)Hv zk`spGQ8=Wsc_6aTYQ;k{;v9-bp_P#)XK|We61G+s5}u&9r{2y8r^Jbh(pp2wR$~=o z%FYa9u}pzn=fZ<4PQ^9ZJK@TM9UN-72QnQ|VH0CYFig36rT6Uo=`4ghQqp`19rekO zEV0|X=Gs}5K6aiWwnMn z>>3mgj9{}sBv;ucFvL-tEErb`2YId?Ucm|vCm4qyW8hMOnx@?7RCUDe>Br5Rqe2l! z2|Om#J5|pNEzC$Y;#>_yQeg)s38ov7-EE6#mK1sx&yK0=vqMxKkIwr~AJeLFS8ua` z74A$)tF9!sN`zvKk3Rf>uYK*e*$?Ls$@@U99DdL+JVvgSJztA!zovnoJjU}-6Jm5+l#?|IgG(G~ zPVG*3svB49*no>F=w$KA*FO9`-hcnXyXWVr9L%gepT56EsVC&CvyPVgdd-^aqLUMF z8Y_mTo+zIU4fpWzpBi@+N z5l#~H7_0(9WtGZBGY)vxmEiiezvMaj0f-3VNHdx*#vNH8B~f^s`9u|TFk@|nt3$Ih zJA z=jG^1Ril$b>Lze1is}W=k(||>I@1fWRG4h}lq@TySq|X##%R|-gL!MC{lP!@hi-M@ zy!DRg+oM+B9=6FiiJQVAHwat29Z}wW@eW`4>eu=3_r68dE5YD#HqN$kX9JJI?h_N` zTvob}eN=Sz)~KF{?n^YJCk~quV8&v17@bS)m?|@1p9=K^CcM*(kG}m8U;Ul0@xdtU zI7>{%9Nbmo#rYYn!RA3f9EmGChD7CD45<}p1d3=rC4T<<{s8~|-}pK1AMW4&KfZy{ z<-j4|QBdB@DEu2D)7y>DO<@xF%%?xi*FXM{-~RG%5JlM?`prktsu7y>Si22#!eE%D z`IIz=7pW9o2%QiKW?bi$+H+9t(ZL#ii@}>uGM1U`(=G$kg}oZDKK>T3cj4~*4(MQn z;<_V|EAQDmT_>v=A`AFLn0TxihmAat6sP!3uJ;SQ2VRZJppQlyaFq*kY9K+M^H!y> zu+PFChH~LDgp=fsYKT&0a@I+)3hwmooR{p5z0BYtV0ci>FgchgvkF%k;GI_L?O<}; zgh?P%S>2cnnk4FBjLE$UQzx4%Mx_tu1Xu(2|DUXPi@9vg&a<8|#`n#``v1SGcJJNW z-R^e#)FEjHC-Et6AF#y*N$$u6;vf+tfsk*4kPreX2zvto142lE#3dJqEA9eHKyvIj zpd5^y1mj~4j?;EJ?e5;)dso%J)|zvE-!}#qV^!^H*ju|)TUCFR*810+bA0c3-{&=k z!qFQ~HHSh$37?43QO&iQ#>5tlT{T%P&126siQKW>=&gvN#ju_O--sitHNq%1VVVQgWJ-)in$U$&g|nx(G9nv| z6~DQmk|h5AdE>?7CBK$rqRbi$I!h!9Lj#JWA^fsCD$8rd@)hU}vg!Z<%&_I*;XNtB zJfFY^!?VUdJCkp_p{P9Er58Y=pyQgTdNs@&BDcw#V3~t`1Q&;hjX`$fELM;*pfw7? zR8H(o7;da;tjm%nGim7$aRC)VCfdmTv)74>ZwSI&nc3n<--9U46fY$!+C6c^iZI#W zXjf!;NO?XolKbRVxfRdViKD|lS{lDd1DQleZmXDD z3Mct6E4h6}6}~e!6hh5-k8)owa>H>c(~5WD($jo6X|Q_`p8kf%9(X@M7WUY)ywVlvPPe>)tj8dx1m#)F z5<%^aYK524SZv|#3dqb6%Iq6q#&$SwJzIzhADjozah@%O!zV7yc~+f=(;c@Z1Q98zRlnKrN7Rsjq{K^ zO(N_^Py!yNyKL0j>NYY!@V)e#Kn#14J*M!s!82DYK~Hv+JORB z;49}~c*BSD%@1$$t)KZ6ym$dP&yStUw&Mee1!i|yau^f$3VR!la}MBe!2SBlAPfVsVQ1>@&`{x4;<0ShY5Au~wlRD(JkQ+o}K zS}Y~_9tTHsCR=F~kj@nO0PtHfqm_IJR?~zxj)a$~OcWi!j7wo}7oM#r{^LLYU-H>M z_*wq)&;Bg;(>>icvVE=-$G{k7*xA3nNfNk$chza9ms$ONvPW) zf|lUWmE%^Hd33=AigbJwJpAT~2uf6jSgr}EoTkco9EsppXDfw5Ws-v7^cz%?5kwV0 zDU$2VdTV`dIK_+>%5Y6Gs1?k6uC~Nj<`Z!%EuCZJ>PISVzy+tMFo)AM2tByFwJ0_N zk(%Bj20Ow-QSL^iOCxI565Pq4$HI`3hzcbK5l@&}wVJ&-D6Y`y%r<2*MHCD?T7DKJ zu@&K|U{nTSl|pB7aIH7&zaV2Uvoj(ae$hPK7cEp7cw~yDs&LhjBwp!=HhSnSxB`2J zr$wonc!%DNS^-mbrW|Zal3#rYcT<{KcOQ5=aG97SJK~a>ItU->`sy9k0Em7WK!OK^1!hjTt}LH zCTqzy>4T=iu0ac>92GO?x!x!XF$hoM-(+h_a#6VM!rnKM2^`e2;KONC;cyUfYF%;2 zh*)1}W;7F)E&VCThSY-lib?Jlqvk_FSSbT8am9*rAHt;h&7O3o02jaT=#EY&CRgr4 zIfrp}<*phJF>&?Efg=i!O*qaU@MnMWC-~eS{-gZT-}oh#D17$}u=QxEXqb7cI-mt_r>* z0z)Ru7Oul6_6RhN)_B=EpLpwmPrUsWUw!$U)r}F*aPDQ`%*^a;I(X@owG6snK_(~* z*ntt~esHRO^Au#aMS}#TNy80PX0A7r=>2qy8;^mw@>H_flj%wByJJx4T#sOy3lYjb zlp^31vVO~Hl9l3T0xbvg=p3HiF)|h;E*!BFKJo72JomwMo47C8Hl0R5;o@2QZv7=M zhf|plK=&&TPoMBDpZV4|rjPu=QWtrx66AU0)i82XSH9sPEqv_RGk*IE|A?>s{#Q}W z8%g&Iqa>-gi&6txfwKw1&JdyON$h;y0G%jh<+(a# z1p6|xxihuFe82F?XCLRwFP`(^{)qa-B7=D{b`&4NLxs5%E{A5aFB;$d9pB2I`%iv~ zhx;e5-;>wF+3kn8t#f!|0C~OM`u`~=`D?EL*}wabzsS%1++SrCXWVY&vrbqw8imWT zvr6_f6$*jznCUTwS27_94%KxCo`6!xJ}sz-S$L7)LX%x3*9Cnl%a4fCz^Kd$HpF( z(dS6CTIGcK4TxuhF_a<7TQ%FsI|Hi=jgE#;q_Rt(svIMY%Mpr2URPK8Ey-k<++$Xe zaj=YzPlYx#iKD&bJtCZYX-o<|8k^=J^kl~7g=nAz_c}2It^%bA^DV$pRN2RE2|#CD z(-?a0pd~Op@V2s=vFpIy35>$Qi;-Z$S%P5W8hLQdl}sLh*P3-1AXHQ8P%cA}>f8&o zsO*~N-FZ(vD+#!2zdo}%ka&+4>PtrdHNnbZj+^8 z5gDz#8Ft)3!dcgQ#w~``Wnnf@Zxm6wRhkb51BTOj@L-iEb!Ly2IpuJwrgOe}KCr8$ zS7Z-kc;Qr6yee&6xGRGD1TnELN;GHfK_?qUE1kQkCX9%|wVl}=>inw5XX4zhm@Ei0 zBd!cCOt*5b%V^Xn%(l~HqiAKW4_xDx2C~9Sgb#XWiNc}^ZO`r?IdRehtg%H<`d}`F zLkHTOVk?g$NurZBOf#KPZa3_y2R<5obWUcNEj;?*;upl8r5D2wUNW(3Fo!b`6l01^ zZrn{!pWN}n2hxOD66<_K$6}{NA-ZtwFZfeG`h%>~#9#a6|C<(9zVx-{yfv+9))N5+ zi-MGeLygDqjP`oRiqVHL*W}Ms?`*ZQsbC|xqjUBh=MGmOdPX2o&JJ@ZM_AqzQSg$d z4b8^g&4bQNVPz@>Ih^O`7hD^xk@E0D#}{LmQQC!BOP+c-Ql*&}Y!~)8pjIZSxC^qL z(BT~Y;6SKSsg|jVv1ih0t`mm7ZjlxxAIilzqA-tvSuo0pyC)B{ejsgN7^cGE1D}Hk zZn13RXa(~LwS^Xr$Awao(mK_ZYK0fqopWzIQ(=rinR3t-W0lT_dt>MhZGak53elBc z`L$o?$A9dfxp6u2=J^V^=JLjqnOD@;S2+7TNxl9p=|-Vy;g|o;UuPOlsAW-|C#cXR zcsQ*@KNxLii8~aB;%xIo_)PI!P41iy?T;hHc7Bm7r;3NM)jd-q497Sk{Fx z3D>Xx6Sh9M4&hY6t+0=vhjXtf@tZrB8_{K69{8F6>Swrr!|3|vYDV5rMP9{(zhMgb zNLu36AMpR3Q~vA!?!VzHzxR6>B@LGz3~h)xm)5wKm3}imYGeUlNOrzd3z$|+kL;I< zmd0^bBpQKa;^uG;gtcD?aqg@zD75|pwa!rzk?`|B`8Z zeO#PbmEM&t?s%vN^n+Q9MY30=NfwM=+DAy2bcV-Pf90zE@A|J}G%7M`$uo$ci#!Vp!GGLM( zlft4U6*IY|2d&&}6cc8O_Ki+r^beFVI*MR7rEGJ@M46Zn4K4vQ4W^Z$O7X!Fonn?| zT!K)gPBVfc?p*uE)A_`o`4|3q%!0r5tG~gzKBM?f^_B{b2t%`5&t&EpEmaRwCh3U; zC~0)AA*dQxf`T%#Yo;;i$2ahh4`E8^(u1BXGJ7Jwg9KAKq>M%AFJc9Yy znd`)*2ukJ7CiZsaW2c28gX?vJo;@bZIy3ytBscnG?3hkO2zSw#=9w)DPXo}I-glTg zRSMbZH|S+z31Jt(EiV9S!CJxNO4VF5T}8RCD?YL^eiAUt=q#?ZX=fRY$to|ZaM`ZZ zXi$a21~XYHJw}=_?@u#7`wRaUzxu2H49S& zdHLZ>MyV_glLa9YeV1gg=*WZwjf0@qmBp0kosM$9OzeF??>u{0DdKQ6Y`WtbJChIA zGP8L@V<3H?rBKz`_Qur@7Ay4X93|y+6H7VSv+N30dQYREw86%ewPfAy< zmIlH*Rk}7#rSil&7of)#6G8i+`3{=>os&A!0wE(etApb6|l_e)5}<>7L*Gjo+fs>7J(BSpYfn*0k{A zdT^lW?T9OjN&=r`!)mg6?jwjg-8S)^GC6gEJ2Sc~2NO@!7;J=Ah98Vj);jU*{vPel zSFRV-;mN$R9|wax?Yh+4(5M{lOfh(Jzwq9F^wWIPCq8j|Nv~d`zM&eu*~*;J#5ZIS z-b^yd>p|utbwz-`@W1@8eEDl%rf5*OV^U{p+0}9%!J$r+$|Hk4jH!}6AOTlT^WYer z4X8FVJeaf~Z1h-w1S3{0OeT1TQJn+m%v2h)&d3NJkA@bgLufkj+%x$wBe-_VJVAn^ zv)-=hJqn@9xiw~)KquaQ_HlmX^FPRo_kW-9VnbBvH3%0L5#CxRUN)hS{ajK7Z&}D` zuAF7dxGaTj1dH9&7vLeXhiosx#gn^2IHfq@N)@G*hWd{76Qdep@ZgPI46|}WmRCX@ zM>xFZ{cJXd=Dk3yp{kTP2${M1PQ$3CG!A?OGs?qVVQ9||o0<{tyPE!~jl!J>Bb2nD z4^YRMSjb9@9Vk|)BN-t^P%ILMK@cRuz0sIUHjiIjFx^?yn1=9{jZ{U#scIOSj1)H* z&i!dYr^>mVVK`G1Tn6rYu4#tzl0hxXuKTW*;aE2Z#FZ{P93mwu05`3HZGqbrLFB0*yUEp&p?9hHeJ-WwD( zs%L*vXnJ!zGGRJNP1^2FHNEVP(+EAYaHgRK}|3f&vx4qCX^gF~F6D=YN|-nnvk zev=1{yI9yp8vAz1aw&T59U}~3r)jXank9b>`bZ_m$YQFMgEe5MaM)n7%&O0k1iCsu zu;U!j(Fg)%-*;pj91`qpLVX}69MKrPr;+cbB-QzW{pfu1*~~XRU3mWd1=lAraR~qb zAOJ~3K~xZit{i}SV{!1blyS1bNoTOEh#pN@b>YxKbf_{@^+fUD&JVOeDM<)C>BJ@n zt(1Iy;aLfOX%LZ^d%GY3k8Q&3Leb8!!Yl=3Aj_Kk12-0#u<^*&2J5Wsed7ZG8_C4D zi{QiaK_9_gbgofo<3gy@rP4;{&N~rKugWT&t*4``TYfmF*!kGQ1JB-i%5}T2w;dwk zYmLs)4kmHL3JZnZcQ%AE1@CAY3(ursFkjNo4od z21P0@(vg2vMZME)rbp1sIDEo`^tA^}F*wQ0*9nSb;o>C*4{Ruzir6$2tl~Ro->Fr3 zS|*v%mtTNe#gfUq1aRm-cP<+XYeuho-});k}KFd(lvF<<%0SNWg+r~eT}xsJ}AH_%f?=A$7tp%Ey~ zQfFk}Ifh{JgxM}kYP=W~9~*aN;lV4a!R9;K3NAtSWDFH^c2-JRcz-zRJ5vOM1#u&! zFe2GMdx6DHY~ER>!fMWha&_T|LM@r(+KBufdF4R4SEY@LmBwd3@r?I>_e*@Rw}hwB zGDT7WQCdsuCAeqYlqOBadjHlF2>w z9LjvKqnvL&O2sP_~wtjg_fD; z=YtkbmznM8T!*4`E~8V)CSzQwI`h)OIS7GTD!n(F3ssy#5N?Fc#NjMfIjY`P+66RM z&xJWTU6SV88iiq%@P-*!0AVa8xb)zYDhJ<0}v{6tr8|yVvoRF3?fj}+r{Jh;fCYca46(T&-RR$`8_l_<1 zPv7h5)25cf@WJ8S`2G1s7(9Kr2Uo5gOe=Tn^f9v&GIfI+M>#&1npz24$qH_|qT%IITIO9aNK~ zF~$|Y4LIhV7|K$U)9?akSj`4ygf=QGJqwL)7vQBBD+MW$5iDJqJa?Gg9qG=P+fB%*XqBqF=8RI!}sa*NrMwG6i*x z4nvsh1S7aa!h2c|<~WirC@vrm!-~R(Q+56U}{d)Mgt#n?$ zDIX1D-}vkD=G%6Azux#lfuH%A|BNsG_HT1qS0*d8F_KQ%uUsg&3Y5wmci6a4*g4fD z-~Uid3srYUz$Io(8`Uq2o3gx~W?~#P&s5JC2k4at3gQa4Qop$2@3j=Vu1uq*a#WQ$ z;3^0H>hmGaj`3m$ccXDq%huQ%*}K@zwqN=6U;7<4%LuLxSjfH^kDcotOfuur88NUi zI4NBF;E1G(4kos7uv&WAx{&vIFYG#4OOnI;C=3Ht$6eVZho}qL)mx&lH1snNy`|ZPWXPOB<3+C7;I#I{LcAG-9AE+ru zR0dAfj+&(+G;VFX6e7~oQHnEp0uzhW8<%O~7#$aAar?YFj3WuJv(0INq~6T-dA(jO zsn+I(*NN_MC%LM14RS~2x zV|Y$J2A8JX&m<*wbR-fQR&?hslKWpB+Sr-OOf8+G4|*io&#WSH5FTu!Qj4+}>GYM9 z2Gy+?&s<6g|sRYU$M|8HaVNscVXB!7Ek6_X}s&34E=PEO$RvPJ}7$j8f z;zB=QZ^1mxloG6`JKmmFw(HI!ohD8*qjcjkf=K{&idBjUqjx%kszLM(%ECK!CPu<} z=BaV?VDEX_G@Cgolo*VCV@M~8;-zwD!sZ!mUd6JwF@!}dDT8IAYp@h!^aa$p6JhU0 zmx@+USr|C?=BaqO&`j7V^gc44SMRtSP8l1e%!KAcW{(LmSc`z~95>I>(Z~p?W`D?4 z20>79t|QC6PP1`7F0|gcAI4R)e@KozEo}~X=T1TGL@v36%W#Cu{FiVzvg&;l<>NNE zdLUNWJ@MhS9;{`i-qfZ!3il<4n?>`4Lxp29_GsuavinDzBDvr0Hs?u48zoM36_7-~ zKg3{D;n2dp3RRs818>G48=3DlA4nGwIC}OlY4E+@^S!9vZjNu-CWM=k@XBApYj(iv zNU^+%8K*h4o>qSOZ~Rr(@&uhK$JhZ!WuQz%F|NI{#$Yvw`joi&VVpS&!)#`2PHhKh zr%I!QP;^N{w5;s1vCj9*_jjE4E73Nt-jFENfZaEuPE?Gg2Mp*2PsG^={7XOaXZVwU z;!p9)C6liyZmXD&*d(uBq<_Pp@=7gvwcz;(?f=Rk`)Ww}i~rmI&d>hEzrfZy)09b! z-*3UJ!PBx3I&riMb6NP*I}dzte#zE4#nKFYb!Et)mwZr)50HlANGPI($I&qnpcAbi zrfjZxZO0DWQQe1hZH@HSy;oPALG zpiYIZMtI(vI}^ipw8IlI+&3QE&b<~U%K$;``T2X4MyZJ-DC+FJF?&f*h&ARAA}U?e zbi9WnE$<;#KxMG^8S6bs%c=;Sq6a;qXul;sF$iXFE#hK-%gp>6O zc7K2Wo<~lL)2jwS)7uTnZrIqu$L~%o3Y$0f$ldo)qq}e^xtm;U=7TYy4_Yl8+Hub} zQ`G6U;2bcA zg_9Ul2-lG^^k<&E!#m5$hdpU`qvc*rWzhSCl)+YZ;Kl>>y0ZJ6TC*@WgHX^?0}=5*rgzCFijcL^WE6B z@X3!a2*UZC{s@r`w*X6mY`D|3aFWI)gjNiR!b)XmW6*K$jG+jI+lAf)mmG%V#%-{e z8Qu_C2;I1!7k=OeKM!g*jU;Z(!yldeIb@gDn@jUjvVQphZ*d&Yn)SWgWxjr83#gJ~e=MZbgjeacb{V^ll-MH6^ zNvD>D#)*DB=1MgxC!IhBp)=p}LqEz-{Hy;mrrEwK@eveFU%#?fYn@lK$v6BDZ!T>< z`sa;Bj=<0V<-fxJ@ZbLTyx4bYtz5RCIcY{Tp-Z92Ks<1*^y|jf4lZToh!ep}h6G`a zWduu^Zi$o`E0x_7^40xj;w=Rt3;bqFHiavUTZ8*d!p8QPsdHkSKK;%!e(aC`QU1x- zA89R#$6{$5RR)s}Tr$vVB7_Erp`&D%Q!TWBS%c8PrBDIC6}uS?72}SqB{)o}o}Z8z)LpKhm1tA zPbZ8@WFVU1oo{*P9e(ul-_IZUuJ7Vs{L_DuU;VA$;Br2*M6j!H9D}aPNeUsUe3*3% z=NP$csgq@asy7a)j5)S!NCj1m9bh9*rjAThk;qc0&jj+LfV_daSSZ(Igwob%Qv7M;`3R}1P_yk{}p1gNFNjX^U{uY@U+ zHP%VF^n)HwsL;n1QKgip#NqUKnWvmFQEEfW#*0xXWkLPmypJr@ zBW0;zFv-egC{;G})(k??l*M!@R8Va8yScQ$qzLf#b#=$DKqySwTcTwS!wR*FrH2o7?cq9 zJqJSOGJ!t?XNrrD2D#>6sUkAs8C zJ375v#@_|xORu#e%t$k9vq3?rjyhNs%igS!BTb-EYM5j}W@I*UX z-wA!75*#vk3?rhlTF0#*QIHnk2WM4!Ev(G!qZ8t+de0<=9XkpPtBgL_8I)R?yzy)@ zzI+LMJGd8ErkUBZfq2)F5_aoQ)A+ZHe0)|6Z;hA@$q+rR2baE3nes#vBTwk6aGY_g z)Y`K3_wtk>F<0)ZW@(!`y)>FAu@7oDdTi84Z-|v( z#n?o6u|0wWPm3ZW{Yu4@);r(#Pyb>5?7#DGA!e@!54jB(PRL^%LvN#%pd#gXZW!n z{$YOoH^0CKkB`(yBJFd@$n7Q#H(?^<#%jTivPZDYN*TGb-?Xr(uu!<%I*ClP%+vkg zr8`4cGzP6H57LRz_|OYQ3JZp4&GoQ569c=|2Xus)q}{fg&tVbe-Dhv{ybn5pVf4|U z++(AI9t@+OWMkf^t&}JOs*)-MV++W7$+617-clBJuiuG ze(NdU^678kt1llZWuP8(3iZ}JY*eZobd%)baAi@W1f0jgN*4X?2pXMGXAxt#qhU06 zmM1gc{av49|L{Y`aV4~%5}5>(lAg00!b2q!qDM3qHTG-A+m45z6=oF8Rtc z{cz~OrYG;brxcn*#(1>iHxI|6w=a?4$&;rEU`o;s&mG8(ITMjpL0l}fRDj$`MHpma9RkNTid7_5HqLJDfD|Xw1>k`93SCH85G2ZA+q}E;!Dk3sW`b$XMeP!DBg47Zx2^a` z#9+}v4`Jg*>6GA;pLmyED!p|UX4L0j|wMq4(>Qd=S~l_2ob@{2BkNu2~OcW6p;jVIYx<%509N;Q=a|? z%w9N0&oo1WS_GQ2N>FTNxKN~XXP^K+LnKeKv zixg%Hj#u6sg(qs<*8~FX=Pe__a)%Z}uYpe!yYHC8T5nJ;t5ls?{X(^Y7X#@Wd&k8X z);NV`vO^XMM>1>-h6+Q4Vt$iqjZc5#<9y%uem`i&fK?zuUd8F&7*9Sjf`$mrD;jLv z_7{?JuE62J-}&3WNVTV^56gS!DiMvvPQb*27$@;8c~hsCimGx4 zD1%)VhUE#e%3vvaTSZNv$|x-rg)I|dU;O$@{?@PkCNCa8L~v$HAl9+JfMP6StkVh6 zO7Sawb3XTN-^^z}^)A2jIaaEd5%95mbMQJA8##X%qGvDmMV zy!*~QA`{2aSw#41>wIwD`3GP45`XQNe;pHJ#_>?jLwT|&51#C-2nEf9h(6JB6A zB`+|RC}?E5-OZRrux>K6-SPS73YZ+VsVaofH zB;|yxxI&AwYWj-~F&?yV7*s8oA3W|kjv}|7BoUl}ieggo-V~0l_aA%DY-AUs4;UM0 zWtygxgZ#iz?(Yl38bU?dj*D|C3$q4$WJXye%cdxWNfO_^yK|?VT25>Yx;sTW;VV~D zX0dcoN2A%y%92A79Ulk7BvUt9naaWzU>I|8Tn1NydjxI9&d$`0qh$N+Yzupge29$7 z?!nM>cy}G(9hW>&_vw-5juRYAJa^?7ohKNZH?9&q^PP~&{jzY9#*1U4>IrYoEW$oI zkK4v%6V%MUOLZO*?r9k_^kBA~7l$*3Qs>H}cm7|p-Y(YGHOuSzjq!ZE@0@e3z0W?U z>U33gpRTU{0t!N)!ET@>KrliGMhzEYVggD>gOZ>I2}qEN8ZM z7zlpR#BQNzx~r?Zx|*);>Z&?*&fa^iIp_O6<mtG1oo^ygA7_d#~)d=9=&GjF12S z_rH^cqQa{=X)#%gQAN;5yId=V$6)h@u%+!)gxxbwhvf?X*w(9(&r zFi=7!wH7|GpebCh8%w0!OJm1y9>Vwozw@6U&d#rV>ziydk3q_RZ4XKKTvZ``_ z-}!_8C=7f~o-YTMQm|oMT`&g6SXm@v0#p?X;WC9HjmMd|^ShegGc@gu;t9u_74FK! zM&Vg0T&1S7M0duXlQ=6gMOx)R4dcTte?Jd5?n#r4+B%_dsgJDD2y%42pOSv+!zps$ zPSe6@X3SApmqLlbD~n{klnul=)>C%qX1JaZ%Mhl!PbNz8iWx?OOo48L&KGK&Z?KC!Gknp4I2 z7yi)i=5pQnzklWzSniT6e1HE*{`9}~r+N1~zT?dVD}ni$M>@4;WUIiwET~XO^JuzIk`V~WQ5lU1#h218$ zJ+fOTMr1&ur9t7W4Jpc$LXUK~lw08h33P*ki7^aXRZf}^GZ*13LNA5uocx1d_@zv( zE=e8_T{(xKmia|Z3xq)!JrdgZNEV9`1B;}Qy9RbU6Q&4N8*^^7XzVWRy-?=lSX&B% zWl~E=s0>SM{2mjNjuwzxAYv^~4`9$DSSh@J9cU45)|%9WQW63fneL^cl=XD@!nEy1 zrpr-eiDc%_Qt9P{X`!u?B^FdG-JDB3ps}N)02Rv0TqcWTMWoa4o47`;5=A&gpepP| zS*vn#M#qs+(c4vGgN%syzAwTfj9kd*fMM*nLMrcqSQ=bXo#q=YfSL#x^FGOJyw^!**uP zz3LDD&=2vue&l!Y#jpG#*o7Grv%xU}4dv0UJnst^f$1wjVT#kWqPijG;5E}CC6h}p zY8km56R(|f7{vvx>5e*Rt*K%4MGzy3Y`#^3yZ_&a~^=cr76 z`Sm&ZE6W{Ij2AXI7kF)F4*O(_PLq5XmuT$m$VBNLv?9qN>54_gw6gS-KA@Gta!81m zkWisRdq$X1ieoCg9+T(AsOE?iq~|{LJd+nvS+Lj$7mh9W$}SJdA~B2j$8Y_ao2fPz;;G8K^e6tDUX~9^5D~>DE|lCn?7{1w6>Yvj%4yND(wv zycqcjXq@+JX5xgi8ysU&HSnTbx4{qp$PcIZ)o*Zmd0Jt7G&2Dwsd2fwkf$qJ;Axj3 zx4A;8m6zXqpNCi9WZQRKmCt|AyV(Akzx6l%Ci|-kk3MjNV}V@@Y?6ln03ZNKL_t)K z$Sh>2d+MtQCrVIcP(rB-_y`P1gtr$C;#|j0r7*6>T@^~*`Fmgd5?}n4_gVTviJj<` zFZ_kSz-K@AIi65VPtw*bI&w;qotNhG9v>IL#;pMPXu|TQPJ8opc8CANU-@zVyZ`>b zrADQ-B`;s|VI{g?&fMLKmuUqo&eW#JI3< zFlVt1M;YN5g=6g$_c!UpyI1zuseTjHs^x`Zg=1A(SI(h4SD`g9OCqZ|nPS_6(1oFe zWhs31SHI3r|NJ*NmWFFfK1Db|XTd-kB1c4X@-RIux4qo4$Bxf|OGT3=5^$E1AJbuMvY@SSY{K-$Nj9#RV9cH4 zAurKMCaV*f*xp@{-q`|<)fnEnP6JB~+o=bO!t1H@P!_HETHUxr}srngu` zDOFGrwy0dyFfW7~4X0{h@`UdC^3HZ2MClZtcw8v;z{I)n z*-^c)gwdxFs;J)3`s8}AiZQJwCc+2Pxw(c0Qwq*Jh3kRJ{G4MOwf~#E9W;UFm1LB@Lh0DG(EQs3Ca*rTf*>O<@leQdmQgxnsqdeMv!V$%pe(@4Ul1&+hrVU;2mm7--pWKcQ3}im+%}ZhbcHY!WpX zvf+E~VTmj_qTI%PuFNYOwXiRRVZtiL8WSy*ZEjQ>G+mjtA;WJtbD`8mSWrkv)$mCX zXO9)CG2M{}M!=yzqtiJqlgq>8vIWa29Rl4R5ZP#YWB?uyP!^Wz?AwHPBx-Pde8pe? z$)Dwehevu}smqan?T`LJ-h1(kzx6X;qAUlFvhaLOchA@g=*l7Ba!sM#Wo&GIVJV%H z4rb|WR$1niqQQersvc;*VR~*yME)L^Ni%#?cZ8F6vGl6B% zJGyTSH3mV|$_!=36|P%swXO7AlBRr_CH0d~#-BTB}w3RAgBhWhWvOqK@LSGwAJHPhftK_X{7N>vWkN+6I z`M3O*n^xwjg!o8P^HhZek}HPrkLhNfs<4j%=!ERXkdGBG@C#r4MgF7z@GrAqG?lbk zsx$3@t2IKEwHRVfDMBfQ-7BT-d1w!)ZB3hVTxoi^6%$!}ca}`%l|1CTI7=w!nugR8 zLAzxx$v!!e=7IBc@MLM6flDX{lv8sa#sw=&lDC-&yt196U8yceH3}V_#s!Eud0U|^ z3tLQ7m8n7~V(>h;nI}efsoO~9gknXd%8BQ=~Ey`9>)b8Gr+6%OB0x&5Y z#nMG+L1hq7)wJ$#RjPGLfiUJrk3O z%nB-O>^8v*wK%`wz3=2YgqII5vv`b|8Z$a#N#cEd-9Ks;+z3h9tK815oaP#(pN?NB z2v9%yZq zy?5W@{_ZV4c-V3$B^ef_AxIBuKhSK)_Xl1^;aM@fB=xaK&D~`fn_iJ1^9*dVq13uU zIK{G9*h=F(C#9szh?q1VJi6stCK|%P)sV6P6J=)$WlHDZ>2R+UOlMl?aJY#`?^n$L zy;}LzU-@PJ-rxUedT$wZEsdflP)T7|2m_@nNJ$3sE{#KR#)PG%jrMUC7#DuiZ~XOq z?lYg^>%aCPhOk{7-N+bjlwB9*a89=ovJ1ReIw1pzfob4=VQOYa%nXjC=-?WSf>OjV z6E1V({A%!fe(QVuh9CSce)=E2&wV&G94!kMsq96lo*j?Y&TdA`4I|K~sUKQX^Dy@- zzxTI)p8fjBPyWm=aX1_q?m4m1JI=dN?E+O;7iEu~87otbWlbfH+or-D9n21dUbTUXEM2t{8{g+a;38@BeCHQn}F)%d2Tt=-Xih&i>ez{S;ZD-?|2h=+$xfzq_s9|Yw2iLW zS@bHXW;WHd&SoniFHtS@cE{W{KD16{;o(|h3nX;`iw(cS(eVR7S49z;)T z^8YVBQZw?ACHmvS5(R20dH96`!R37BFaE_p&xap;m<6FKqbhyI4X(Je$_+p%jXKj> zw95cfx+@oRmZE5Z2TKC7Q@Pfa$C*K9hc(0VJSxVHH)mtP4VGH637l6H;X#CrV5xz+ zv5OGRaZ^T2wixuf<_a!u)1qlyq@hJoE$kyuyP`GdZDkukD6?hZHo_TRZ|UR{T4UT$ z;>9Z$j8$?HHf5l0`8uWK=fG#2Zzd;`0{QnSXzj&OS3)w@A&7*>|cq zTZKbu5Ltj*G!79&2oEaMxu+4Ltl5#fQ3PsqLUI-BHrXuw9wRy?7eLtb$h1MsoI=;5 z;>_e_kfM5JqONSiXf`+$Wz)3lYspom?x0l>aaKuV!Q(UGW_+OWM6X3y)cx)j^})YV4N!o|Mi*Tv3@E zsxqRWA@r_@56lAbhPtJwUsGRJMTjW48&MlgT7prnvBjX(bPkT&L)d{PK`BaDaNdl^ z^M$aAsv$+Gy5Lq>+&RjX_cupK7hWbvJwYJzNj1+xtgNSJUx-`8GErzHnf2qw;Mbbj z4~Iho=}EY>N5q6q?jq;5Q_B(66N~Iz)Yz$cp@_4FW2GlVt7O9BW)<;VHlDfd2W#;5 z^Ar0uXf}A=;h?Za;jEDklhTm5a^TGL&R~HWoSIPO$}2Cdy0VDmTK5*2z1^a(@k}W` z)XGY5@kCKfH&hx`g2@p*dro^iKXQ;mcGR3Hc8jF8D-T=aJHF#B7P<2Czxr*~QW-Lc z(%81(q!m-=F&vrBNgH>yVWsfMPE!F>21k~*@ZamU-F*lAp^?DN8v z$`Hp61vRI%#vabIS~ic9bsava+&%26e;YYyl6*^4fFKduVrOp zp>PHQEg3|G4c_UMGACPH89u@E23AXv-kjhi4^E|UF2e2)h%{#FnIbExzcLXX$AzO- z4qX{ucpOHN#se#BjkG&o2SpouSE?qfW-Vu?u9U+&@A>+3C5I{aM*FIhBDycO&tOvgM#h>N;c%d{H z=5$e9b0=+95f-Koh=rmPk(sH}vZ8gTRhXs>c}A(hb=!#>_s3gjr4Z9@l-`Dg0>(iH z#Rot1JAMy;?2rE#dK30O30y^<3Mv8lh)|;33KhvIkVL%En7pY=o=O=>H%!qSAOCy* z{(rz%e){i&E2XZ?){xDxx#I}ORWk|K3egmof!pNNoySl%Np1#VOe?g~86{8#)f>lf zNs$81kxGr=~4x(F8&p2Y+@Q#&Vbx774J^GnG9I>qT;7$w~%tE@TU zo#%9x$%5<7ZmGe#iI`Y$#>~`|=k=7ZOqrQ=B@2Y{+9p-gsyo;aG44c&8w(==^;rs_ zJ3c2~3o4)?Y_8O$Qj1ZB;ZYDxu0~%g?>w(OT%E^l;dxigF07^$j(|ZglvXL83D2Sx z^(*0-L)AnOnOtYkO2d6}ofE0a^a#@oLJjzEI%^mz3qcUkkr1q{s0Eb`)yh&6SUGHh zPij9AGLru+f?B4>A0?+m7Y#P=bbSim4W>@ScB)RQrhca~+1)uvMQ%k?#N_IZ$buGF z8H8tWE0+8xs&Y2xs2z>{W(97vrE>5M2d)9^PF1DU)Fzq3<2ETo3Z)G?U?dyOWy9sj z>uo@qx8G>LJf5^}DO?vRl;!mH7et+2v+t_4WCbbUnibx3cx(bCbH$Ca6JD%`yGo!X64Ul}qOCd|l0O!L88A}lqq zNs576ri5<$On1m|uC6>+#fR|H6xV_(tZc+AsFzzZXJItqQH19Ns3po*gw2D6j(A>J z?!kR;%-MK&Jo5*C@9*ckzvr|3Uw`{=^ZvJ9-k2Z4-M%AD+3UnqdA{D!mV#?#X)CG* zWudeM>1h)y;feT-VB9*NBB?NMDj2zkzAue_gkSpQZ}XL3`H<%)!I{ihkef_lhO-i! zjwe(H;qWk>IVT4Jl}ze%-!M^@HMl<<@R_2sA&Sk$BJ*ZdE-Z3kvkPv8QafuEUhh|) zl{_@n)4I4c<4Rh?4~LZx_QHJ(q}M#SO%g&DgL`rXvsa_dGY1SxN$c{c6y3Ot$p;2Q zDlb~vxi>GE2$Y3u1X60k0!yKlog$qPo#u(m8&&YAJX%L3cnm= zeZ8TZg^O42>!3>pj+N_Vgb}6So_6<9gzAm8Ook?&yvfE@vQYZ$r@xEue($?)*RlYf zbW}dRzRBHr)+EV-%?O70*gE8+f(9T&`RSkfJE&bT5xNSy85Wg8nMiXmc(y3(QF*<= zbvV}>VKNe8$$6e>DvTXGHgs+HoIDQap;nq}x^{R(2|B{N-}xE-BPd!>RsQq;;=kmt|F!>-W4j~j%2cIGNBm3( zTs4dKqbN-~!za5c@06NrM`@fyY3`i8Qh|e9lW6J+D6M4TvlVa+LX=QpACq1xP0l<_ zN4;|irTFCC(;ZO_yIv_a35>HfI)$Svhthdv7m8Jul4-ch7|b}Q=vW)aWx?GUW(*st zAFPv#F-19%;4h=xcKj2UV3l;KXj~BKm^r05t_R$5GH@1QiI#766?PNMcc$bj`r^WL z<)95`WZ<3eG;#LZI-|I8wnD9nt1{=H)}U)cnCw(23rA0O($*@3uug^AFiR-dyeYCw zJoC#0VhT%i=*lkHl$=g0FZ#-duge#A&7A z?nqZyI@j}+s*@I#mt=^GO2c$P$tVoNF^681Ybe9h20o+^s_CSOisatv!9{P`H9JEB=9NQDyX|2{ zcJsBNrBZbuV=`)RE`!rzsILr9wEHugTyOTs%id_sxNDuq%ZW|48(sEDlSgI*cV%V7 zMzugWFnlog4T^BDh0Fe$Qxn_|j21AJC7gA2o|T33bfyU>HQX*#sa)@#QPikgP}|N` zv#T^!q%K&@)Ga6s8$e}iLK8TSz*{9EaJk~qajvLl6!xL!A<%&CsnV|MycL6QPUtK| z>Fit(*-*byHFzjWl+LGHAgywE=RNN4@3=eNQTs|Q1yM;v^3%cWDVCJTsf|tN+u!~s zuRnarw=W-1&w*-1t6-Lz1?K^42h4)Q8cBy73nEu)9qE+vore&tR(vn?I5GXg2t!%| zcP^G02}dbB`VJ_59ehG3@AHfkkIW(rtxP-9IpyfLH148sjx$$QD)+p)KJctsR@X(i z#LAc(O6BYas_kfLJk!qmyhNl^>=n<7FzX$Vd26gihXyg^R-u(6acw-vbJ) zo|M&T!R}{HI)Nj;-UNDc<$zJ;!et6?mCj~6W`$afPNB^sk0h%4R93DsaRxFAg+lYr zwQLk%wVjJi&K;UJswA5E5``IQkJd;FDf0>*oWi(N#iMcWuleP#eTA?eMHQZOBiVx_ zQ|65gC)Hy_|kwI;vAoGpT7J@V<}!Z%)h zD^r!DVhUrspri7<8ZmaBwZ`jm;^pfL-}3{%jwr#eefej(I~@3yIJI_E3h#XCJ^sv} z`!ksqOx#v9fk@ytfwIc&XT3#VA9M7 z?>x@NvB4Z04ba`$M7Wov(Y~k+o6ff$UeYz$JF6E=ltTENO<=IiuFG-YB7rv4b8E zQ8wFI%}@zOGzyg>I}42sM>rF+VNxhHID4hkh3gDN4JkV%8khY_mCC)ORoArh$?=-2 zU%ALaqqDeSvGd4;Iq6byt(XmpR?LJ&H(FU}5xkt2q_ob3jx%1q;;UX+v@nYD+BQVs zF@$5w?6Ts6i*3A=6GvCnl~EK?V>RJb&8)M7?abj!Q(9f2=j7xl1ruj4#!9Zc9z2_= z?g9*K3bjVGEKE-)ZfH%*yaY0@1cu8sHxmdZgNS-dX->;HIy2bM3*~V4>&%$rQ&j>bywO`=(pY=rLz$GZr$FzPFEdAQYzuWyS>Lxj zcaRN*c3>EsM;^pBm2Q(ol&ejq6ox2cW z)rGfD%Fe=hhtc8fUYKKJ8&|fnaEVUT154S_*7^Hi{u00TjraNf@BSXX`@PTbna_Sd zpMLLq`Q)d*i)U}W&2qY@_XE8r`o7dcZJkmIy*AdqqRWA0T{)bd@#39#dG}MF=2M^e zE?&Iz2|SGLVPmt5;Wj3e1&_f2L*vM6(S*)v`pnN3l&I;5(JSW8w`@=~5M3BpX6cYq zq>Z#FGo4*G+A@*avDlgJOwD|qee5(B=z{Nxve7kIQ9^cVJ#m?VNaY}o`DEI{ZceQ& zt+b_c7~l^x}jE9xIDfHqGfk z8G~rbx2Ayz(}U?5#Aa?RA_+++&#RXbC7ub5%>!c4-+8zxkv{W7#TQ3RAC~P?nOI1l0pFmGCp=?f_DFwIvT` ztqZkIwkR;TSw@vh1iMxa6{^<6-z!)VnsgN9IyNj8iUd-iTVon%OzyohOu?a-EeqD# zXp*rBd%q{7q|jSn4X4Gt3G|g?t%w>U(w48a@$Ry6RCpabV|SLA95fSx^=6Lpw&0N< zu~LM%#f9vqNNJR!T*gE^9X_H^E`i!6Iqv;Y>+}kZL0o zN=z!LL%KUG{8K;roB7PAKg~BkI5V%0coFtiD3P*;QVNB^h)Pk(9H>x^;x^UGjR!&ti-@t^c8dG3*=-ud=N_nNT z7r3Z%l*y2KBP$kUY&;kkja_!6G)8nDykICY9#bjv5i*h$N&J)50 zO@)&dMjO1|&K&!JDV5{CQ`?D0y;5!BTkg}NEi69S7|<3D?L>*pHYoGLNtOGzzk|{q%Qodj5jm*Ng*C`5&s;18aPYbV)wwp{X8m(xLEVvkWaP%YoDVb6$M% z)4cueCs=O*ePv{~y)n^p&k$wd%r1h);7)cfa-{S?$0HF=FP%GSCyhH0R5nkQPimVz;`$Px2yL6^$BWd-#; zJ^%QIuy9<1sFk@7js#^L%*zA6`m66l%Ux_6HB(a~=zA99p*h7W3^pGObrv;jHr9Sf zK#^PtpDg`IDJ5g>nXI1UcUuawHpcF}iq8JI zym_4=a?_o}?dQxX%11@Z)5PT?r_Q&&`3?TupZ{~bzP_YOLsjT)#coZDyR&PhHAQM? zn>$@6Qi2yH7&C5dR4`&PMd)Rv?pGdMdDe3B_9}v=4WETmsYJ~jrkKhgL5hVdFKI*( zMyZ_lE05$Qcd8w+jXi{pr}IJ!r!bakgmiZ4Tt)^=ih|aiL8Bl{%N0P2TT@{>hcMg= zltC$lS}RB(UYG>*Y zxGhAaF!o+nioq-2DYa(a&2B6-Rt1{!dca-`MCnm(yqkh+utw@iq#tN*yc&Z){Cj>I zpL_S7fAEX%vvYtj7MWNasC3G_P-9{=HkmxTd&cM9eVgm$kze@Q*EwGw-(<^~1#=dP zL`pY2@5T~?s0(IU_&JrkQYjK#+(8rWrlN!gQqnpfwiCKDEaL@Spi{Xo!H~q%n2)D2Ff+UqkR1EH zdt524v&^*UJ_r29`2gK$6v8WaRnf7h__x4SHtKX{6n3p#+n|pDQ8_f>B92LCDOs$EfZ2ts zRH}5|5~V~?i}S1tMS{&Q3<|9*XuvMPp%h*`e~Zt2?+^0cd!Oa>>@8aDw*&a*N|4-D z`wf01x1vKtl9qdu3`lV64wXrczS9VrMW^2EWWBGvc>9w)d;4t+;p;EY1Oth}6`?!S z`kF-q8}#8VMad*vs7 z;_sxL(yy4q0DC}$zcqwS@2EZ)cIH%$-1m;n3&hTBjTa@y$`XptK`VK=R5zlWkg^bU zVz#G1j{`sUV}F9r|Hj{xlUhD1LPU5|WTgExc=LbcNoJB$gf}juCvckNGxMfyCpcd& z{H6c+Kjnk3{W44K9NHbP?ZS0lDSG4xY)p0vck2nY{O(zAvlekIf@4`wHO}?Qs>*6D z15SIV>R|Uy*)m?fl!aCvSyT{~+X@Oc-&x8biw8OL*0U2fA;y+W4K=1G?93up>b)vw z+i=TOoDU;1=V!EJhE|;pi5){KLlw`>y2Sq7`X(krsik>Enq3iYZLbK1#KM_ z;oy@;HYgQyM~bF{F#}fFv%3Cnsy#MC=!|ST{|)?S9vnX6bPr_T&XFv zH)Dp-;+C4rpq60wASM)vn_eP#zAhZ3AQPm5TYk>O3m)axz+K63K4H$JY-`Cx;AE~$ zT*=rMNEv}&eT|>{+OH<#WJ%3TjYvv(o0 z%5JZtOJ#FGbfP!1^#Pc}aus`P9A59a#i)@wm24|C8;HoiPy{>KQWfybj4i;c2vgyRs@JyBoP7$VqEzUynR{`xAWPtveoHe@KmuYvf*g zA+5KFFnkaZ)M$iV*!{rkdB*ihtq0~*LJG4Kx)>7BwC5$H3%dwy?7Ss~%VK#6S>aF% zu}{uO3JLAP#nWacMY+bL*@4~`rd*Jypf^FUE6h&BhQ>W(W=9~gQ`v}6N>35>@CoIJ z#!klxJ#jIkw+>bjS#W}B!m=FcG;D5J2yo!g1-HQ%`T2D!ZpOF2{&oJ?AN?cz%m329 z$m8{aAOD|zocsGDn+w5eLxVFaX8^wiP4~R7=SKNc^I4AnLu596i4YnanNrAHB zh~_xDg|m7lONT0_`#XN%`+o5M&h?#6bNcyV}*&UAL~PbN1eA%{jlz;K!KzoNCU$I@)KSRcEjD&GEhCeV;dE)Lk!dk2j5S zzr5JjAo~-4Crp3@yC_mGfovBXapB=J&+w^V|1|ylE;n6}-ncqURGc=P2cis140=QZ zJIv{X37orgX&cu?U^WOE0 z^HlwLk2!Wf0A(Mzp2VW}mCk?h(?7#Yzx!LX`~dF*q(_2)SjjRsrj(ePbMa0ZcZ?_p z!$xHtaInHzg=Wr4qcytY5r-ZEWK5$r!UaaZph+3EAZurn##LHSnWNhZVaSPDjl1>C zLy3|!uY!_TdS#48@y-Pym%^D~LQGi@ue(l^xYmN^iP4=Q18a?>%9IAhGu00$E2C@A8{LnzK2UmGmXaenGZRIp)ice6QwlE1N@7^UCEAbc2#ooh zB^uMkxblSBU>$=^!Mc$o6hS)iTuB*ip;jE!Lj}S?b!Tt|ux<1(_*&{zH*BoPh_72m zBl!k8gBZrb)|BFc88{ndPcZhrt02-5nMgyxB9x&Rt*=i8>Mq6*p^d?8gQYb(g|EKx z7H>aVvBM0$AtOk=hs4ewORUw%Qph^E-4?1SIdx7LBF^fEJhtb}hzK-j7(MU~<4{J2{xxmYlq z`p&PwcEf&fO=LJ$PFJ5Cd%s04iAD;Ljl|?+5=BeTo(`Bg9_em0&7`s5mRO{a+JciA znn+d=ic~MTKYI{~^BVTfUv+)fGuJ4rgLe8WOM>{E3DTw^yS0sf&X|zeD&1VsLT2uR;n# zpgy@}#_ief`;Yd!wTt4(I9*-y{If66*3P+C9+n2TXKth*rd%s*lBvB$CAxH`wDG7F zbY!ll=-Uu)uqs;;jyiCiS+*N;cic{Ks1Mii&a>!kC0}caX-1 zpFcr5&|4zu3bnE%L-zwflcEH+zYDBt9GY=d=OP)JFwq#cQDkP5Xi=3M2tR6~0doOV z(2=ORg`Wyx>y5Qn$Wa`*jZUWV%+(dvDvuw($#4J0|IHWPsLTS-B;`)R^xbu0V?#R} za^Z37wASOMLSxQ_z1ELuyFoSca6U#SkyqBu*vbu-IyMpsAthMcxj8@PPkj6nsOpm~ zM>Oi*lRloNZ|;*h_bik9_sP=-|NVO9lZ7K zBNhf%hl!iM^D&ZR?wo7oLGJOe^o8Pa@XHYXAm7P zkz@q;tHx*MVG=gr(gx?p?_g4B;w*9@lgT#Gd_f1SEjqul&s1Ncwbzx6jN8nhvms;~ ztZQSmO36<1DH^4%GF&M6h^hn_%{z!OPl+}J?SqoSZ?N?qq*#?$MY}^6`o85-7CI^T z6EyBnmXXNmh}**B%fh#P^EdM07vIMhfB#GL+E7WPbfESPv4Oji>KPM7%&1+tXtdoP z$+#EJqtT?1voR0h)*G81nJu7uBN;v#wHpT&<~#@(eM3Dn#sFE#xkT4kbB1LOC1JhN zhKIK;Ptc9EMXbMDVr7t;l4+PG1gE62U$7e4JC0B(D8@-Dn}%vKdVm)fgz82XXV^e` z!+T;)6(7nFqmJ+hxxxgoa_akVuS(&V{SOzO-bI#onb+UnvEmZX}uo11o2|=V&+f(%XI)cHRH8@;( z7Yn)vgj6Nt9;)`Gt%$`E_^wq9D8&1JjLdLl7-&)O2GyC$5$P?|MN!86`&GbG;_hx? z4B1t{9;%57d0*?Gq43)A;R~NsF@|g$OCd>N8xk&A6f;G4`D=*K)$n@ZDrXpp>P8z* zr}NMfLtE@Q2b>Zh#zi(}(HMGwVP{s~Xs(>*X|L_BTt=XblMS*sSqrmw#5bmHm~Tk0 zdudec6j3Ah$|4n;rrkdh_-2toU!&F4O{voHWRyOl^ys8K+A766Iu$NmDSpPq={?c= z!g)XN+vdFSwYT}t{^ozcAN$Vl;D7l0KT8*3>od|DO$&&TwKB#|Ni}5}hWCgFrxZ7? zIN`)p1ee2{r z;~Wq=g)^-V+zU%zcwm+5!yH4+fOR;dWU4zwCwvTsG;W7873XAyWm$MeqapOXG_($u zZKa8@SRwfqIPVrrnsXWS%}JU`qcddV?K*g1Q3WryVv@=81By+kckZ@@;^*MQsFGV4 zbkBRjBDaB!%$%Sl<=JQ7&mVm0%luFO;1_x8wYN#fL`He-(GBlBx@DRs zj#)9^&}pXA*lNSPlH9R$Mfd1vk~Y{>nB|%=E=;+jKC!uR0&<5cnXQMp62I{1-7`P< zLw}M(35>cwF?BvopP(+-^b0V&p%_oEa~JtuN+g1jHL-iw)gI?4PmKmYUm!~gYXxf-C^s1iey>qM5p zx;VGKK?_mev+zwH{2;frbGd{vwdGTsUg}(KF8q;i{T9CW6Mu?VUi~7uI}h_SG+C$= zaw}|pW}1vyuDI(fn|7)te8fYn`@+zQjA(!@K9DTI0U4dapje{yOiG8HH6E=7Oh;q$uF4T4UYRjhdW! zL`_2%2}V+HxO8SKtm8sALmh_0+5)oxhWW}jf5SC5O?iA*Y1XiwgDgvrh_o8n8|SS; zHj1ol9eNI^=dlmAn)W`guw|Gfl0e;GJHFApvWhSxBn3>ljEc6XgfSD$Gi4+y0qeZ7 z*f!W$x%L*_NMk|Szy(#<+|VIR)@e4A5#GIQ`+3v%6l(-mx_3krabu`q)Aci-%+fG~ z+KqGDPz_LuiPH!!#k1ELO^MWuR3hX3&WIZ6gfgkHw2t`}DuZO20Bn>o7~{Zfi7qRn zI#)T82$vyDI-x_K#HzBwL7X}=G8)tjW!siUKDCW_P6HEs~90lCq(l4PP~9EgKMt+Ena>3v%K`u>(rhi zZD5^)H;NFv2|vWY$7o287U8_Dm^a?{;s^O>zU@1irW4R&rQtDDbO{8o@5i&;Uu0#M z^CkF~zT=(~Bc@Co7mE*x_x%u$-U^WTdLI!fMi?GA`gkY^()XL@Ug7=lndiy5aCg3? z)P=5@3!UmKI-);9{6KXf_r_Evsx_8Y$kOnvXjg75Q?zo>Inpof%)w@y!KQ(MH#yK+ zWsEb$jzLtE%4qTaNDAxdOddwSbKUSMp%QiUW|?Qw#3Gq&nXQE(*;E)dp=wNd12OtI zVqHmk;dXbhTRXFQr)cJ6(PnzKPGe%~#<4W|C^5JREN#PR;f8OOt>3W8;B=g!oG6}o z{P;0{=_h`ifBDb;d4BD;K120|L7}t_@9TaD4sxClSEdd%JLf(J%u3FT=7<*h7@X!t z^8lJA;CFuaRi?DkTStCxQ@YcS-3Q%_koUuwL2F*@bB+ z=lGFN`~aW+wO`@Qx0c{7sWWxuI%jV3ppM4y&el5O#;n4nS>Wx}5uXt6$UXPMJ5=W+ z(UKmefg4x3u+@lrmm;)r4nk&9f)3$~V$>erE9p*`bs?wBMy0mKlmc%s#!9oo<}2De zqbIsl5>WhriDL?NSAM!D4pKRkgia@{8H0u-r|d@H4!Erhb&4ok??|4JJngpY!8SIU z6pmK#5z0XJg)7b2?l&l=yzubE%U^kex6hB6att2c27S~>K{e%_%Poz;oCF=6StmLJ z?FmL>(*QBfrfhCIGb{q^)p*8|B3#mt@ID+f6s`GBhO)i>|BtjfwD zo1(i(l@SGfv%+J-hA@*b&#WFBj*|#0&=`B6q>3^(D z$w;cmfa;yDLJ>n!*a12XS7r1l&G4KUuIO$hC^AqBg}je}%iywwr-;^YOGHCz$Hg&= zPB|oFr>pssLxPQ9JtlKA!$fIg32DVE@4J4$CNp!p(8ah=v95GFu0gqMebAG0Mm1sY3jAV&3VpY|2x!jgnZguw*l?CwNgT-xZgp_!6Z42P#sEqh=rl1bGuO&h3c1Q##0anE zBfsz~pW#!#@!K39JjY!foJ8rev89#d6WxvGjfV2j4s5c~Q_v<~{K!Z7#t(ffqy#A0 z18~;w<#vk!1s@Dz!j1YUK{c@JO_Z=L`tA{k!&pOB31Y?0dl<-W?Aj+Bk^Nxz{X1yf zaP|jQJhL2A<@Dfr#5-@k`!-9OseYj#430ct?CXve{(&THK9RK}qhr0t%|r{$2aLf@ zb%rI970$IHzF~Ug!r&x#K@{!EL$iISTS@uEL7Z6%PGj>-DVZyAd^B| zdTCU1W)Ygs^zJ+}gs;8*7XR)~{TqDrqu;{c{rUfsqba9sSekifJu#)qY?-@J>FvTc zGCd`(CW#@wUlnz_T+K z3qx@dVaNfM6<4A5%4CE0zxZMP!@u^|xVnC@dq3_IGxwv#|IZt9zhd&Iap8Ma=>9Xn zy^3O(ue|byxG#MF_kK4&_dovwZqIM=aDK?SI%gjgYt*r#k~mtySQsP@Noi}O z?NCeEJ0!KvrB+rP$%+l(Ac{z= zkE#S{Je#1ySexx~y*_y;w&oN~JO3gZovKno9Oc4Pow6TQZmurBu zPprdv_L%slVmw382_ONfzZr*T)AG8LXOEBr%yVwTPH@ zx$x}67kK#KdA1Gi`e2d(wX8CsW~@3e9rzF?8Cb!sV{vU3pl-ShS@h%^ODo$o7$sevIed z_f7llp%Zw_c+|TzoLJGc5eG_ebo%}E5e3X;|8VW2hU^a+7nF`mkM>X4y(Ld2@%v+6 zWyB%wQD%rl>AgSUT7+tV3Re%G7|=Acf; zn6$I?&P4@78Eqm1?i)!aW;52NG;gH5a>x&;y<@d885}JK@1#dl_Vb6rXbV{)%J=wo z;~Ub1uy(W!EvIjnvG8_dl) zNL1C|-^y#z7+4%VQ6otMW;m{Cyq%un=nlFDE>^B zjj1_PS*fac3q{o?`1k+HzsLK&@dNLfC;aOalJ|}y2zwFXj;7zeBeD-4UpJWSzwVtT zue|by{LJ6_Ta@+|FTeZ}zyIk z5(s^1FbQv7E`0Tsx2PKFK=0vQa|sVvYEbMz8;Y2NS5!{Sxv^A7>fjDRbNIy8+Td_x z5=f)rhlyz@$3E!Rs3u?sdJkne8)#4@=m^Pc^g5Z5dm!>lA5;}AIlT*Iv`{WAvu%!f z$64vp8O+Q+*c`+s@>t0wgD6c_yv&@pjoY<_cc72`OpKP|?46Mct#y(M)lQLa+!~v& zSQa*&ICi0q3&T6=2eL&cO{3AaPO`z(RYAl8EJleUzx~1e_RTHd@y#FNZ~iBLgVS92 zrBD4LG99U{GD!zXp@52#Txk}3TOA-6#f;t-9&eDWU=x60-ANu1<;`1kAL)qNjOM}f zN=jp}4ddX3o3ivMXY?U-iECuW7&@Y$vPGF)cQ7(4&KOF!%!%ledFSTLT|YDBX)n-i zv|cHycxoI}*)HKB5iyDw3ysxy} zfQV|P5$eqtMjL`@!Lo7F8zUc4hu(KXhDWl?_H>N_c&AI?BE$z+G#(dem?QvhmKxz2 z?Rbk}PKf@b=bnEd*l4X`^Y!&75y3}1xP?v=!!eGMVvlFWbUHG%j*k^appuhZp(aQw z9Lj;=o%6CF8epkHmBxrr*)&;Q{bEWmjqi-$xdXAQ8<^J^RW5As0jB%+iF% z+aRTmYT_ZzBzLS$$$4hVgI1MAoa+t`jt3sjg}d90iyAE#MqenSlD)8bCbKaYXB{h} z6(!@22 z>7aHGQzHrWBU|s}-nmLw1f$Y8N>r@Z+Gy#-0=VBXS>}#GDe&eHnkdOD<#6EY^bBv_ z-r=rfovBtR$@$7VH@xxY%EQBftwY-?)|ANx#T8K)!>JNA^;sLXW0eHup;e~TxvWR9 z#6-pCME8tilsrWgRR)*aNBptx`+nx*>4_p15BN~m?gv}(AQ|6}0l~q!9}L)6CHn*3 zcekf5bO` z%eOu;uI^&Z)4_RHa$+^f)1g|P4j}SG83}{<{fn3V8wkSXa^^q(+y6B;Z@$L=^-G`O z)1UbqFFtsHamA*J`i4qp8=2MvnCH3RT9^plNY+B}$|Awbpocf5+ZE6FiXe39xNfM= zB$*;z(uF3SAPsL^JQ6WI4>ZGaD| z8wp{-nL5Gz(1A;3Qr){!CagCqYk)Onrb_41oWe>jVW^x$k*(7tx_Ax-hvfJeY}+jx z&bw8WEXsjF>yFz@MWHVwRdghvAv(~J5D&m) z?VXcmCfV>2hEn%Vx6EYGj6B-HpZg0x%EN~bdF$1enA0&D$B9zNzHK~OE~qNUGO;pf zHH@vvJ7n8S7Y9i;=&@?YW+sio!#K$874uke`hNKtZm3k~mDVLZ zOIO#=eNx7tdOXCHD3?MKVY!Tk$>$GOoJWmjOG_j&n{F{5s?oOvSr^*aP*%JLyCm5S zwl-E*&_UJ}(}Zf~(v{>5GvPP}Xk#E`RW`juu~9iddlyqd@`+>_X&vptQD78cbW(M) z&J39;EKIV18Qm*Z3bPB+I$1Nvlz8NWY>B25naV*2#XKGf?MH%2uoV& zD6Ln{>lU%VmiXAWe=F8kUj6FZbg5i5r&-}6-~L@Zd;LPh0zE)i!);%YJ!LMahLSNN z$H{$~LL{0{>$>vAm%hLke(!U9?JHm6?Kj@$^62$oNQ}y5y@Tq!dvoE@yKnHutFQ3r z&9Ct2?bjJD%(;+q4%u`#PLyAngjq~Pao_2-@8LhZ`NkVuzV-%}9+l&p2%~PCtgzW& z5~Xt0j&-fN^Kd(NJs$&f@}O!}Un@ z%sf@p36B$lOUfh>RO1%g1w@q@&0upyC#+_fd zvV>R+hj~goYR+93#5alww`t-&q^)$=R@4rt9a&oEkV6_(zl|o;RCxZFd7F)j^1ht+ zE*wS3v?f%kBoQVHnf~!{@>X7?9&eIjjlQhf|CP*kKhk51~f92O{Y_ze^5$1BBdlb5b zGL=~R1(BIaqi((WAh{wvGZg-wCV3`_|)oU&#}YzI^?lB61&gzklub!_%&d z+^a0Rp_iS3vs~`@FaP#`#p^Hq9yuw;s{_wJd>HE=6}qn^FI1mMx>JH=rlmq|l|rQE z^60E%V;jb#g{FgfDoi$bXAMeFP7^bQG6qeBDH&5Atd>9;-UkP5)K1i5(05o@C=n05 z;;EoXB5LfNX)fdx{WhyNHZewnWDOY`qSMY4xi2`}&{3H+v8ZtwV^2>ME*3xIK7?!q zJx-j@7hagJ`QVH1=iNtNV;d9MCZ6TOMKVbY%W%`8tT0>R(i1u=q(sriB$;G0%!%q- znBd2T4KU4IymE4-ME@igPiSO~Im<>iWtF(OOG;QD`wzG9;s-y>$cgjaEwfaz8pDMv zlQ4@9Mo89Lq`i0P@IEyWVtYsu?bke5ZsOkA`IWiWXuY> zC*&p-dUqBTl6F!JW!ViDx9D$6!qQ_=ezZ`fHW#i_LhZmJkvMC}SAa zoumm(N^PCZ6EbI{3O0xXUIIg~T+SpPG}YZ^(6E#kl33P_;hi}vmQD{p$!;8t&}j}# zxi{Q243q+=s}q)>jKP#;Y!-a^8}z!P^v$<{Cd z9YXhvh_Kc*SSW2}LpWHpDKFm8D$FLB4cZn!8AMQPJnYd_+*9JH1w{G$%dc>I`x@6J zbAxf`XFl@L@8!9N&!ZA>E|YdT)ez3~dK zeB})`;wD|D6De&B&B%1%#b+L(BD{5WBrVX5Q##P=Bi?-d9c~`qF#1NGW~QWQ2sQ7a zgT~<=sf_4W`P!SW@!8+{Rni#LJR{yHJ)lR2X{PToeNG7(aqGKl@!_l9xFRE#xs1l+ z3MtQA+llkzN2I!PI9~IPtRyiMXRQ^NKugnuPG~Ziz0!xUxX?$XO2UVcS|`iKhN9xE zd-uaUj${tpv9Q^M%0_F>hB4WS$ogb2YQB&(A?_@7i?+{`aeKK7#Y(|EF>Bz(lXOlZ zh+e@^wsqmTUYU3K-$>Yq*xs;cSrvQ8`>$tueTTMYniPsIk@o44YD;3wHc>|9Xq6!| zm%cHJVdFv_9cc=zm~>W*O@%&`$&F=O_}=gRKHdvhyElO9eR5_0^#q>E?k(C^82gro z`#p-_Ow-J-f9AJnH*fKL&U7Y94y^cSLb33|WDA-2Zh#GVAf2X#o}54Z!=K<^{Lvpn z&3NJt@h86SuN#r>hmQBYMz{yTJsFvvPBOeleL?uUf9LP;`QP|7Ztz$-CdTZAN8Z?$ zg=-}$Dx|^~s5*T#@-T`hODePx+=Zr+sScJdoRYF7 zr{#!Qk8YTEuBOb=2d!>YhcX%O_A|K|bM7=NTsB47c<0d@=yc@SIg@&{+TNOwypU}0 z>~V@Rx<0tnJ6i9Q`}ZR$BC=9YH)x>qkz^jVx#DD?89R)v(^N4_Z2JWur%v;Us!2&o;cOn_W zz4>hfAWQC}go*2uaUexO)!4|%!6!7INNF(o88lIFE}kfAySY`vAZQ2f>fq=Tb=dCQ zj}o+Sei^3F#b|Xwx?(BQTj!93%V>0jDxIT7>}qj1g{_Ch4$M|L_Y14Q0~1El*va}J z>%iQ&&52=&JOY=i9V7{kk+daioRGUr;$ZOI2hd$f#KZXJa^~gFe~vd^d5O0lUwCx8 za5~PEoJqEE*a1eXcMRj|Fw<+tedUk}RRgHzy|JaldA;TQ&X=j@PDLok8Iv3e+1OV| z8bAN)%A0R|h0px@uh8YpA)R2X0fkEjEq)H_2X0lVvXCVxmLeM^DRnG7OwQJw)e<== zbAq?mJO1d$KElHfeT+B1@>&47ykXh7E;CDCSzI}$2NYTugEa;w7eVdFBm=J(x)daJ zuB|gXp{;T{K8P6b`4I@sZ2L~5Mns|3{t}vdPqRG^Ja2}P;IT}mzOx4C|7)LUT zNAcmMD@no3&=g*UQo$sw($xhUiPd4nvEI3yAMr!~{GUQ?@1?=Nj^_dQI^0eY<~|_& zRI!LF`2A=8ejtE%-+Y5Fzy1nW*M+tSkI#+kE8$x|@Eq^dg}PMK2kW|W$b)%Q>PT$E z`RD%l$N7n${K+T@Lw2R)sXyeNqw@8C=Tqyeh&(Cgd+%%V`(Z}z1M~3re)jM4fBeJ$ z4eySpW85l{D1P%AhD1@`c4h88)Ik&QjMvVpj{2bV$B>ooi6X+qM=%>ixNAa^MsnCH z)X91O)d9b`a66P$2Sqwf9QDlPDaf>HyEiOz@rBfsCWej9wqFoZ&fK(0m*DgGh!*pd z63qrdhmv&T-G1O^xn+!%Q;wdrwL4RCN-i{wyZhzcclnVY{(k=Y-}p~S zVtnqmew%GBWP}5WEEV;{);1P8+q&R&jgA0vS)zHY_A?Vn zg>?XG%-W-+9>XNF5q>ohBhgS#oO`1dFCKPCTJ;n>uMsp-WMk8aL>odWu`FF% zLexkyIAn?qTr<~X%z@}XkdZVb&fTe4kQ<7M` z2c&Jpu+#Sx&alB{#6Y16Ced_kDbBYcgH3{>n?2H&q{2EjvV;n99!l9SYGX7^I(IIV zoS8=u)v>T11SMwW`sx{SKCmpek;5MVLLr28B zEu9{GQbt0oBe{?WRbdd|vAj<+*TA!-gQyH9aw@GCVjI<`t0xLk8F>yeMNOTkt&^AYI~ra#Zk0t6<6y-OV(SZfSI~ z8EJGbswAJuW6-Q~5+h6O{KXPU8_Q;l77?eKL#SSQz;Kdf<`e~jXN$b|Q4^aQYu_kr zFyO+0_kZL2`M?K1j7ijg4>9~+_?8$xeD|>=Y+v(qR0PBM@~f}#d!PGF`g%sBa8)L* zpM8ef8+AK#w29m5oE;8cXkB?{x#LpLWHYoIW*7Q!woN$XnIeNiM%;P%^;bDB3lE-o z=1D^_GPuVEZ*PB%PyfcJaF3N;lR@sv^@A66pW?+_`}6t*?`OoE_L4!HA#J5jcn z3QND^fe1ItnMZHF$QIOa2m(8C@;+wlzMH2thJ|&h{N``|CXctyb6Qx~P^qZEJ9mxh z7ffYW{b1Mu)cD~0KgeJH%YTXaaCovhx_?3K%rg=w@&S|_FQBB3 zItxmgCZZTiEr=zGfQEtaM4Z(}t8sVXylkW*86}6ZCAfwmU!j-5P05#skBB;(zCk3i zdLV4YI^vyf#>0!qK{^t5oTQRXsGcY|S&wMXR2e{@1We(KBTS6AR@KoL5@e!v#aPBc zB%_}qrWNU+VH#4mIfp*rMvutsCs0{AbO9nKZKROtOlTZ<-rKTpkZ~9koCzcJ#7UH- zMgjJIf;QYUsuj6Ik87n8nez^ph~q3n{=MC~f=m&K~F+6G2KtwQ&F5b6lS*UK)!fR0;eGRRd#gmcr%j06b(Y)Db7JEJKz|Vd%+2-V-i_q z!X)tn-}6D%(<6TEw|*1pl?w?p%Txv}ID5xqB&ri@VV7r)KwkrDmDM3jVzrgkGjoVs zq!BM^9WLMVGSvc0JySKZb7jsGkF79aZm$2CQSK&0NPX0P2WQWM=KL&LcM3vd;wnNNk1;ArDdS+s0YrD?IP)-7 zB8ek2`0ZAf7N{OM8%%0k%yrzv1!%&>)qTF<8{ZFKgLh}EBDj+m?q2A3!+}3jBDVSh z`5HjqHpoo-iC_Bl-=Oxs}oq5VxUMGDl216mW8c7dwj;LgL~kf z25J?u2C^*N_D(WJ@?itPUClG!`>o&3i!Z&*>tB9@i;yuH-z9WMkP!-~NlDwGo?^l* zQ5b50AS3M)hiP?uha)qMvk0Y6%q|37psehf+2zPd#>L2pTgtA{MPS2?hi+qN!&zG( zdnHDprG)o|*5e?YQplo+?FgY$bRgX&1P=R5>wyRN@A3IBe2M?-pZ-%m{puHqb7ayu zh@ferct)r!p)(sqRq!-^e_|9*?Bfm(>v+-ihH79Ai71^!p!*=hu9j$iB+#%v5CE%< z6-L%f)5y6EMwdvWNoA)>ZIN3KbS-pixF?$Ck#yXe?oC!qC+56E%8BNcvj;A`BQdaA z-6GgVx8)gSx$D+AjG%Gl+?*KlSk*V98iX{=$)^Sv3X3SgI!LAyp%nzDNF(&oKpw0j zG2$}H6Sa@^ol0PDgCdL!RJ>ar!wze_Hei$94@au zf-5l|5EB;fbVkXKFq95=REh1-z|X%mLR% zV|ZF3jawIb?MTji_RL)bJ3zhmCwK5pFOP);C*sMDJBv5)^Q?a5b1Mm!(L9uO2{mUi-pl`NZ#h6b-_(pDEsG-kIV&

rbK>%1$LaP=Bv3=ZS#jTL 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
oqorS9=&`G2!rck71eAf-KJ><35KKpA3!UhR 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�%7DLdm<>7vZE^#$mdNw7H-k}tSM65`ks zdyKnF#cJZR$LI^MhzgyNNPA6e@`fgkuZf(C8FjW05Y_|9<`^k+;C!u?npV0Mmc{5v z8FXT+=Uk*j8z-_?iW#?32#4gllGVbMT~R#ih0#weddc1SiV8HXEGIaqa~#eP6V7!($PCs< z;{hoPrx)+=($i0oPKULd384=X2ZVG7YnU04D%x-wn3Ft`d9kpT%@C?)j|0jjqQ-}m z(UfD~-#dqS;f3d(<#V6^3{QOaKl0oQU&XXA_(aPIEnBXZMsnpc38pYGuy2J;OR!|- zenMoA*F^1!Q3keY%aCSlzJO-58sx)Nf~p$WHVAfTTy*XlUDLdfPo2?5)Dl<6g=&eb zY#i$q$Q%MVD@@iH32b)SZJB7~1-y>n1*cyTvd-RXEya@b!l~r7cW4d;~YfT|*H=+1?Q@TF1gw~udJn;oS_Q!v~crrG`>ZGlw zU-s+gZ(Ls7VG-ErKv@#A6z;myb;IUlj4T}M!n21v%+|QY#4Z^p3gc$v_U+g6b#Hk) zNv_ugEe=US>=#RxPR|<-+Xq-Qva7lWZ$RXFT@`z2TMz4NR!Q6r`g#zrBi41*v9{Gw zoB$2OR-IG`8}(j~E(E~rnpN>v9)2sMhuCc|PO^dCCrVOo6zDZG&z;7C<`csJyCRHB zbgY< z7%2$`9ZBgFtLz?yv^S?#W~JcXBjK*AoqJNF_%{CNV}Hbt{@9Q5=p&DEVSaPg*63T+`)n}jM(U1QH z))Uqij$RQCY&@WTix44ndCP7Z(Xn$7Wsq=KCKBGjYD4?Tzxl{-@$vun_c0b0)&Sci zK@RrHz`}sASf;Mbqah1jAuE*e23IeAk-zwVKFrli&y&)IvQc(pMS7>IP^Qdg+TbXI z2&NgU3Tg0m=jMhq)jO7udFs$U+?NAUY%$<7vXY7^N9mK155B@c8H`f@?Pe2I(G5hxL%ElL=E zoyN6ZAq2$%XAAYbp=>$!*)7WE zoW{C)U&q9K73bP=ij*S{}w<>{|J%U}NaCwStiCn?^T^1xv}Qgq_x{r7P_6n7CW?q2fAPyPwDRtBK2 z(eYAiIIPskq8zl5y|Yb~x(KrwQ(j1}eCJ>NYiw@ZUJpoLg9z7_pC}Ttz^N}hd$)77 zKcUv{346nB6qe|OtXs9Pp1Sn4zztYdAWLEavifksv?(#(H%TCAEo!0!5l_KY5W`GX zH-T|N`OFhvqL@*;upx2q6U(TKDQL<%3S(&uQfT=MRcO7^e1S4DOc}jL^@V*qvXexT&O=}KFz@;1cg5=>_q;jlXXjeP8Uj&WuhDq7R;SMOdIwp_vDcH4 zn6kvn7ys8J!egI*jGz05KhG1N`#gCZL50*qt0Ov~zM)%->69v@g11g_L$uJ{Nm`k0 zOYsJrkX$gC5uEOY+KrSHN&-=QuKeb2|2wwlXMEE)zWv_C8rJ+M5w90_@eE|OHOIFG z)8%@47MIZrFFeoB{Or&0D zg%&AiCRLCQp6ITjZ`97s%?{%Rb32m6krh_wqL?^mWd}=->6OGrp}X=Q{=>)lJ3sJ4 z=(L5@$QFwR*TSMkYmLo#hKwVoos%8VRw-#jB(pH^_>+(E^Z)3d@DKi%|CNoyc~Rc< z@SAz1HGDo%isC8L13Zo9L|$$AuCd0*qR2GzsZT%7Z++y~`PAc&lg0_}PC}6mO6X{w zyZZ`;k_EP=@p()^w^onhD{EsQb72Yf%BYpB6UW-vO%wmc_kV!P`HC++{Ve0C!LC9{ z;!G0Qi6%;K;ec%=QJYbKlmyoSZxv68-j$pJaZ$wCs8e)gJ0?nwm8>aTtr(CHLn}x_ z*6`CvM32H%ZolCT-qsOW7ANI%cALa2hYNC7%obcaZ+qxXm}SHo=Ek|sv@$TCz_R1k znESvkWmJyLT}f$&ic?Cb_=!_>x;RH482UiYoyE&Kn%rYPQj*a6DQ+eht%r5^{_TdH z4!m%@%P~z%%K@O1-jFLF=YyH5ar~sGv_P`mu8477cA_= zNY!}(MWk_C3!LB2jp+=wBa%nLFKG;Gh+3CKqBEeJ6x18Z6J~-)V}CqyI_|+1j{5^w z`@5thbPGzLh;ektsu4F}4M`o+25+6}ThefWw$9)ic2i>C7HZFkHuiHtnPcp3!YNmB zog*GRPmFybONdoZvr~5WMP#`OXEJi=M>IJF#cG3NV^3pA#tq3xf~(Vsvl8K1wMR7g zBArq@(=gDo(pw`pVM(2h8{QLVY8<9B4)sVeqb1ntK<}%NaRn-EIHT#FJ;Ff7PH^E@ zYHqsdHGfx1LofrcYyWWsvq9pCn?e8W55 zh2&u^UBl~tZ5veyhnLIsm_7>HC<9Z7tJkTOtWY#rskg3iSgFVLCM&4TS#O-zD-e~i zNQ>bTZlu26_>ky;RN}Z!PIR@RyzuHPeCYr9-|01DenPcUlCt>1u@|!4V9`pFJ);fb zTEJ*2GuJ&g&(Am??&s;3o+qaPL0No;VPepL+_Fo0eZscKJ!_A=cB*N zr~mwu?D848WHg6HXIUzqonzl{PN7ms+CvbYw!wQMcof;Av63`V`yO$_he(H}LS6X} zXDM@G%AlPp!m%ghc;vnB{APaSCw`oFzU!T@l_L`4ad4VM&X8VDd{&Edmk`eX$)9|T zU;Xf}@u@%mG-H|QR$&xw>6T-iqah=cW#&o>=Qt-j;%tx(b226pVgm~ml~Y*x7x>3N z_YZjQ``*9O{jM+G)wSl0Kl|jL@!$Us{~gPr(lEwxz-(rzP}V|oZ(GE#7|THMO&BKn zLhF@XGM1jGqAY!3q_Zi7y$n=lhVB&6K)3e@s2n6dW9}M_A5ND-uXlO-Ti(Y1^gsUs zZ+_?&;>MAVq=|{n+&XEvK^c|hbYzeNbmh4hUgF<>^bh&95B~*4St;rm14)G2 zyTnDGxi}uVt(mH0xcA&xn3+t`G~z(*s|}w8@qzA@Nt|2?tr^J+H92)@jKCs>uNs?C zq5(WbJTM|kF+pUZTf#J4h0=_k`|itfs+ zLbgbctg0*xh7=LlTL~ZY+#91NN>S=ObI}_}W5*dyJA)V{kND{>O%ge6SzI~!!p@ShLk*dgyrIAs5h3+_H zN4t>HjB94;ov8~+jq^NmT;PJrFgB7+(3FvxR}qFHcw0ygn`z>BII&n^r^2F*C2uKd zNR=PwAanjB!mN?I`UK`CAw6V`S z25FqPBd?HrRAJfR(pdb&zGh0UZ0O9jvnh##Dml=3bgwK3JA+!4S{g-X zj>~|Fv2#PqK$T9?Lh?kNdvwcr2+#mJ!b*w90q{^onW7xD4z)Q~Sc$g*=S3 zya8G8(~B(Wj5-+G+AtHwQYgLBdZWvTBnKOqb7P)ou*9Y}v?M%_3^{Xtw!_Gr_It)b zIm`?5aZgUp(l>Oj&<^*N4J|JmYvKk<*$A&R<9NB}#x}FN`4G>&bR_jXn^E!9nHOhF zPRfP0*m@`xCZDmKnX9vt&PgWT@X#Chw(s~)*iO596j?}dfNHGxL^S|OtGv|(Ok)@B zln4tGTirxa#Hbspp%HO(oxohPOrl`9mVi3(yTTT%VUJ$*OzHZuTzBPISVxH)Oa}hh zFZ>*LFOD2@rsx8;gFZ96QPPGi3(XUYbtQTX<6dmr!lmT%$B zU-uT?`o=fXEQGEBGy^d1+_!pAWWq5@3zw;m1Kz+_mrPEv=CtNaQ|5<$;0O2{-}6D<{~g~(7iX{@ zAWY9(ULAP+vB!DzKR(L8|LE`W#ABZg-C*9bQK7d+MaapK)v}v`lQ=tZ3I)?l6XVim zHjT*gk;IUM>Y;Iz;f!oGf&v|m7~TtJhUJ-TO7U3sM;={6HPby&n5hUmolt|52cx@gUU(I^Io9M-u9v7mU+fWCv6z#cgnA>(Lid7a zLwlgO+sX^*y)l;?A>y;>E{-xGJ@O4oG4AwA$*{M?)P+M^I9I`KPc`LsDO}2ix+Es8 zAPXumOau5i`S22+1s?`VQZ^hIy;I%kX+Y~9>qlnWP}4#YM|xqK9qVDYs?0FLV4XTg z09T;~RE90&&qh@Uvfj!n)C9O*VusHoSVk(Mo`!=BF2W;)6NC`+e|nL9a? zdO~c(HQ@Z(BszDw%jCkO6Ey|?+mbS*4VMWvbw+3$dSaW5rdw1p!*HaO9PX3mjOvIF zBnobwlXd6^R7bi@(Dw}EhPeh&wbm1-eqvnr{f8{18CLj8+-Ofi45p_ee;J z$fdGL36(8Nx&@!{n% zvXusTqN#J#6ew;Ms#Kmkj2Q3@Z+a6CJ^VJ(@(Qn>jvV&RPAhXOEN+}goO`9q!n`PB zt{eu~$-ph`EX^2pBky?Ex1i$~YZZg8j!I~1k_UjyJjAa^2#gJl4Id!VU(@#>aX7~i zjwaV}36Uk!B?^m9yIxeRtBzRJ0I`Y?RvYq4#u4sWue0d&wh1G+F1OzNc3yn!GhwCd zWgX`ZY;0kc#-u@mjL**r@`j;Tz^T6Fxa_&Pi96unGbI-;pg7AT001BWNklsCc zc?UV8l*YML4yPVORS~XyA*Dnyr|U>RUh$`&{S>ED<&cdt5w_Mjr4eMq-BV(e$~D`$ zDQs1^c=1*K`Gv+o@lR{JDJVVM8qh?Oc zac10LCNU;wrztXw+}S2WQeuh7P^gWPz|u(ZnYkup7;zR_QJ_$&QpC~m45xC|mDw}1 z?Ss~wM<#2eT*#$z_bO7D#^fwLraE0?+NTmzOwEO6!D31}gzUtGSqqek)P<~xAsf~r z(R%65jBrN5P8O4>Bn)cwRvF4j8whr`lSS1PpRUT&WT(uXJ{P^JfhudkV*g#t-2+Mu46%UwGjBjA9c>H{hM6cV-ou z3bR&3L(G`FGipaB4_yV$W=))}J~Ji|-J&$kL_(BPFWFAhN}F9M-Do6Q$>0Ot_mtk5 zb;Etb06K)YsKaDKkW=Zn_PA(zCZQ;mk|zccoJz`_qhz#qigsKEk`?lhn3pRy8TO3K zH8ZMlK5khq_FSDVIEvxcIH%&RVQE9k9qWnBTK&y7aI1s}^-lHpy}nSrkUg`X_m~zm zDQ9V*>O`%Lw#;nRkTh_Y(5p;ENM#G@4BIFVYzKy#IG=_!%`%fb?69MsNMvS=?J$w4 z%-%WKz@`dW8a>TSDYKJ_USriDD83w-bH}sM)R5DRI?O54jKGb{$YdLeEgW$M-H;KE z)kz$wS|}D)(v}Kl3%$YySUd+XO@yQ)=8;!44g;rl#7r5}mfaF5omm}`!a!rO3MJ8W zh$Pdl>@W^}203H#6A#@~e(WcHln?&x|B|^YFFyS|)39L?1)JFS1#d@EU-cC-L`a)< ziU_Bc*ibbt$DXWn$iiU8)!j>e_y@j^_kQcU z`PJY3ebU?+2f^kF?o?B<38^*IM>fUR5Xq6&qPT5Zc<=kao%`PKP=KjcjetwAebreZ zU)PW<=yL6T;-2P!mFjz)RT7)QP{6pQ5F@YOdfijI7}=q%Yt-xYhpZx6@%6C~9c!0> z&qajA${BVGG!M#iue`!DUwoR8g;Q|`64s%nf$EOR5a2PboNT0dxB!$uYrmAvT7bC9 zlsS^|b@x5E(7dC0WTO^i@03{DLQ4Zb@O|G;Ng0&@`*mMO!#J!_4TkeOzx`X>xqG1C zNS+W^cE#dQG3VtwFLU+E%NRmeVd$Ohrcj2FQuq8fKlNYpcYpjRdEtex@W{XYD8sm8 zgONN~H>66hfl!zwBibn|!FHB`WR+0%Lj=V?uyNF1*gYIlZmBKLx1L3Q9@iPny2 zhQz>4Q3k1)!L;3wi_=WWd8G8pyx;TUi?4>BA_>(JI^>wnCSfcYTBi<~?KE;#?=oVD zBwFhXsiM+3w1#C30d;LG%}|^1Ot@iW;7TBA4TqN-+61?T4~bz=k{VtUnxLh|q#IPB zXyafDR>LMc+lu#-#>NGoZXvBv>XEsHiz&&#VlzV$MhCabg&R#_Oxq}uwU9-bZDtf< zGi_+@C<{kPWDlxv^~&G{B{2>_kDx@;LP;aOoOtG$FLOHH2{)-Gk`^{YVb+l;!<+^0 zLP|pGot-*E&eR_KpdlwppwVz?h*YuuA!+VwBj$auQ?1 zfVwbuNLeG&!Pn1|b;e|rF=5SFe1SYL$-wNf3RIja#iX_QO0Aa2Zm*sh%utP~UUy*; z7*at~T49L|vBv#x{09E|_x>;x<=GdXB`XmZ;PE?34p-LQ{hsG9UgBzR*y7wh9B~q| ziqOr&xY1B@4vW1Aq~^rr7OJ~gLaBnPCZjZs4bB1XDPGU6;e(tM{rx{s<@4`wtzSXjBXjF zQ8ZRKDw$(D#%4}rCCU}LMMU&TM~0BDStFja4Y}~R~0%o+0bcN49 z^A+w~+~I69l1hjzdu?b5SWv?0-ueHidbc0Rvg^$6x7ONwpNPoJs%o-%XX`FeYKao{ zG`2C4JT_p!7|e_HV*And7^62o83t_F1pMb1h6e_0SRRc;N}ADSG}3S=jV=@^QM`z1 zHoL1TGb7@hz4uyvSSOqCL%%etP>~rC`>egb@B4k%nK#$41yQBRmCLA{87wA<_k>N& z$s8-ka$t*+W!O{e#?9<^B8DXggtJW0Q&0V9*j4 zX3lfJNydvQAuaV=aomqI6E2qr{=J|0B>&`B{t18o@Bb3-zWZH%;|u>Uy3Pn3d-GGwgo*n7B?owtAL$N8Zj{fR8z z(j+9x-tY1>q&yYs$)0G)DuX9OqwEjz-T%SvRYJ3B0pWWuUvpS0CV@&Mr9L2bva4$T ze~JCZy8j!#Z)Wngvq$yQUBY~lf&kZ)cdqLrU-`&P;) z8(SGO{c0kGUJt}jPC$_)NhdHWF#`+($oN+su$$qwNDdQZOkwXleip7jnyhE;tkO1($-crq4}XP`VAZ_H+P?}vN74~ z(lwE>v6E0CeI?HhH=JcMxZok&7NJIGn+b60^O7!qGlmC?H-;W?pFG##m{o`QAVzp5 zgNqz;8n=Zx3buWZ>G0T&tT@kAFx|K?ILbl`7&X@&6LuANHf?r=mUxQ>-m?-V&QORxqM4%~^clA7xfVH4*WaJ1m1 z3xmnC<-q*}oz7j^`zxlbQT92!lH_dE5{OqY<%bCBY*pMFZsw)aGdLKPD^fBTDjZ7Wm(7W>-rRAMQ?BT z#795IPyWp3sLOGeBJy65d6C`mAf97D>`l@L>Q93LSr`Y@DC}sf%$i6J7hn1}|CYb_ zcVFU%f8>V=v!{JR@<@Qt9Wv!X));v5TS#306Zt&1CLj_!Jn5;InB7<_^y}a+zw#B< z?Lv)(sV%D{^~^;&4db~D&H)~slRcsH1xmx+sj+c~aHVjs8<@d1>En?Z3quAAmCyY6 zkMZ`;elEW|dk#tD2`!h1aYTse{O|wte`5)UazdnXYoH}TJt32du+bP%Gp%4xV18%O zjW7SfzvGL)_Urt`SHI4+Rl0A;oSC|bibqGHFa(A?!mJ3L+j3>wdt=tvsI}#mWqKBy z?ptUpM)ZZz3RN=ayAb*P4acqU_<@Pp@S3;t8L|6+X5tZiV~YhBqnT3;x)dTdj18TG z7|^9r^}yyvSGX;M*o!j-~w zs2W&-l@r6^WS;Do!ZY;>S7UFeZ`{TY&2^)2}1o6oqtQC{Dl8M+{mK8eemEb3Sc zwqAL@RPM*1Z-aw1uA@`Mn0}?H>|3fqNM(yeMjWLh3@#pcR8BadmY4u_h}?Kb_4aR(gfUxH*V)(dH$}xZV z?GZKTp*(u(rQL<2!4G`;qx=`Y{Evw9g>QZRZxE}TX2zbp!XYY6oQKWnq1>o*F-4@& z7`%v1_<_Uihd8xhu4ir!3qE^d)$N8hSGMUn43){~Q1pVUvUzSOZq#_#oR7a*_=z9- zINyAEW*x#}2Ref_0&fTUH4pw{DU5)Ab$;?kKEZ$akN;cle&EM=|F8Zn$9BU|D50o9 z?SuQvh1nYF#-kgmm06NYsN%?CY!Qr2Gd4C?&=>T+p>d|^!m}nQ6W==&)HaGG0DPO< z2V1U9f>RWR99ZjQ3@}w}cC<~F@{CI#tlH5joJ{B?4X?$6^|~g2N++A7N2kZ+TGB(% zYNChFKGDcD!NTMa4UL{(1j&}&mCDr>iARMieQENae-IgWM%I zOlAwKI%PPEOqwKIOJl_rp?F7dUd76v{p&yC_rLh7{Qe*RHHFTtDgXID{6$`^ulUY8 z?@EnYq zZGs3j8;d1lv?>$ZO|8lEnh9?V+h3FK!%yD0b!TMU-rn(hzyJGOqi`tD*ByFZpBNzt zT++ocQ6Bu3N};JCb8zsEER|jybElQcVcjroG@G;%5QQmTM)S-lbsbgqP-vB*Ni7|MB0UdfTGF8H=$ zGZ>O=l_F5vfz7j0;p~kjE4QVvslo(Pqs4;GE1O?&$@ry9p=u_lCKskE$2d?txUw=J zQ;WJ#w+9wcHjaB!bEo*q92xmO6s2(_8k}^X6COh`nZ%qp%EL@D^P&eLvcjUGta~wG zw(4zD55)@r>XSc^p7l~}DXRwW@)LNi(vY4gZZAvr2 z+*u`Q)hF_jeY`ty)B;+VrrgA2&cW11xH7zQMj?b_XtF*$pOvLl%nH*LVp1fVkc&iK z_GcCZnr5#|7p1DAbLK!P24mYDM6gC7qGi7ljufG~anQ04L6g-o1?TeszEQ#nIbv1_ zn=~f#x zBOEG^j}KH9rUv1fE6v{VazHVjoAbCd9H)(vcXBfZoidC;;~WDkY3|iAdF-*9ufAUv zcr?dV&{~jb=$1Kmk%`EKlNF}iF@|%iFyd*gdCX?nv7xf@@d{@SR1vgJL^iAoT~jx{ zpPhH#d&OVBd&wL9c4cWte&`c#@Xc?3hnKGgtto|I)g#@7yDhQep+>XHa<0Bvb7+sj@Bq)IMD3~EWG{p&+ws-eR{t=WE}UY-COp-LNvQ=CfRRO*f|{eG$v!Q897G4 zH9KMe{^}dw;-CM<7np0BmOu5@r+IesEcXDyeoP2^pcHnqVZ?5<-Xov6;oW5(A=4|K z=?{|x&^-w}BEet%#h=r+_c{BdsB%!}B7%Bl%84qK=W{aU$mkvFf|}4`rE5d9vh_jn z!7R@*{Z(PO;hsNTZH3SN%+K@ITW{rWWPhz9zBm8M2hG;s`sTO!{eSaEEQ@eZV;$Ls zUJ$AdRx#8ZpBqMFofkq6`Oxr8H+6Ah23m|cCx@ck1w4dOwLniB@lghgbh?3P;}VVT z%5e_1$aeK9L5a!gm4jx2WRQA&73DC42c1l-6gyGFxQWTD>zS!14(bpcmBNse(VH5z zOo%HbCf6AZwKSS`pj2?j^h6Y=u+jJT)>J802zHq!Hq4>O#s%X*NvWR663O}~mRmL5 zVQ;kw>o%z-EK`{ARJdo{DO`FE!UxSiuOf8d)P$vwn=0#w@0FOc;nC1CGhnd}zW3NU zmYSCsH3kLmj_%vdWkUB2D+g3Irgzi|#j<$x{a_yiE2@(|5&*faIn{q;QDSz+Fh*S% z^ellDIC`bjAWDAsG$s-GtSqAgxiv8@DM>P^Qm|+=6V5;{aFWRk#m&;6M=(OUdeUxB zNE-BkhcPqh>Iqo928nDi=O}RTPfixT3rsSVnW8&uAs#1n=aCo_9(nx%w zDuh&s7ToQ2e{N_O2SGZSqvE9!9-MT6k~(iErIGJFbbkL!U*$YjZf=fvub54GPXzmz9jT2Woudt|-0+%U z=__V8NvOs7uvVHW@5aIqq50$?4Dl;cH0zzWjcqDN8>j~O#zB=s1Z6rjMA)rXP$rU;Ue}^WJyAiMVsJlBuG!;WJvNc*j||45#YK zCTp4n?UWpv@yOAZbPYt`Cyt3(qetPk3fngL(VzZV-ulERcA3fda^a^TEuKU#{@ovc ziLZY38|jM(WfjL3?trm^a`g`36ookxj5x$mTbQE*D@CBk z;JFRvT#&wCbP8GPel^W_@l5mOaS0w#)^+1X1@|n6SvxKA5a|7(J_+S6W|DK=v zvA6im-}@a(S!h^-487wbSxo1h9v#;ciwO(xKrl25@D66I0kb=(q1xD@(4;WEfo}Uo z%)lp`8bu4k3q=yPwun)ufD|0#B3YN=kx;aS$~iotmXg~kCylEsIh;u-ItEIiNyDVk zr&A*kV~;*VwStgX|ByxyoKhU5OEA1*F|tWvFMOPlCS9?;gwr=d_jd45nj~3PEQ?e} z9}J&4c&aiGOlNKYqNUUqoe)V$O9v0GR7n}ibx?HMx0Hs7FlDBn4Y;V%B0YC>M{D7r zP9Kw1Htr4wVvpml0*4}Ob22Sg2di`< zurR`*)Vx$&`XIb#({KSDLXp_3C^}69na;#n+;FQL4~=$X+&`o&IAu_E=aQ9z#5Fsu z#M1kyaM{LwhNY~UygA)DLObpTuyT9%c@-nO4JuWY3rR1mI}LI~;ff;@kwYD^g7``+22^hP9>J+@*;o$@YDF^0!AYyW;M_%?aiIyW_YeNwvWV1v`?j<0^@8+`Fs|0%!wh2NyF9a)T%!q#C*!$c{p zY}Tl~L%?LPNkiPTG;meSN2UoF=(a*ruG;8ha17gV(w(pag@s4in5MialO7XY3WY|A z#v3)biNY5725%^>2{AjePD)i)G9j^wWdT$L?LlLqOZJ~Qnlw}kv^p1oAqO1TN+4sf zAy{pU{mW`MotqX%cm zw81zt=o}YiIoxn@=UEMObuJ8ClzWU8gLwMSlDhY90Da%HA$xXb zr?ll@!h>JdcPx-$_LDcq`~(g?_YG%OC}Esuq_Tm~O12 zQzFwtS0A~#nb}En*Rp7H+qYjZ(K#ql5p~}0olhT+{PKVLOFTZj=2w5~kGQ)jOv}>7 zjSUxp-Y8YLh%mh|afWQT7Kn+tuq(~23?BDN1hyww>i_^C07*naRNtYts)|^$hS%ww z-6&-czB0scf<^Z4DV3s1!8s#TOZo7Tjf!Er8QfGEK4`Xp1Va-ck2FL&H70%Jrs$Km zN7gG$>2$f`t&)7kD@=F@I8->5%6W8%%4B6u`1jxbL7txqfA{{&jJ#?E)4XILm^}Hv zoX~|CmqbpOF*Tdlx1BCNhwos>d|_o~%B6=8ab=N0(Y8OINvNMJ9Aq#EI(e>a?yS+W z6Gtn{6B5Le%!=lgN+qZf6w7|2wujM!H3wZuS?L;)94bjf##IORqtowKDv_V5$Y$Y1 zR%8m!iB7(!(uA0By`J~9FQBsbKm`&7#Xs28T6y--&llTik~2%ll*|%~fv6B8_{g&Z z!KBNANU+dZO0bN{4Z&-K9)m-w(Nvi{XuznsMk@zGC+k>IpjGEp6dq+z)j37-{YyQu z5xKgP{P10dbF`rK&SC#Wm$@OaylWq^JCah7=vEkkM&bVQ13!8Kf+u*(r z%nFKf8IOQs1va0QDjC%(0-Ljib1V%l5FB!%kt+vngc}+a>ldm9g=}aPTRB*68D4ea zP#d!KyzMT^Ij%fz8{&;(!se4$ju1kWibp|u$>)yF1Or`jaCneORUt}#z-ky}IFG(D z1eVB$`F&KD*|?FwEwHEzRk~lOYFM1GxFS9{Xu+)D)>u88UBU_sL#NZ!_|!)~O00vp zZWLV@Gq(v%0%1B*E!%dV!@CAejSqkLL;Tohe~#1f*)HMa<8yv6Xrx%PM0Eqb_r&2RkH7kU4^Z(<5nk1(ChgopDzKlS6Ep)M&~N#w&}M&4n{PL=)t zc$*>Fk3zae$-=SM~-UaPD8d<}bhgS8P(KBUkmW!&u0YvxxLUp|Uri2A6&8 z5ej!z89sUW@S5A@hA?LYjDBHvHBj1-U-H_-DV$JFj1Z zRBqLgdf>SCr*sz%rDRRK2-0&YeqW9h9ywC5!@`(G>51+>mIFoe1~~dgmm6f89Awg} zrNIxSF_@X!AF|HW_r z!N1}8?emlgP<#fpq(i|%Xtkutb1H|(3Iv;=5o|QN1vhg;N=^SzIHjhy>@tFbr9`p$ z;8-_8m5U2M^6?j0=y{3chm@5X#-vi|94wf!Fvs8=otx!I_ll1v9|EAkfh22BQO*>K zZ`so#HCY$h5j_xNf=py)B)6+mGDe1LdhBGEl~jc88FelWRWkC5C=E^DRlw{JKB<~p zi-(?tj7^+sC)5qyeIT8|BEe#XSL;Bna8MFPCUD!F>t*BdaU!BDJJHlVgAYYBNu{%L z(8)BASn@(IFk+=e5^0A`JO)O?OJNH~O;A%@QpTAqG#N+;OUabbw2^<`7u-9G2So(8 z-3lI^3x%b?3VTOUMut}ktpq0#R!^gNcg1Y(8`%Ui8j7jy9+5(c!NyL0t(Kwa>4+wu zrIZ^!e5`E!%CRWVmm}}Je#q^r?m#}-xkv$``a!9!-8{Sfyu0OrrWxN^v?Q}&FN!jp z+h<2^tgx+(HLjd2m$&C=3{|YdkYzvI9(i_n#(9?jV(Unqsh!1zo277XFF-nXYQTX@ zm(;JUf=|jc9;LCc@*HD`;w&7+S#1InGvR(ts5P1V{Q`Yq#!N@E@9W%SPL~Yla2GHG zxdfv*%&g>&vLT_|hvpa9;mtR0IUE=M>g6Nij|?juWno>fDXWNZk}T^RKDnQQ^gV8E z$`+HY3kRHo9VnJ>u6k#srz5{KPHl2OGNPvzTz#^}mFgw?bF5)C&AO$mbd1#(R0|Q`{8H{NOUWqC#$M_ZJ7$RL^`aBjDr4)cAFld?_vT+(ea zcNW6#N0R-45$S^&?)>?meucvZ(^5YcaT=2`8*0I1Vp3Ufx+;$xVdTG9SXtT~pZe@C zazD=W*Wcp=gyoG`MX++qfAk;zLjK%5%_iTEPb2$q70z$}?!RC=KN12>G6Az8JZyn! z`dWIQR1|6?LR>0MXP%J`qZCR>*(O97WpeHTkx4d-m8hPEeytR{aE;24z{jBI$hEa9 zhkC=Sb)(tdlcnjs5O+!_Xhp2Bdh$*d6=JNsbM1^!Zlw@oat@)Fo>HziqNW^luwcfD z?=7-pIzsxK2xk?gQ*kzQ=Q0g4YBnP;nnc>J3mOZfuZby8=$t4KY;xW^ms*<6XE4<%Qt2L; z!ATE%_q_++yIeR}&HhO*_*`)YCmJU$tRZ{D`bOEU>{AjlS9adl6mYM39u#4OCf;Jg zB4cl(29qr>s=gsoD4Hf#!I+Ytue*an6ug75agk(|t#eBWXFpP06j7tmIfv0>V~N2e zFHhGo&qyATl0!D4g%2GokFjfSJ2CEMG^o!QzOs$ZO{u`7TDDS- zv9Uy_oeBfPdQi$C{THKhTqdO!wo!?B<)V4>8d8yNoW~=FR%xy9YJ*mwtFq3ZN*Ylq z2f`Y7V3gEUXAou_7o*2uPDMs)T`w>9=z8JM4qSaufW`toxJV&Faf26TymP+rcke#X zA`R%(ve?g~X6xU3lu!np zD{yK@N*r(*8ROD4=Z-it)p%YT$AFG8_cfdtEDB>5x=c=eu(_~`Bc)JkO&g!US%TSx zXQqrP+y%&zrF~U8FYoW^vqK%=gU*q4?s4L{;AOB{V~VhNXVe45HX`;_u?E$YX-Qx_ zZ4-54vB|~rAa<|WuIhqUV++}DOdA?24CQQ!llA1iRkjF@rW`G?`_F6;?wqXw6~>Cz zfh>)~sPwtfY^6`77DJgZIwlRHBQmo)W-;FWnV;v4kA9qlzwe#A`u%N$?J|VR4lR0$ zzU~j)5+gY$vKs{5KPc84BlyB^e}TXK&evG9ec;c*3@t+A$|gaC^64M`(KNYgdW_7$ zWbP+|?88dzevN#kqPy%9o>G9aZ%=~D!+pB^Ya#Zi=U2Y;hpenzLX$vAFvD4k^0>Eb zHw*eyx~1XvHjJvld0cqo;~(RH_?3Um(VXA@m%qz$_X3>_KKJvV%S{RF z_@<046Z^JD6!*#h{eS)+J2$A}lDv~g@98tqBUT*dnT0~Jg)t`w5zZ8l^f1{Tb01r- z+;x^@$(U0lrMoFlm%GlY3e#!5XMasN#>VQE`*Y{c1m8VzI%^tYEzP%&Gg05!2>iei zp-E6m<*3P*m}TLrl@qb2*Px;t5$-*kc^4*^p@bV)re7A##M3pP`DJ%51%=>HI$;I% zlLUkF^?DUyxMO<>AkkXv-|V3i~|8VGB1W~N6s@1hUUR`yF|NBq{6y4BEh~3r^5BWTUu06oH9K+oikNbhMwy<2!CYBA zqf>wHGjH(&KkzBO^PTsZ{efCeJd;9bCW-=M)k52ptEN%wK(MMKv2nDL=E$DrD_0{l zKM-4F=K^}7kIqF#n%Cly>&O{7Y@l|V3lo5 z&au)|SY6O!9K5jj%DqfNwshFA-an(Wut;HOdVH!o-Z!pg5V5ahYhu8U zwjk#-5*IF3xfSEEEUaVF=b73Tu5&PI@WPCsarP6U;ANp5PTbT3(>3*1OCraItD)XO z)4YXFjxxEG$|W-DdJG7MEh;BdYOIJ9Bns1@=^157yt{7c1M_^T@T%v--2Q#|`@ME2n$*UR}3&YKtUWI7GToc!VM{Vsp|jjwS~V_XMa7Q6&D zgVkYaNql_y>LqW#{j+E(d*krafD))AvDZT&o`#fNy4ly^8N=NroxP#B)yh}?^3V9l zn;+c?j)gz^!{1}O-qT%K)fllra}KdF`yjN@0GooCr`g&Ain0W3*NMaffBYw3=Kk@F zm@&htv0y&<(8u27vp@Y=o(!uZdp8c5#*s))|9kJh&%gdx|B6WiEqM+_Cf@Eeao-}H zvajhk95-X}CFL;_I>P9kYJ$~;)f3v5W~qkDpiE;?qt(KU;JO7dv)Z6)#RWDmsE_1* z)X6b67Mu||v~^$Twu9x=38~ECEX#uGLQ`jBaP}irCd@5wqRPIRi3DwVZr_&3fh20d zeCDMrBBg-1u+R`KECNH68Woolje(C28o803!ZRxzD*Lt$uDif$I>9x-HHAW8n z?jOkf!Nlt6@cF8i-6f=^xM;4}Itnh-qTJrR*lBtf)RYyc_>rbYlS#G0yI1GzL2Dza zd(yCa$D>cQ51!Q{;v1ta;7)X$eA`L}hiRnEQ=<|^XID~PjaI0{hlNy3+pfk-~ z51w5J8k68asAP*}soC}z8F@09OrP{{3Z2fvI?vpSQg!2A27@JU#kPP4$K#P1hKxsA zSx|GD!g+;9g)y%*Efmx2WtiY0Og$0~&lG0aI8Pu7kE$#R2Mbosf~)8CjxF*=H6=TO zmT_fB;i@ZY=?NOMCEnb#z^f35u8gQ$Ik41~bvvVN;UJyqlF{oZ3{hfSSwcA59V!!_ zkLl{CB>|H=%FJ@8J_|E8(1OZB%rn|s9y?@PIUvmm& zl)_q#zHJxX`nQWJ%4k+^vg z$>Aabi#-uT>_b89x7h@c?X0k5j_i?Mq@W@E$)Ef&-~P)lQ)FB?F0DH5>q)>;_0<1Vi2YXD+qvHtl zl{cO~p)ZxTU1>2`IAxxNyk!qv=pJ+{sHPnmgKElS>y%jY02(ztELE6e%E_tcB+W&b z!m>%IB>d7VVag+x?4ja>PfS_}8r>7oK8LYYA@Nsv3n#9aW&z?^ccxG#o!R2b0z|1i zU!UU+RVu~udn7Rkt&9-~Cc_wgWDc$;Rk$fUsgnOl0J2bPGtB1b>U=7 z9v0mZDOAfqFdc41awSO6P$DL7MKZ4gxmpl`$QS%v$e{43%$m8E6+x=8Xi$B_y;H)t zdZnpwmH{#|B-qEsTqjB`Y{Q^+T8uncgwb8tQC1gjO6A4%InOQ^&P&>hVPoGRG%d&) zk)@L(3_6>zmjcbH{b;$F)1)42$i}7}8xX@7F1-HQD}3h7*Z7O?e;3;>lz=si>8NpM zRk+ic7^Cv+!wV0W6;VxPK@>`v_?<6)8kNfPXZK7pXnW(=-u@i_#ee!D z(@`IJ<|`9IC5EHLm_>5~_lfC3^tAu&Yun|NKJ?npd7of=8$OMEE^@z$i24z9K$w zZ^$V05T+P-G48YxtD|y*)Sc2hK4w0UbO_wKvirpD1CAz&72|d~@WK(y6;8IH7(f2t zIY0gRJ-6kY?Ua~!h`_>`6+{Y`wsV#HJhj?{nz5A1iqpqHe8#O1(r5#Uz*HP{<>9D^ zR?U5Rc%fPD`cx*?BO!hogIDKDNMkA!k3jQ|MV>k*3MGPz?<~`t0X&?Y+)cYb((4)R zJ6)Bn%k%?>6ys>Q;OlB^cw}+e3VH^fy31V{| z0jtg=6K9gj8xGBKXZ>>*nnH;yTTF~{#z=32nDcO133ZCyvZ!YZqjx4LgmwxIib8D6 zQL#zcVz3Z=uytI7S4*Lli8ns>I=}Sxudyr(IE+w+Iuf4Q4S_fgB67515Xr+!-+mGTD3*LVFH+bt4Zyp(! zm+-lR0`n5Ug7WQmzQqr|^G(baRCCSdhfm~!Qf*_BnY9aXxL8hQrg>JyJvwuAM8RsI zj}60cn|N_~!Dw(>l%k#Mo`WNN($_PhvrwuYkqJfnqgPS889-~gIo>pF0XBX#GlzkLtaaL2-4wG7@ zr%X_9oXvO~*)dzR!M@|gSmq_!I3b7{RfR1e#?I-;%50u1{+Ei7ot_QAWBMT~yizKA z&!6G@7w=Q28MB$uE(FF!2L_zg4<$>X4M$uUo(!QP#y*mPq;|qQtM>co6lv6#$9NMS zeb7em#GHrL`O5G9V}9o=U*X%|`!;8V?KmPJHS;S0cd9h$>^(`Z#dFb{g@nT1;7*OG zlJ6gZF;Xr$EhnD8_a0yW#vibbgepGn8%-wqP{OipnTxs%(}zS>f&q8u;&4-g-}=&9 zyjXX>_p|p{#E`c0d;j1oeD%NoZ+N(W&hP*0|DEA!B9AD9>5&&PVr*#132Q~zRMQqL zg&M-cwqB?#gsp2nxozlLYEn_!pRfQ zJ4%KuJ2T;(R;DyC9y;^e+XdBN4$pmFyHGU<7Ixne7w#tG{>WYw%ZIy^iMvu5?79&MU^d#Y7^0%&9i2BBU3UN z+?mXn!l&@ON^MtRA~Q9c?pOq-g1WJLCtL_Ub1ur`7)*2J?7`Lwww#!8HotJc@4R?y+?9z- z-`Hd2>Jxa!wB(H@g5d*GXDN3SBJ(uEsgbM~li-B0yz(kv`qf|KeDeg3DCy9b)!V=2 zZ0O6BI;7?K$eCoVE{UB9K1-^!5@-nD`|I!Vr(geLim#X@r(r|TSkPE`+&dSWcx4() zasr1NZLF7#FaGM=Io%+r@p9Ub`Lf*EfFFk^1I%A?R3uq9;m33$TQMIz`+(=qUhu{n zZvycA#fSXxufN0dXCG3^jLgdW4;y6|CW^`czj8Y{G76ig)GmwA&Lj(CL^2%8#5Rno zxo$8Y{LVl8N4)aNE1B?@ydBERvHa2AkO=8;dp|f@LxU*BY?Ug?i*?7F zG1mpe*#+*`juPCQX14K2kHTvf^bxppHZykDgtWyeX|dMmBUnOM1sD@8Hk3vmgVA=* zwXn-zIzq+Wg>!eF=t%yE-C{BjZ&X?E=pb2in50l*W;dmUFEZx~jEtF%5vUNCF=Rf@y{~0>p@Vy^=2d#;^kSN?B zv@vK1s4#~>N#%(}6307vKq*H#U~!TgwE%U30hL#!QcOFKKIE_@U?G# z^ML(jZe~PIORE~YL-j(jq%WTs)T%TUwl=t>(4(`F8it{HfW`{ujajd_-Z4xu4LTK% z9o1B#RI7yN1#+@r7GocgNP9hg-iPqc_kYNT&o0cTTPT8;nQguB?q7X_Z+z|R{P4XC zD(Rt0YU`ZOu1JNA*ql;6Z0J+xDh&^kEXxafuJMi#5 zPqR3V)A|_;V=XyqTVE@hhJSlUw zOH?w4B97HU)hj1~xhw}l-%&A&b#67GI&G{36SD;(2~;{8GzO0&zYNoyw%H(<1lG`0 z)l27zO<3fVp_!q6%BIR<3?A9W%4JcaRLcIqbkt~{$^-BI>;=!>drlDrCT4G}{aKFb zr(3R(3HBSE*vz?ZE815o&c=y4Rc4er8cW-#G4N^OHJ!LALX@4wbH_T5PB>h9?vN>i z(H>a3@E}1SD}@uy1C0~9oe}Sh$R>hi@q@Ee+I8mEI?HLWoCfL_N@>ZQ(UlWU?*Tm< z5@R^k7OI_4GR571ZUf}PwhbZ*Hz(!El0Vxv0-}L7LKdEf^8UUuj|mB9ijD5cu+Sn5 z8V^i3!PW~GjJjUAiJd(rB09Ce<+SiCzw#^0x37Nm1&kyAV38yEBcX{Ozt3V!&l^Q} zHU^F~ibo!7!Yk&MT+PKn&b2ptaJ<%Ob@q6eTc?k;N93GDYIa--gxL2E~8UO9l<_2QxB>FCcN=v;q6bn$wLd)ZG)}R2sUwwSEk5G zvIewfJl`Mj?Kx9aPHJdbc7OwHfQ#PP%%qj*VD^zyIYg@cB=EjQhuIVirxwUY9{=p}Nz%Gt8)# z>mh7sjmC*|!Fg=7Xms7^vC~FD_WYhsrrfAuT*1e4&7m@sZ_^Nb;KqfJ&lZ~!@j%gPFTa5 z9w*J*hi!J3FK4Y;1D2q>;C;tcz?_rjO{)7&U$5Lgd5!7jHTwQQ^}Gf7bc6OZ7@j9f z7mzvhz;#fhfoj6tJdpl?S6KU%C)1hN=Uevu1t(pgK!0dFZ=Lf5A6qKzcmdZ^@X^yk zI}B9;DjrH38>d=OEA-Vdgn1UEuiV(o?S5t73(Ioi3r`k)vF8+`mO?uw50fY!9bw0# z5*CEF+;?k5N9EcZLpqamJZ{kL4C{Pwzw%%G%m0{v@_YZ7KmU_=FdYDpKySZnSGq}i1EhoY^mgvlW;W6%bu?ll_u6=M*CQM+BjW$k%bfPz023JNB z7}pQEi5aBQ57c`fCayH9RwfNDo6`j}I_sp2I&*ovM}4E4LUg=e5PL!?Gb&e>y>ZbqMQ5sIknAMJ zBXBD_y~3jxs_)1MoPtj?UM8+>XOf9u`;9O2^!2wWhr1>x9nKU%h~_QKIe=gTmtbJ1 z=R;A%@@Jiq;<3nEj}!dlXYcaOum2(JkJM>q6J^~yU7R}=9%%G{GZkY$I1h=%CY-f5 zUU~9_H$L%c5IusgFUcRB;K;E^GE|Tp;ig_E7{^)(35Hp&r!EhC=R5E4rC811Cr(pNrDE(5^U*>GC{F93p;QWOC^NxSlv*-*Q_T1e z|LK23Lgq4{>&L9+|9`lO2>$IK{vr2|7Z8}Lz-ZY(Duul(#6Vn$u56-2Y@DR#VbUsH zp|j@E@>nySmWjs1Uw`*oeC?0^fDc-(!Dp_t(RdhxRbZA%Nbu-clXUO-J(h~HA>Ej) zu=>tqupXRzHrpIE0&rXX)MK9uRCA)(x>?H7eCD(ef!50JF3Ma+h}ss zO?wzfW08$sYl`uJutxJk&L=zOg~bGAr;Wxc3+<@?(}er=8Kn&x6RN?)j`&6?C7T?( zG8ru1In~N*Z@kH6YiX|5!8Aw%u4E8$566l!hcYBH7ywf_5u%Ld*huFL9&{g6pcF$7 zZNg-Q1XK)cTnVWx0%Ez^o2cwQ@r^(JfB4JqeTVaOhcK8Etic$aT`R?%iGq-@JC7ap zKw`opl1&pUB?J+pd1V^e4&2edo!Gfx8dU3CdS`3L0ay#`(R@46ki!~1TQb77=7=eX z^5M3#t{bjGs8h{QH?|l@!zaVc;ep4(R0Q?GG#OK!pgTeuqBEPeF-c_;;o2KPMMZI6 zvB=LClD}Sa^8GS)%pIQ=iq3i5AB_@9NZ{_ABjK5INy~WegIiN}8SL&%^~Auru2)1V zfnkiC8j(1CkB&qVe$_Q`)Zqdo*lG*S0GU+=Gca(y0>P6qu_N?7K}@wQu&;D)sr?># zirQ+j|Ib?Te{2kj-OyC&GALspd#Cr#>Kmt6nCumr3KA8p0LnBTu>P1oGziX&%EnFE znFzEO9`=oGU$NbI7!z-N@)P|1FTIsjz<}@z zgc>!UsVBpBhF5;~w|<*{@H=15{rDJcaSOb{F3!xF#>{YrC}lNfpZK_)S+<=|Jw5S- zPkn-ia^|hiyuq*jozKw8#Q&xPw~fibG%3QDVmwm0krSbvN153y>)6_rab$=}Rfa#n zP-3gd=?T$;$DY>dX}xE$T;H)@nL@d8;(gLrVm)Y5*~^KJQ;V~Y#ylq4z z!^MwF0g>^ZV14uPoFZCon3;$#PjzbS?@cw z+~B2h=@&4eP77|8=7oy~f-&jDu)?S-e+{#3qR|ae5z~+LMi8Y)igUXU&Rmqj!*c5u_o8SMC zZ~b`ZW=ht?E(KF#t`j%r2s@4a$nR86V$`v)#sL#Uxr|P&g=wDC(CgV^D{?ss2{kRT zDm=6+R(4LN*$OHP-}>H<_&@&LH+fovQiKn^@Q_zhUeRM=sDsmd27AJK&9Vcd;TxRX zF$>C6SZbxaviU^lM5uF)!h-N{eZZeT65%vW{*+lk$UKhF={DHS5)5VrQ{g-bdrMhf zqoBIyi!h+doTl4z<*hef&z4y4Jkn?iDjT5*NEEHKqG&ZV6vMI6*?^nVi4rsSk$C!D zVC^ZY+uSiW9_|~y!su5{k`?;<*a=;jednUeD1&{hXxK5CF?wuZg_8_IX6CYhAKwXG zxP&tjjl~dn;kkC{TX16G=?rQ@Wl*B#CZf!Q2a8&sp__2FLHEISWNU^Oip~@V22ARl z^#=0^Wk>WxDGOFN+;>Ekv2JW@V~jz!j!C0LZXGU?Ek2zVOedNI6M+l}PfUE6GgR1* z0P`jCLQ)EttPCAIS4-6dgPltELf?hQK9G`JqnW}aGrbSI2OfDCwK$Nw(IFap!t*f+ zpkb$**S;DIB9tMZlBxfyN)M-Gs)?uPDfQ}RjImQpSn7$#(dp4yCdG9khJ)<1%~)n= zrqGk!u`<}Y5`CiJESmD4A&Pj(op?>!;urz7Go(O+?t@V*xg+8{vVzSloEdVM61`zH zO~b$V$-7)*!ewKyQD3$WB6wh8nwQMg#Lm8s#P`~S>fpU_L{G@*gb2#Ub-QF$6v4gG z)p=@J54>Kkpm)qQFxd&OIW4lhsSH`rDA|5#7hG4K&NJ18OP{Gra2?KzZj|lHr#|~x ze&z4|6W)FIU3`6HOcft6VN7gvPeGn|j@b?8g0hrsTSz3De?9iHccLsZ^ZKh3-+SjB zzWI%R&-b@%DyiohX;M(TW$i{8fs}>nS7bCAPOpQz^Ak27eD~e=`0xJ9f5AWdC;x!| z`CtDV&Zk!~7s4+rDqLeQyeFY|GJL;J-;D@k9KC!MCTem~yiuD`%ft&$e&key%e51B z=B8YM2Gbo^sd%hxzH>jI^ua5o=H50OiHR7>$4t4l2SSXydFDkltOzcHb#3&`IalXg zrp!Xc2|aQiv0jM1vmY;vl|l24W66)GN^gx&r+49%^TO_h%ib9}U>GtU_`;Wem$%;f zG*S-BX(mG8B^WInA{jrS{Owvtlu6>K>w;yYnz4G>#ewAW*`vhl@V^xz>Ly)MV@r#7=tFt->_arN_KZ%rcWkN{8371W`o42x${F}@&#LT*MtFW- zx_4aj*>To_ci}Q}g*Pmx6e_~%Yc?D)C@ZQt?JBxsJ^53c7eb9KcD6oPv{1z;%!pg& z*kZ#Fq*h$~us&C|xN>VbNptb6%Zg=%-!w0MY7_%;p%-H+6$d)*H0Y*A&(5%3# zrXJw2rxdYDwygRHaK~d{hh;ewCKcQ(O%$UM;dIgCH9rtfVWx^;IM>k;B%NciADNtr zdS)e8Z&WY1S1JycEl!JZkaM#!2)Sl2VRSP(osy$BjE!N*5;Kp?u^fN>a$OPHff>lT ztjf!0jb+A;flW8BeN{E9mPMgZP#J`$nKPfC!W*x?&K85_8z;}e&MwLEk7CT~?2($} zCnZ+^Eg}yaUAa+Xlr-#~P1t>-s&X?sTU16g?qX-w$|O50#$_CGusWki(nkrr4jRg- z=PfhT8IilR*IzyJ@wYz1FW!GZ`wLp%DLNr$%%+LP9xLt}sHXLG?z|F(iJ7X6&YqGa zH_Vf0cdKXCu~DbO(=stdB#PV@<~n0sxY$hC#5_P~^!&*LRh*~v*0` zI7NA}J9~qNz4JHEANh+9KHwBP=EgEr#0K{*AO@j9G3AzaybK%Q>{htkU${OzfSfqX zh5HZR}^L*f%}ev+G;8y@z1@WE1pO=hl5v9WVgE4Pzl z4lnuvFOuMnVCYWoPM|z03DnvP4MV1ts_?kC4BWQ#|40bhF6eNoOgxN7KK|w#eDbrO z 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
  • tHf;@q36bW$G4QCt95-EXjz9b1Ua0<$JEctpg-X!9-yU(0t zU~HH~D=8m|1|*|turTO7vxy#zk{lDIU!bfa^{1_Gp{cXTwk3yp9|MoI4yt~@Lc zTrLl2a`rxWZiclRecN%%WHauqA?2{6H>XKHz6VilE3Od{Hv<{u%(n;ho*;{}dt_#k zA13es1+jZR0{hNlMoXDya7l()N9)AqMsep%3fG;(%|^&(wMI^e!8RfYoMg~C+lJIXUDCFYbsCwy;Q%7mO}(r#p{cs}f$!`QUb zd?H)rU3*LS$|V)LRJIm1;lxTqV#Fd8Ki|R3YOAIw8AM64H<6Oc_+8`V% z;vsmWp($gwv*oCfHIM#6@3-JVq#1SRM2f6O&$MKm3Uq{BgzT03*pQ@Aze^J{%Gw1l zO7$7BxQPfsOKcq|3#mADH;e^xp;M`Q1Uw}}$}_`PR^mnPB)YWN%a6j86CgZ1eu!us zK)S`jd1xF|GT)FUmHRgM`qLki?VDR*MpfYm&lO+ko>(nGjgj~0fr^$9IQC+~Qk*9b zIhhP6PsYP?;np^A&|27rB0Y!5GAomBbP_X}GBGmp2 zWk!>-_B&aGbO^_)1_gGtIK(W&DI*0n)Zml^?K{;oW2&@qkF0}bRGqs)4r32lCb~FM z1aE`q`xB)^lKOA)LTgr5Sao_mWFMq}NzV}gx_#9jvMdJ|fv3gMzipNx>5eF9`!gztkiGx>E z4FkXyj*!SqnMRu~9X|sOCz8X^co2$bf-DKG8UO1)```H0-~5zCj3JRD*^cH;IzqX4 zL9&u`@Hj0ziLep3=*OvG$8Y&`Ef@1LK!-B;GzjobZ&r)CT{l5Z%3mpyK1suA{8ix>MIvqc~# zXcx)kJToMkT^C6d&+rWnLqk%#OXT$20=`#>1F;Zje8bpWIF+af_hFbOGGVSqrqEH0 zxHvagbPVn)NQp+&Z3~g$G3f$Vk)H5!|NZY`H`j;(rCCUsV=z39|n}i z)5KgBPIRW?-26=09JRq?tt6d!*x{K&enyg7P@c8 zG$Ye`JVbZNaRci?1I!YYziTSE#+YvMfldh{h?KXXz)nwFcnBADh+8Cd*HdyyYsR& zUfN(AH<}w+3wwf+PWTv6@e*j7urf2uXnn)PIpz8-8eH{)Wkp9kEOJ(!8_3wmS;;c7 zd*laFNenwyN+lk;UEoP3vO@PYxFMbodZSR~&Wq(EmCd(2jXF)3ID5J?xzeSQ*xBt) z;d~f0cf^!U3@JOwGk%P|TX$S{hB;$*=IYD@N$^DnDuY=nrDn1S+gK@WkB4imJgtp} zaIWCmNJY5a?wqf$DN9HIgVLE$O>vm^&d{Jc+Pd=D7r(^E&bcH?Nj&YaX{dct@czrOal9g3~1-vhu1J znFV}fwgkzjxga>%IungaVbuVO%^K6QpZ?-!JihsW^E^jxglPMQa4~M$del85jG1Dk z6Mx$z;=c{`xY2uLRQ$+|AV=Mmc*&SsEcQgB8XWTy4B?BCTIUz90=_lc-5!8x`j?S9CdXzpW&J zYY}$K42&f!XMrX{aUqusW3VAK&kQ$Qjc4F`e#OHwaesc|q?H$-N~}&cRVL3Q-+2-c zNn~?Mk5<$WWfEm|2d|h6N(#6cDUFg;{O{hK}EufI)B?*R&XQ7grNTgg5jlgq5xRlV72u4j8mL-#G zm3J@idHejr=WpNg?&X=6+lt-pY;8v!nkie~Fl&6%d0Wj6%5gMo zx(CcH5skw0a^^Sw_P@htU%n+-qG`s5GjeCJgzQzFZbECFqyhI64Ih{dn3G_5tWl+~ zD6B^gW*biaR(mnnm1xI~j^xZFi7^VI%6+|sa%H(-1~wv){!LBXIrIyc%j+M+X*3)n z8-YEaDeNQE7phJ@CFTrS6L%VUbb87RZ%q6qpXm4yum}+7t(M?(AD>53pM+LW*NKEGxw9IVrK-jcV zJX{Oiz{s5InY#t^;BuN7)|eWk3C8FwQzg|PSJYZq@=nSVWf2xhBy&VMqXU-6*4b2J z#Lb;a<0dtVQnH|Z<=PA4gO>x6bV?fZ$@UV^Es0Tmv&4|FEEbOn+k+dF6WD}{lg()o zJc=qx%{v#5FZmNr^+D^I<-B0}#5x9)h1nMt5<{Kh851L?bo9puyA)nY+&=CSu(j?b zNK9lBf+j!gr*T6ukJ0JLj3k{cIbzR9TBuT4*_gzU;fz`^SBmZA5-p^y_uyZ6N3Ebz zArCI8(qwRJj(NB=&JSbiv&-O=PEiLGV|ZiIDMGx~xaI_HkaK3T%!^0h8b**85mGVIFs^0BeDKm5 zb*U7D;lVt(i*u70f3^X43jmW_520fz;~mn zX(WMrni+dz_7)Bi3&i~eXPXjtYjjsS1Vl{}Z9ox)F_?4a<=ObRfBiFxK+?);i9TXf ze@TXTAxmN1UdWb7c_Sr9%o)XLqhPYpb+C=j$)cr}QsVMz;io_TF=ak+y1t6rGkUZ& zBK+#^k*^W`HhgRnS%yr<)iKL_<3duRQPU-yEZ;bGoWam^fYmH!3I}ZO&;I03_~8%# zcW&!DBr9{RbP`D>iezS);_}t*q!IuA;Q#*+wjeiv=fae{C1$joRkW8&kXC#6sBq7 z-Z!)>DxhMdBU2U#^9gDuNoH?5YkwiRvLueRl}2FLp`^3BVJGYk?)_r4rx$&|$x`SB5 z#vXxuI~-K@O|EK(q};nv#mM5ZDM%83&jp@t1M_eosXB$I=e7~X-%S3Nfzkx3Dxx9e zR0Wr#R6yd%{9Bo>cuZ0(B~Gr0LQ@XJeu)dH1q*6jH&9{ScD(Nh2BLHc$5vJYGt&9; z@B>SNXxtX92fM@*6b5E-6Z*~v3-9-V1J)8}GJEc5skD73^^Q*i^$j5&_@O#UoHT=t z2(_dXI%JE^bJK>|%rzNig7nz^y`;iLJ2IS8UbyK*9>Oc%X?>%Yunr@!tDMWs^F3PD zUO-0$&14yDG0>+=Vzn*mmX>+H?_`<7=aU;cP2_Z@mc*$V(_Cm&uIHItYMd0yf|Hnw zamgLaCpN3NzaXv*S8|ROPxb*6MoKh2y747yRSZ~;;8;%ul`RzB3C_vl1(PZx1;KP! zBbC7z&ZZgl&O(q}YggVkC(DiG8TAw0TlgZnK?_bp6UDYQ#=dD`_Qq{g2Ay*;a@*-7 zHXBq^MlR&knQ}q;3CoRQ&zK9RB_n%GXRyJL5{Y}l1Cyk1lg=q+(1{m~2E*iuzTaZk zs5RtTDJDqGq8?qu*{MwRM3P2ZJEw;?Xs)CKl$GSTZcFU5zy9J^*z?z@I!PCbc-)eQ zAIS3-p=*Ua3$+U*;g%ZD>rNGA0@ftt(HTQ{w>h4TlQ=J)k>N-R!etqW$CL50!C(IL zZ+L$CnvXvE9$7;F;2IS~voI1Th&i?B0oOXJ!VYLu9784;JQF=q2JxY=gHw`Fk5C^7 zUwrWeKm3=!&!7F}pQ1W=RLH4fDwt)m1bO4m9?X;;822PW&rHb!7p}@C!kptkAGm<% zF7F|@X$eM*7^63eHL^^E<<}T#;muUh60w6iC8lNOq0U?%uKe2fKjv?L z^lNdN;%{x08n^IaH%oAYpe!@7A8Qzb>awVo)`LY*dh8$3O|@Yz>i^U0TA@x@nP z^Y-mCU%tQb_W6nTPcOV*pSbr<+jhqN&U0^seriM1BRAHgF{L7G#__Coa>^u8kVIC< zl4yJ9v#-7&WhEz=@Msr}P`Pv|G*xErWQk{4Md%~ed~?m*Z3KZR7y7!>j?7@Q!8lrC zV;GVJx1A=5tU|UHTo`dk#=0414icIKBiLy|w07Jhyq=cx`3IdE5-bBhnlsIVLRwTX zGp_T(K$waC^iAUH*d0`jD~ZhuDxD>t5$ogxWf(6Cr&8&C#CSg`x6SA&p|*2Mg`FA` z7Fj7d^M1SG3Xe5K_^yPMPL2mslFa0ONCF3!d8X^c7#;I?fX^;eaVAZeDlJ8KJ&Pep zf{utYPl<=q8P64UVV)DO&lg_JXD*j3y;P>6f%BEjzZI8r!5tHW->vu1iS)RoRoO^IyEdyf{3^@?ku zrc511Cqj!ui0b1|5|t@Qti70+Sb1`zn38)#B(aGgX&@y8ecc5n!GP8}mNf9z+ELrs z?>A1@*OVOQ$&gO~zkQi1HxD^vHQWpP*!lSTf0x%Ee3zem_EUC@Dv<#wqj4#P7X@jJMU7n*?^EoH zQ>LjS$fv#7iz9f7AOg)uwCH|!=fmO}<+WNSQ;FpRSpnSvtJ3lG;*MoDrGvF`y)5 z41W3Lr*u^=%PC0E?o2gcR?0@r<*>{q`Y~~Iy&!#Hz0paODFmkB^Q!TXPl>x{iVJsd zbQc~pZn>+#H6_l;Xk>PBWT?cL#aNAK_>95G^ASMp>}%)OKX~A~kFWU2Ctt?Jrgx+} zqRLx5)EGpAGE*4dY3ZA)w==ttHT+&l1XAKI6-hmez^aT9?4W=6AO1GhZ~TjY^>28r zm02_0Ks84@hZy(oKCuGt-hRqI`iK7+KlmsAgesjs{Lvq=Of?SCM*w=VE!H(D*gr0V zES*b=Fua?h-Z3BaV|^q&fjyp zpkddTyqz?&6y@yj`Ezwz&9-CGPtR z-d0)_6rXq1<0WrLjohQ1Q%G#4m?)Pb;hM7?5Hk-9gC;$Y@`Zeu zg|h%wc)_t0TLO*RDp?XkARPcvO%mC+qqwoQMnlmGZG2~ERI}8cKU{Pb18MRvk+luhQ!fU^=Xr;9yIJGw(&WUUpCvhKJ zjOTD#?|4qAcQz}yZkQOa#dwm=x_`sfD3p?zTY_G3;xBisH>P zfSQ%ICgwWPdOTRVWG3n8sZH_C*u==H+z?V75*5nF(pYcLa5Hh3O$($<;68D?&m>1F*Y`c)^g0OSf zuTfJvT_iiK9GmEmzJZvyQ~GKT%UK6JX$aii4u>m|v(E-3!BvQ(wtaXtuIg z#cV?8bT-r)(uL=3<-ht*e~0sY;@|%9|HFKp@jiH!D_SNtYcv|C5@E?Sh+TOZunTvI z&v!?^{qon|@GMvgX256}A+gKKY#rCaOOBV&;u}qGkp<|3T{?ACt~HURqeEG3a8^N7 z=w)KvIfB7$d$WoX1cUz3qn>St#=oOMl(kLYk!rK^}#90TFVk8rG z-?>_0E*Z{+|M7qNpHb=j`t=dB6qh}#tm95$#VNGBAl-RP!k#az&tI|r^3UlnU*TEU zjuu<&>^5y%t+}0OP z)69E)!KGmY&i?Z+*5jR}wAOiPFRW`c0NeJ=OBZhYO18mE3*|!VjkHI&8!w18USy|j zPVLI@Ms9^c;>)*hamzGSCI&_WPs}J@01KFz;jBGq+`ClFBYPPzzA&lF5Sj%Os3Le4 zw1w0&Yy2+ycIWBVIGrk#iLnRMWCAu5PUQ^tj&+A~PLK;ZhnVzfZ(Oo-&ce+H8#z=a z5IGWYx*KM37_Z4`-WcYja(?`QG0>D_j5A=Q$~bh!W{RYphwDtY6uUVF-bOr}QsQAb zk(a{egKaolE=&T$4hI3wyX}tZ&XSK`s0jO^M&*42i{y3USCesse+_Pp?k)?qc-pcRVyw|GqC2Ywo=oAHOFKp%SK7_anNgA zRgraPNasm<7<;Rr7FhYGE^POe#6~0)GN!`rhMTj|X=5;Ndo+49)=Za@a5*vOiL-ZJ zERfqZOQ`3&uv%hP#aj#3MUDgEt2%|w9Dy-#cUCR@_P_fvZ%$X{__J zd_k>eYRx>|pLqW2m$bbxl}r3wDp`dmQC1IA@oU-1{!Obx$u5jqIE!IvW7uFbVJaG0 zZX0YW>~ye$2O>wiCdLwH= zWRBZ~ZZuc6oatg*Jmb0Yr_Gd+r`tGu?&1_d9=w|K`8=&$&H)%^&{ZA5!Kp-&6)W;j}Rl)+2m7yfR7D zAUn|%E2{Ku4;;bKGQtMkI(fia6y?N&2sd{sm153IhoW`}P!-3Jlo;;JIn%`cKce2{ z*VZ+=&w9pqFW)!kTx;#isdLI@JCyCRBL@P$P)RIdg@gt-DQR$N(LkaR5pb6V9aMh; zLA2=7umlnkNC;>o#EFQV;1Dap7s{&psd62kbN1eAuQliVzV|W)jWMgzJkpW&+H24G zz27^=@Ao`ld-z=(4r}H<37?;zSPmaL4APs-g*Y2`0;!#_PKW{`h;J z@xT0U{|Ddw_;ZfSkp%&t+-0a3Z3@E*3vkSdHen9KtMbzyd`NcV+BZ}(f}t#kcT^MI zXPj`7aALi%_noE2=WkI!CaDiF4MvrW+j^&yt)Xe*t`sJPQ?0zdJK+dLgj6e(BS{iR zjSI&CBYk#l|OTKJ(RI{Y!lH*Zu-+d!+3f z8K-Ir&4GdV2-Stf#apwm4P#2=>t-4Ns1=4eZSN?4o5p662<8F!bn_oyFw%0m`Es1Qf*n~8BxIa=(A5dPtR;Uf^zvXE4w(?cH#9}Ih$g>vDZo- zCrmRvL9!*d3a(TyJk7>22{qTaVM`q1pN~dPl{>9;jTgX_m81)z5z1SbRELDp?8;Sy zRg}>?&6ZHIJDBvqmwV?_7Mdv4h3il*7A_F$gV%S7U;KriX1i{D{`ihZ*_g)39ba;o zU%fL^O!evw-JfehZR6>(^ZlodH5Cp9SBb+|Whc#rH;>O()pXDMIhOty-OrzKa?(AAvb1-eXq+6|aV~DbM z!Bb4thQpcymNq2FGiw?*n{BKCkEwE*#%1665C7V~#aDmnEBw~q`#b#Kzw;0I{7*jS z2Y>Q8m;J(=gSIvH{X)?MHhKT}$YtAkdjF2^{@{mv=bPW;_kQ;u^NnwQosWO;3H|a& z#>iDU0BuIKe8<^MS!Bl~96ZaR^8U>eU;q8T&p-O7-ylgsvrtmJOr5)7vQsV4?mv=K zCJDnw)`}S2Co-ul~@+4}Q4?4NZk%5zD!)E~OmbFrJavcMesBjj8=7DsV(MT!X z!hx~U8GYlkZ6nE%lAIzdk{7=F$tQg8`)^nd(e}dvpDq*bJl0xW8r77AXvMWLaB-## z)*^gxII)koWH}zzXjy*TCfhaRz6H)*HNyJ0K)4Z^0+Ns>6ffv{;C{`VM`KQ~30MXZ zt{yp>wPwz(p(0ti)-s99C$t4sai=$2(r#KhXNT zt^FpZ5xBn>3;Hj@k}@d?Q-qWYSm)*IFQCP-=SQ}AvnWe}c?NfeDSb2=lWn`Q?Tvml zuKUi@g;`w}z&*SsXyQhu!=QEe^T~UPB)U1NhRtevh;g62k zm^E?=jd!NA+<(B`de7tgx2X5X4#i>;)%bgh+}gn^q{GYCUo&&6j6fdih}xbtU?QoK zDSYAKp6ubT5egllE*34CDeTR8e%_f=A|+ljGDDcOY2qM|E%v$QL8h!rA(bOyC&Y|3 z6{-jq$ykrxe9FeM#e=V`8ZXHRRZlFn@_IEsf4XoyJn$F))nDYV{_FoXKk@QQJnwIi zl=$H8jzhU4w&(K9*&AGpS$wA?D%^dIVDNEuDFCX~u)k|J|^Z_qlykf~K zGM!7m#2aDTIbYt=Tkr`sI%PEWIk>oxhr}U655AxnB#7rBtm3Td zoW0$`xX$K-O_T*?XE1J!n4FA9Ur5&QQW+^~&8C^tQn^D&eP=F}A%*wDd6*NKaK7<6 z$}OvNU~tMOE(4NH@^ZpxkTcTb-;G?E7 zpX_6h@CYvooTs3RBR0^HSuJj@QxiiPNu#z`isH#JG9{fUeMel_=b)B)n;JMT4tJbA zEUBVLc5y_uFqDq46b~29Bx)9pCG5j~dzckBF4xJL3G};1;N3jP$rIzCQIl6XDG6mP zhzB*`<@16cH{CmYhBs_=0E( z*dO~XjG9O~*lyHOG%<#=?^mX#TQ2ewqL4AN)>$##C^NNtF4ZX}RTw6qY!~w{fde=Rv>j zJYIU(zJ0(91blbp>H{A}+k50&#=!TDwl~hRbKN>)!24}uKW~h&@ow*2x54OFwh3+D zXk(IG@!n__(~vxcy*=WCLa=7m!?e``M>_<)=R6MTYO@!cav=0OHYK-8%&OwT9>l5`eH zXiii*g%#5S#|-PidESku-dI$)Btfc^W?~zLmX%dPos3TIlJl}IT&MEgAAHK^mv{X7 zpZ^*D`oH(@^H=`Ozs~*ZSA6#EZ}I8VhVsn5ooSawmyY#LHRs|^)`{2fQDlW^ZfXhcAd0iSc8_^EqjV% zMbMNf(z$qIl>^-e%#Fb_E(f-;v!sQFqilS1qwPL=An=nbck9AezVdTi_Y2$kGo~Jy zsc=8J(KQ{R!mS-Zs;I|9rg^v;t`;qnqlFs$olNY~aaqV~LOmnC(r3q1$(pcvrAeY_ z)cwR8n`J7-GWU3RryAkEIk;P2#we4F>Jjsuk{q>Q@jMhI7hyLg`((q&$+#=Tm~+Bu z3cDy$JZ_F{#AHbd%qv@R-kWf>L3N`fVfDoDLGx%*QSWGTGDP_D7hkZA3*H+h3%Ud? zbQqSHv8gwsQO6FDkf*Dj!WyjNjZ3@PfMUN~c zAqVGJGW5a4L%>o$AWTgr1=1410wHn_UqK%ToFNyHEN2(b&xqO zK$1##$7LrCL8bG!4~EacbL&dU$`vD3rAnetp(f?3192f~MHz_0-R;JS-wxB9FoP_E zV@Z^(afqX24wO=ub4RUV>4=E4B;)74^ppJL2P@zE>|NA^313rj3!l=6gLl;xl|fI5 zI(81jdGE$Z6H5tiDH;$&3#4kaAySGEYZYZ$0-rR8RV`LSlF8b*S`Q3}L_Jq*XE3>| z3)K_X0ZnEY-%}1+c5wwRN`c?AJ5bvGcq&u9pp!Gs7GmAuvRZ-i_3QSnJ8z%-BXa zqY$SPjFyxK)Dzjl-4v7W5o#Gt0kxx$OVs=|C9)(|3*^LL1afZg6r!nPC6EF-o%=;F zw^+MaG-VqT(G)Mb(qsK6g5G#I-Gtx!2fxK{{oTLKH{NHKEF4O#gUYBB0zI(1QhlH) zk*oy3EemeOB85Jj)^@I~2ZdQu@VaEiXUao&pc0wXbob)**RndP1RTdL_RE+D{#%?e z8>hQ_x;*0Aq33wp_0HKdi$wC7EO!~zsK@MlBa+sl?>|W$js5Xka!-AZM#Ip z2?JkQn9LC&rbX{jg~U$s%-IKJ>_~!(4g7H8_1yzs{a5}BfB9egbxt4r1lOle_=A7) z5Bd5xzsLE!v9$}+Hkt|8Lbqt<B`F-)&?5l=-g(arRDD z;Y`PTVe|OFu4%H*o#QR!q++OspzRT(q{NpVA_P0PjpUWN6joK<_fE3LTHvY0{`pmM zt~Zk4?46p0U4yhpQg)R4oVc%%*f-1Qn3!E6SSmdNdA?EvY(68oaG9AoBbQAOJ~3K~zZZj9OWfgk*4buBK7F zb)k&O^nqzi;thYDP_1( zX=_oK9d%fwl4T9q-;9Y?E*8128z-b9coK#xD-}1tO=<_wqXO%OkHK+9XnANyrIV*I zw32mU=BUAo?AUaC3Mqx-CNf|PS(Th4Yfx2~CUg-N_mJ#~VB)ISR;O;p6YW z<&VGdF;>D3Eauc&Xf4>z>ez??_GI$Z z4V|#N;aSw4f_v(YdZLdW>p(9&Ud~t&Bst48+AZfNCQJcMmE1c`5`Xp=e+6%6 z-oE{mQ>nN0dxxCK>TF|Yt%=imqWO=$_rzM?gfS<52C;ihicjURt{h9^x=+Lvr-c9! z!)jy-lRJx^7~Z3;W6=ca4xe2cpX@Qw7_;13eVw7sa3N6`?(yug!7*1($Ggatvc~0G z6;tJD+bBN{s0U2c$+(5OA#B-3I^LhYR(yhY`iM1wrWnz>XJAlM;pN>6O0FzD-pYC& zbT?Ehrx7)`GzUn(?Hv=j#BJo0H*dJFE2}g{59msh9hJr^2`3(o!fhw*f_F&PN!7@_ zryHy}@Z!g{Q1w84c+K(t$ctm8Ay~U|dG{&5_fP&2zx_}DfcNJsZM$$Ng(d}B;wU?1 zH4Z#b^N}tWL@S59a6CPb*BlbBHM1`9(0%vjGv2;?$NP8hdG~zbd_Hr%Jac}2&)9Z0 zI!yR|wu8e6Uhb)J<@%u*WJF*szWQt7=GPrI^w#kS0M{Jxq%?RRJUdSndR_avx z+b3TC)C2#`fBm=kmA~{={)gZE@1d?7%1ZBNWKK$Qn(a3MlYOY3) zB?>)d&_j5I8juRTHNN-B_ra9aR=Px(X{3p=V7{Whv)P~~Wy!*mhF{@06Q50E)dllC z0!><3tB{j(ZCCQ`a51~E)Wr0R^o2DytYmD0&I>sSq9JKij*y+9i4WHkr+nafdt&-T zbK|1M!eC9x)hac`uC>mEL*7B+aO+)g4NgxIXUhv-CI=VHoK-T1tTgM$Enl~YF(0TIjxB85TXF2x}v&ACcusqn#vN45?&3e#YYjjRJSQzSE~baM{th${JX zdJ-~%+ksLVk`=YelxRm)VBUzr({_*?V6zd^kLWIicE0C5os$Y_ zCZ@%jaNIWMZgD6pJ5wtv`PLwsh-C0MSo`f+dt`;NGu+5|qIz3r+r*PXn#hmnoIv#z z6XB2pL}t@4Z%A60K4~7ArX@|#Oid{&*fVadGiltK#cwP7jHVE>sb}Wgf{v=8h`0{p zr9k&Ym(H4@Q<%W+j;0bU8E+(=G)?rmAX2C$M3dE(J_7}ilS4Y-V<+F#0%r3^`z1WB zh(sH%S>*MqPD~T^^nx*s3yFg`(qa5Gjcjf=&4uCCA!Ulk$--?^G`IGrdAwr$cS2iepEPUf>SrsBlf zN;FYinWO)hO#JlzGsfi!ks6}A39gxhB0Z)o-Hf7w$iUsA`FhhB7#>sSK^X0;n2-^p_SU6uVw{>qJL=JMB9BJ%Fxf$Z~>EUY~XLCri1=^N`s7A0w9FxlF zP*|kX<_LgJs`xM#ATJ&dBo8yBqcDy4@80t7{N-QcH~z+N@X6!GKl|f9=3!0XD_xW# z0U*jbI2XGJuhK%1PA>_=Sq>prnhv!rEIDyHRMMhcc4yx=&d-m$egB@{|7U;1AN=m` z@`vB}A>aP&9a)6C*I(qi3;W*5$&hu$)S2C>7TEJ+&Wt4d!k_to`}IWYP*TNd%x+ws zFFd_}SxDM=Hz&Ks!NJ&Y z7M^sW+6cw?FrNEPXVN6GTValdWAq%5t7FXoqd;80{PMs2^L+mK5Bcri{>L2ai7m~r zL3*OiD-T)8dEw0*96TdTCeCgXVQ@+wV!CN8IuSR<9PFM@Q4VA9r4N6Cul)SK#Giiu z+l+Kz$%AEfw&CC}+R?bkq`FDqjXoW$;(lULep1(K37 zC=3~#QoQ7zyOUePOD1Qf?;W2TcT1+pk;NTmC)iM#)>pDPCm{LG&d!>JWh_WqKOFRFcr43L9Ha6T*gANLCT$xSF#Bf8I4JC_l(n@lVES29haAS~iMze95lW8Fb%s|(|nkHE+XsM~P%tqIV zky%~h#l~QcO3Fq}%6TXyC9+-F#8^_)@=J0WjXpJ|rxIeu#V3-&BXgb3y#04lSVkC} zyF|$KP$qMXV2=>NM@<5IJmc{Z8NjR|KV%8HpBZZkv0b-4Ou{L0T+;@53hT{Fb3sT& zasTI5_-Q+1PE>_mopm%`9PhYD#m06kI7n2gMWaFEesk&!nsdr`obelRBi3#iMJJVCdKZwDC$ja~(t}2x0OPo80ERpAvAoQHCH^I;CLK4q= zj}fURTrCL1_pe@k%{@N65KWi}F6AHl45oLE#~kCWET{-~J!r8P$z*9<+)3+70X!|t zl-aKE=l{%!pZm&}`NQA;Lq7hK&*%k~Lq>lMW8-PR(ybu- zVCckHFv}dQ^E4w6*k)8jkE-+xXA}l;6V4j@_zt3j^{(>%%`<=Nzy0s{+rRbq_?a*N z1l|nmEe;sXJac;}OyN$#p)knQWpbf&aG}b^aOWTyd~)uSykxT0sBe4X)$znf_xF7J zvrn11;U0(6^aH6n3!OX+)k#eYecT){x-#ZJ_quq$aHt2w7w+nTnuWL1NbX1oK6x6( zQ41wku4se`{mK)9=M%NYxO+Ne?TB@ryP|&Jpp_?S6x+zAG+8j4oY-(vkb;Zd{!CDb z>6B?=n+Y|TG6D-P(M)^qm90;XEo zbnXmSye!}yYdcQ{qd01r>4`FhcQ@MYD|g7zx^hqK2&*bZS1c9wF&O)qtOqn@SO$}5 zG8xVo?}LKL8# zC8)1C8{OhrkxW5^q?s(4RvLL$CeTYJwJ@~`gXsk=nd*b?nVLFT0ua@AVM$7pSRd77 zba$?!vgBxHte&{cPQyvsSyh-M_R*thl?s_FjfL~=HnyrV6z-&gP0q7{E2k9UYRMr} zv>wn#Pcat%Q8gLOu@W=oln4WB5~?-CZoBb$OKwf)bt>Gi3+Dl8P7b21Q^Fr4laD@l z;C{_qFFRc`JvmFBNGdQgV@xC`(9CU*$z+ml7dr8clvYMpHtW=sa496ljffj{V_eB) zx!GGIcOfaU$b#FXo6#kv0!b>9jJb0q>dr>EffQw%8tWl4R}YhHO$n1Fo>|&4GS!Xj zkpo+O;JIQf9DR^vi|hjnI(CFu3Eby9T;ltfZVcZkiKB)JMa0=%V0J!vd{0Wws>VJp z42=wij`$|HSg>Zq*fsheg^8<>Z3(%Y8wID7%6Sq~HXHoxm%ogtaCttn2y_#g)f@Gf z@L9RBTcODy=Sg?tP(cx{mriGr61V2b#AdK}gp7%Ek_bqL34KyMtmOxwX0TfpO(`Ug z*3R@n7NuDs)j`R61CGYDLgp4IiH;0;7=f@;x;cZ!P+~fj3RxzIao!?yYd@Z91y~a_ zvZ;7L6U*`NHT8s$=rQX6HQWsK!Bitj=Jj2S{d12{qNf#fr7CpGY%(z7FjuW;zwq+q zk*|O2Q~u}w>3`(S(}nw2ClZM|JDJJpcDu-9XU{EevNN~@WzD47m>jV-N#;!7LoBr1 zQA`kNoC?TLwpz%^@url+U~A6%OXKW8Zn>g*+i6?j&3SNb@3DEI zS-5IiyK>&IJYII*KR$7JI&*nGbKcHiiA&2oHp6D(E`^9{A3MoLh}QB#VP)8rk_SlT zU;Kri=Wsaj^zI#L30h~h!ND@MLb1vL$E7n3Ua&GR@A>kt{xbi`fA(K+c=3~b{p-I+ zE{RnuyEvK}iyWC)r1G;O2^K9JQ-tTzh!)10lx`A?n8V6w#v+QQNy|dNyyaWp{T`>~ zj)ZdU#><*`wn+PnI8{6137wUl!NuX23Ysd9BXSx0n5-qLlONnKuv9LW!J341HV!`` zb@~;tM02Ac+^0lKigiOJZWehsBQ1VZ)q?U=LFrq%>63748LJFywL&|Kom$Tx85Kb~hQ;dXf>HI|-X_2U+YGusMkwTJ* zYvHKD*_n*nE#7bu+VG%h$_Yfd_=XrXfk7gt0;2T32US=qss@sACTb0l1+fG=IHZKu zO!0c}`As56(jG!4LRXRJ#lxacgNgBBM$0^ie-%U+~_kiwej-qz~&i4IY_i&@>II-I3P(VWzu@% z~y+ne21p zPBI5gTwBQv*L)sRfXa6_97xdlh$xY4ci$Kw)Ei^FFPu?yhoxmBK_l ze!f}?T|m0gB(XB+9xv9o;2Hom#G~1%#B-Y*vv}`xhr65Z!9_`|6miUzdJ8sB39+4d zkiT8RcO)}{?1V+1pXH28=pCq&2km|`CccY}p6E%zMn^*ylu<9)e z%~FEm-S&1Pn<~jSY{WC6$)I|`#mp6#i8$m0O`L^{+9We^Dm_C>J6jZ;c>z zBC9by)2)*=Cht=VMF&PFxv=EIkXWgmw+2!`LO>{DH?>HK#;*_@lX5tIO|#tg_>mIU z;ciEb-EuDaM7ueXgv_0bMdf0ylde6G;c$ zL)%@`1vIgwL&)t+cpC8flxZUPcq9Q`Get8CJFajQ;oOyBLK9=Riq6SB60DICJe22Q zs7zD}Oed$w#SJy#ko86t9Nbr-py39w#JlT-OLMNfFfPwLJ$}x9Idj>rT(^$5K`KU` zLhl<`fa-RS3Y5CD-Nul$?=&(Zl`nsI$r9*j0ftQS&1G?L`0gif z`5XW7f5312r~f(TlmGQMf0Lhl@xVJOS)J6Qg|HFuqWhwZA=GSiGsH48Ia`ai)LEd2 zaMTTKV5W>I+$hl8Nr{a-U7kwg1OL=a&0>)32QE>WEwk~1}27( z_-H-Sym9G<_PBNFjkY)lRlLqd>VipP7o{e}bmi{VhvsrE6cpb$X5&T(`_`l;{Jf=cnI2XrZ_#rnsO-VWwMfjlpH9> zxWV66%~_4zokc45Oj1th3^VZ4?1*b^v^_MEH^N|=aCV{ShKz#f!d2qAP?9m#SqbRmrFVuoM-{xTd~kncdZW#SnkHE$ z-DB#r)D@|B2nH7NHP4mvK6$eni-gB(_n1t0j>$lP4jVmL9G=!#G|}gv;j99y8&{1? z#4w|aqms$FL_^I7su{7Hi-?Bbazt}FXayHaDikp;eW0nZVU(C_wUe0b+##z;zo^q@MoXdk__0*cCv;bqZ0zFnp&VjI%jSCoKQ(b_lOmm@fF7`1u`x&< zV96voR+Dpb$nkSOTY$OlJ*u~{7Kuqu^%O+l>9-e-+e;{kEI~IlwUD?jD^0*qo-fbL zF@Xqj9&({s!+dh0&~jlnLuN-rS#6*)nGzC6Ri|pE`++%j_Bm0VxWx;35+RpRS)iRm zNv92DsY*QZaUSN?#bpk6uqLwA1 z0ez#nQt}BEV%a5!&>rYyxrI?j3LcY7$JAMpQye-Ife?kxPIe>JmEbK$qte_EgN)GU zq*2jiTrSs`-rd+nMg-S`mk|M55g~oy_3N)q86lCC__F5PsD@G_4eiFu^`4?piNhBL z&Yd@MsXWd2gX+!GQoV7OjLpKGOso_(-!KI+A*V`Co##H;Y-4)ifl4pIX4oejEFs4u zCJo;^XHM+W5x>wmFtl(u@1zVVLpJB&0iZGyxI$SGHn7us-&3aE1Jp);zvaGxO$=h>WD7JlZ{!sY2xe)o6&F5mw4 zTMqXJQs1yK*tL*UnPcNV38r`4$>i!A+buw--bkfT@*TJ%?2M*#b!JfpN*=~oKE!-N zzff{UW%5~rH5FDJT=YO08P(1;c`zJWs1ipC<^8k>G+GIV&YgDpFop(QQPx7&inq=s z)u7}~!^;6uw27vLgQNJQX&8)s2Acd>g7t8<2$#AKOcpLG)YRx>QpLj7(50v|;8HUpc#CIpkK$G-{5p_Qey)m-qr_C8ddIy&cxj z+Qu&R7L!qsmCI~sS(tMN5vmlb3tbhJ32vn9h;0m6U_^!PuvGA!i*2|sK_*QJlLOe5 zUM7#TKnBB=WfEa^>xfUB zOw$oJ>X})~LUy6s;0qr;@WqE$e13g|oH%&KX*5mbWo3Kb_?2J%6@K}beu-~>q2&AVq8UUD+ohVj?Zu4EU9{AAA5u}UAXqnD?pO5k+{p5@&6O`Hb1v**?rbC#+Y-i zwfFnJ=bn3SeI#}X6MqC!wo#yDkdX}tI)n(MAbJ)8lz$*dw4vHawCU3XDbOH7Bo?CK zIFgAX93+hJXSp1g>+9Zo&UyFVYpprw7&OMZMXwsSj_%!O@3rO}Vu%ONIxx?* zq>G@UJO;de_z{2SKmR-Y#((mk@w@-mKjw$u|6v}c)=I}IQYo>~?E+eZvXQ2e|gC2Pn%rxO#Qvv2^l z1~v{Yg9t4AnEl8xFsnnf5AS7RIA`4=iHt=k~lo;8LRHNoS7$?0- zAsL_)l0qs`u;_Tn^=UsQQCAQn=9U!GGVs%@gup6_sAirbGRNTIr!iR>QZg_2h zo*K0TJHi-)F@lE=rY3QDP??gfltr?|HeJ~@&~VleW+aunM^692m_1mZ63@`1GPIvZ z&U@DRN#YeQ-=q-GeBhgW(gk%0ADFh056?TG++UNlIRxO%xMHEmuo5 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 literal 0 HcmV?d00001 diff --git a/img/graXpert_Startbadge_Umbriel.svg b/img/graXpert_Startbadge_Umbriel.svg new file mode 100644 index 0000000..871f33f --- /dev/null +++ b/img/graXpert_Startbadge_Umbriel.svg @@ -0,0 +1,72 @@ + + + +Release: 'Umbriel'Astronomical Background Extraction© 2024 GraXpert Development Team From 2b6db33246b8cd331a46318ec27c188b6e1cfcab Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 23 Mar 2024 19:43:24 +0100 Subject: [PATCH 35/59] Stretch after denoising with images linked option is now done with gradient-corrected image as reference if available --- graxpert/AstroImageRepository.py | 6 ++++-- graxpert/stretch.py | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/graxpert/AstroImageRepository.py b/graxpert/AstroImageRepository.py index 9488619..1f6cace 100644 --- a/graxpert/AstroImageRepository.py +++ b/graxpert/AstroImageRepository.py @@ -18,8 +18,10 @@ def stretch_all(self, stretch_params:StretchParameters, saturation:float): if (value is not None): all_image_arrays.append(value.img_array) - - stretches = stretch_all(all_image_arrays, stretch_params) + if self.get("Gradient-Corrected") is not None and self.get("Denoised") is not None: + stretches = stretch_all(all_image_arrays, stretch_params, reference_img_array=self.get("Gradient-Corrected")) + else: + stretches = stretch_all(all_image_arrays, stretch_params) i = 0 for key, value in self.images.items(): diff --git a/graxpert/stretch.py b/graxpert/stretch.py index 6474922..6f2a00f 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -97,12 +97,15 @@ def calculate_mtf_stretch_parameters(stretch_params, channel): def stretch(data, stretch_params: StretchParameters): return stretch_all([data], stretch_params)[0] -def stretch_all(datas, stretch_params: StretchParameters): +def stretch_all(datas, stretch_params: StretchParameters, reference_img_array=None): if not stretch_params.do_stretch: datas = [data.clip(min=0, max=1) for data in datas] return datas + if reference_img_array is None: + reference_img_array = datas[0] + futures = [] shms = [] copies = [] @@ -112,11 +115,11 @@ def stretch_all(datas, stretch_params: StretchParameters): common_mtf_stretch_params_per_channel = [] if stretch_params.images_linked: if stretch_params.channels_linked: - mtf_stretch_params_for_all_channel = calculate_mtf_stretch_parameters(stretch_params, datas[0]) - common_mtf_stretch_params_per_channel = [mtf_stretch_params_for_all_channel] * datas[0].shape[-1] + mtf_stretch_params_for_all_channel = calculate_mtf_stretch_parameters(stretch_params, reference_img_array) + common_mtf_stretch_params_per_channel = [mtf_stretch_params_for_all_channel] * reference_img_array.shape[-1] else: for c in range(datas[0].shape[-1]): - common_mtf_stretch_params_per_channel.append(calculate_mtf_stretch_parameters(stretch_params, datas[0][:,:,c])) + common_mtf_stretch_params_per_channel.append(calculate_mtf_stretch_parameters(stretch_params, reference_img_array[:,:,c])) for data in datas: From 7e5dd83a319875e77813cc76dfd88044b2e7a72d Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sat, 23 Mar 2024 19:11:14 +0100 Subject: [PATCH 36/59] fix s3 configuration for macOS x86_64 build --- .github/workflows/build-release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 09792fb..22a422b 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -134,7 +134,9 @@ jobs: echo "endpoint = \"$ai_s3_endpoint\"" >> ./graxpert/s3_secrets.py && \ echo "ro_access_key = \"$ai_s3_access_key\"" >> ./graxpert/s3_secrets.py && \ echo "ro_secret_key = \"$ai_s3_secret_key\"" >> ./graxpert/s3_secrets.py && \ - echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py + echo "bucket_name = \"$ai_s3_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + echo "bge_bucket_name = \"$ai_s3_bge_bucket_name\"" >> ./graxpert/s3_secrets.py && \ + echo "denoise_bucket_name = \"$ai_s3_denoise_bucket_name\"" >> ./graxpert/s3_secrets.py # github actions overwrites brew's python. Force it to reassert itself, by running in a separate step. - name: unbreak python in github actions run: | From d240db4a0eb5f976945963c9b40f7294b959c56f Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sun, 24 Mar 2024 01:06:09 +0100 Subject: [PATCH 37/59] Fixed error in stretching after gradient correction and denoising --- graxpert/AstroImageRepository.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graxpert/AstroImageRepository.py b/graxpert/AstroImageRepository.py index 1f6cace..ca501e8 100644 --- a/graxpert/AstroImageRepository.py +++ b/graxpert/AstroImageRepository.py @@ -19,7 +19,7 @@ def stretch_all(self, stretch_params:StretchParameters, saturation:float): all_image_arrays.append(value.img_array) if self.get("Gradient-Corrected") is not None and self.get("Denoised") is not None: - stretches = stretch_all(all_image_arrays, stretch_params, reference_img_array=self.get("Gradient-Corrected")) + stretches = stretch_all(all_image_arrays, stretch_params, reference_img_array=self.get("Gradient-Corrected").img_array) else: stretches = stretch_all(all_image_arrays, stretch_params) From f1f0b47c6b01bed8d46511121dfa9b0573eaf721 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Sun, 24 Mar 2024 18:25:12 +0100 Subject: [PATCH 38/59] make cli backwards compatible; improve denoising cli --- graxpert/cmdline_tools.py | 14 ++++++++++++-- graxpert/main.py | 13 +++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/graxpert/cmdline_tools.py b/graxpert/cmdline_tools.py index 4749b97..b602944 100644 --- a/graxpert/cmdline_tools.py +++ b/graxpert/cmdline_tools.py @@ -199,6 +199,7 @@ def get_background_save_path(self): class DenoiseCmdlineTool(CmdlineToolBase): def __init__(self, args): super().__init__(args) + self.args = args def execute(self): astro_Image = AstroImage(do_update_display=False) @@ -217,6 +218,8 @@ def execute(self): json_prefs = json.load(f) if "ai_version" in json_prefs: preferences.ai_version = json_prefs["ai_version"] + if "denoise_strength" in json_prefs: + preferences.denoise_strength = json_prefs["denoise_strength"] except Exception as e: logging.exception(e) @@ -224,6 +227,12 @@ def execute(self): sys.exit(1) else: preferences = Prefs() + + if self.args.denoise_strength is not None: + preferences.denoise_strength = self.args.denoise_strength + logging.info(f"Using user-supplied denoise strength value {preferences.denoise_strength}.") + else: + logging.info(f"Using stored denoise strength value {preferences.denoise_strength}.") ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.get_ai_version(preferences)) @@ -231,7 +240,8 @@ def execute(self): dedent( f"""\ Excecuting denoising with the following parameters: - AI model path - {ai_model_path}""" + AI model path - {ai_model_path} + denoise strength - {preferences.denoise_strength}""" ) ) @@ -239,7 +249,7 @@ def execute(self): denoise( astro_Image.img_array, ai_model_path, - self.args.denoise_strength + preferences.denoise_strength )) processed_Astro_Image.save(self.get_save_path(), self.get_output_file_format()) diff --git a/graxpert/main.py b/graxpert/main.py index cd0a910..bf727fe 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -229,21 +229,21 @@ def main(): "--denoise_strength", nargs="?", required=False, - default=1.0, + default=None, type=float, help='Strength of the desired denoising effect, default: "1.0"', ) + + args, extras = parser.parse_known_args() # assume "background-extraction" as default sub-command - if not "background-extraction" in sys.argv and not "denoising" in sys.argv: - sys.argv.append("background-extraction") + if args.cli is not None and args.command is None: + args.command = "background-extraction" - args = parser.parse_args() - - print(args) if args.cli and args.command == "background-extraction": from graxpert.cmdline_tools import BGECmdlineTool + args = bge_parser.parse_args(extras, args) logging.info(f"Starting GraXpert CLI, Background-Extraction, version: {graxpert_version} release: {graxpert_release}") clt = BGECmdlineTool(args) clt.execute() @@ -251,6 +251,7 @@ def main(): elif args.cli and args.command == "denoising": from graxpert.cmdline_tools import DenoiseCmdlineTool + args = denoise_parser.parse_args(extras, args) logging.info(f"Starting GraXpert CLI, Denoising, version: {graxpert_version} release: {graxpert_release}") clt = DenoiseCmdlineTool(args) clt.execute() From 11a0a57fd782ff40ed238985f626c7bba2981117 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Mon, 25 Mar 2024 11:58:08 +0100 Subject: [PATCH 39/59] make cli backwards compatible (second try) --- graxpert/main.py | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/graxpert/main.py b/graxpert/main.py index bf727fe..113e23e 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -180,8 +180,17 @@ def main(): available_bge_versions = collect_available_versions(bge_ai_models_dir, bge_bucket_name) available_denoise_versions = collect_available_versions(denoise_ai_models_dir, denoise_bucket_name) - parser = argparse.ArgumentParser(description="GraXpert,the astronomical background extraction tool") + parser = argparse.ArgumentParser(add_help=False) parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") + parser.add_argument( + "-c", + "--command", + required=False, + default="background-extraction", + choices=["background-extraction", "denoising"], + type=str, + help="Choose the image operation to execute: Background Extraction or Denoising", + ) parser.add_argument("filename", type=str, help="Path of the unprocessed image") parser.add_argument("-output", "--output", nargs="?", required=False, type=str, help="Filename of the processed image") parser.add_argument( @@ -195,8 +204,7 @@ def main(): ) parser.add_argument("-v", "--version", action="version", version=f"GraXpert version: {graxpert_version} release: {graxpert_release}") - subparsers = parser.add_subparsers(dest="command") - bge_parser = subparsers.add_parser("background-extraction") + bge_parser = argparse.ArgumentParser("GraXpert Background Extraction", parents=[parser], description="GraXpert, the astronomical background extraction tool") bge_parser.add_argument( "-ai_version", "--ai_version", @@ -212,7 +220,7 @@ def main(): bge_parser.add_argument("-smoothing", "--smoothing", nargs="?", required=False, default=None, type=float, help="Strength of smoothing between 0 and 1") bge_parser.add_argument("-bg", "--bg", required=False, action="store_true", help="Also save the background model") - denoise_parser = subparsers.add_parser("denoising") + denoise_parser = argparse.ArgumentParser("GraXpert Denoising", parents=[parser], description="GraXpert, the astronomical denoising tool") denoise_parser.add_argument( "-ai_version", "--ai_version", @@ -233,17 +241,24 @@ def main(): type=float, help='Strength of the desired denoising effect, default: "1.0"', ) - + + if "-h" in sys.argv or "--help" in sys.argv: + if "denoising" in sys.argv: + denoise_parser.print_help() + else: + bge_parser.print_help() + sys.exit(0) + args, extras = parser.parse_known_args() - # assume "background-extraction" as default sub-command - if args.cli is not None and args.command is None: - args.command = "background-extraction" - + if args.command == "background-extraction": + args = bge_parser.parse_args() + else: + args = denoise_parser.parse_args() + if args.cli and args.command == "background-extraction": from graxpert.cmdline_tools import BGECmdlineTool - args = bge_parser.parse_args(extras, args) logging.info(f"Starting GraXpert CLI, Background-Extraction, version: {graxpert_version} release: {graxpert_release}") clt = BGECmdlineTool(args) clt.execute() @@ -251,7 +266,6 @@ def main(): elif args.cli and args.command == "denoising": from graxpert.cmdline_tools import DenoiseCmdlineTool - args = denoise_parser.parse_args(extras, args) logging.info(f"Starting GraXpert CLI, Denoising, version: {graxpert_version} release: {graxpert_release}") clt = DenoiseCmdlineTool(args) clt.execute() From 1ab60b4a8ef67875ca2d613a10f2d4c5bdc63883 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Thu, 28 Mar 2024 21:08:12 +0100 Subject: [PATCH 40/59] fix pyinstaller build for macos-x86-64 --- GraXpert-macos-x86_64.spec | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/GraXpert-macos-x86_64.spec b/GraXpert-macos-x86_64.spec index e1b77f6..428e466 100644 --- a/GraXpert-macos-x86_64.spec +++ b/GraXpert-macos-x86_64.spec @@ -1,13 +1,19 @@ # -*- mode: python ; coding: utf-8 -*- +from PyInstaller.utils.hooks import copy_metadata block_cipher = None +datas = [] +datas += [('./img/*', './img/'), ('./graxpert-dark-blue.json', './')] +datas += copy_metadata('xisf') + + a = Analysis(['./graxpert/main.py'], pathex=[], binaries=[], - datas=[('./img/*', './img/'), ('./graxpert-dark-blue.json', './')], + datas=datas, hiddenimports=['PIL._tkinter_finder', 'tkinter'], hookspath=['./releng'], hooksconfig={}, From cb20873e9fe89dd2bac88c1ec68b47deb980c354 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Mon, 25 Mar 2024 17:49:04 +0100 Subject: [PATCH 41/59] add batch processing for denoising --- .vscode/launch.json | 4 +-- graxpert/denoising.py | 78 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 16 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 82bada6..fd654f6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,10 +3,10 @@ "configurations": [ { "name": "Run GraXpert", - "type": "python", + "type": "debugpy", "request": "launch", "module": "graxpert.main", - "justMyCode": true + "justMyCode": true, } ] } \ No newline at end of file diff --git a/graxpert/denoising.py b/graxpert/denoising.py index f3fbcfd..1b134d3 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -1,5 +1,6 @@ import copy import logging +import time import numpy as np import onnxruntime as ort @@ -7,11 +8,13 @@ from graxpert.ai_model_handling import get_execution_providers_ordered -def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None): +def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, progress=None): + + logging.info("Starting denoising") input = copy.deepcopy(image) num_colors = image.shape[-1] - + if num_colors == 1: image = np.array([image[:, :, 0], image[:, :, 0], image[:, :, 0]]) image = np.moveaxis(image, 0, -1) @@ -42,11 +45,16 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None output = copy.deepcopy(image) providers = get_execution_providers_ordered() - session = ort.InferenceSession(ai_path, providers=providers) + ort_options = ort.SessionOptions() + ort_options.execution_mode = ort.ExecutionMode.ORT_PARALLEL + session = ort.InferenceSession(ai_path, providers=providers, sess_options=ort_options) - logging.info(f"Providers : {providers}") - logging.info(f"Used providers : {session.get_providers()}") + logging.info(f"Available inference providers : {providers}") + logging.info(f"Used inference providers : {session.get_providers()}") + last_progress = 0 + + input_tiles = [] for i in range(ith): for j in range(itw): x = stride * i @@ -54,28 +62,70 @@ def denoise(image, ai_path, strength, window_size=256, stride=128, progress=None tile = image[x : x + window_size, y : y + window_size, :] tile = (tile - median) / mad * 0.04 - tile_copy = tile.copy() + # input_tile_copies.append(tile.copy()) tile = np.clip(tile, -1.0, 1.0) - tile = np.expand_dims(tile, axis=0) - tile = np.array(session.run(None, {"gen_input_image": tile})[0][0]) + input_tiles.append(tile) + + p = int(i / ith * 10) + if p > last_progress: + if progress is not None: + progress.update(p - last_progress) + else: + logging.info(f"Progress: {p}%") + last_progress = p + + input_tiles = np.array(input_tiles) + input_tile_copies = np.copy(input_tiles).reshape((ith, itw, window_size, window_size, 3)) + + output_tiles = [] + + elapsed_time = 0 + for i in range(0, ith * itw, batch_size): + start = time.time() + session_result = session.run(None, {"gen_input_image": input_tiles[i : i + batch_size]})[0] + elapsed_time += time.time() - start + for e in session_result: + output_tiles.append(e) + + p = int(10 + i / (ith * itw) * 80) + if p > last_progress: + if progress is not None: + progress.update(p - last_progress) + else: + logging.info(f"Progress: {p}%") + last_progress = p - tile = np.where(tile_copy < 0.95, tile, tile_copy) + output_tiles = np.array(output_tiles) + output_tiles = output_tiles.reshape((ith, itw, window_size, window_size, 3)) + + for i in range(ith): + for j in range(itw): + x = stride * i + y = stride * j + + tile = output_tiles[i, j, :] + tile = np.where(input_tile_copies[i, j] < 0.95, tile, input_tile_copies[i, j]) tile = tile / 0.04 * mad + median tile = tile[offset : offset + stride, offset : offset + stride, :] output[x + offset : stride * (i + 1) + offset, y + offset : stride * (j + 1) + offset, :] = tile - if progress is not None: - progress.update(int(100 / ith)) - else: - logging.info(f"Progress: {int(i/ith*100)}%") + p = int(90 + i / ith * 10) + if p > last_progress: + if progress is not None: + progress.update(p - last_progress) + else: + logging.info(f"Progress: {p}%") + last_progress = p output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] output = output * strength + input * (1 - strength) - + # if num_colors == 1: output = np.array([output[:, :, 0]]) output = np.moveaxis(output, 0, -1) + logging.info("Finished denoising") + return output From f210734ea78bffff456f2f41b767bfbbc2b9491c Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 15:14:58 +0100 Subject: [PATCH 42/59] optimize denoising memory footprint, optimize bge runtime --- graxpert/background_extraction.py | 52 +++++++++++++++--------- graxpert/denoising.py | 67 ++++++++++++++----------------- requirements.txt | 1 + 3 files changed, 64 insertions(+), 56 deletions(-) diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index e4d43ad..f5e689a 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -6,34 +6,39 @@ from concurrent.futures import wait from multiprocessing import shared_memory +import cv2 import numpy as np import onnxruntime as ort from astropy.stats import sigma_clipped_stats from pykrige.ok import OrdinaryKriging from scipy import interpolate, linalg -from skimage.filters import gaussian -from skimage.transform import resize +from graxpert.ai_model_handling import get_execution_providers_ordered from graxpert.mp_logging import get_logging_queue, worker_configurer from graxpert.parallel_processing import executor from graxpert.radialbasisinterpolation import RadialBasisInterpolation -from graxpert.ai_model_handling import get_execution_providers_ordered + + +def gaussian_kernel(sigma=1.0, truncate=4.0): # follow simulate skimage.filters.gaussian defaults + ksize = round(sigma * truncate) - 1 if round(sigma * truncate) % 2 == 0 else round(sigma * truncate) + return (ksize, ksize) def extract_background(in_imarray, background_points, interpolation_type, smoothing, downscale_factor, sample_size, RBF_kernel, spline_order, corr_type, ai_path, progress=None): - shm_imarray = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) - shm_background = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) - imarray = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_imarray.buf) - background = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_background.buf) - np.copyto(imarray, in_imarray) + num_colors = in_imarray.shape[-1] - num_colors = imarray.shape[-1] + shm_imarray = None + shm_background = None if interpolation_type == "AI": + imarray = np.ndarray(in_imarray.shape, dtype=np.float32) + background = np.ndarray(in_imarray.shape, dtype=np.float32) + np.copyto(imarray, in_imarray) + # Shrink and pad to avoid artifacts on borders padding = 8 - imarray_shrink = resize(imarray, output_shape=(256 - 2 * padding, 256 - 2 * padding)) + imarray_shrink = cv2.resize(imarray, dsize=(256 - 2 * padding, 256 - 2 * padding), interpolation=cv2.INTER_LINEAR) imarray_shrink = np.pad(imarray_shrink, ((padding, padding), (padding, padding), (0, 0)), mode="edge") median = [] @@ -77,7 +82,7 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if smoothing != 0: sigma = smoothing * 20 - background = gaussian(image=background, sigma=sigma, channel_axis=-1) + background = cv2.GaussianBlur(background, ksize=gaussian_kernel(sigma), sigmaX=sigma, sigmaY=sigma) if progress is not None: progress.update(8) @@ -96,13 +101,20 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth if progress is not None: progress.update(8) - background = gaussian(background, sigma=3.0) # To simulate tensorflow method='gaussian' - background = resize(background, output_shape=(in_imarray.shape[0], in_imarray.shape[1])) + sigma = 3.0 + background = cv2.GaussianBlur(background, ksize=gaussian_kernel(sigma), sigmaX=sigma, sigmaY=sigma) + background = cv2.resize(background, dsize=(in_imarray.shape[1], in_imarray.shape[0]), interpolation=cv2.INTER_LINEAR) if progress is not None: progress.update(8) else: + shm_imarray = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) + shm_background = shared_memory.SharedMemory(create=True, size=in_imarray.nbytes) + imarray = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_imarray.buf) + background = np.ndarray(in_imarray.shape, dtype=np.float32, buffer=shm_background.buf) + np.copyto(imarray, in_imarray) + x_sub = np.array(background_points[:, 0], dtype=int) y_sub = np.array(background_points[:, 1], dtype=int) @@ -154,15 +166,17 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth imarray[:, :, :] = imarray.clip(min=0.0, max=1.0) in_imarray[:] = imarray[:] - background = np.copy(background) if progress is not None: progress.update(8) - shm_imarray.close() - shm_background.close() - shm_imarray.unlink() - shm_background.unlink() + if shm_imarray is not None: + shm_imarray.close() + shm_imarray.unlink() + if shm_background is not None: + background = np.copy(background) + shm_background.close() + shm_background.unlink() return background @@ -258,7 +272,7 @@ def interpol(shm_imarray_name, shm_background_name, c, x_sub, y_sub, shape, kind return if downscale_factor != 1: - result = resize(result, shape, preserve_range=True) + result = cv2.resize(src=result, dsize=(shape[1], shape[0]), interpolation=cv2.INTER_LINEAR) background[:, :, c] = result except Exception as e: diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 1b134d3..3b86358 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -53,64 +53,57 @@ def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, logging.info(f"Used inference providers : {session.get_providers()}") last_progress = 0 + for b in range(0, ith * itw + batch_size, batch_size): + + input_tiles = [] + for t_idx in range(0, batch_size): + + index = b + t_idx + i = index % ith + j = index // ith + + if i >= ith or j >= itw: + break - input_tiles = [] - for i in range(ith): - for j in range(itw): x = stride * i y = stride * j tile = image[x : x + window_size, y : y + window_size, :] tile = (tile - median) / mad * 0.04 - # input_tile_copies.append(tile.copy()) tile = np.clip(tile, -1.0, 1.0) input_tiles.append(tile) - p = int(i / ith * 10) - if p > last_progress: - if progress is not None: - progress.update(p - last_progress) - else: - logging.info(f"Progress: {p}%") - last_progress = p - - input_tiles = np.array(input_tiles) - input_tile_copies = np.copy(input_tiles).reshape((ith, itw, window_size, window_size, 3)) + if not input_tiles: + continue + + input_tiles = np.array(input_tiles) + input_tile_copies = np.copy(input_tiles) - output_tiles = [] - - elapsed_time = 0 - for i in range(0, ith * itw, batch_size): - start = time.time() - session_result = session.run(None, {"gen_input_image": input_tiles[i : i + batch_size]})[0] - elapsed_time += time.time() - start + output_tiles = [] + session_result = session.run(None, {"gen_input_image": input_tiles})[0] for e in session_result: output_tiles.append(e) - p = int(10 + i / (ith * itw) * 80) - if p > last_progress: - if progress is not None: - progress.update(p - last_progress) - else: - logging.info(f"Progress: {p}%") - last_progress = p + output_tiles = np.array(output_tiles) + + for t_idx, tile in enumerate(output_tiles): - output_tiles = np.array(output_tiles) - output_tiles = output_tiles.reshape((ith, itw, window_size, window_size, 3)) + index = b + t_idx + i = index % ith + j = index // ith + + if i >= ith or j >= itw: + break - for i in range(ith): - for j in range(itw): x = stride * i y = stride * j - - tile = output_tiles[i, j, :] - tile = np.where(input_tile_copies[i, j] < 0.95, tile, input_tile_copies[i, j]) + tile = np.where(input_tile_copies[t_idx] < 0.95, tile, input_tile_copies[t_idx]) tile = tile / 0.04 * mad + median tile = tile[offset : offset + stride, offset : offset + stride, :] output[x + offset : stride * (i + 1) + offset, y + offset : stride * (j + 1) + offset, :] = tile - p = int(90 + i / ith * 10) + p = int(b / (ith * itw + batch_size) * 100) if p > last_progress: if progress is not None: progress.update(p - last_progress) @@ -121,7 +114,7 @@ def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] output = output * strength + input * (1 - strength) - # + if num_colors == 1: output = np.array([output[:, :, 0]]) output = np.moveaxis(output, 0, -1) diff --git a/requirements.txt b/requirements.txt index a9c5f27..8855640 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ ml_dtypes numpy<=1.24.3,>=1.22 Pillow pykrige +opencv-Python requests scikit-image == 0.21.0 scipy From 1b67343eccbde764c4b8e16c692b84baac0e59d2 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 15:39:24 +0100 Subject: [PATCH 43/59] fix conflicting cmdline arguments --- graxpert/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graxpert/main.py b/graxpert/main.py index 113e23e..36de75b 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -183,7 +183,7 @@ def main(): parser = argparse.ArgumentParser(add_help=False) parser.add_argument("-cli", "--cli", required=False, action="store_true", help="Has to be added when using the command line integration of GraXpert") parser.add_argument( - "-c", + "-cmd", "--command", required=False, default="background-extraction", From 1fbb3a4824b97f003bd2325b0409d7cb12aeca62 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 15:52:53 +0100 Subject: [PATCH 44/59] fix incorrect clipping of tiles during denoising --- graxpert/denoising.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 3b86358..76345de 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -56,6 +56,7 @@ def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, for b in range(0, ith * itw + batch_size, batch_size): input_tiles = [] + input_tile_copies = [] for t_idx in range(0, batch_size): index = b + t_idx @@ -70,6 +71,7 @@ def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, tile = image[x : x + window_size, y : y + window_size, :] tile = (tile - median) / mad * 0.04 + input_tile_copies.append(np.copy(tile)) tile = np.clip(tile, -1.0, 1.0) input_tiles.append(tile) @@ -78,7 +80,6 @@ def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, continue input_tiles = np.array(input_tiles) - input_tile_copies = np.copy(input_tiles) output_tiles = [] session_result = session.run(None, {"gen_input_image": input_tiles})[0] From 5d09eaa515bfcbb206d53f2a44488d07d5da1be8 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Mar 2024 17:18:25 +0100 Subject: [PATCH 45/59] Scaling factor is now correctly calculated when loading a new image to exactly fit to the canvas --- graxpert/ui/canvas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index 30b5bd2..065458b 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -486,8 +486,8 @@ def show_progress_frame(self, show): self.update() def zoom_fit(self, image_width, image_height): - canvas_width = self.winfo_width() - canvas_height = self.winfo_height() + canvas_width = self.canvas.winfo_width() + canvas_height = self.canvas.winfo_height() if (image_width * image_height <= 0) or (canvas_width * canvas_height <= 0): return From 49ec537186686e3a9e71ab6bd23fd996196f1fcc Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Mar 2024 17:54:49 +0100 Subject: [PATCH 46/59] Crop mode is now automatically turned on/off when crop menu is opened/closed --- graxpert/ui/canvas.py | 37 +++++++++++++++++++++++++++---------- graxpert/ui/left_menu.py | 14 ++++++++++---- graxpert/ui/ui_events.py | 3 ++- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index 065458b..c451040 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -119,7 +119,8 @@ def register_events(self): eventbus.add_listener(AppEvents.DISPLAY_TYPE_CHANGED, self.redraw_image) eventbus.add_listener(UiEvents.RESET_ZOOM_REQUEST, self.reset_zoom) eventbus.add_listener(UiEvents.DISPLAY_START_BADGE_REQUEST, self.on_display_start_badge_request) - eventbus.add_listener(UiEvents.TOGGLE_CROP_REQUEST, self.on_toggle_crop_request) + eventbus.add_listener(UiEvents.TURN_ON_CROP_MODE, self.on_turn_on_crop_mode) + eventbus.add_listener(UiEvents.TURN_OFF_CROP_MODE, self.on_turn_off_crop_mode) eventbus.add_listener(UiEvents.APPLY_CROP_REQUEST, self.on_apply_crop_request) # event handling @@ -142,9 +143,13 @@ def on_apply_crop_request(self, event=None): return graxpert.images.crop_all(self.startx, self.endx, self.starty, self.endy) + + self.startx = 0 + self.starty = 0 + self.endx = graxpert.images.get("Original").width + self.endy = graxpert.images.get("Original").height eventbus.emit(AppEvents.RESET_POITS_REQUEST) - self.crop_mode = False self.zoom_fit(graxpert.images.get(self.display_type.get()).width, graxpert.images.get(self.display_type.get()).height) self.redraw_points() @@ -395,8 +400,11 @@ def on_stretch_image_end(self, event=None): def on_stretch_image_error(self, event=None): self.show_loading_frame(False) - - def on_toggle_crop_request(self, event=None): + + def on_turn_on_crop_mode(self, event=None): + if self.crop_mode: + return + if graxpert.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) return @@ -405,14 +413,23 @@ def on_toggle_crop_request(self, event=None): self.starty = 0 self.endx = graxpert.images.get("Original").width self.endy = graxpert.images.get("Original").height - - if self.crop_mode: - self.crop_mode = False - else: - self.crop_mode = True - + + self.crop_mode = True + self.redraw_points() + + def on_turn_off_crop_mode(self, event=None): + if not self.crop_mode: + return + + self.startx = 0 + self.starty = 0 + self.endx = graxpert.images.get("Original").width + self.endy = graxpert.images.get("Original").height + + self.crop_mode = False self.redraw_points() + # widget logic def draw_image(self, pil_image, tags=None): if pil_image is None: diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index f166255..85d2517 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -106,24 +106,30 @@ def __init__(self, parent, **kwargs): self.place_children() eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "CROP" else None) + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: eventbus.emit(UiEvents.TURN_OFF_CROP_MODE) if not e == "CROP" else None) def create_children(self): super().create_children() - self.cropmode_button = GraXpertButton(self.sub_frame, text=_("Crop mode on/off"), command=lambda: eventbus.emit(UiEvents.TOGGLE_CROP_REQUEST)) - self.cropapply_button = GraXpertButton(self.sub_frame, text=_("Apply crop"), command=lambda: eventbus.emit(UiEvents.APPLY_CROP_REQUEST)) + self.cropapply_button = GraXpertButton(self.sub_frame, + text=_("Apply crop"), + fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], + hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], + command=lambda: eventbus.emit(UiEvents.APPLY_CROP_REQUEST)) def setup_layout(self): super().setup_layout() def place_children(self): super().place_children() - self.cropmode_button.grid(column=1, row=0, pady=pady, sticky=tk.NSEW) - self.cropapply_button.grid(column=1, row=1, pady=pady, sticky=tk.NSEW) + self.cropapply_button.grid(column=1, row=0, pady=pady, sticky=tk.NSEW) def toggle(self): super().toggle() if self.show: eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "CROP") + eventbus.emit(UiEvents.TURN_ON_CROP_MODE) + else: + eventbus.emit(UiEvents.TURN_OFF_CROP_MODE) class ExtractionMenu(CollapsibleMenuFrame): diff --git a/graxpert/ui/ui_events.py b/graxpert/ui/ui_events.py index 07de140..593fa02 100644 --- a/graxpert/ui/ui_events.py +++ b/graxpert/ui/ui_events.py @@ -7,7 +7,8 @@ class UiEvents(Enum): # menu requests SHOW_MENU_REQUEST = auto() # crop - TOGGLE_CROP_REQUEST = auto() + TURN_ON_CROP_MODE = auto() + TURN_OFF_CROP_MODE = auto() APPLY_CROP_REQUEST = auto() # right sidebar requests HELP_FRAME_TOGGLED = auto() From 0c8601aa261cb0f42ff2a605ea2baf482908c810 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Mar 2024 18:10:59 +0100 Subject: [PATCH 47/59] Updated localization --- locales/de_DE/LC_MESSAGES/base.mo | Bin 9889 -> 9731 bytes locales/de_DE/LC_MESSAGES/base.po | 20 +++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/locales/de_DE/LC_MESSAGES/base.mo b/locales/de_DE/LC_MESSAGES/base.mo index c81fc47580b322b195888a7faad51b9680d74642..32bde808beeef4fd73190bd42a3d6f3b7c66d76d 100644 GIT binary patch delta 1723 zcmYM!YiLwQ6u|M5WY@%)hpr}Re5}_dQChp^?qbv~wqQ-vXp%x>`mkuZHRHO;_D1%h z6hADYAr&c#^@aGvv_(G%vS2BRSh^@hXj-fv#19cP6?{`lA+%WgKkgP6mfy_WJ9EyQ z8Sd%!oo(q+pXZ?PTgQJU|3`(|d-)soij>j4ge7b$*7YQ@tS5J}5J8l?=>vU&pRu?mmiG(3+Lm_-e69UJiu4xn$M$eVZ+b)6eH z32)=)_z*p4c&Lf?poQD9ocMAq|KJ?*t_-0Dyn>p*4XnresEJjux)1A7-&>6AK~~^l z>_FY=J=DsLqps_vqw_0~A!)!8;!BXm>lns)XmBBZiNus2aS#5Cx`U6(a{+r$1I2MR z?!syu#C9CYk544a6#dumZ9IvcIEv}_XoRS1Gxnp6*N|uO4^G8WqH1D()aNUZwPhQU zlk}tRXg_MgCy=Rf7ImHPaXS8lwRku0v&qz7AJnjo4h$jpM0TK-^b6Dk_TecU#J8}8 z`fK2wsFm7>d+`ePU>B3R@CU5HYR*wBy#N~vxKpSJk5)0N0UvNMx}!f(ckmoZQc9^O zF=YleVE{XEBmRQl;VU>mlsKNkAWmhFT%-k4_#v{SjN~0dP2le|4SjI}bh09PExQgT;*D;LuQQxbdk-NN2sPC;tJ(Bm)kDE|8l>g_1zwjbHM=j+=J`y@Uf?AoIsPi76&XZZWqpQRa-5RuTb-v$=FYX8q=&78g zp_v6qi*JW4L+!7`I{W}Bl5EEq9zbGA0at!M`teh|fUP*q5?O^Ca4CL^OK=ReGPCC7 zHoO4q^j0jVVe=q@dZ~_}mh5ZPJ8=PZXO~fTI+E{?Aw`itk=RoCYR*O^M|l@NK^I?C z40Y!>kyDksc(R4YGa3;*&UQ6JFJGHQSdA%c$Mu-SE}YYl3%m{c=zrCa@fS}oDtBDh z#1d94>h_xMOjGG_!93&kMH9wq{mh9NY0mdLlX2rllAH4bQ8$u#I_aCj;{ zZgwzctgR;A>t=_yY)WRvYs(6Q??hwWmT{ADCzaT^*|^g3e>>$y5{YDXFy3ok4jMO8 dH1koRx6SFM`NY55Q?kWGnHYC7sk%3c{sU*W>2d%7 delta 1891 zcmXxld29_)6vy$?*Vl*E($=%oQm-vatEFnKrA4V~tF~4eL^PHViL_D)!HW<}NC+B2 zVu{8U{9){|Cn`iD{vnbg68|+t_(KWd`~m}=VCXk#cZs{MR)?+@fYg4@7$ym<2sq; zm_@CUPCO^J;CkGRJ@7Y%F_|yBVkQp9F}Mp?;&}Xw{MnEMGyW`}!$vH`Al^nLcpoG9 z5_P|?7-oF?OJ^V_!c0>GkH=)JME$T9N#5%42yR5pB&my6nG7UX8-cpM0J){jK~-!q zX5k9V!~-}AZ(%&+TN|Cd*pA9{2cv3$MjU|WuqQsn3ViRMA4a_!_*{;Y@iETF7;Z8T ztFRc);|Od+F11u{-W_u=s*I-4(GON5IoL5|l6D?7lk2DwKSIW^7pNPxU>|J76bw-| z89|*dz}Z-Zs$dgp;7fQ4A0|`(NpzNRRs)_ymF5!e$B(!M>(~fY*n+)qBz0EhW??AC z>^UmYSClD)?@$x@gi8DyGI{%hJ`U^8ViW&8V60L|u0jbzSrd9j(nh9Endbg6;n2 z6h>DG%W)SjL?!mY_X}q5`7f$+8SL1#I1$OgF5p3I##*e2c+dY`oT*g|rSW6FsKjx& z54BcLP&0jv8lV-mNxP+cd!-0fxeC-;*Pv#!3N^zG{^xy2G3_{#gWdFfgQ?m@KjA4-^_PlZi{QfLtiOv7F;GWg8Y164H+H7j29#)PE{QfYUPN=Gr2))Eu zO{4Hp_Z_aCsit>;nqHe!(S56FQ>y7PoJMGgMiY8U{x>~xS`zI8y>R9bS^~8RL^h$# zs5YF?zS4VQu8~?9om_%tbl(Lmm)quX%pp1uW8E{(owz=+&ZmyIW1Qyrrhrr5B{Asi gNh*tV{)9UPos^V>fK%PKHQ Date: Fri, 29 Mar 2024 18:16:47 +0100 Subject: [PATCH 48/59] Localization for tooltips --- locales/de_DE/LC_MESSAGES/base.mo | Bin 9731 -> 10011 bytes locales/de_DE/LC_MESSAGES/base.po | 6 ++++++ 2 files changed, 6 insertions(+) diff --git a/locales/de_DE/LC_MESSAGES/base.mo b/locales/de_DE/LC_MESSAGES/base.mo index 32bde808beeef4fd73190bd42a3d6f3b7c66d76d..4e9a74ca05ed8a83b9629ff3c925a915ff86e0cb 100644 GIT binary patch delta 1781 zcmYk+TWl0n7{Kw*rlq#qTB!w8upE#UEwV*KBE&+}l1j=&g$iW;V@& zabr-INTLQpYf=-M_`m~=8fzLveISU18YO8=co2)1P@}ww*Qk;IXKP@S-QPL0bIx}; zv%7yy-@3wBZRru=wT<^I-hY?q?E33snMf7WukmL538&&!EXT4bBDZ2S)?hs@z&LKj zE%*lxp{{#}MXT`?E)*$9j9n|auna?N#c6l~>+lP_1;0lP@G~}JNrgxe7vnNKiMr1( z7{h-tk1;Nm;!CKBzJdn(u$uVt(c~8+$Qt207Tk^6`OoV3Y`#gPodeO#_t7^E zTtuzxRn$t}M3R?dNNhQQ58?=JK;8X3Y{c7f9v=a=;Qjb6lAC;odIY~BAtha)d>y=i znm{k=jc=h=G=zHQSFjzsX_G!gr%@C79ACsS)b*V+C(ho-<;-73z3&uKw2Y$O_X9Rz z;VJ_?qk4Y)^%zI3Y%S`7{iq4PfqI5-qbBe%4&g9rYoEVs;(8Bihx$?1y@$H)Eb38S zz{Pk8jh;d+QT4(DsIBh8BJM#=>`&ysMk;u;bzXya<7}jh@)%}t8p)Lk$p{JMok^qdsIiP+ONpeKzu_l@(Dd?U|ep zAWfAIksRd0q`xDz$P6}r7MEg$WzfSwEAK~+S&rjTJcCKJ{OkO8*0_}U80K(VgUEI~ zh#mMNYT%WPBI|K0`gpu?@MKw4nX!=#vaV-C6Gnmcl2OX|T_#~Y-wja|Ho}P`~UY%A!4fOx2)nR-p*e*nZI*7|70Ei<^8Ok6!8MPd7bYu-`nM- z<@}TjB1&<^pvHw}tG~%2XL3Iq_$6z3oEhK@+xZ)ZSYI9S2tQ!1bCy&1E8pT3PULzw zGtqvwax15aA0Jh2d`{2C2s7XbW&&qf_dXd?=>&$fv zCi#9HU5YkVi65N?_pzJza6KR3I}|g1;7g>s5PW<`6L34cPb#u4T^ zU-M4>$Yx%scw@T$=Zz+1^sLkV|IEW+b1|v%!J2gx|#tm+nB8AFJ=WdDaokOPcdT_7jXesa~)6fE8f8&Q8x1+ zJ2}HexkL{KxQ3RD(Td~D1pY1=dfZ=Dei<*pnt$jmyW<=YWUne!(&kIzw)VkKL=~bF`~*fd_gFZWwIj$I8tN3%)iFvXKK^ t$rpK?eVp4?4!ni0o9}HKK3|wx7_OSKse1TyLviwO%j_jJd%u|f#(&J;o8SNd diff --git a/locales/de_DE/LC_MESSAGES/base.po b/locales/de_DE/LC_MESSAGES/base.po index 98a4b35..e723988 100644 --- a/locales/de_DE/LC_MESSAGES/base.po +++ b/locales/de_DE/LC_MESSAGES/base.po @@ -294,6 +294,12 @@ msgstr "Speichere das Hintergrundmodell" msgid "Save the processed picture" msgstr "Speichere das bearbeitete Bild" +msgid "Use GraXpert's denoising AI model to reduce the noise in your image. This may take a while" +msgstr "Wendet GraXpert's AI zum Entrauschen des Bildes an. Das kann eine Weile dauern." + +msgid "Determines strength of denoising." +msgstr "Gibt an, wie stark entrauscht werden soll." + msgid "Save the stretched and processed picture. The color saturation is not changed." msgstr "Speichere das gestretchte und bearbeitete Bild. Die Farbsättigung wird dabei nicht verändert." From a097de700d4462d0f65680d18399ae32f87b0d80 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Fri, 29 Mar 2024 18:22:04 +0100 Subject: [PATCH 49/59] Added cmd/ctrl+d key binding for denoising --- graxpert/ui/application_frame.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/graxpert/ui/application_frame.py b/graxpert/ui/application_frame.py index 1e3bdea..77a89d2 100644 --- a/graxpert/ui/application_frame.py +++ b/graxpert/ui/application_frame.py @@ -57,6 +57,8 @@ def create_bindings(self): self.master.bind("", lambda e: eventbus.emit(AppEvents.OPEN_FILE_DIALOG_REQUEST)) self.master.bind("", lambda e: eventbus.emit(AppEvents.CALCULATE_REQUEST)) self.master.bind("", lambda e: eventbus.emit(AppEvents.CALCULATE_REQUEST)) + self.master.bind("", lambda e: eventbus.emit(AppEvents.DENOISE_REQUEST)) + self.master.bind("", lambda e: eventbus.emit(AppEvents.DENOISE_REQUEST)) self.master.bind("", lambda e: eventbus.emit(AppEvents.SAVE_REQUEST)) self.master.bind("", lambda e: eventbus.emit(AppEvents.SAVE_REQUEST)) self.master.bind("", self.undo) # undo From f3600a9d4bb9d4107a90174d2b79daf2e546b0b2 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 21:47:07 +0100 Subject: [PATCH 50/59] add license information to help menu --- graxpert/ui/right_menu.py | 27 +++++++++++++++++ licenses/BGE-Model-LICENSE.html | 45 +++++++++++++++++++++++++++++ licenses/Denoise-Model-LICENSE.html | 24 +++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 licenses/BGE-Model-LICENSE.html create mode 100644 licenses/Denoise-Model-LICENSE.html diff --git a/graxpert/ui/right_menu.py b/graxpert/ui/right_menu.py index 2b516db..cba8021 100644 --- a/graxpert/ui/right_menu.py +++ b/graxpert/ui/right_menu.py @@ -1,4 +1,5 @@ import tkinter as tk +import webbrowser from tkinter import messagebox import customtkinter as ctk @@ -83,6 +84,32 @@ def create_and_place_children(self): HelpText(self, text=_("Mouse wheel: Zoom")).grid(**self.default_grid()) HelpText(self, rows=3, text=_("Ctrl+Z/Y: Undo/Redo sample point")).grid(**self.default_grid()) + CTkLabel(self, text=_("Licenses"), font=self.heading_font).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) + + def callback(url): + webbrowser.open_new(url) + + row = self.nrow() + HelpText(self, text=_("GraXpert is licensed under GPL-3:")).grid(column=0, row=row, padx=padx, pady=pady, sticky=tk.W) + url_link_1 = "https://raw.githubusercontent.com/Steffenhir/GraXpert/main/License.md" + url_label_1 = CTkLabel(self, text="", text_color="dodger blue") + url_label_1.grid(column=0, row=row, padx=padx, sticky=tk.E) + url_label_1.bind("", lambda e: callback(url_link_1)) + + row = self.nrow() + HelpText(self, rows=2, text=_("Background Extraction AI models are licensed under CC BY-NC-SA:")).grid(column=0, row=row, padx=padx, pady=pady, sticky=tk.W) + url_link_2 = "https://raw.githubusercontent.com/Steffenhir/GraXpert/main/licenses/BGE-Model-LICENSE.html" + url_label_2 = CTkLabel(self, text="", text_color="dodger blue") + url_label_2.grid(column=0, row=row, padx=padx, sticky=tk.E) + url_label_2.bind("", lambda e: callback(url_link_2)) + + row = self.nrow() + HelpText(self, rows=2, text=_("Denoising AI models are licensed under CC BY-NC-SA:")).grid(column=0, row=row, padx=padx, pady=pady, sticky=tk.W) + url_link_3 = "https://raw.githubusercontent.com/Steffenhir/GraXpert/main/licenses/Denoise-Model-LICENSE.html" + url_label_3 = CTkLabel(self, text="", text_color="dodger blue") + url_label_3.grid(column=0, row=row, padx=padx, sticky=tk.E) + url_label_3.bind("", lambda e: callback(url_link_3)) + def setup_layout(self): self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) diff --git a/licenses/BGE-Model-LICENSE.html b/licenses/BGE-Model-LICENSE.html new file mode 100644 index 0000000..6c5a42f --- /dev/null +++ b/licenses/BGE-Model-LICENSE.html @@ -0,0 +1,45 @@ + + + + +

    The provided GraXpert Background Extraction Models by GraXpert Development Team are licensed under CC BY-NC-SA 4.0

    +

    We would like to thank the following people who contributed to this model by submitting training images:

    +
      +
    • Alistair M.
    • +
    • Axel L.
    • +
    • Bernd L.
    • +
    • Christian B.
    • +
    • Christian <chges100> G.
    • +
    • Claus-Peter S.
    • +
    • David S.
    • +
    • Elias <TheAmazingLooser> S.
    • +
    • Francis M.
    • +
    • Frank <frasax> S.
    • +
    • Georg I.
    • +
    • Henry <Minusman> L.
    • +
    • Holger R.
    • +
    • Iris F.
    • +
    • Jürgen <jt> T.
    • +
    • Kurt K.
    • +
    • Marc <PapaBear_Marc> B.
    • +
    • Mark W.
    • +
    • Moritz <MoMa> M.
    • +
    • Niccolo C.
    • +
    • Nicolas P.
    • +
    • Norbert L.
    • +
    • Olaf H.
    • +
    • Rafael S.
    • +
    • Reinhard G.
    • +
    • Riccardo A.
    • +
    • Roger B.
    • +
    • Sherwin C.
    • +
    • Steffen <_steffens_> S.
    • +
    • Steffen <Steffen> H.
    • +
    • Stephen R.
    • +
    • Steven D.
    • +
    • Thomas P.
    • +
    • Thomas G.
    • +
    • Ulrike <astronomy_ffm> K.
    • +
    + + \ No newline at end of file diff --git a/licenses/Denoise-Model-LICENSE.html b/licenses/Denoise-Model-LICENSE.html new file mode 100644 index 0000000..35733a3 --- /dev/null +++ b/licenses/Denoise-Model-LICENSE.html @@ -0,0 +1,24 @@ + + + + +

    The provided GraXpert Denoising Models by GraXpert Development Team are licensed under CC BY-NC-SA 4.0

    +

    We would like to thank the following people who contributed to this model by submitting training images:

    +
      +
    • Florian <Florian>
    • +
    • Holger <Holger> R.
    • +
    • Julian <Julian>
    • +
    • Jürgen <Jenafan>
    • +
    • Kurt <ku_kro> K.
    • +
    • Marc <PapaBear_Marc> B.
    • +
    • Matthias <AstroMatz>
    • +
    • Moritz <MoMa> M.
    • +
    • Rafael <Rafael> S.
    • +
    • Ronny <Ronny>
    • +
    • Sabine <Sabine>
    • +
    • Sebastian <PurpleCloud>
    • +
    • Steffen <_steffens_ > S.
    • +
    • Steffen <Steffen> H.
    • +
    + + \ No newline at end of file From 26e8247dcce0dc6a142ad2f8c7c0b8db8d79c2af Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 22:19:23 +0100 Subject: [PATCH 51/59] add ai_batch_size property to preferences, advanced settings, and cli --- graxpert/application/app.py | 36 +++++++++++++++++------------- graxpert/application/app_events.py | 1 + graxpert/cmdline_tools.py | 11 ++++++++- graxpert/denoising.py | 2 +- graxpert/main.py | 9 ++++++++ graxpert/preferences.py | 1 + graxpert/ui/right_menu.py | 8 +++++++ 7 files changed, 50 insertions(+), 18 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index 3514757..eb8c74c 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -84,8 +84,12 @@ def initialize(self): eventbus.add_listener(AppEvents.BGE_AI_VERSION_CHANGED, self.on_bge_ai_version_changed) eventbus.add_listener(AppEvents.DENOISE_AI_VERSION_CHANGED, self.on_denoise_ai_version_changed) eventbus.add_listener(AppEvents.SCALING_CHANGED, self.on_scaling_changed) + eventbus.add_listener(AppEvents.AI_BATCH_SIZE_CHANGED, self.on_ai_batch_size_changed) # event handling + def on_ai_batch_size_changed(self, event): + self.prefs.ai_batch_size = event["ai_batch_size"] + def on_bge_ai_version_changed(self, event): self.prefs.bge_ai_version = event["bge_ai_version"] @@ -133,9 +137,9 @@ def on_calculate_request(self, event=None): try: self.prefs.images_linked_option = False - + img_array_to_be_processed = np.copy(self.images.get("Original").img_array) - + background = AstroImage() background.set_from_array( extract_background( @@ -166,7 +170,7 @@ def on_calculate_request(self, event=None): self.images.set("Gradient-Corrected", gradient_corrected) self.images.set("Background", background) - + self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option), self.prefs.saturation) eventbus.emit(AppEvents.CALCULATE_SUCCESS) @@ -312,10 +316,10 @@ def on_save_as_changed(self, event): def on_smoothing_changed(self, event): self.prefs.smoothing_option = event["smoothing_option"] - + def on_denoise_strength_changed(self, event): self.prefs.denoise_strength = event["denoise_strength"] - + def on_denoise_request(self, event): if self.images.get("Original") is None: messagebox.showerror("Error", _("Please load your picture first.")) @@ -330,12 +334,12 @@ def on_denoise_request(self, event): try: img_array_to_be_processed = np.copy(self.images.get("Original").img_array) - if (self.images.get("Gradient-Corrected") is not None): + if self.images.get("Gradient-Corrected") is not None: img_array_to_be_processed = np.copy(self.images.get("Gradient-Corrected").img_array) - + self.prefs.images_linked_option = True ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.prefs.denoise_ai_version) - imarray = denoise(img_array_to_be_processed, ai_model_path, self.prefs.denoise_strength, progress=progress) + imarray = denoise(img_array_to_be_processed, ai_model_path, self.prefs.denoise_strength, batch_size=self.prefs.ai_batch_size, progress=progress) denoised = AstroImage() denoised.set_from_array(imarray) @@ -345,9 +349,9 @@ def on_denoise_request(self, event): denoised.update_fits_header(self.images.get("Original").fits_header, background_mean, self.prefs, self.cmd.app_state) denoised.copy_metadata(self.images.get("Original")) - + self.images.set("Denoised", denoised) - + self.images.stretch_all(StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option, self.prefs.images_linked_option), self.prefs.saturation) eventbus.emit(AppEvents.DENOISE_SUCCESS) @@ -375,13 +379,13 @@ def on_save_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - if (self.images.get("Denoised") is not None): + if self.images.get("Denoised") is not None: self.images.get("Denoised").save(dir, self.prefs.saveas_option) - elif (self.images.get("Gradient-Corrected") is not None): + elif self.images.get("Gradient-Corrected") is not None: self.images.get("Gradient-Corrected").save(dir, self.prefs.saveas_option) else: self.images.get("Original").save(dir, self.prefs.saveas_option) - + except Exception as e: logging.exception(e) eventbus.emit(AppEvents.SAVE_ERROR) @@ -425,13 +429,13 @@ def on_save_stretched_request(self, event): eventbus.emit(AppEvents.SAVE_BEGIN) try: - if (self.images.get("Denoised") is not None): + if self.images.get("Denoised") is not None: self.images.get("Denoised").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) - elif (self.images.get("Gradient-Corrected") is not None): + elif self.images.get("Gradient-Corrected") is not None: self.images.get("Gradient-Corrected").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) else: self.images.get("Original").save_stretched(dir, self.prefs.saveas_option, StretchParameters(self.prefs.stretch_option, self.prefs.channels_linked_option)) - + except Exception as e: eventbus.emit(AppEvents.SAVE_ERROR) logging.exception(e) diff --git a/graxpert/application/app_events.py b/graxpert/application/app_events.py index ad5a1b1..147d585 100644 --- a/graxpert/application/app_events.py +++ b/graxpert/application/app_events.py @@ -76,3 +76,4 @@ class AppEvents(Enum): CORRECTION_TYPE_CHANGED = auto() LANGUAGE_CHANGED = auto() SCALING_CHANGED = auto() + AI_BATCH_SIZE_CHANGED = auto() diff --git a/graxpert/cmdline_tools.py b/graxpert/cmdline_tools.py index b602944..4dd9487 100644 --- a/graxpert/cmdline_tools.py +++ b/graxpert/cmdline_tools.py @@ -220,6 +220,8 @@ def execute(self): preferences.ai_version = json_prefs["ai_version"] if "denoise_strength" in json_prefs: preferences.denoise_strength = json_prefs["denoise_strength"] + if "ai_batch_size" in json_prefs: + preferences.ai_batch_size = json_prefs["ai_batch_size"] except Exception as e: logging.exception(e) @@ -233,6 +235,12 @@ def execute(self): logging.info(f"Using user-supplied denoise strength value {preferences.denoise_strength}.") else: logging.info(f"Using stored denoise strength value {preferences.denoise_strength}.") + + if self.args.ai_batch_size is not None: + preferences.ai_batch_size = self.args.ai_batch_size + logging.info(f"Using user-supplied batch size value {preferences.ai_batch_size}.") + else: + logging.info(f"Using stored batch size value {preferences.ai_batch_size}.") ai_model_path = ai_model_path_from_version(denoise_ai_models_dir, self.get_ai_version(preferences)) @@ -249,7 +257,8 @@ def execute(self): denoise( astro_Image.img_array, ai_model_path, - preferences.denoise_strength + preferences.denoise_strength, + batch_size=preferences.ai_batch_size )) processed_Astro_Image.save(self.get_save_path(), self.get_output_file_format()) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 76345de..17d9935 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -8,7 +8,7 @@ from graxpert.ai_model_handling import get_execution_providers_ordered -def denoise(image, ai_path, strength, batch_size=5, window_size=256, stride=128, progress=None): +def denoise(image, ai_path, strength, batch_size=3, window_size=256, stride=128, progress=None): logging.info("Starting denoising") diff --git a/graxpert/main.py b/graxpert/main.py index 36de75b..a8b903f 100644 --- a/graxpert/main.py +++ b/graxpert/main.py @@ -241,6 +241,15 @@ def main(): type=float, help='Strength of the desired denoising effect, default: "1.0"', ) + denoise_parser.add_argument( + "-batch_size", + "--ai_batch_size", + nargs="?", + required=False, + default=None, + type=int, + help='Number of image tiles which Graxpert will denoise in parallel. Be careful: increasing this value might result in out-of-memory errors. Valid Range: 1..50, default: "3"', + ) if "-h" in sys.argv or "--help" in sys.argv: if "denoising" in sys.argv: diff --git a/graxpert/preferences.py b/graxpert/preferences.py index bc25e93..dd92073 100644 --- a/graxpert/preferences.py +++ b/graxpert/preferences.py @@ -40,6 +40,7 @@ class Prefs: denoise_ai_version: AnyStr = None graxpert_version: AnyStr = graxpert_version denoise_strength: float = 0.5 + ai_batch_size: int = 3 def app_state_2_prefs(prefs: Prefs, app_state: AppState) -> Prefs: diff --git a/graxpert/ui/right_menu.py b/graxpert/ui/right_menu.py index 2b516db..4951b7b 100644 --- a/graxpert/ui/right_menu.py +++ b/graxpert/ui/right_menu.py @@ -159,6 +159,11 @@ def __init__(self, master, **kwargs): self.denoise_ai_options.insert(0, "None") self.denoise_ai_version.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.DENOISE_AI_VERSION_CHANGED, {"denoise_ai_version": self.denoise_ai_version.get()})) + # ai settings + self.ai_batch_size = tk.IntVar() + self.ai_batch_size.set(graxpert.prefs.ai_batch_size) + self.ai_batch_size.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.AI_BATCH_SIZE_CHANGED, {"ai_batch_size": self.ai_batch_size.get()})) + self.create_and_place_children() self.setup_layout() @@ -206,6 +211,9 @@ def lang_change(lang): CTkLabel(self, text=_("Denoising AI-Model"), font=self.heading_font2).grid(column=0, row=self.nrow(), pady=pady, sticky=tk.N) GraXpertOptionMenu(self, variable=self.denoise_ai_version, values=self.denoise_ai_options).grid(**self.default_grid()) + # ai settings + ValueSlider(self, variable=self.ai_batch_size, variable_name=_("AI Batch Size"), min_value=1, max_value=50, precision=0).grid(**self.default_grid()) + def setup_layout(self): self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) From 95d84e340fe01244abae2f94881cec664d214ab7 Mon Sep 17 00:00:00 2001 From: David Schmelter Date: Fri, 29 Mar 2024 22:55:12 +0100 Subject: [PATCH 52/59] move stretch options to dedicated menu --- graxpert/ui/left_menu.py | 102 +++++++++++++++++++++++++++------------ setup.py | 2 +- 2 files changed, 72 insertions(+), 32 deletions(-) diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index 85d2517..8ee3567 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -11,9 +11,9 @@ from graxpert.ui.widgets import CollapsibleMenuFrame, GraXpertButton, GraXpertCheckbox, GraXpertOptionMenu, GraXpertScrollableFrame, ProcessingStep, ValueSlider, default_label_width, padx, pady -class LoadMenu(CollapsibleMenuFrame): +class StretchMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Loading"), show=True, number=1, **kwargs) + super().__init__(parent, title=_("Stretching"), show=False, number=1, **kwargs) # stretch options self.stretch_options = ["No Stretch", "10% Bg, 3 sigma", "15% Bg, 3 sigma", "20% Bg, 3 sigma", "30% Bg, 2 sigma"] @@ -32,22 +32,12 @@ def __init__(self, parent, **kwargs): self.create_children() self.setup_layout() self.place_children() - - eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "LOAD" else None) + + eventbus.add_listener(AppEvents.LOAD_IMAGE_END, lambda e: self.show_menu()) def create_children(self): super().create_children() - # image loading - self.load_image_button = GraXpertButton( - self.sub_frame, - text=_("Load Image"), - fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], - hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], - command=self.menu_open_clicked, - ) - self.tt_load = tooltip.Tooltip(self.load_image_button, text=tooltip.load_text) - # stretch options self.stretch_options_title = ProcessingStep(self.sub_frame, number=0, indent=2, title=_(" Stretch Options")) self.stretch_menu = GraXpertOptionMenu( @@ -80,15 +70,59 @@ def next_row(): row += 1 return row - # image loading - self.load_image_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) - # stretch options self.stretch_options_title.grid(column=0, row=next_row(), columnspan=2, pady=pady, sticky=tk.EW) self.stretch_menu.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) self.saturation_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) self.channels_linked_switch.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + def show_menu(self): + if not self.show: + self.show = True + self.place_sub_frame(self.show) + self.sub_frame.update() + eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "STRETCH") + + +class LoadMenu(CollapsibleMenuFrame): + def __init__(self, parent, **kwargs): + super().__init__(parent, title=_("Loading"), show=True, number=2, **kwargs) + + self.create_children() + self.setup_layout() + self.place_children() + + eventbus.add_listener(UiEvents.SHOW_MENU_REQUEST, lambda e: self.hide() if not e == "LOAD" else None) + + def create_children(self): + super().create_children() + + # image loading + self.load_image_button = GraXpertButton( + self.sub_frame, + text=_("Load Image"), + fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], + hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], + command=self.menu_open_clicked, + ) + self.tt_load = tooltip.Tooltip(self.load_image_button, text=tooltip.load_text) + + def setup_layout(self): + super().setup_layout() + + def place_children(self): + super().place_children() + + row = -1 + + def next_row(): + nonlocal row + row += 1 + return row + + # image loading + self.load_image_button.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) + def toggle(self): super().toggle() if self.show: @@ -100,7 +134,7 @@ def menu_open_clicked(self, event=None): class CropMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Crop"), show=False, number=2, **kwargs) + super().__init__(parent, title=_("Crop"), show=False, number=3, **kwargs) self.create_children() self.setup_layout() self.place_children() @@ -110,11 +144,13 @@ def __init__(self, parent, **kwargs): def create_children(self): super().create_children() - self.cropapply_button = GraXpertButton(self.sub_frame, - text=_("Apply crop"), - fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], - hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], - command=lambda: eventbus.emit(UiEvents.APPLY_CROP_REQUEST)) + self.cropapply_button = GraXpertButton( + self.sub_frame, + text=_("Apply crop"), + fg_color=ThemeManager.theme["Accent.CTkButton"]["fg_color"], + hover_color=ThemeManager.theme["Accent.CTkButton"]["hover_color"], + command=lambda: eventbus.emit(UiEvents.APPLY_CROP_REQUEST), + ) def setup_layout(self): super().setup_layout() @@ -134,7 +170,7 @@ def toggle(self): class ExtractionMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Background Extraction"), show=False, number=3, **kwargs) + super().__init__(parent, title=_("Background Extraction"), show=False, number=4, **kwargs) # method selection self.interpol_options = ["RBF", "Splines", "Kriging", "AI"] @@ -256,12 +292,12 @@ def toggle(self): class DenoiseMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Denoising"), show=False, number=4, **kwargs) - + super().__init__(parent, title=_("Denoising"), show=False, number=5, **kwargs) + self.denoise_strength = tk.DoubleVar() self.denoise_strength.set(graxpert.prefs.denoise_strength) self.denoise_strength.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.DENOISE_STRENGTH_CHANGED, {"denoise_strength": self.denoise_strength.get()})) - + self.create_children() self.setup_layout() self.place_children() @@ -279,8 +315,10 @@ def create_children(self): command=lambda: eventbus.emit(AppEvents.DENOISE_REQUEST), ) self.tt_load = tooltip.Tooltip(self.denoise_button, text=tooltip.denoise_text) - - self.denoise_strength_slider = ValueSlider(self.sub_frame, width=default_label_width, variable_name=_("Denoise Strength"), variable=self.denoise_strength, min_value=0.0, max_value=1.0, precision=2) + + self.denoise_strength_slider = ValueSlider( + self.sub_frame, width=default_label_width, variable_name=_("Denoise Strength"), variable=self.denoise_strength, min_value=0.0, max_value=1.0, precision=2 + ) tooltip.Tooltip(self.denoise_strength_slider, text=tooltip.bg_tol_text) def setup_layout(self): @@ -288,7 +326,7 @@ def setup_layout(self): def place_children(self): super().place_children() - + self.denoise_strength_slider.grid(column=1, row=0, pady=pady, sticky=tk.EW) self.denoise_button.grid(column=1, row=1, pady=pady, sticky=tk.EW) @@ -300,7 +338,7 @@ def toggle(self): class SaveMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Saving"), show=False, number=5, **kwargs) + super().__init__(parent, title=_("Saving"), show=False, number=6, **kwargs) # saving self.saveas_options = ["16 bit Tiff", "32 bit Tiff", "16 bit Fits", "32 bit Fits", "16 bit XISF", "32 bit XISF"] @@ -366,6 +404,7 @@ def __init__(self, parent, **kwargs): self.place_children() def create_children(self): + self.stretch_menu = StretchMenu(self, fg_color="transparent") self.load_menu = LoadMenu(self, fg_color="transparent") self.crop_menu = CropMenu(self, fg_color="transparent") self.extraction_menu = ExtractionMenu(self, fg_color="transparent") @@ -385,6 +424,7 @@ def next_row(): row += 1 return row + self.stretch_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.load_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.crop_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.extraction_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) diff --git a/setup.py b/setup.py index ab60703..8564be8 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ "add_to_path": True, "data": msi_data, "summary_data": msi_summary_data, - "upgrade_code": "{8887032b-9211-4752-8f88-6d29833bb001}", + "upgrade_code": "{d0ba2b1d-e18e-42c9-9ded-beb9cadad494}", "target_name": "GraXpert", "install_icon": "./img/Icon.ico", } From bbb7663be74425ab3d83c5263c43a768aacc276b Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Mar 2024 15:32:36 +0100 Subject: [PATCH 53/59] The median value near the mouse with a radius of 2 pixels is now shown in the right info text in the lower status bar --- graxpert/astroimage.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/graxpert/astroimage.py b/graxpert/astroimage.py index 243a570..ea30942 100644 --- a/graxpert/astroimage.py +++ b/graxpert/astroimage.py @@ -208,21 +208,21 @@ def save_stretched(self, dir, saveas_type, stretch_params): return def get_local_median(self, img_point): - sample_radius = 25 + sample_radius = 2 y1 = int(np.amax([img_point[1] - sample_radius, 0])) y2 = int(np.amin([img_point[1] + sample_radius, self.height])) x1 = int(np.amax([img_point[0] - sample_radius, 0])) x2 = int(np.amin([img_point[0] + sample_radius, self.width])) if self.img_array.shape[-1] == 3: - R = sigma_clipped_stats(data=self.img_array[y1:y2, x1:x2, 0], cenfunc="median", stdfunc="std", grow=4)[1] - G = sigma_clipped_stats(data=self.img_array[y1:y2, x1:x2, 1], cenfunc="median", stdfunc="std", grow=4)[1] - B = sigma_clipped_stats(data=self.img_array[y1:y2, x1:x2, 2], cenfunc="median", stdfunc="std", grow=4)[1] + R = np.median(self.img_array[y1:y2, x1:x2, 0]) + G = np.median(self.img_array[y1:y2, x1:x2, 1]) + B = np.median(self.img_array[y1:y2, x1:x2, 2]) return [R, G, B] if self.img_array.shape[-1] == 1: - L = sigma_clipped_stats(data=self.img_array[x1:x2, y1:y2, 0], cenfunc="median", stdfunc="std", grow=4)[1] + L = np.median(self.img_array[x1:x2, y1:y2, 0]) return L From bf0a8042b7e475f1234ee99ef9cd02476e435c63 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Mar 2024 15:33:33 +0100 Subject: [PATCH 54/59] Nearest Neighbor is now used as the interpolation method for display of image --- graxpert/ui/canvas.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graxpert/ui/canvas.py b/graxpert/ui/canvas.py index c451040..2e9b050 100644 --- a/graxpert/ui/canvas.py +++ b/graxpert/ui/canvas.py @@ -441,7 +441,7 @@ def draw_image(self, pil_image, tags=None): affine_inv = (mat_inv[0, 0], mat_inv[0, 1], mat_inv[0, 2], mat_inv[1, 0], mat_inv[1, 1], mat_inv[1, 2]) - dst = pil_image.transform((canvas_width, canvas_height), Image.AFFINE, affine_inv, Image.BILINEAR) + dst = pil_image.transform((canvas_width, canvas_height), Image.AFFINE, affine_inv, Image.NEAREST) im = ImageTk.PhotoImage(image=dst) From 482c1ef0247b0b7f33339a4457f184942f6f929f Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Mar 2024 15:33:57 +0100 Subject: [PATCH 55/59] Stretch options are now shown in the lower status bar --- graxpert/application/app.py | 3 ++ graxpert/ui/application_frame.py | 2 +- graxpert/ui/left_menu.py | 85 ++------------------------------ graxpert/ui/statusbar.py | 53 ++++++++++++++++++-- 4 files changed, 58 insertions(+), 85 deletions(-) diff --git a/graxpert/application/app.py b/graxpert/application/app.py index eb8c74c..0a2a361 100644 --- a/graxpert/application/app.py +++ b/graxpert/application/app.py @@ -185,6 +185,9 @@ def on_calculate_request(self, event=None): eventbus.emit(AppEvents.CALCULATE_END) def on_change_saturation_request(self, event): + if self.images.get("Original") is None: + return + self.prefs.saturation = event["saturation"] eventbus.emit(AppEvents.CHANGE_SATURATION_BEGIN) diff --git a/graxpert/ui/application_frame.py b/graxpert/ui/application_frame.py index 77a89d2..371f8b9 100644 --- a/graxpert/ui/application_frame.py +++ b/graxpert/ui/application_frame.py @@ -33,7 +33,7 @@ def create_children(self): self.canvas = Canvas(self) self.help_frame = HelpFrame(self, fg_color="transparent", width=300) self.advanced_frame = AdvancedFrame(self, fg_color="transparent", width=300) - self.statusbar_frame = StatusBar(self) + self.statusbar_frame = StatusBar(self, fg_color="transparent") def setup_layout(self): self.columnconfigure(0, weight=0) diff --git a/graxpert/ui/left_menu.py b/graxpert/ui/left_menu.py index 8ee3567..7787a78 100644 --- a/graxpert/ui/left_menu.py +++ b/graxpert/ui/left_menu.py @@ -11,82 +11,9 @@ from graxpert.ui.widgets import CollapsibleMenuFrame, GraXpertButton, GraXpertCheckbox, GraXpertOptionMenu, GraXpertScrollableFrame, ProcessingStep, ValueSlider, default_label_width, padx, pady -class StretchMenu(CollapsibleMenuFrame): - def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Stretching"), show=False, number=1, **kwargs) - - # stretch options - self.stretch_options = ["No Stretch", "10% Bg, 3 sigma", "15% Bg, 3 sigma", "20% Bg, 3 sigma", "30% Bg, 2 sigma"] - self.stretch_option_current = StringVar() - self.stretch_option_current.set(graxpert.prefs.stretch_option) - self.stretch_option_current.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.STRETCH_OPTION_CHANGED, {"stretch_option": self.stretch_option_current.get()})) - - self.saturation = tk.DoubleVar() - self.saturation.set(graxpert.prefs.saturation) - self.saturation.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANGE_SATURATION_REQUEST, {"saturation": self.saturation.get()})) - - self.channels_linked = tk.BooleanVar() - self.channels_linked.set(graxpert.prefs.channels_linked_option) - self.channels_linked.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANNELS_LINKED_CHANGED, {"channels_linked": self.channels_linked.get()})) - - self.create_children() - self.setup_layout() - self.place_children() - - eventbus.add_listener(AppEvents.LOAD_IMAGE_END, lambda e: self.show_menu()) - - def create_children(self): - super().create_children() - - # stretch options - self.stretch_options_title = ProcessingStep(self.sub_frame, number=0, indent=2, title=_(" Stretch Options")) - self.stretch_menu = GraXpertOptionMenu( - self.sub_frame, - variable=self.stretch_option_current, - values=self.stretch_options, - ) - tooltip.Tooltip(self.stretch_menu, text=tooltip.stretch_text) - self.saturation_slider = ValueSlider( - self.sub_frame, - width=default_label_width, - variable_name=_("Saturation"), - variable=self.saturation, - min_value=0, - max_value=3, - precision=1, - ) - self.channels_linked_switch = GraXpertCheckbox(self.sub_frame, width=default_label_width, text=_("Channels linked"), variable=self.channels_linked) - - def setup_layout(self): - super().setup_layout() - - def place_children(self): - super().place_children() - - row = -1 - - def next_row(): - nonlocal row - row += 1 - return row - - # stretch options - self.stretch_options_title.grid(column=0, row=next_row(), columnspan=2, pady=pady, sticky=tk.EW) - self.stretch_menu.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) - self.saturation_slider.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) - self.channels_linked_switch.grid(column=1, row=next_row(), pady=pady, sticky=tk.EW) - - def show_menu(self): - if not self.show: - self.show = True - self.place_sub_frame(self.show) - self.sub_frame.update() - eventbus.emit(UiEvents.SHOW_MENU_REQUEST, "STRETCH") - - class LoadMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Loading"), show=True, number=2, **kwargs) + super().__init__(parent, title=_("Loading"), show=True, number=1, **kwargs) self.create_children() self.setup_layout() @@ -134,7 +61,7 @@ def menu_open_clicked(self, event=None): class CropMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Crop"), show=False, number=3, **kwargs) + super().__init__(parent, title=_("Crop"), show=False, number=2, **kwargs) self.create_children() self.setup_layout() self.place_children() @@ -170,7 +97,7 @@ def toggle(self): class ExtractionMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Background Extraction"), show=False, number=4, **kwargs) + super().__init__(parent, title=_("Background Extraction"), show=False, number=3, **kwargs) # method selection self.interpol_options = ["RBF", "Splines", "Kriging", "AI"] @@ -292,7 +219,7 @@ def toggle(self): class DenoiseMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Denoising"), show=False, number=5, **kwargs) + super().__init__(parent, title=_("Denoising"), show=False, number=4, **kwargs) self.denoise_strength = tk.DoubleVar() self.denoise_strength.set(graxpert.prefs.denoise_strength) @@ -338,7 +265,7 @@ def toggle(self): class SaveMenu(CollapsibleMenuFrame): def __init__(self, parent, **kwargs): - super().__init__(parent, title=_("Saving"), show=False, number=6, **kwargs) + super().__init__(parent, title=_("Saving"), show=False, number=5, **kwargs) # saving self.saveas_options = ["16 bit Tiff", "32 bit Tiff", "16 bit Fits", "32 bit Fits", "16 bit XISF", "32 bit XISF"] @@ -404,7 +331,6 @@ def __init__(self, parent, **kwargs): self.place_children() def create_children(self): - self.stretch_menu = StretchMenu(self, fg_color="transparent") self.load_menu = LoadMenu(self, fg_color="transparent") self.crop_menu = CropMenu(self, fg_color="transparent") self.extraction_menu = ExtractionMenu(self, fg_color="transparent") @@ -424,7 +350,6 @@ def next_row(): row += 1 return row - self.stretch_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.load_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.crop_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) self.extraction_menu.grid(column=0, row=next_row(), ipadx=padx, sticky=tk.N) diff --git a/graxpert/ui/statusbar.py b/graxpert/ui/statusbar.py index e4f6520..1344806 100644 --- a/graxpert/ui/statusbar.py +++ b/graxpert/ui/statusbar.py @@ -1,16 +1,33 @@ import tkinter as tk -from customtkinter import CTkFrame, CTkLabel +from customtkinter import CTkFrame, CTkLabel, StringVar from graxpert.application.app import graxpert from graxpert.application.app_events import AppEvents from graxpert.application.eventbus import eventbus from graxpert.ui.ui_events import UiEvents - +from graxpert.localization import _ +import graxpert.ui.tooltip as tooltip +from graxpert.ui.widgets import GraXpertCheckbox, GraXpertOptionMenu, ProcessingStep, ValueSlider, default_label_width, padx, pady class StatusBar(CTkFrame): def __init__(self, master, **kwargs): super().__init__(master, **kwargs) + + self.stretch_options = ["No Stretch", "10% Bg, 3 sigma", "15% Bg, 3 sigma", "20% Bg, 3 sigma", "30% Bg, 2 sigma"] + self.stretch_option_current = StringVar() + self.stretch_option_current.set(graxpert.prefs.stretch_option) + self.stretch_option_current.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.STRETCH_OPTION_CHANGED, {"stretch_option": self.stretch_option_current.get()})) + + self.saturation = tk.DoubleVar() + self.saturation.set(graxpert.prefs.saturation) + self.saturation.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANGE_SATURATION_REQUEST, {"saturation": self.saturation.get()})) + + self.channels_linked = tk.BooleanVar() + self.channels_linked.set(graxpert.prefs.channels_linked_option) + self.channels_linked.trace_add("write", lambda a, b, c: eventbus.emit(AppEvents.CHANNELS_LINKED_CHANGED, {"channels_linked": self.channels_linked.get()})) + + self.create_children() self.setup_layout() self.place_children() @@ -20,14 +37,42 @@ def __init__(self, master, **kwargs): def create_children(self): self.label_image_info = CTkLabel(self, text="image info") self.label_image_pixel = CTkLabel(self, text="(x, y)") + + self.stretch_option_frame = CTkFrame(self) + + self.stretch_options_title = ProcessingStep(self.stretch_option_frame, number=0, indent=2, title=_(" Stretch Options")) + self.stretch_menu = GraXpertOptionMenu( + self.stretch_option_frame, + variable=self.stretch_option_current, + values=self.stretch_options, + ) + tooltip.Tooltip(self.stretch_menu, text=tooltip.stretch_text) + self.saturation_slider = ValueSlider( + self.stretch_option_frame, + width=default_label_width, + variable_name=_("Saturation"), + variable=self.saturation, + min_value=0, + max_value=3, + precision=1, + ) + self.channels_linked_switch = GraXpertCheckbox(self.stretch_option_frame, width=default_label_width, text=_("Channels linked"), variable=self.channels_linked) + def setup_layout(self): self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) + + def place_children(self): - self.label_image_info.grid(column=0, row=0, sticky=tk.W) - self.label_image_pixel.grid(column=0, row=0, sticky=tk.E) + self.stretch_option_frame.grid(column=0, row=0, sticky=tk.NS) + self.label_image_info.grid(column=0, row=0, padx=padx, sticky=tk.W) + self.label_image_pixel.grid(column=0, row=0, padx=padx, sticky=tk.E) + + self.stretch_menu.grid(column=0, row=0, padx=padx, pady=pady, sticky=tk.E) + self.saturation_slider.grid(column=1, row=0, padx=padx, pady=pady, sticky=tk.EW) + self.channels_linked_switch.grid(column=2, row=0, padx=padx, pady=pady, sticky=tk.W) def register_events(self): eventbus.add_listener(AppEvents.LOAD_IMAGE_END, self.on_load_image_end) From 1bb527f39714736304d177c4e4bd7f1e8d26cd6c Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Sat, 30 Mar 2024 20:33:25 +0100 Subject: [PATCH 56/59] Fixed bug in background extraction due to cv2.resize removing the last dimension of mono images --- graxpert/background_extraction.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/graxpert/background_extraction.py b/graxpert/background_extraction.py index f5e689a..27d0343 100644 --- a/graxpert/background_extraction.py +++ b/graxpert/background_extraction.py @@ -39,6 +39,10 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth # Shrink and pad to avoid artifacts on borders padding = 8 imarray_shrink = cv2.resize(imarray, dsize=(256 - 2 * padding, 256 - 2 * padding), interpolation=cv2.INTER_LINEAR) + + if len(imarray_shrink.shape) == 2: + imarray_shrink = np.expand_dims(imarray_shrink, -1) + imarray_shrink = np.pad(imarray_shrink, ((padding, padding), (padding, padding), (0, 0)), mode="edge") median = [] @@ -104,6 +108,9 @@ def extract_background(in_imarray, background_points, interpolation_type, smooth sigma = 3.0 background = cv2.GaussianBlur(background, ksize=gaussian_kernel(sigma), sigmaX=sigma, sigmaY=sigma) background = cv2.resize(background, dsize=(in_imarray.shape[1], in_imarray.shape[0]), interpolation=cv2.INTER_LINEAR) + + if len(background.shape) == 2: + background = np.expand_dims(background, -1) if progress is not None: progress.update(8) From 5b84ff37278ef0b33ffa8b76e771b1cf89591fdd Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Mon, 1 Apr 2024 12:47:18 +0200 Subject: [PATCH 57/59] Original and Background image do not use Gradient-Corrected image as reference anymore after denoising --- graxpert/AstroImageRepository.py | 43 ++++++++--- graxpert/astroimage.py | 5 +- graxpert/stretch.py | 128 ++++++++++++++----------------- 3 files changed, 91 insertions(+), 85 deletions(-) diff --git a/graxpert/AstroImageRepository.py b/graxpert/AstroImageRepository.py index ca501e8..675073c 100644 --- a/graxpert/AstroImageRepository.py +++ b/graxpert/AstroImageRepository.py @@ -1,5 +1,5 @@ from graxpert.astroimage import AstroImage -from graxpert.stretch import StretchParameters, stretch_all +from graxpert.stretch import StretchParameters, stretch_all, calculate_mtf_stretch_parameters_for_image from typing import Dict class AstroImageRepository: @@ -12,21 +12,40 @@ def get(self, type:str): return self.images[type] def stretch_all(self, stretch_params:StretchParameters, saturation:float): + + if self.get("Original") is None: + return + all_image_arrays = [] + all_mtf_stretch_params = [] - for key, value in self.images.items(): - if (value is not None): - all_image_arrays.append(value.img_array) - - if self.get("Gradient-Corrected") is not None and self.get("Denoised") is not None: - stretches = stretch_all(all_image_arrays, stretch_params, reference_img_array=self.get("Gradient-Corrected").img_array) - else: - stretches = stretch_all(all_image_arrays, stretch_params) + all_image_arrays.append(self.get("Original").img_array) + all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Original").img_array)) + + if self.get("Gradient-Corrected") is not None and self.get("Background") is not None: + all_image_arrays.append(self.get("Gradient-Corrected").img_array) + all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Gradient-Corrected").img_array)) + + all_image_arrays.append(self.get("Background").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + + + if self.get("Denoised") is not None and self.get("Gradient-Corrected") is None: + all_image_arrays.append(self.get("Denoised").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + + elif self.get("Denoised") is not None and self.get("Gradient-Corrected") is not None: + all_image_arrays.append(self.get("Denoised").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[1]) + + + stretches = stretch_all(all_image_arrays, all_mtf_stretch_params) + i = 0 - for key, value in self.images.items(): - if (value is not None): - value.update_display_from_array(stretches[i], saturation) + for key, image in self.images.items(): + if image is not None: + image.update_display_from_array(stretches[i], saturation) i = i + 1 def crop_all(self, start_x:float, end_x:float, start_y:float, end_y:float): diff --git a/graxpert/astroimage.py b/graxpert/astroimage.py index ea30942..0486371 100644 --- a/graxpert/astroimage.py +++ b/graxpert/astroimage.py @@ -118,7 +118,10 @@ def update_display_from_array(self, img_display, saturation): return def stretch(self, stretch_params: StretchParameters): - return np.clip(stretch(self.img_array, stretch_params), 0.0, 1.0) + if stretch_params.do_stretch: + return np.clip(stretch(self.img_array, stretch_params), 0.0, 1.0) + else: + return np.clip(self.img_array, 0.0, 1.0) def crop(self, startx, endx, starty, endy): self.img_array = self.img_array[starty:endy, startx:endx, :] diff --git a/graxpert/stretch.py b/graxpert/stretch.py index 6f2a00f..2e682c6 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -49,96 +49,31 @@ def __init__(self, stretch_option: str, channels_linked: bool = False, images_li elif stretch_option == "30% Bg, 2 sigma": self.bg = 0.3 self.sigma = 2.0 - -def stretch_channel(shm_name, c, stretch_params, mtf_stretch_params, shape, dtype, logging_queue, logging_configurer): - - logging_configurer(logging_queue) - logging.info("stretch.stretch_channel started") - - existing_shm = shared_memory.SharedMemory(name=shm_name) - channels = np.ndarray(shape, dtype, buffer=existing_shm.buf) #[:,:,channel_idx] - channel = channels[:,:,c] - - try: - if not mtf_stretch_params: - mtf_stretch_params = calculate_mtf_stretch_parameters(stretch_params, channel) - - channel[channel <= mtf_stretch_params.shadow_clipping] = 0.0 - channel[channel >= mtf_stretch_params.highlight_clipping] = 1.0 - - indx_inside = np.logical_and(channel > mtf_stretch_params.shadow_clipping, channel < mtf_stretch_params.highlight_clipping) - - channel[indx_inside] = (channel[indx_inside]-mtf_stretch_params.shadow_clipping)/(mtf_stretch_params.highlight_clipping - mtf_stretch_params.shadow_clipping) - - channel = MTF(channel, mtf_stretch_params.midtone) - - except: - logging.exception("An error occured while stretching a color channel") - finally: - existing_shm.close() - - logging.info("stretch.stretch_channel finished") - -def calculate_mtf_stretch_parameters(stretch_params, channel): - channel = channel.flatten() - - indx_clip = np.logical_and(channel < 1.0, channel > 0.0) - median = np.median(channel[indx_clip]) - mad = np.median(np.abs(channel[indx_clip]-median)) - - shadow_clipping = np.clip(median - stretch_params.sigma*mad, 0, 1.0) - highlight_clipping = 1.0 - midtone = MTF((median-shadow_clipping)/(highlight_clipping - shadow_clipping), stretch_params.bg) - - return MTFStretchParameters(midtone, shadow_clipping) def stretch(data, stretch_params: StretchParameters): - return stretch_all([data], stretch_params)[0] + mtf_stretch_param = calculate_mtf_stretch_parameters_for_image(stretch_params, data) + return stretch_all([data], [mtf_stretch_param])[0] -def stretch_all(datas, stretch_params: StretchParameters, reference_img_array=None): - - if not stretch_params.do_stretch: - datas = [data.clip(min=0, max=1) for data in datas] - return datas - - if reference_img_array is None: - reference_img_array = datas[0] + +def stretch_all(datas, mtf_stretch_params: list[MTFStretchParameters]): futures = [] shms = [] copies = [] result = [] - logging_queue = get_logging_queue() - - common_mtf_stretch_params_per_channel = [] - if stretch_params.images_linked: - if stretch_params.channels_linked: - mtf_stretch_params_for_all_channel = calculate_mtf_stretch_parameters(stretch_params, reference_img_array) - common_mtf_stretch_params_per_channel = [mtf_stretch_params_for_all_channel] * reference_img_array.shape[-1] - else: - for c in range(datas[0].shape[-1]): - common_mtf_stretch_params_per_channel.append(calculate_mtf_stretch_parameters(stretch_params, reference_img_array[:,:,c])) - + logging_queue = get_logging_queue() - for data in datas: + for data, mtf_stretch_param in zip(datas, mtf_stretch_params): shm = shared_memory.SharedMemory(create=True, size=data.nbytes) copy = np.ndarray(data.shape, dtype=data.dtype, buffer=shm.buf) np.copyto(copy, data) shms.append(shm) copies.append(copy) - mtf_stretch_params = [None] * data.shape[-1] - - if stretch_params.images_linked: - mtf_stretch_params = common_mtf_stretch_params_per_channel - elif stretch_params.channels_linked: - mtf_stretch_params = calculate_mtf_stretch_parameters(stretch_params, copy) - mtf_stretch_params = [mtf_stretch_params] * data.shape[-1] - for c in range(copy.shape[-1]): - futures.insert(c, executor.submit(stretch_channel, shm.name, c, stretch_params, mtf_stretch_params[c], copy.shape, copy.dtype, logging_queue, worker_configurer)) + futures.insert(c, executor.submit(stretch_channel, shm.name, c, mtf_stretch_param[c], copy.shape, copy.dtype, logging_queue, worker_configurer)) wait(futures) for copy in copies: @@ -150,6 +85,55 @@ def stretch_all(datas, stretch_params: StretchParameters, reference_img_array=No shm.unlink() return result + + +def calculate_mtf_stretch_parameters_for_image(stretch_params, image): + if stretch_params.channels_linked: + mtf_stretch_param = calculate_mtf_stretch_parameters_for_channel(stretch_params, image) + return [mtf_stretch_param] * image.shape[-1] + + else: + return [calculate_mtf_stretch_parameters_for_channel(stretch_params, image[:,:,i]) for i in range(image.shape[-1])] + +def calculate_mtf_stretch_parameters_for_channel(stretch_params, channel): + channel = channel.flatten()[::4] + + indx_clip = np.logical_and(channel < 1.0, channel > 0.0) + median = np.median(channel[indx_clip]) + mad = np.median(np.abs(channel[indx_clip]-median)) + + shadow_clipping = np.clip(median - stretch_params.sigma*mad, 0, 1.0) + highlight_clipping = 1.0 + midtone = MTF((median-shadow_clipping)/(highlight_clipping - shadow_clipping), stretch_params.bg) + + return MTFStretchParameters(midtone, shadow_clipping) + + +def stretch_channel(shm_name, c, mtf_stretch_params, shape, dtype, logging_queue, logging_configurer): + + logging_configurer(logging_queue) + logging.info("stretch.stretch_channel started") + + existing_shm = shared_memory.SharedMemory(name=shm_name) + channels = np.ndarray(shape, dtype, buffer=existing_shm.buf) #[:,:,channel_idx] + channel = channels[:,:,c] + + try: + channel[channel <= mtf_stretch_params.shadow_clipping] = 0.0 + channel[channel >= mtf_stretch_params.highlight_clipping] = 1.0 + + indx_inside = np.logical_and(channel > mtf_stretch_params.shadow_clipping, channel < mtf_stretch_params.highlight_clipping) + + channel[indx_inside] = (channel[indx_inside]-mtf_stretch_params.shadow_clipping)/(mtf_stretch_params.highlight_clipping - mtf_stretch_params.shadow_clipping) + + channel = MTF(channel, mtf_stretch_params.midtone) + + except: + logging.exception("An error occured while stretching a color channel") + finally: + existing_shm.close() + + logging.info("stretch.stretch_channel finished") def MTF(data, midtone): From 0f70695e09506e0ab5ac29429401a569021ef1ce Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Tue, 2 Apr 2024 17:30:51 +0200 Subject: [PATCH 58/59] Fixed error when No Stretch was selected --- graxpert/AstroImageRepository.py | 47 +++++++++++++++++++------------- graxpert/stretch.py | 3 ++ 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/graxpert/AstroImageRepository.py b/graxpert/AstroImageRepository.py index 675073c..9c29c15 100644 --- a/graxpert/AstroImageRepository.py +++ b/graxpert/AstroImageRepository.py @@ -16,30 +16,39 @@ def stretch_all(self, stretch_params:StretchParameters, saturation:float): if self.get("Original") is None: return - all_image_arrays = [] - all_mtf_stretch_params = [] + stretches = [] - all_image_arrays.append(self.get("Original").img_array) - all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Original").img_array)) - - if self.get("Gradient-Corrected") is not None and self.get("Background") is not None: - all_image_arrays.append(self.get("Gradient-Corrected").img_array) - all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Gradient-Corrected").img_array)) + if not stretch_params.do_stretch: + for key, image in self.images.items(): + if image is not None: + stretches.append(image.img_array) + + else: + + all_image_arrays = [] + all_mtf_stretch_params = [] - all_image_arrays.append(self.get("Background").img_array) - all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + all_image_arrays.append(self.get("Original").img_array) + all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Original").img_array)) - - if self.get("Denoised") is not None and self.get("Gradient-Corrected") is None: - all_image_arrays.append(self.get("Denoised").img_array) - all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + if self.get("Gradient-Corrected") is not None and self.get("Background") is not None: + all_image_arrays.append(self.get("Gradient-Corrected").img_array) + all_mtf_stretch_params.append(calculate_mtf_stretch_parameters_for_image(stretch_params, self.get("Gradient-Corrected").img_array)) + + all_image_arrays.append(self.get("Background").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + - elif self.get("Denoised") is not None and self.get("Gradient-Corrected") is not None: - all_image_arrays.append(self.get("Denoised").img_array) - all_mtf_stretch_params.append(all_mtf_stretch_params[1]) + if self.get("Denoised") is not None and self.get("Gradient-Corrected") is None: + all_image_arrays.append(self.get("Denoised").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[0]) + + elif self.get("Denoised") is not None and self.get("Gradient-Corrected") is not None: + all_image_arrays.append(self.get("Denoised").img_array) + all_mtf_stretch_params.append(all_mtf_stretch_params[1]) + - - stretches = stretch_all(all_image_arrays, all_mtf_stretch_params) + stretches = stretch_all(all_image_arrays, all_mtf_stretch_params) i = 0 diff --git a/graxpert/stretch.py b/graxpert/stretch.py index 2e682c6..6cf4b0c 100644 --- a/graxpert/stretch.py +++ b/graxpert/stretch.py @@ -53,6 +53,9 @@ def __init__(self, stretch_option: str, channels_linked: bool = False, images_li def stretch(data, stretch_params: StretchParameters): + if not stretch_params.do_stretch: + return data + mtf_stretch_param = calculate_mtf_stretch_parameters_for_image(stretch_params, data) return stretch_all([data], [mtf_stretch_param])[0] From 309a2247412468cb5210b0e8bfaff937f0bd34c1 Mon Sep 17 00:00:00 2001 From: Steffen Hirtle Date: Wed, 17 Apr 2024 17:53:54 +0200 Subject: [PATCH 59/59] Denoised image is now cached --- graxpert/denoising.py | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/graxpert/denoising.py b/graxpert/denoising.py index 17d9935..d8484d6 100644 --- a/graxpert/denoising.py +++ b/graxpert/denoising.py @@ -6,15 +6,21 @@ import onnxruntime as ort from graxpert.ai_model_handling import get_execution_providers_ordered - +from graxpert.application.eventbus import eventbus +from graxpert.application.app_events import AppEvents +from graxpert.ui.ui_events import UiEvents def denoise(image, ai_path, strength, batch_size=3, window_size=256, stride=128, progress=None): logging.info("Starting denoising") input = copy.deepcopy(image) - num_colors = image.shape[-1] + global cached_denoised_image + if cached_denoised_image is not None: + return blend_images(input, cached_denoised_image, strength) + + num_colors = image.shape[-1] if num_colors == 1: image = np.array([image[:, :, 0], image[:, :, 0], image[:, :, 0]]) image = np.moveaxis(image, 0, -1) @@ -112,14 +118,28 @@ def denoise(image, ai_path, strength, batch_size=3, window_size=256, stride=128, logging.info(f"Progress: {p}%") last_progress = p - output = np.clip(output, 0, 1) output = output[offset : H + offset, offset : W + offset, :] - output = output * strength + input * (1 - strength) - + if num_colors == 1: output = np.array([output[:, :, 0]]) output = np.moveaxis(output, 0, -1) + cached_denoised_image = output + output = blend_images(input, output, strength) + logging.info("Finished denoising") return output + +def blend_images(original_image, denoised_image, strength): + blend = denoised_image * strength + original_image * (1-strength) + return np.clip(blend, 0, 1) + +def reset_cached_denoised_image(event): + global cached_denoised_image + cached_denoised_image = None + +cached_denoised_image = None +eventbus.add_listener(AppEvents.LOAD_IMAGE_REQUEST, reset_cached_denoised_image) +eventbus.add_listener(AppEvents.CALCULATE_REQUEST, reset_cached_denoised_image) +eventbus.add_listener(UiEvents.APPLY_CROP_REQUEST, reset_cached_denoised_image) \ No newline at end of file

    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 z z=0i8%%&AkS;?AU|zr|vYzF*~1XtD`uFw5gqh6StphB!&?#)YxjL1q~;e=8iVTVxD$ z3O$Q;JNWZ|D0}