From 1f6d819217de6eba9548e75980a2c217c408b157 Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 14 Aug 2023 22:45:59 +0500 Subject: [PATCH 1/2] Add HDR compression methods --- src/vstarstack/tool/image.py | 39 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/vstarstack/tool/image.py b/src/vstarstack/tool/image.py index 8f3840dc..6170cd1c 100644 --- a/src/vstarstack/tool/image.py +++ b/src/vstarstack/tool/image.py @@ -13,6 +13,7 @@ # import os +import math import numpy as np import imageio @@ -26,11 +27,25 @@ import vstarstack.tool.usage import vstarstack.tool.cfg -POWER = 1 SLOPE = vstarstack.tool.cfg.get_param("multiply", float, 1) FLOOR = vstarstack.tool.cfg.get_param("clip_floor", bool, False) -def _make_frames(dataframe, channels, *, slope=1, power=1, clip_floor=False): +def compress_clip(img, slope): + amax = np.amax(img) + img = img / amax + img = np.clip(img*slope, 0, 1) + return img + +def compress_atan(img, slope): + amax = np.amax(img) + img = img / amax + img = np.arctan(img * math.pi/2 * slope) / math.pi * 2 + return img + +def compress(img, slope): + return compress_atan(img, slope) + +def _make_frames(dataframe, channels, *, compress_fun, slope=1): if channels == "RGB": r, _ = dataframe.get_channel("R") g, _ = dataframe.get_channel("G") @@ -40,10 +55,8 @@ def _make_frames(dataframe, channels, *, slope=1, power=1, clip_floor=False): rgb[:, :, 0] = r rgb[:, :, 1] = g rgb[:, :, 2] = b - amax = np.amax(rgb) - rgb = rgb / amax - rgb = np.clip(rgb*slope, 0, 1)**power - + + rgb = compress_fun(rgb, slope) frames = {"RGB": rgb} else: @@ -61,12 +74,7 @@ def _make_frames(dataframe, channels, *, slope=1, power=1, clip_floor=False): amin = max(np.amin(img), 0) amax = np.amax(img) print(f"{channel}: {amin} - {amax}") - if clip_floor: - if amax - amin > 0: - img = (img - amin)/(amax-amin) - else: - img = img / amax - img = np.clip(img*slope, 0, 1)**power + img = compress_fun(img, slope) frames[channel] = img return frames @@ -85,9 +93,8 @@ def _show(_project, argv): dataframe = vstarstack.library.data.DataFrame.load(path) frames = _make_frames(dataframe, channel, - slope=SLOPE, - power=POWER, - clip_floor=FLOOR) + compress_fun=compress, + slope=SLOPE) nch = len(frames) fig, axs = plt.subplots(1, nch) @@ -121,7 +128,7 @@ def _convert(_project, argv): channels = None dataframe = vstarstack.library.data.DataFrame.load(path) - frames = _make_frames(dataframe, channels, slope=SLOPE, power=POWER) + frames = _make_frames(dataframe, channels, compress_fun=compress, slope=SLOPE) nch = len(frames) From 539bb82f97d42a157d086b6fa93e65eeecaff714 Mon Sep 17 00:00:00 2001 From: Vladislav Tsendrovskii Date: Mon, 14 Aug 2023 23:15:58 +0500 Subject: [PATCH 2/2] Add HDR compression support --- src/vstarstack/tool/image.py | 90 ++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/src/vstarstack/tool/image.py b/src/vstarstack/tool/image.py index 6170cd1c..7be1f2ab 100644 --- a/src/vstarstack/tool/image.py +++ b/src/vstarstack/tool/image.py @@ -29,6 +29,7 @@ SLOPE = vstarstack.tool.cfg.get_param("multiply", float, 1) FLOOR = vstarstack.tool.cfg.get_param("clip_floor", bool, False) +HDR = vstarstack.tool.cfg.get_param("hdr", bool, False) def compress_clip(img, slope): amax = np.amax(img) @@ -37,34 +38,35 @@ def compress_clip(img, slope): return img def compress_atan(img, slope): - amax = np.amax(img) - img = img / amax + img = img / np.amax(img) + img = np.clip(img, 0, 1) img = np.arctan(img * math.pi/2 * slope) / math.pi * 2 + img = img / np.amax(img) return img def compress(img, slope): - return compress_atan(img, slope) - -def _make_frames(dataframe, channels, *, compress_fun, slope=1): - if channels == "RGB": - r, _ = dataframe.get_channel("R") - g, _ = dataframe.get_channel("G") - b, _ = dataframe.get_channel("B") - - rgb = np.zeros((r.shape[0], r.shape[1], 3)) - rgb[:, :, 0] = r - rgb[:, :, 1] = g - rgb[:, :, 2] = b - - rgb = compress_fun(rgb, slope) - frames = {"RGB": rgb} + if HDR: + return compress_atan(img, slope) + return compress_clip(img, slope) - else: - frames = {} - if channels is None: - channels = dataframe.get_channels() +def _make_frames(dataframe, channels): + frames = {} + if channels is None: + channels = dataframe.get_channels() - for channel in channels: + for channel in channels: + if channel == "RGB": + r, _ = dataframe.get_channel("R") + g, _ = dataframe.get_channel("G") + b, _ = dataframe.get_channel("B") + + rgb = np.zeros((r.shape[0], r.shape[1], 3)) + rgb[:, :, 0] = r + rgb[:, :, 1] = g + rgb[:, :, 2] = b + + frames["RGB"] = rgb + else: print("Channel = ", channel) img, options = dataframe.get_channel(channel) print("Shape = ", img.shape) @@ -74,7 +76,6 @@ def _make_frames(dataframe, channels, *, compress_fun, slope=1): amin = max(np.amin(img), 0) amax = np.amax(img) print(f"{channel}: {amin} - {amax}") - img = compress_fun(img, slope) frames[channel] = img return frames @@ -82,19 +83,12 @@ def _make_frames(dataframe, channels, *, compress_fun, slope=1): def _show(_project, argv): path = argv[0] - if len(argv) > 1: - if argv[1] == "RGB": - channel = "RGB" - else: - channel = argv[1:] - else: - channel = None + channels = None + if len(argv[1:]) > 0: + channels = argv[1:] dataframe = vstarstack.library.data.DataFrame.load(path) - frames = _make_frames(dataframe, - channel, - compress_fun=compress, - slope=SLOPE) + frames = _make_frames(dataframe, channels) nch = len(frames) fig, axs = plt.subplots(1, nch) @@ -107,9 +101,13 @@ def _show(_project, argv): else: subplot = axs img = frames[channel].astype(np.float64) - img = img / np.amax(img) - subplot.imshow(img, cmap="gray", vmin=0, vmax=1.0) - subplot.set_title(channel) + img = compress(img, SLOPE) + if len(img.shape) == 2: + subplot.imshow(img, cmap="gray", vmin=0, vmax=1.0) + subplot.set_title(channel) + else: + subplot.imshow(img, vmin=0, vmax=1.0) + subplot.set_title(channel) index += 1 plt.show() @@ -120,29 +118,33 @@ def _convert(_project, argv): out = argv[1] if len(argv) > 2: - if argv[2] == "RGB": - channels = "RGB" - else: - channels = argv[2:] + channels = argv[2:] else: channels = None dataframe = vstarstack.library.data.DataFrame.load(path) - frames = _make_frames(dataframe, channels, compress_fun=compress, slope=SLOPE) + frames = _make_frames(dataframe, channels) nch = len(frames) out = os.path.abspath(out) path = os.path.dirname(out) name, ext = os.path.splitext(os.path.basename(out)) + ext = ext[1:] for channels, img in frames.items(): if nch > 1: fname = os.path.join(path, f"{name}_{channels}.{ext}") else: fname = out - img = img*65535 - img = img.astype('uint16') + img = compress(img, SLOPE) + img = img / np.amax(img) + if ext in ["tiff"]: + img = img * 65535 + img = img.astype('uint16') + else: + img = img*255 + img = img.astype('uint8') vstarstack.tool.common.check_dir_exists(fname) imageio.imwrite(fname, img)