diff --git a/src/kbmod/configuration.py b/src/kbmod/configuration.py index 367d70e0d..ee6b7fc7d 100644 --- a/src/kbmod/configuration.py +++ b/src/kbmod/configuration.py @@ -18,27 +18,6 @@ class SearchConfiguration: def __init__(self): self._required_params = set() - default_mask_bits_dict = { - "BAD": 0, - "CLIPPED": 9, - "CR": 3, - "CROSSTALK": 10, - "DETECTED": 5, - "DETECTED_NEGATIVE": 6, - "EDGE": 4, - "INEXACT_PSF": 11, - "INTRP": 2, - "NOT_DEBLENDED": 12, - "NO_DATA": 8, - "REJECTED": 13, - "SAT": 1, - "SENSOR_EDGE": 14, - "SUSPECT": 7, - "UNMASKEDNAN": 15, - } - default_flag_keys = ["BAD", "EDGE", "NO_DATA", "SUSPECT", "UNMASKEDNAN"] - default_repeated_flag_keys = [] - self._params = { "ang_arr": [math.pi / 15, math.pi / 15, 128], "average_angle": None, @@ -53,7 +32,6 @@ def __init__(self): "do_stamp_filter": True, "eps": 0.03, "encode_num_bytes": -1, - "flag_keys": default_flag_keys, "generator_config": None, "gpu_filter": False, "ind_output_files": True, @@ -62,11 +40,6 @@ def __init__(self): "known_obj_thresh": None, "known_obj_jpl": False, "lh_level": 10.0, - "mask_bits_dict": default_mask_bits_dict, - "mask_bit_vector": None, - "mask_grow": 10, - "mask_num_images": 2, - "mask_threshold": None, "max_lh": 1000.0, "mjd_lims": None, "mom_lims": [35.5, 35.5, 2.0, 0.3, 0.3], @@ -75,7 +48,6 @@ def __init__(self): "peak_offset": [2.0, 2.0], "psf_val": 1.4, "psf_file": None, - "repeated_flag_keys": default_repeated_flag_keys, "res_filepath": None, "result_filename": None, "results_per_pixel": 8, diff --git a/src/kbmod/masking.py b/src/kbmod/masking.py deleted file mode 100644 index 99d6b21f2..000000000 --- a/src/kbmod/masking.py +++ /dev/null @@ -1,122 +0,0 @@ -"""Functions for performing masking operations as specified in the configuration. -""" - -import kbmod.search as kb -from kbmod.search import RawImage - - -def mask_trajectory(trj, stack, r): - """Will apply a circular mask of radius `r` around - the trajectory's predicted position in each image. - - Attributes - ---------- - trj : `Trajectory` - The trajectory along which to apply the mask. - stack : `ImageStack` - The stack of images to apply the mask to. - r : `int` - The radius of the circular mask to apply. - - Returns - ------- - stack : `ImageStack` - The stack after the masks have been applied. - """ - - width = stack.get_width() - height = stack.get_height() - - for i in range(stack.img_count()): - img = stack.get_single_image(i) - time = img.get_obstime() - stack.get_single_image(0).get_obstime() - origin_of_mask = (trj.get_x_index(time), trj.get_y_index(time)) - - for dy in range(-r, r + 1): - for dx in range(-r, r + 1): - if dx**2 + dy**2 <= r**2: - x = origin_of_mask[0] + dx - y = origin_of_mask[1] + dy - if x >= 0 and x < width and y >= 0 and y < height: - img.mask_pixel(y, x) - return stack - - -def mask_flags_from_dict(mask_bits_dict, flag_keys): - """Generate a bitmask integer of flag keys from a dictionary - of masking reasons and a list of reasons to use. - - Attributes - ---------- - mask_bits_dict : `dict` - A dictionary mapping a masking key (string) to the bit - number in the masking bit vector. - flag_keys : `list` - A list of masking keys to use. - - Returns - ------- - bitmask : `int` - The bitmask to use for masking operations. - """ - bitmask = 0 - for bit in flag_keys: - bitmask += 2 ** mask_bits_dict[bit] - return bitmask - - -def apply_mask_operations(config, stack): - """Perform all the masking operations based on the search's configuration parameters. - - Parameters - ---------- - config : `SearchConfiguration` - The configuration parameters - stack : `ImageStack` - The stack before the masks have been applied. Modified in-place. - - Returns - ------- - stack : `ImageStack` - The stack after the masks have been applied. - """ - # Generate the global mask before we start modifying the individual masks. - if config["repeated_flag_keys"] and len(config["repeated_flag_keys"]) > 0: - global_flags = mask_flags_from_dict(config["mask_bits_dict"], config["repeated_flag_keys"]) - global_binary_mask = stack.make_global_mask(global_flags, config["mask_num_images"]) - else: - global_binary_mask = None - - # Start by creating a binary mask out of the primary flag values. Prioritize - # the config's mask_bit_vector over the dictionary based version. - if config["mask_bit_vector"]: - mask_flags = config["mask_bit_vector"] - elif config["flag_keys"] and len(config["flag_keys"]) > 0: - mask_flags = mask_flags_from_dict(config["mask_bits_dict"], config["flag_keys"]) - else: - mask_flags = 0 - - # Apply the primary mask. - for i in range(stack.img_count()): - stack.get_single_image(i).binarize_mask(mask_flags) - - # If the threshold is set, mask those pixels. - if config["mask_threshold"]: - for i in range(stack.img_count()): - stack.get_single_image(i).union_threshold_masking(config["mask_threshold"]) - - # Union in the global masking if there was one. - if global_binary_mask is not None: - for i in range(stack.img_count()): - stack.get_single_image(i).union_masks(global_binary_mask) - - # Grow the masks. - if config["mask_grow"] and config["mask_grow"] > 0: - for i in range(stack.img_count()): - stack.get_single_image(i).grow_mask(config["mask_grow"]) - - # Apply the masks to the images. Use 0xFFFFFF to apply all active masking bits. - for i in range(stack.img_count()): - stack.get_single_image(i).apply_mask(0xFFFFFF) - - return stack diff --git a/src/kbmod/run_search.py b/src/kbmod/run_search.py index 066eeed0d..2278b9177 100644 --- a/src/kbmod/run_search.py +++ b/src/kbmod/run_search.py @@ -11,7 +11,7 @@ from .filters.clustering_filters import apply_clustering from .filters.sigma_g_filter import apply_clipped_sigma_g, SigmaGClipping from .filters.stamp_filters import append_all_stamps, append_coadds, get_coadds_and_filter_results -from .masking import apply_mask_operations + from .results import Results from .trajectory_generator import create_trajectory_generator, KBMODV1SearchConfig from .wcs_utils import calc_ecliptic_angle @@ -233,7 +233,8 @@ def run_search(self, config, stack, trj_generator=None): # Apply the mask to the images. if config["do_mask"]: - stack = apply_mask_operations(config, stack) + for i in range(stack.img_count()): + stack.get_single_image(i).apply_mask(0xFFFFFF) # Perform the actual search. if trj_generator is None: diff --git a/src/kbmod/trajectory_explorer.py b/src/kbmod/trajectory_explorer.py index 507a75551..06a3f8fca 100644 --- a/src/kbmod/trajectory_explorer.py +++ b/src/kbmod/trajectory_explorer.py @@ -2,7 +2,6 @@ from kbmod.configuration import SearchConfiguration from kbmod.filters.sigma_g_filter import apply_clipped_sigma_g, SigmaGClipping -from kbmod.masking import apply_mask_operations from kbmod.results import Results from kbmod.search import StackSearch, StampCreator, Logging from kbmod.filters.stamp_filters import append_all_stamps, append_coadds @@ -48,10 +47,6 @@ def initialize_data(self): if self._data_initalized: return - # Check if we need to apply legacy masking. - if self.config["do_mask"]: - self.im_stack = apply_mask_operations(self.config, self.im_stack) - # If we are using an encoded image representation on GPU, enable it and # set the parameters. if self.config["encode_num_bytes"] > 0: diff --git a/tests/test_configuration.py b/tests/test_configuration.py index 5c76223fd..9a29969a5 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -71,7 +71,6 @@ def test_to_hdu(self): "im_filepath": "Here2", "num_obs": 5, "cluster_type": None, - "mask_bits_dict": {"bit1": 1, "bit2": 2}, "do_clustering": False, "res_filepath": "There", "ang_arr": [1.0, 2.0, 3.0], @@ -82,7 +81,6 @@ def test_to_hdu(self): self.assertEqual(hdu.data["im_filepath"][0], "Here2\n...") self.assertEqual(hdu.data["num_obs"][0], "5\n...") self.assertEqual(hdu.data["cluster_type"][0], "null\n...") - self.assertEqual(hdu.data["mask_bits_dict"][0], "{bit1: 1, bit2: 2}") self.assertEqual(hdu.data["res_filepath"][0], "There\n...") self.assertEqual(hdu.data["ang_arr"][0], "[1.0, 2.0, 3.0]") @@ -91,7 +89,6 @@ def test_to_yaml(self): "im_filepath": "Here2", "num_obs": 5, "cluster_type": None, - "mask_bits_dict": {"bit1": 1, "bit2": 2}, "do_clustering": False, "res_filepath": "There", "ang_arr": [1.0, 2.0, 3.0], @@ -103,8 +100,6 @@ def test_to_yaml(self): self.assertEqual(yaml_dict["im_filepath"], "Here2") self.assertEqual(yaml_dict["num_obs"], 5) self.assertEqual(yaml_dict["cluster_type"], None) - self.assertEqual(yaml_dict["mask_bits_dict"]["bit1"], 1) - self.assertEqual(yaml_dict["mask_bits_dict"]["bit2"], 2) self.assertEqual(yaml_dict["res_filepath"], "There") self.assertEqual(yaml_dict["ang_arr"][0], 1.0) self.assertEqual(yaml_dict["ang_arr"][1], 2.0) @@ -117,7 +112,6 @@ def test_save_and_load_yaml(self): # Overwrite some defaults. config.set("im_filepath", "Here") config.set("output_suffix", "txt") - config.set("mask_grow", 5) with tempfile.TemporaryDirectory() as dir_name: file_path = os.path.join(dir_name, "tmp_config_data.yaml") @@ -139,7 +133,6 @@ def test_save_and_load_yaml(self): self.assertEqual(len(config2._params), num_defaults) self.assertEqual(config2["im_filepath"], "Here") self.assertEqual(config2["res_filepath"], None) - self.assertEqual(config2["mask_grow"], 5) self.assertEqual(config2["output_suffix"], "txt") def test_save_and_load_fits(self): @@ -149,8 +142,6 @@ def test_save_and_load_fits(self): # Overwrite some defaults. config.set("im_filepath", "Here2") config.set("output_suffix", "csv") - config.set("mask_grow", 7) - config.set("mask_bits_dict", {"bit1": 1, "bit2": 2}) with tempfile.TemporaryDirectory() as dir_name: file_path = os.path.join(dir_name, "test.fits") @@ -172,11 +163,9 @@ def test_save_and_load_fits(self): self.assertEqual(len(config2._params), num_defaults) self.assertEqual(config2["im_filepath"], "Here2") - self.assertEqual(config2["mask_grow"], 7) self.assertEqual(config2["output_suffix"], "csv") # Check that we correctly parse dictionaries and Nones. - self.assertEqual(len(config2["mask_bits_dict"]), 2) self.assertIsNone(config2["res_filepath"]) diff --git a/tests/test_masking.py b/tests/test_masking.py deleted file mode 100644 index 5f8479046..000000000 --- a/tests/test_masking.py +++ /dev/null @@ -1,114 +0,0 @@ -import unittest - -from kbmod.configuration import SearchConfiguration -from kbmod.fake_data.fake_data_creator import make_fake_layered_image -from kbmod.masking import apply_mask_operations, mask_trajectory -from kbmod.search import * - - -class test_run_search_masking(unittest.TestCase): - def setUp(self): - # Create the a fake layered image. - self.img_count = 10 - self.dim_x = 50 - self.dim_y = 50 - self.noise_level = 0.1 - self.variance = self.noise_level**2 - self.p = PSF(1.0) - self.imlist = [] - self.time_list = [] - for i in range(self.img_count): - time = i / self.img_count - self.time_list.append(time) - im = make_fake_layered_image( - self.dim_x, self.dim_y, self.noise_level, self.variance, time, self.p, seed=i - ) - self.imlist.append(im) - self.stack = ImageStack(self.imlist) - - def test_apply_trajectory_mask(self): - starting_pixel = (20, 20) - velocity = (50.0, -10.0) - radius = 5 - trj = Trajectory(starting_pixel[0], starting_pixel[1], velocity[0], velocity[1]) - - masked_stack = mask_trajectory(trj, self.stack, radius) - - for i in range(self.img_count): - time = self.stack.get_single_image(i).get_obstime() - self.stack.get_single_image(0).get_obstime() - - origin_of_mask = (trj.get_x_index(time), trj.get_y_index(time)) - msk = masked_stack.get_single_image(i).get_mask() - - for x in range(self.dim_x): - for y in range(self.dim_y): - distance = (x - origin_of_mask[0]) ** 2 + (y - origin_of_mask[1]) ** 2 - if distance <= radius**2: - self.assertEqual(msk.get_pixel(y, x), 1) - - def test_apply_masks(self): - overrides = { - "im_filepath": "./", - "flag_keys": ["BAD", "EDGE", "SUSPECT"], - "repeated_flag_keys": ["CR"], - "mask_grow": 1, - "mask_threshold": 900.0, - } - - bad_pixels = [] - for i in range(self.img_count): - # Make the pixel (1, i) in each image above threshold and (10, i) - # right below the threshold. - img = self.stack.get_single_image(i) - sci = img.get_science() - sci.set_pixel(1, i, 1000.0) - bad_pixels.append((i, 1, i)) - sci.set_pixel(10, i, 895.0) - - # Set the "BAD" key on pixel (2, 15 + i) in each image. - msk = img.get_mask() - msk.set_pixel(2, 15 + i, 1) - bad_pixels.append((i, 2, 15 + i)) - - # Set the "INTRP" key on pixel (3, 30 + i) in each image. - # But we won't mark this as a pixel to filter. - msk.set_pixel(3, 30 + i, 4) - - # Set the "EDGE" key on pixel (2 * i, 4) in every third image. - if i % 3 == 1: - msk.set_pixel(4, 2 * i, 16) - bad_pixels.append((i, 4, 2 * i)) - - # Set the "CR" key on pixel (5, 6) in every other image. - # It will be bad in every image because of global masking. - if i % 2 == 0: - msk.set_pixel(5, 6, 8) - bad_pixels.append((i, 5, 6)) - - bad_set = set(bad_pixels) - - config = SearchConfiguration() - config.set_multiple(overrides) - - # Do the actual masking. - self.stack = apply_mask_operations(config, self.stack) - - # Test the the correct pixels have been masked. - for i in range(self.img_count): - sci = self.stack.get_single_image(i).get_science() - for y in range(self.dim_y): - for x in range(self.dim_x): - # Extend is_bad to check for pixels marked bad in our list OR - # pixels adjacent to a bad pixel (from growing the mask 1). - is_bad = ( - (i, y, x) in bad_set - or (i, y + 1, x) in bad_set - or (i, y - 1, x) in bad_set - or (i, y, x + 1) in bad_set - or (i, y, x - 1) in bad_set - ) - self.assertEqual(sci.pixel_has_data(y, x), not is_bad) - - -if __name__ == "__main__": - unittest.main()