diff --git a/src/vstarstack/library/photometry/star_background.py b/src/vstarstack/library/photometry/star_background.py new file mode 100644 index 0000000..31a8149 --- /dev/null +++ b/src/vstarstack/library/photometry/star_background.py @@ -0,0 +1,75 @@ +# +# 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 . +# + +from typing import Tuple +import numpy as np +import cv2 +from vstarstack.library.data import DataFrame + +def calculate_bg(image : np.ndarray, x : int, y : int, star_r : int, bg_r_big : int, bg_r_small : int) -> dict: + star_mask = np.zeros(image.shape) + cv2.circle(star_mask, (x,y), star_r, 1, -1) + bg_mask = np.zeros(image.shape) + cv2.circle(bg_mask, (x,y), bg_r_big, 1, -1) + cv2.circle(bg_mask, (x,y), bg_r_small, 0, -1) + + bg_pixels = image * bg_mask + bg_sum = np.sum(bg_pixels) + bg_npix = np.sum(bg_mask) + bg_mean = bg_sum / bg_npix + + star_pixels = (image - bg_mean) * star_mask + star_sum = np.sum(star_pixels) + star_npix = np.sum(star_mask) + return { + "star" : star_sum, + "star_npix" : star_npix, + "bg" : bg_sum, + "bg_npix" : bg_npix + } + +def calculate_bgs(image : np.ndarray, stars : list) -> list: + bgs = [] + for star in stars: + x = star["x"] + y = star["y"] + r = int(star["radius"]) + bg = calculate_bg(image, x, y, r, 2*r, 4*r) + bgs.append(bg) + return bgs + +def calculate_bgs_df(df : DataFrame, stars : list) -> Tuple[list, set]: + values = [] + all_channels = set() + for star in stars: + channels = { + "x" : star["x"], + "y" : star["y"], + "radius" : star["radius"], + "channels" : {}, + } + for channel in df.get_channels(): + if not df.get_channel_option(channel, "brightness"): + continue + all_channels.add(channel) + image, _ = df.get_channel(channel) + x = star["x"] + y = star["y"] + sr = int(star["radius"]+0.5) + bgr_small = sr * 2 + bgr_big = sr * 3 + bg = calculate_bg(image, x, y, sr, bgr_big, bgr_small) + channels["channels"][channel] = bg + values.append(channels) + return values, all_channels diff --git a/src/vstarstack/tool/photometry/measure_pollution.py b/src/vstarstack/tool/photometry/measure_pollution.py new file mode 100644 index 0000000..137616a --- /dev/null +++ b/src/vstarstack/tool/photometry/measure_pollution.py @@ -0,0 +1,75 @@ +# +# 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 json +import csv + +from vstarstack.library.photometry.star_background import calculate_bgs_df +from vstarstack.library.data import DataFrame + + +def process_image(project, argv : list): + image_path = argv[0] + stars_path = argv[1] + report_fname = argv[2] + with open(stars_path) as f: + stars = json.load(f) + stars = [{"x" : star["keypoint"]["x"], "y" : star["keypoint"]["y"], "radius" : star["keypoint"]["radius"]} for star in stars["points"]] + + df = DataFrame.load(image_path) + backgrounds, channels = calculate_bgs_df(df, stars) + with open(report_fname, "w", encoding="utf-8") as f: + writer = csv.writer(f) + header1 = ["x", "y", "radius","","name","mag","lum","", "star pixels", "background pixels",""] + header2 = ["","","","","","","","","","",""] + for channel in channels: + header2.append(channel) + header2.append("") + header2.append("") + header1 += ["star value", "background value", ""] + header2 += ["Total", "", "", ""] + header1 += ["star value", "background value", "mean star pixel", "mean background pixel"] + writer.writerow(header2) + writer.writerow(header1) + + for item in backgrounds: + bg_npix = 0 + star_npix = 0 + row = None + sum_star = 0 + sum_bg = 0 + for channel in channels: + if row is None: + mag = "" + lum = "" + name = "" + row = [item["x"], item["y"], int(item["radius"]+0.5), "", name, mag, lum, ""] + star_npix = int(item["channels"][channel]["star_npix"]) + bg_npix = int(item["channels"][channel]["bg_npix"]) + row += [star_npix, bg_npix, ""] + row += [int(item["channels"][channel]["star"])] + row += [int(item["channels"][channel]["bg"])] + row += [""] + + sum_star += int(item["channels"][channel]["star"]) + sum_bg += int(item["channels"][channel]["bg"]) + + row += [sum_star, sum_bg, int(sum_star/star_npix), int(sum_bg/bg_npix)] + writer.writerow(row) + +commands = { + "image": (process_image, + "build report for clusters", + "image.zip stars.json report.csv"), +} diff --git a/src/vstarstack/tool/photometry/photometry.py b/src/vstarstack/tool/photometry/photometry.py index ce1ac40..4ebbe9a 100644 --- a/src/vstarstack/tool/photometry/photometry.py +++ b/src/vstarstack/tool/photometry/photometry.py @@ -15,4 +15,5 @@ commands = { "measure-mag" : ("vstarstack.tool.photometry.measure_mag", "measure star magnitude"), "measure-fwhm" : ("vstarstack.tool.photometry.measure_fwhm", "measure full width at half maximum"), + "measure-background" : ("vstarstack.tool.photometry.measure_pollution", "measure background light level"), }