diff --git a/src/vstarstack/library/data.py b/src/vstarstack/library/data.py index 4c8a37cb..8488a61f 100644 --- a/src/vstarstack/library/data.py +++ b/src/vstarstack/library/data.py @@ -198,7 +198,7 @@ def get_linked_channel(self, channel : str, link_type : str): return None, None, None if channel not in self.links[link_type]: return None, None, None - name = self.links[link_type][channel] + name = str(self.links[link_type][channel]) layer, opts = self.get_channel(name) return layer, opts, name diff --git a/src/vstarstack/tool/image_processing/drop_unsharp.py b/src/vstarstack/tool/image_processing/drop_unsharp.py index 29021e36..bbd15efb 100644 --- a/src/vstarstack/tool/image_processing/drop_unsharp.py +++ b/src/vstarstack/tool/image_processing/drop_unsharp.py @@ -26,35 +26,47 @@ class EstimationMethod(Enum): SOBEL = 0 LAPLACE = 1 -def measure_sharpness(img : np.ndarray, method : EstimationMethod) -> float: - if method == EstimationMethod.SOBEL: - sx = scipy.ndimage.sobel(img, axis=0, mode='constant') - sy = scipy.ndimage.sobel(img, axis=1, mode='constant') - sobel = np.sqrt(sx**2 + sy**2) - metric = np.sum(sobel) - summ = np.sum(img) - return metric / summ - elif method == EstimationMethod.LAPLACE: - sx = scipy.ndimage.laplace(img, mode='constant') - sy = scipy.ndimage.laplace(img, mode='constant') - sobel = np.sqrt(sx**2 + sy**2) - metric = np.sum(sobel) - summ = np.sum(img) - return metric / summ - else: - raise Exception(f"Unknown method {method}") +def measure_sharpness_sobel(img : np.ndarray, mask : np.ndarray | None) -> float: + if mask is not None: + img = img * mask + sx = scipy.ndimage.sobel(img, axis=0, mode='constant') + sy = scipy.ndimage.sobel(img, axis=1, mode='constant') + sobel = np.sqrt(sx**2 + sy**2) + if mask is not None: + sobel = sobel * mask + metric = np.sum(sobel) + summ = np.sum(img) + return metric / summ + +def measure_sharpness_laplace(img : np.ndarray, mask : np.ndarray | None) -> float: + if mask is not None: + img = img * mask + sx = scipy.ndimage.laplace(img, mode='constant') + sy = scipy.ndimage.laplace(img, mode='constant') + laplace = np.sqrt(sx**2 + sy**2) + if mask is not None: + laplace = laplace * mask + metric = np.sum(laplace) + summ = np.sum(img) + return metric / summ def measure_sharpness_df(df : vstarstack.library.data.DataFrame, method : EstimationMethod) -> float: metric = 0 nch = 0 + if method not in [EstimationMethod.LAPLACE, EstimationMethod.SOBEL]: + raise Exception(f"Invalid method {method}") for channel in df.get_channels(): img, opts = df.get_channel(channel) - if not opts["brightness"]: + if not df.get_channel_option(channel, "brightness"): continue amax = np.amax(img) amin = np.amin(img) img = (img - amin)/(amax - amin) - metric += measure_sharpness(img, method) + mask, _, _ = df.get_linked_channel(channel, "mask") + if method == EstimationMethod.SOBEL: + metric += measure_sharpness_sobel(img, mask) + elif method == EstimationMethod.LAPLACE: + metric += measure_sharpness_laplace(img, mask) nch += 1 if nch == 0: return 0 diff --git a/src/vstarstack/tool/objects/cut.py b/src/vstarstack/tool/objects/cut.py index ae256cc5..5139ad1d 100644 --- a/src/vstarstack/tool/objects/cut.py +++ b/src/vstarstack/tool/objects/cut.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2022 Vladislav Tsendrovskii +# Copyright (c) 2022-2024 Vladislav Tsendrovskii # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,6 +14,7 @@ import json import os import numpy as np +import cv2 import vstarstack.tool.cfg import vstarstack.library.common @@ -44,10 +45,14 @@ def run(project: vstarstack.tool.cfg.Project, argv: list[str]): print(f"Loading info: {name}, r = {r}") if r > maxr: maxr = r + disk_radius=int(maxr+0.5) maxr = int(maxr+0.5)+margin size = 2*maxr+1 print("maxr = ", maxr, " size = ", size) + mask = np.zeros((size,size)) + cv2.circle(mask, (maxr,maxr), disk_radius, 1, -1) + for name, filename in files: print(name) with open(filename, encoding='utf8') as f: @@ -67,13 +72,14 @@ def run(project: vstarstack.tool.cfg.Project, argv: list[str]): print("Can not load ", name) continue - weight_links = dict(image.links["weight"]) - - for channel in image.get_channels(): + image.add_channel(mask, "mask", mask=True) + for channel in list(image.get_channels()): layer, opts = image.get_channel(channel) - if opts["encoded"]: + if image.get_channel_option(channel, "encoded"): image.remove_channel(channel) continue + if image.get_channel_option(channel, "mask"): + continue w = layer.shape[1] h = layer.shape[0] @@ -108,6 +114,8 @@ def run(project: vstarstack.tool.cfg.Project, argv: list[str]): img = np.zeros((size, size)) img[target_top:target_top+copy_h, target_left:target_left+copy_w] = layer[source_top:source_top+copy_h, source_left:source_left+copy_w] + image.replace_channel(img, channel, **opts) + image.add_channel_link(channel, "mask", "mask") detection["roi"] = { "x1": left, @@ -115,14 +123,10 @@ def run(project: vstarstack.tool.cfg.Project, argv: list[str]): "x2": right, "y2": bottom } - image.replace_channel(img, channel, **opts) vstarstack.tool.common.check_dir_exists(filename) with open(filename, "w", encoding='utf8') as f: json.dump(detection, f, indent=4, ensure_ascii=False) - for ch, value in weight_links.items(): - image.add_channel_link(ch, value, "weight") - image.params["w"] = size image.params["h"] = size