From b197b9c65b6df82075c2fd2b07b476d1a08f4646 Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 02:04:13 +0200 Subject: [PATCH 1/6] Make normalization work more correct --- src/vstarstack/library/common.py | 7 ++-- src/vstarstack/library/data.py | 6 ++- .../library/image_process/normalize.py | 37 +++++++++++++++---- src/vstarstack/library/merge/simple_add.py | 22 ++++++----- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/vstarstack/library/common.py b/src/vstarstack/library/common.py index 4e559700..43afde94 100644 --- a/src/vstarstack/library/common.py +++ b/src/vstarstack/library/common.py @@ -14,6 +14,7 @@ # import math +import typing import skimage.color from skimage import exposure @@ -126,7 +127,7 @@ class IImageSource(abc.ABC): """Abstract image source""" @abc.abstractmethod - def items(self) -> vstarstack.library.data.DataFrame: + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: """Take elements from source""" @abc.abstractmethod @@ -139,7 +140,7 @@ def __init__(self, images : list[vstarstack.library.data.DataFrame]): self.images = images self.index = 0 - def items(self) -> vstarstack.library.data.DataFrame: + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: """Take next element from source""" for item in self.images: yield item @@ -153,7 +154,7 @@ class FilesImageSource(IImageSource): def __init__(self, filenames : list[str]): self.filenames = filenames - def items(self): + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: """Take next element from source""" for fname in self.filenames: yield vstarstack.library.data.DataFrame.load(fname) diff --git a/src/vstarstack/library/data.py b/src/vstarstack/library/data.py index e9aad2f0..2f596771 100644 --- a/src/vstarstack/library/data.py +++ b/src/vstarstack/library/data.py @@ -69,17 +69,21 @@ def add_channel(self, data : np.ndarray, name : str, **options): options["brightness"] = False if "signal" not in options: options["signal"] = False + if "normed" not in options: + options["normed"] = False self.channels[name] = { "data": data, "options": options, } - def replace_channel(self, data : np.ndarray, name : str): + def replace_channel(self, data : np.ndarray, name : str, **options): """Replace channel image""" if name not in self.channels: return False self.channels[name]["data"] = data + for key in options: + self.channels[name]["options"][key] = options[key] return True def add_channel_link(self, name : str, linked : str, link_type : str): diff --git a/src/vstarstack/library/image_process/normalize.py b/src/vstarstack/library/image_process/normalize.py index c2081584..3fbb7ca6 100644 --- a/src/vstarstack/library/image_process/normalize.py +++ b/src/vstarstack/library/image_process/normalize.py @@ -24,17 +24,38 @@ def normalize(dataframe : vstarstack.library.data.DataFrame, deepcopy=True): else: new_dataframe = dataframe for channel in new_dataframe.get_channels(): - image, opts = new_dataframe.get_channel(channel) - if "normalized" in opts and opts["normalized"]: + image, _ = new_dataframe.get_channel(channel) + if new_dataframe.get_channel_option(channel, "normed"): continue - if not opts["brightness"]: + if not new_dataframe.get_channel_option(channel, "brightness"): continue - if channel not in new_dataframe.links["weight"]: + weight, _, _ = new_dataframe.get_linked_channel(channel, "weight") + if weight is None: continue - weight, _ = new_dataframe.get_channel(new_dataframe.links["weight"][channel]) + image = image / weight - image[np.where(weight == 0)] = 0 - opts["normalized"] = True - new_dataframe.replace_channel(image, channel) + image[np.where(weight < 1e-12)] = 0 + new_dataframe.replace_channel(image, channel, normed=True) + + return new_dataframe + +def denormalize(dataframe : vstarstack.library.data.DataFrame, deepcopy=True): + """De-normalize image layers""" + if deepcopy: + new_dataframe = dataframe.copy() + else: + new_dataframe = dataframe + for channel in new_dataframe.get_channels(): + image, _ = new_dataframe.get_channel(channel) + if not new_dataframe.get_channel_option(channel, "normed"): + continue + if not new_dataframe.get_channel_option(channel, "brightness"): + continue + weight, _, _ = new_dataframe.get_linked_channel(channel, "weight") + if weight is None: + continue + + image = image * weight + new_dataframe.replace_channel(image, channel, normed=False) return new_dataframe diff --git a/src/vstarstack/library/merge/simple_add.py b/src/vstarstack/library/merge/simple_add.py index ea24b5e4..89cd872b 100644 --- a/src/vstarstack/library/merge/simple_add.py +++ b/src/vstarstack/library/merge/simple_add.py @@ -14,6 +14,8 @@ import numpy as np import vstarstack.library.data +import vstarstack.library.common +import vstarstack.library.image_process.normalize from vstarstack.library.data import DataFrame from copy import deepcopy @@ -30,24 +32,24 @@ def simple_add(images : vstarstack.library.common.IImageSource) -> DataFrame: channel_opts = {} for img in images.items(): params = img.params + img = vstarstack.library.image_process.normalize.denormalize(img) for channel_name in img.get_channels(): channel, opts = img.get_channel(channel_name) - if not opts["brightness"]: + if not img.get_channel_option(channel_name, "brightness"): continue if channel_name not in channel_opts: channel_opts[channel_name] = opts - if channel_name in img.links["weight"]: - weight_channel = img.links["weight"][channel_name] - weight, _ = img.get_channel(weight_channel) - else: - weight = np.ones(channel.shape, dtype=np.float64) + weight, _, _ = img.get_linked_channel(channel_name, "weight") + if weight is None: + if (weight_k := img.get_parameter("weight")) is None: + weight_k = 1 + weight = np.ones(channel.shape, dtype=np.float64) * weight_k if channel_name not in summary: summary[channel_name] = deepcopy(channel.astype(np.float64)) summary_weight[channel_name] = deepcopy(weight) else: - try: summary[channel_name] += channel summary_weight[channel_name] += weight @@ -57,9 +59,9 @@ def simple_add(images : vstarstack.library.common.IImageSource) -> DataFrame: result = vstarstack.library.data.DataFrame(params=params) for channel_name, channel in summary.items(): print(channel_name) + weight_channel_name = "weight-"+channel_name result.add_channel(channel, channel_name, **channel_opts[channel_name]) - result.add_channel(summary_weight[channel_name], - "weight-"+channel_name, weight=True) - result.add_channel_link(channel_name, "weight-"+channel_name, "weight") + result.add_channel(summary_weight[channel_name], weight_channel_name, weight=True) + result.add_channel_link(channel_name, weight_channel_name, "weight") return result From 1170eb9ab4a31a035978a1988d96dd7d0f794fcc Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 02:55:04 +0200 Subject: [PATCH 2/6] Clarify code of kappa sigma --- src/vstarstack/library/merge/kappa_sigma.py | 103 +++++++++----------- src/vstarstack/library/merge/simple_mean.py | 2 +- 2 files changed, 48 insertions(+), 57 deletions(-) diff --git a/src/vstarstack/library/merge/kappa_sigma.py b/src/vstarstack/library/merge/kappa_sigma.py index 178b6624..a81b1536 100644 --- a/src/vstarstack/library/merge/kappa_sigma.py +++ b/src/vstarstack/library/merge/kappa_sigma.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2023 Vladislav Tsendrovskii +# Copyright (c) 2023-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,91 +14,84 @@ import numpy as np -import vstarstack.library.data +from vstarstack.library.image_process.normalize import normalize from vstarstack.library.data import DataFrame +from vstarstack.library.common import IImageSource - -def hard_clip(delta, sigma, kappa): +def _hard_clip(delta : np.ndarray, sigma : np.ndarray, kappa : float) -> np.ndarray: """Hard clip where |delta| > sigma * kappa""" - return (abs(delta) - sigma * kappa <= 0).astype("float") + return (abs(delta) - sigma * kappa <= 0).astype(np.int32) -def calculate_clip(image, mean, sigma, kappa): +def _calculate_clip(image : np.ndarray, mean : np.ndarray, sigma : np.ndarray, kappa : float) -> np.ndarray: """Calculate clip array""" delta = image - mean - return hard_clip(delta, sigma, kappa) + return _hard_clip(delta, sigma, kappa) -def _read_and_prepare(dataframe, channel): +def _read_and_prepare(dataframe : DataFrame, channel : str): """Remove invalid points from image""" image, opts = dataframe.get_channel(channel) - if not opts["signal"]: - return None, None, None - - if channel in dataframe.links["weight"]: - weight_channel = dataframe.links["weight"][channel] - weight, _ = dataframe.get_channel(weight_channel) - else: - weight = np.ones(image.shape, dtype=np.float64) + weight, _, _ = dataframe.get_linked_channel(channel, "weight") + if weight is None: + if (weight_k := dataframe.get_parameter("weight")) is None: + weight_k = 1 + weight = np.ones(image.shape, dtype=np.float64) * weight_k - image[np.where(weight == 0)] = 0 + image[np.where(weight < 1e-12)] = 0 return image, weight, opts - -def _calculate_mean(images, means: dict, sigmas: dict, kappa: float): +def _calculate_mean(images : IImageSource, means: dict, sigmas: dict, kappa: float): """Calculate mean value of images""" - mean_image = {} - total_weight = {} + signal_sum = {} + weight_sum = {} + new_means = {} channel_opts = {} for img in images.items(): + img = normalize(img, deepcopy=False) for channel in img.get_channels(): - image, weight, opts = _read_and_prepare(img, channel) - if image is None: + if not img.get_channel_option(channel, "signal"): continue + + signal, weight, opts = _read_and_prepare(img, channel) if channel not in channel_opts: channel_opts[channel] = opts - if channel in means: - clip = calculate_clip(image, means[channel], sigmas[channel], kappa) + if channel in means and channel in sigmas: + clip = _calculate_clip(signal, means[channel], sigmas[channel], kappa) else: - clip = np.ones(image.shape) + clip = np.ones(signal.shape, dtype=np.int32) - if channel not in mean_image: - mean_image[channel] = image * clip - total_weight[channel] = weight * clip + if channel not in signal_sum: + signal_sum[channel] = signal * clip + weight_sum[channel] = weight * clip else: - mean_image[channel] += image * clip - total_weight[channel] += weight * clip - - for channel in mean_image: - mean_image[channel] = mean_image[channel] / total_weight[channel] - mean_image[channel][np.where(total_weight[channel] == 0)] = 0 + signal_sum[channel] += signal * clip + weight_sum[channel] += weight * clip - return mean_image, total_weight, channel_opts + for channel in signal_sum: + new_means[channel] = signal_sum[channel] / weight_sum[channel] + new_means[channel][np.where(weight_sum[channel] < 1e-12)] = 0 + return new_means, weight_sum, channel_opts -def _calculate_sigma(images, means, sigmas, kappa): +def _calculate_sigma(images : IImageSource, means : dict, sigmas : dict, kappa : float): """Calculate sigma in each pixel""" sigma = {} clips = {} for img in images.items(): + img = normalize(img, deepcopy=False) for channel in img.get_channels(): - image, _, _ = _read_and_prepare(img, channel) - if image is None: + if not img.get_channel_option(channel, "signal"): continue - if channel in means: - if channel in sigmas: - clip = calculate_clip(image, - means[channel], - sigmas[channel], - kappa) - else: - clip = np.ones(image.shape) + signal, _ = _read_and_prepare(img, channel) + if channel in means and channel in sigmas: + clip = _calculate_clip(signal, means[channel], sigmas[channel], kappa) else: - clip = np.ones(image.shape) + clip = np.ones(signal.shape, dtype=np.int32) - delta2 = (image - means[channel])**2 + delta2 = ((signal - means[channel])**2) * clip if channel not in sigma: sigma[channel] = delta2 clips[channel] = clip @@ -112,7 +105,7 @@ def _calculate_sigma(images, means, sigmas, kappa): return sigma -def kappa_sigma(images: vstarstack.library.common.IImageSource, +def kappa_sigma(images: IImageSource, kappa1: float, kappa2: float, steps: int) -> DataFrame: @@ -130,17 +123,15 @@ def kappa_sigma(images: vstarstack.library.common.IImageSource, kappa = (kappa1 * (steps-1-step) + kappa2 * step) / (steps-1) else: kappa = (kappa1 + kappa2) / 2 - means, _, _ = _calculate_mean(images, means, sigmas, kappa) + means, _ = _calculate_mean(images, means, sigmas, kappa) sigmas = _calculate_sigma(images, means, sigmas, kappa) - lights, weights, channel_opts = _calculate_mean(images, - means, - sigmas, - kappa2) + signals, weights, channel_opts = _calculate_mean(images, means, sigmas, kappa2) result = DataFrame(params=params) - for channel_name, light in lights.items(): + for channel_name, light in signals.items(): weight = weights[channel_name] + channel_opts[channel_name]["normed"] = True result.add_channel(light, channel_name, **channel_opts[channel_name]) result.add_channel(weight, "weight-"+channel_name, weight=True) result.add_channel_link(channel_name, "weight-"+channel_name, "weight") diff --git a/src/vstarstack/library/merge/simple_mean.py b/src/vstarstack/library/merge/simple_mean.py index ca61dd30..577be500 100644 --- a/src/vstarstack/library/merge/simple_mean.py +++ b/src/vstarstack/library/merge/simple_mean.py @@ -12,8 +12,8 @@ # along with this program. If not, see . # -import numpy as np import vstarstack.library.data +import vstarstack.library.common import vstarstack.library.image_process.normalize import vstarstack.library.merge.simple_add from vstarstack.library.data import DataFrame From 0363d99e65194a309902f0992da768cc63e17efb Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 03:08:13 +0200 Subject: [PATCH 3/6] Fix --- src/vstarstack/library/common.py | 6 +++--- src/vstarstack/library/merge/kappa_sigma.py | 4 ++-- tests/test_merge.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/vstarstack/library/common.py b/src/vstarstack/library/common.py index 43afde94..818d890c 100644 --- a/src/vstarstack/library/common.py +++ b/src/vstarstack/library/common.py @@ -127,7 +127,7 @@ class IImageSource(abc.ABC): """Abstract image source""" @abc.abstractmethod - def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame, None, None]: """Take elements from source""" @abc.abstractmethod @@ -140,7 +140,7 @@ def __init__(self, images : list[vstarstack.library.data.DataFrame]): self.images = images self.index = 0 - def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame, None, None]: """Take next element from source""" for item in self.images: yield item @@ -154,7 +154,7 @@ class FilesImageSource(IImageSource): def __init__(self, filenames : list[str]): self.filenames = filenames - def items(self) -> typing.Generator[vstarstack.library.data.DataFrame]: + def items(self) -> typing.Generator[vstarstack.library.data.DataFrame, None, None]: """Take next element from source""" for fname in self.filenames: yield vstarstack.library.data.DataFrame.load(fname) diff --git a/src/vstarstack/library/merge/kappa_sigma.py b/src/vstarstack/library/merge/kappa_sigma.py index a81b1536..60a6b9c1 100644 --- a/src/vstarstack/library/merge/kappa_sigma.py +++ b/src/vstarstack/library/merge/kappa_sigma.py @@ -85,7 +85,7 @@ def _calculate_sigma(images : IImageSource, means : dict, sigmas : dict, kappa : if not img.get_channel_option(channel, "signal"): continue - signal, _ = _read_and_prepare(img, channel) + signal, _, _ = _read_and_prepare(img, channel) if channel in means and channel in sigmas: clip = _calculate_clip(signal, means[channel], sigmas[channel], kappa) else: @@ -123,7 +123,7 @@ def kappa_sigma(images: IImageSource, kappa = (kappa1 * (steps-1-step) + kappa2 * step) / (steps-1) else: kappa = (kappa1 + kappa2) / 2 - means, _ = _calculate_mean(images, means, sigmas, kappa) + means, _, _ = _calculate_mean(images, means, sigmas, kappa) sigmas = _calculate_sigma(images, means, sigmas, kappa) signals, weights, channel_opts = _calculate_mean(images, means, sigmas, kappa2) diff --git a/tests/test_merge.py b/tests/test_merge.py index ada5cd27..f7e0118c 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -146,7 +146,7 @@ def test_kappa_sigma_4(): weight = np.ones(light.shape) # for repeatability - np.random.seed(1) + np.random.seed(2) noised = [] for _ in range(N): copy = original_image.copy() @@ -162,4 +162,4 @@ def test_kappa_sigma_4(): wn = summ.links["weight"]["L"] summ_weight = summ.get_channel(wn)[0] assert images_equal(summ_light, light, 0.1) - assert images_equal(summ_weight, weight*N, 1) + assert images_equal(summ_weight, weight*N, 2) From 5bba2ba5dde967ccb5c81a6c95597c1c67ba9933 Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 03:18:58 +0200 Subject: [PATCH 4/6] fix --- tests/test_normalization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_normalization.py b/tests/test_normalization.py index 7200be6c..adfb6235 100644 --- a/tests/test_normalization.py +++ b/tests/test_normalization.py @@ -29,7 +29,7 @@ def test_1(): dataframe2 = normalize(dataframe) layer_normed, opts = dataframe2.get_channel("light") - assert opts["normalized"] == True + assert opts["normed"] == True assert layer_normed[0,0] == 1 layer[0,0] = 2 @@ -46,7 +46,7 @@ def test_2(): dataframe2 = normalize(dataframe) layer_normed, opts = dataframe2.get_channel("light") - assert opts["normalized"] == True + assert opts["normed"] == True assert layer_normed[0,0] == 1 weight_normed, opts = dataframe2.get_channel("weight") From f38b21c0552a31032ae25dc48cbdf57af7c2acfb Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 04:32:17 +0200 Subject: [PATCH 5/6] Fixes --- src/vstarstack/library/merge/kappa_sigma.py | 54 ++++++++++++++++----- tests/test_merge.py | 12 +++-- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/vstarstack/library/merge/kappa_sigma.py b/src/vstarstack/library/merge/kappa_sigma.py index 60a6b9c1..409cafcd 100644 --- a/src/vstarstack/library/merge/kappa_sigma.py +++ b/src/vstarstack/library/merge/kappa_sigma.py @@ -14,7 +14,7 @@ import numpy as np -from vstarstack.library.image_process.normalize import normalize +from vstarstack.library.image_process.normalize import normalize, denormalize from vstarstack.library.data import DataFrame from vstarstack.library.common import IImageSource @@ -43,8 +43,6 @@ def _calculate_mean(images : IImageSource, means: dict, sigmas: dict, kappa: flo """Calculate mean value of images""" signal_sum = {} weight_sum = {} - new_means = {} - channel_opts = {} for img in images.items(): img = normalize(img, deepcopy=False) @@ -52,9 +50,7 @@ def _calculate_mean(images : IImageSource, means: dict, sigmas: dict, kappa: flo if not img.get_channel_option(channel, "signal"): continue - signal, weight, opts = _read_and_prepare(img, channel) - if channel not in channel_opts: - channel_opts[channel] = opts + signal, weight, _ = _read_and_prepare(img, channel) if channel in means and channel in sigmas: clip = _calculate_clip(signal, means[channel], sigmas[channel], kappa) @@ -62,17 +58,18 @@ def _calculate_mean(images : IImageSource, means: dict, sigmas: dict, kappa: flo clip = np.ones(signal.shape, dtype=np.int32) if channel not in signal_sum: - signal_sum[channel] = signal * clip + signal_sum[channel] = signal * weight * clip weight_sum[channel] = weight * clip else: - signal_sum[channel] += signal * clip + signal_sum[channel] += signal * weight * clip weight_sum[channel] += weight * clip + new_means = {} for channel in signal_sum: new_means[channel] = signal_sum[channel] / weight_sum[channel] new_means[channel][np.where(weight_sum[channel] < 1e-12)] = 0 - return new_means, weight_sum, channel_opts + return new_means def _calculate_sigma(images : IImageSource, means : dict, sigmas : dict, kappa : float): """Calculate sigma in each pixel""" @@ -105,6 +102,41 @@ def _calculate_sigma(images : IImageSource, means : dict, sigmas : dict, kappa : return sigma +def _calculate_sum(images : IImageSource, means: dict, sigmas: dict, kappa: float): + """Calculate mean value of images""" + signal_sum = {} + weight_sum = {} + channel_opts = {} + + for img in images.items(): + img = normalize(img, deepcopy=False) + for channel in img.get_channels(): + if not img.get_channel_option(channel, "signal"): + continue + + signal, weight, opts = _read_and_prepare(img, channel) + if channel not in channel_opts: + channel_opts[channel] = opts + + if channel in means and channel in sigmas: + clip = _calculate_clip(signal, means[channel], sigmas[channel], kappa) + else: + clip = np.ones(signal.shape, dtype=np.int32) + + if channel not in signal_sum: + signal_sum[channel] = signal * weight * clip + weight_sum[channel] = weight * clip + else: + signal_sum[channel] += signal * weight * clip + weight_sum[channel] += weight * clip + + for channel in signal_sum: + signal_sum[channel][np.where(weight_sum[channel] < 1e-12)] = 0 + weight_sum[channel][np.where(weight_sum[channel] < 1e-12)] = 0 + + channel_opts["normed"] = False + return signal_sum, weight_sum, channel_opts + def kappa_sigma(images: IImageSource, kappa1: float, kappa2: float, @@ -123,10 +155,10 @@ def kappa_sigma(images: IImageSource, kappa = (kappa1 * (steps-1-step) + kappa2 * step) / (steps-1) else: kappa = (kappa1 + kappa2) / 2 - means, _, _ = _calculate_mean(images, means, sigmas, kappa) + means = _calculate_mean(images, means, sigmas, kappa) sigmas = _calculate_sigma(images, means, sigmas, kappa) - signals, weights, channel_opts = _calculate_mean(images, means, sigmas, kappa2) + signals, weights, channel_opts = _calculate_sum(images, means, sigmas, kappa2) result = DataFrame(params=params) for channel_name, light in signals.items(): diff --git a/tests/test_merge.py b/tests/test_merge.py index f7e0118c..06a55863 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -24,7 +24,9 @@ dir_path = os.path.dirname(os.path.realpath(__file__)) def images_equal(img1, img2, thr = 0.0): - return np.amax(abs(img1 - img2)) <= thr + difference = np.amax(abs(img1 - img2)) + print(difference) + return difference <= thr def test_simple_add(): original_image = next(readjpeg(os.path.join(dir_path, "test_image.png"))) @@ -101,7 +103,7 @@ def test_kappa_sigma_1(): summ_light, opts = summ.get_channel("L") wn = summ.links["weight"]["L"] summ_weight = summ.get_channel(wn)[0] - assert images_equal(summ_light, light) + assert images_equal(summ_light, light*2) assert images_equal(summ_weight, weight*2) assert summ.params["w"] == copy1.params["w"] assert summ.params["h"] == copy1.params["h"] @@ -118,7 +120,7 @@ def test_kappa_sigma_2(): summ_light, opts = summ.get_channel("L") wn = summ.links["weight"]["L"] summ_weight = summ.get_channel(wn)[0] - assert images_equal(summ_light, light) + assert images_equal(summ_light, light*2) assert images_equal(summ_weight, weight*2) def test_kappa_sigma_3(): @@ -133,7 +135,7 @@ def test_kappa_sigma_3(): summ_light, opts = summ.get_channel("L") wn = summ.links["weight"]["L"] summ_weight = summ.get_channel(wn)[0] - assert images_equal(summ_light, light) + assert images_equal(summ_light, light*2) assert images_equal(summ_weight, weight*2) def test_kappa_sigma_4(): @@ -161,5 +163,5 @@ def test_kappa_sigma_4(): summ_light, opts = summ.get_channel("L") wn = summ.links["weight"]["L"] summ_weight = summ.get_channel(wn)[0] - assert images_equal(summ_light, light, 0.1) + assert images_equal(summ_light, light*N, 0.1*N) assert images_equal(summ_weight, weight*N, 2) From 145f0e375123c1b837121b96db754c2c01141d3f Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 2 Sep 2024 06:54:25 +0200 Subject: [PATCH 6/6] Fix "normed" flag --- src/vstarstack/library/merge/kappa_sigma.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/vstarstack/library/merge/kappa_sigma.py b/src/vstarstack/library/merge/kappa_sigma.py index 409cafcd..8504196c 100644 --- a/src/vstarstack/library/merge/kappa_sigma.py +++ b/src/vstarstack/library/merge/kappa_sigma.py @@ -163,7 +163,6 @@ def kappa_sigma(images: IImageSource, result = DataFrame(params=params) for channel_name, light in signals.items(): weight = weights[channel_name] - channel_opts[channel_name]["normed"] = True result.add_channel(light, channel_name, **channel_opts[channel_name]) result.add_channel(weight, "weight-"+channel_name, weight=True) result.add_channel_link(channel_name, "weight-"+channel_name, "weight")