Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions src/vstarstack/library/loaders/classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,21 @@ def readjpeg(fname: str):
for channel_name, channel_index in [("R",0), ("G", 1), ("B", 2)]:
data = rgb[:,:,channel_index]
dataframe.add_channel(check_datatype(data), channel_name, brightness=True, signal=True)
overlight_idx = np.where(data >= max_value*0.99)
if len(overlight_idx) > 0:
weight = np.ones(data.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-{channel_name}", weight=True)
dataframe.add_channel_link(channel_name, f"weight-{channel_name}", "weight")
saturated_idx = np.where(data >= max_value*0.99)
if len(saturated_idx) > 0:
saturated = np.zeros(rgb.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, f"saturated-{channel_name}", saturation=True)
dataframe.add_channel_link(channel_name, f"saturated-{channel_name}", "saturation")

elif len(rgb.shape) == 2:
dataframe.add_channel(check_datatype(rgb), "L", brightness=True, signal=True)
overlight_idx = np.where(rgb >= max_value*0.99)
if len(overlight_idx) > 0:
weight = np.ones(rgb.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-L", weight=True)
dataframe.add_channel_link("L", f"weight-L", "weight")
saturated_idx = np.where(rgb >= max_value*0.99)
if len(saturated_idx) > 0:
saturated = np.zeros(rgb.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, "saturated-L", saturation=True)
dataframe.add_channel_link("L", "saturated-L", "saturation")
else:
# unknown shape!
pass
Expand Down
12 changes: 6 additions & 6 deletions src/vstarstack/library/loaders/fits.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ def readfits(filename: str):

for i, slice_name in enumerate(slice_names):
data = original[i, :, :]
overlight_idx = np.where(data >= max_value*0.99)
saturated_idx = np.where(data >= max_value*0.99)
dataframe.add_channel(check_datatype(data), slice_name,
brightness=True, signal=True, encoded=encoded)
if len(overlight_idx) > 0:
weight = np.ones(data.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-{slice_name}", weight=True)
dataframe.add_channel_link(slice_name, f"weight-{slice_name}", "weight")
if len(saturated_idx) > 0:
saturated = np.zeros(data.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, f"saturated-{slice_name}", saturation=True)
dataframe.add_channel_link(slice_name, f"saturated-{slice_name}", "saturation")
if bayer is not None:
dataframe.add_parameter(bayer, "format")
yield dataframe
12 changes: 6 additions & 6 deletions src/vstarstack/library/loaders/nef.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ def readnef(filename: str):
max_value = np.iinfo(image.dtype).max
dataframe = vstarstack.library.data.DataFrame(params, printable_tags)
dataframe.add_channel(check_datatype(image), "raw", encoded=True, brightness=True, signal=True)
overlight_idx = np.where(image >= max_value*0.99)
if len(overlight_idx) > 0:
weight = np.ones(image.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-raw", weight=True)
dataframe.add_channel_link("raw", f"weight-raw", "weight")
saturated_idx = np.where(image >= max_value*0.99)
if len(saturated_idx) > 0:
saturated = np.zeros(image.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, f"saturated-raw", saturation=True)
dataframe.add_channel_link("raw", f"saturated-raw", "saturation")
dataframe.add_parameter(bayer, "format")
yield dataframe
12 changes: 6 additions & 6 deletions src/vstarstack/library/loaders/ser.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,10 @@ def readser(fname: str):
for index, channel in enumerate(channels):
data = frame[:, :, index]
dataframe.add_channel(check_datatype(data), channel, **opts)
overlight_idx = np.where(data >= max_value*0.99)
if len(overlight_idx) > 0:
weight = np.ones(data.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-{channel}", weight=True)
dataframe.add_channel_link(channel, f"weight-{channel}", "weight")
saturated_idx = np.where(data >= max_value*0.99)
if len(saturated_idx) > 0:
saturated = np.zeros(data.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, f"saturated-{channel}", saturation=True)
dataframe.add_channel_link(channel, f"saturated-{channel}", "saturation")
yield dataframe
12 changes: 6 additions & 6 deletions src/vstarstack/library/loaders/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ def read_video(fname: str):
for channel_name, channel_index in [("R",0), ("G", 1), ("B", 2)]:
data = frame[:,:,channel_index]
dataframe.add_channel(check_datatype(data), channel_name, brightness=True, signal=True)
overlight_idx = np.where(data >= max_value*0.99)
if len(overlight_idx) > 0:
weight = np.ones(data.shape)*params["weight"]
weight[overlight_idx] = 0
dataframe.add_channel(weight, f"weight-{channel_name}", weight=True)
dataframe.add_channel_link(channel_name, f"weight-{channel_name}", "weight")
saturated_idx = np.where(data >= max_value*0.99)
if len(saturated_idx) > 0:
saturated = np.zeros(data.shape, dtype=np.bool)
saturated[saturated_idx] = True
dataframe.add_channel(saturated, f"saturated-{channel_name}", saturation=True)
dataframe.add_channel_link(channel_name, f"saturated-{channel_name}", "saturation")

yield dataframe
frame_id += 1
9 changes: 8 additions & 1 deletion src/vstarstack/library/merge/simple_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

logger = logging.getLogger(__name__)

def simple_add(images : vstarstack.library.common.IImageSource) -> DataFrame:
def simple_add(images : vstarstack.library.common.IImageSource, ignore_saturated : bool = False) -> DataFrame:
"""Just add images"""

summary = {}
Expand All @@ -49,6 +49,13 @@ def simple_add(images : vstarstack.library.common.IImageSource) -> DataFrame:
weight_k = 1
weight = np.ones(channel.shape, dtype=np.float64) * weight_k

if ignore_saturated:
saturated, _, _ = img.get_linked_channel(channel_name, "saturation")
if saturated is not None:
mask = (saturated == 0).astype(np.uint)
weight = weight * mask
channel = channel * mask

if channel_name not in summary:
summary[channel_name] = deepcopy(channel.astype(np.float64))
summary_weight[channel_name] = deepcopy(weight)
Expand Down
51 changes: 34 additions & 17 deletions src/vstarstack/library/movement/move_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
import numpy as np
import scipy.ndimage

import vstarstack.library.common
import vstarstack.library.data
from vstarstack.library.data import DataFrame

import vstarstack.library.projection.tools
Expand All @@ -36,8 +34,6 @@ def _generate_points(height, width):
def move_image(image: np.ndarray,
transformation: basic_movement.Movement,
input_proj, output_proj,*,
image_weight: float = 1,
image_weight_layer: np.ndarray | None = None,
output_shape: tuple | None = None,
interpolate : bool = True):
"""
Expand All @@ -64,10 +60,6 @@ def move_image(image: np.ndarray,
w = shape[1]

shifted = np.zeros(shape)
shifted_weight_layer = np.zeros(shape)

if image_weight_layer is None:
image_weight_layer = np.ones(image.shape)*image_weight

positions = _generate_points(h, w)
original_positions = transformation.reverse(positions.astype('double'),
Expand All @@ -88,8 +80,7 @@ def move_image(image: np.ndarray,
shifted = scipy.ndimage.geometric_transform(image, crdtf, output_shape=shape, order=3)
else:
shifted = scipy.ndimage.geometric_transform(image, crdtf, output_shape=shape, order=0)
shifted_weight_layer = scipy.ndimage.geometric_transform(image_weight_layer, crdtf, output_shape=shape, order=3)
return shifted, shifted_weight_layer
return shifted

def move_dataframe(dataframe: DataFrame,
transformation: basic_movement.Movement,*,
Expand Down Expand Up @@ -137,21 +128,47 @@ def move_dataframe(dataframe: DataFrame,
else:
weight = np.ones(image.shape)

if channel in dataframe.links["saturation"]:
saturation_channel = dataframe.links["saturation"][channel]
saturation, _ = dataframe.get_channel(saturation_channel)
else:
saturation = None

if interpolate is not None:
apply_interpolate = interpolate
else:
apply_interpolate = not dataframe.get_channel_option(channel, "cfa")

shifted, shifted_weight = move_image(image,
transformation,
input_proj,
output_proj,
image_weight_layer=weight,
output_shape=output_shape,
interpolate=apply_interpolate)
shifted = move_image(image,
transformation,
input_proj,
output_proj,
output_shape=output_shape,
interpolate=apply_interpolate)

shifted_weight = move_image(weight,
transformation,
input_proj,
output_proj,
output_shape=output_shape,
interpolate=apply_interpolate)

if saturation is not None:
shifted_saturation = move_image(saturation.astype(np.float32),
transformation,
input_proj,
output_proj,
output_shape=output_shape,
interpolate=apply_interpolate)
shifted_saturation = abs(shifted_saturation) > 1e-6
else:
shifted_saturation = None

output_dataframe.add_channel(shifted, channel, **opts)
output_dataframe.add_channel(shifted_weight, weight_channel, weight=True)
output_dataframe.add_channel_link(channel, weight_channel, "weight")
if shifted_saturation is not None:
output_dataframe.add_channel(shifted_saturation, saturation_channel, saturation=True)
output_dataframe.add_channel_link(channel, saturation_channel, "saturation")

return output_dataframe
46 changes: 46 additions & 0 deletions src/vstarstack/library/photometry/star_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#
# Copyright (c) 2025 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
# the Free Software Foundation, version 3 of the License.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#

from typing import Tuple
import numpy as np
import math

def find_star_profile(image : np.ndarray, npoints : int) -> Tuple[float, np.ndarray]:
"""Find star profile"""
w = image.shape[1]
h = image.shape[0]
cx = int(w/2)
cy = int(h/2)
profile = np.zeros((w*h, 2))
for y in range(h):
dy = y - cy
for x in range(w):
dx = x - cx
r = math.sqrt(dx**2+dy**2)
profile[y*w+x, 0] = r
profile[y*w+x, 1] = image[y,x]
rmax = np.max(profile[:,0])
smooth_profile = np.zeros((npoints,))
for i in range(npoints):
r_1 = rmax * i / npoints
r_2 = rmax * (i+1) / npoints

idxs = np.where(np.logical_and(profile[:,0] >= r_1, profile[:,0] <= r_2))
smooth_profile[i] = np.mean(profile[idxs,1])

return rmax, smooth_profile

def restore_star_profile(profile : np.ndarray) -> np.ndarray:
"""If star profile has saturation, this function restores center"""

14 changes: 14 additions & 0 deletions src/vstarstack/library/stars/restore_saturated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#
# Copyright (c) 2025 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
# the Free Software Foundation, version 3 of the License.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#

4 changes: 3 additions & 1 deletion src/vstarstack/tool/merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

from vstarstack.library.common import FilesImageSource

IGNS = vstarstack.tool.cfg.get_param("ignore-saturated", bool, False)

def simple_add(project: vstarstack.tool.cfg.Project, argv: list):
"""Calculate simple sum of images"""
if len(argv) > 0:
Expand All @@ -35,7 +37,7 @@ def simple_add(project: vstarstack.tool.cfg.Project, argv: list):

imgs = vstarstack.tool.common.listfiles(path_images, ".zip")
filenames = [img[1] for img in imgs]
dataframe = vstarstack.library.merge.simple_add.simple_add(FilesImageSource(filenames))
dataframe = vstarstack.library.merge.simple_add.simple_add(FilesImageSource(filenames), IGNS)
if dataframe is not None:
vstarstack.tool.common.check_dir_exists(out)
dataframe.store(out)
Expand Down