diff --git a/src/vstarstack/library/loaders/classic.py b/src/vstarstack/library/loaders/classic.py
index d315c2fe..a7512a6b 100644
--- a/src/vstarstack/library/loaders/classic.py
+++ b/src/vstarstack/library/loaders/classic.py
@@ -18,10 +18,11 @@
import exifread
import vstarstack.library.data
+from vstarstack.library.loaders.datatype import check_datatype
def readjpeg(fname: str):
"""Read single image (jpg, png, tiff) file"""
- rgb = np.asarray(Image.open(fname)).astype(np.float32)
+ rgb = np.asarray(Image.open(fname))
shape = rgb.shape
shape = (shape[0], shape[1])
@@ -47,14 +48,29 @@ def readjpeg(fname: str):
params["weight"] = params["exposure"] * params["gain"]
+ max_value = np.iinfo(rgb.dtype).max
+
dataframe = vstarstack.library.data.DataFrame(params, tags)
if len(rgb.shape) == 3:
- dataframe.add_channel(rgb[:, :, 0], "R", brightness=True, signal=True)
- dataframe.add_channel(rgb[:, :, 1], "G", brightness=True, signal=True)
- dataframe.add_channel(rgb[:, :, 2], "B", brightness=True, signal=True)
+ 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")
+
elif len(rgb.shape) == 2:
- dataframe.add_channel(rgb[:, :], "L", brightness=True, signal=True)
+ 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")
else:
# unknown shape!
pass
diff --git a/src/vstarstack/library/loaders/datatype.py b/src/vstarstack/library/loaders/datatype.py
new file mode 100644
index 00000000..37584056
--- /dev/null
+++ b/src/vstarstack/library/loaders/datatype.py
@@ -0,0 +1,23 @@
+"""convert 8 and 16 bit data to 32 bit"""
+#
+# 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 .
+#
+
+import numpy as np
+def check_datatype(data : np.ndarray) -> np.ndarray:
+ """If 8 bit or 16 bit convert to 32 bit"""
+ if data.dtype == np.int8 or data.dtype == np.int16:
+ return data.astype(np.int32)
+ if data.dtype == np.uint8 or data.dtype == np.uint16:
+ return data.astype(np.uint32)
+ return data
diff --git a/src/vstarstack/library/loaders/fits.py b/src/vstarstack/library/loaders/fits.py
index 1333ab3d..962cfdd9 100644
--- a/src/vstarstack/library/loaders/fits.py
+++ b/src/vstarstack/library/loaders/fits.py
@@ -13,10 +13,13 @@
# along with this program. If not, see .
#
+import numpy as np
import logging
from astropy.io import fits
import vstarstack.library.data
+from vstarstack.library.loaders.datatype import check_datatype
+
logger = logging.getLogger(__name__)
def readfits(filename: str):
@@ -32,11 +35,13 @@ def readfits(filename: str):
shape = plane.data.shape
if len(shape) == 2:
- original = plane.data.reshape((1, shape[0], shape[1]))
+ original : np.ndarray = plane.data.reshape((1, shape[0], shape[1]))
else:
- original = plane.data
+ original : np.ndarray = plane.data
shape = original.shape
+ max_value = np.iinfo(original.dtype).max
+
params = {
"w": shape[2],
"h": shape[1],
@@ -67,6 +72,7 @@ def readfits(filename: str):
slice_names = []
params["weight"] = params["exposure"]*params["gain"]
+
dataframe = vstarstack.library.data.DataFrame(params, tags)
if shape[0] == 1:
@@ -87,8 +93,15 @@ def readfits(filename: str):
yield None
for i, slice_name in enumerate(slice_names):
- dataframe.add_channel(original[i, :, :], slice_name,
+ data = original[i, :, :]
+ overlight_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 bayer is not None:
dataframe.add_parameter(bayer, "format")
yield dataframe
diff --git a/src/vstarstack/library/loaders/nef.py b/src/vstarstack/library/loaders/nef.py
index 1007cac2..dcaa2d6d 100644
--- a/src/vstarstack/library/loaders/nef.py
+++ b/src/vstarstack/library/loaders/nef.py
@@ -15,9 +15,10 @@
import rawpy
import exifread
+import numpy as np
import vstarstack.library.data
-
+from vstarstack.library.loaders.datatype import check_datatype
def readnef(filename: str):
"""Read NEF file"""
@@ -55,7 +56,14 @@ def readnef(filename: str):
for tag_name in tags:
printable_tags[tag_name] = tags[tag_name].printable
+ max_value = np.iinfo(image.dtype).max
dataframe = vstarstack.library.data.DataFrame(params, printable_tags)
- dataframe.add_channel(image, "raw", encoded=True, brightness=True, signal=True)
+ 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")
dataframe.add_parameter(bayer, "format")
yield dataframe
diff --git a/src/vstarstack/library/loaders/ser.py b/src/vstarstack/library/loaders/ser.py
index 0da622d7..e0deadb5 100644
--- a/src/vstarstack/library/loaders/ser.py
+++ b/src/vstarstack/library/loaders/ser.py
@@ -20,6 +20,7 @@
import numpy as np
import vstarstack.library.data
+from vstarstack.library.loaders.datatype import check_datatype
logger = logging.getLogger(__name__)
@@ -43,7 +44,7 @@ def _serread8(file):
"""Read 8-byte integer"""
return _serread(file, 8, True)
-def _read_to_npy(file, bpp, little_endian, shape):
+def _read_to_npy(file, bpp, little_endian, shape) -> np.ndarray:
"""Read block of SER file"""
num = 1
for _, dim in enumerate(shape):
@@ -200,6 +201,8 @@ def readser(fname: str):
"weight" : 1,
}
+ max_value = 2**depth - 1
+
with open(fname, "rb") as trailer_f:
trailer_offset = 178 + frames * width * height * (bpp * vpp)
trailer_f.seek(trailer_offset, 0)
@@ -213,5 +216,12 @@ def readser(fname: str):
dataframe = vstarstack.library.data.DataFrame(params, tags)
index = 0
for index, channel in enumerate(channels):
- dataframe.add_channel(frame[:, :, index], channel, **opts)
+ 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")
yield dataframe
diff --git a/src/vstarstack/library/loaders/video.py b/src/vstarstack/library/loaders/video.py
index a0b9eae8..99b7118a 100644
--- a/src/vstarstack/library/loaders/video.py
+++ b/src/vstarstack/library/loaders/video.py
@@ -14,8 +14,10 @@
#
import cv2
+import numpy as np
import vstarstack.library.data
+from vstarstack.library.loaders.datatype import check_datatype
def read_video(fname: str):
"""Read frames from video file"""
@@ -38,9 +40,17 @@ def read_video(fname: str):
"weight" : 1,
}
+ max_value = np.iinfo(frame.dtype).max
dataframe = vstarstack.library.data.DataFrame(params, tags)
- dataframe.add_channel(frame[:, :, 0], "R", brightness=True, signal=True)
- dataframe.add_channel(frame[:, :, 1], "G", brightness=True, signal=True)
- dataframe.add_channel(frame[:, :, 2], "B", brightness=True, signal=True)
+ 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")
+
yield dataframe
frame_id += 1
diff --git a/src/vstarstack/library/loaders/yuv.py b/src/vstarstack/library/loaders/yuv.py
index 3d15ec7a..6fdbba15 100644
--- a/src/vstarstack/library/loaders/yuv.py
+++ b/src/vstarstack/library/loaders/yuv.py
@@ -17,6 +17,8 @@
import numpy as np
import vstarstack.library.data
+from vstarstack.library.loaders.datatype import check_datatype
+
logger = logging.getLogger(__name__)
def readyuv(fname: str, width: int, height: int):
@@ -47,6 +49,6 @@ def readyuv(fname: str, width: int, height: int):
logger.info(f"processing frame {frame_id}")
dataframe = vstarstack.library.data.DataFrame(params, tags)
- dataframe.add_channel(yuv, "raw", encoded=True, signal=True)
+ dataframe.add_channel(check_datatype(yuv), "raw", encoded=True, signal=True)
yield dataframe
frame_id += 1
diff --git a/src/vstarstack/library/stars/detect.py b/src/vstarstack/library/stars/detect.py
index bc3828a1..edd886e4 100644
--- a/src/vstarstack/library/stars/detect.py
+++ b/src/vstarstack/library/stars/detect.py
@@ -50,6 +50,7 @@ def _find_stars(gray_image : np.ndarray):
"""Find stars on image"""
shape = gray_image.shape
+ gray_image = (gray_image.astype(np.float32) / np.amax(gray_image) * 255).astype(np.uint8)
gray_image = cv2.GaussianBlur(gray_image, (3, 3), 0)
thresh = _threshold(gray_image, _detector_cfg["THRESHOLD_BLOCK_SIZE"],