Source code for ctapipe.image.cleaning

"""
Image Cleaning Algorithms (identification of noisy pixels)


All algorithms return a boolean mask that is True for pixels surviving
the cleaning.

To get a zero-suppressed image and pixel
list, use ``image[mask], geom.pix_id[mask]``, or to keep the same
image size and just set unclean pixels to 0 or similar, use
``image[~mask] = 0``

"""

__all__ = [
    "tailcuts_clean",
    "bright_cleaning",
    "dilate",
    "mars_cleaning_1st_pass",
    "fact_image_cleaning",
    "apply_time_delta_cleaning",
    "apply_time_average_cleaning",
    "time_constrained_clean",
    "nsb_image_cleaning",
    "ImageCleaner",
    "TailcutsImageCleaner",
    "NSBImageCleaner",
    "MARSImageCleaner",
    "FACTImageCleaner",
    "TimeConstrainedImageCleaner",
]

from abc import abstractmethod

import numpy as np

from ctapipe.image.statistics import n_largest

from ..containers import CameraMonitoringContainer
from ..core import TelescopeComponent
from ..core.traits import (
    BoolTelescopeParameter,
    FloatTelescopeParameter,
    IntTelescopeParameter,
)
from .morphology import brightest_island, largest_island, number_of_islands


[docs] def tailcuts_clean( geom, image, picture_thresh=7, boundary_thresh=5, keep_isolated_pixels=False, min_number_picture_neighbors=0, ): """Clean an image by selection pixels that pass a two-threshold tail-cuts procedure. The picture and boundary thresholds are defined with respect to the pedestal dispersion. All pixels that have a signal higher than the picture threshold will be retained, along with all those above the boundary threshold that are neighbors of a picture pixel. To include extra neighbor rows of pixels beyond what are accepted, use the `ctapipe.image.dilate` function. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information image : np.ndarray pixel charges picture_thresh : float | np.ndarray threshold above which all pixels are retained boundary_thresh : float | np.ndarray threshold above which pixels are retained if they have a neighbor already above the picture_thresh keep_isolated_pixels : bool If True, pixels above the picture threshold will be included always, if not they are only included if a neighbor is in the picture or boundary min_number_picture_neighbors : int A picture pixel survives cleaning only if it has at least this number of picture neighbors. This has no effect in case keep_isolated_pixels is True Returns ------- A boolean mask of selected pixels. """ pixels_above_picture = image >= picture_thresh if keep_isolated_pixels or min_number_picture_neighbors == 0: pixels_in_picture = pixels_above_picture else: # Require at least min_number_picture_neighbors. Otherwise, the pixel # is not selected number_of_neighbors_above_picture = geom.neighbor_matrix_sparse.dot( pixels_above_picture.view(np.byte) ) pixels_in_picture = pixels_above_picture & ( number_of_neighbors_above_picture >= min_number_picture_neighbors ) # by broadcasting together pixels_in_picture (1d) with the neighbor # matrix (2d), we find all pixels that are above the boundary threshold # AND have any neighbor that is in the picture pixels_above_boundary = image >= boundary_thresh pixels_with_picture_neighbors = geom.neighbor_matrix_sparse.dot(pixels_in_picture) if keep_isolated_pixels: return ( pixels_above_boundary & pixels_with_picture_neighbors ) | pixels_in_picture else: pixels_with_boundary_neighbors = geom.neighbor_matrix_sparse.dot( pixels_above_boundary ) return (pixels_above_boundary & pixels_with_picture_neighbors) | ( pixels_in_picture & pixels_with_boundary_neighbors )
[docs] def bright_cleaning(image, threshold, fraction, n_pixels=3): """ Clean an image by removing pixels below a fraction of the mean charge in the ``n_pixels`` brightest pixels. No pixels are removed instead if the mean charge of the brightest pixels are below a certain threshold. Parameters ---------- image : np.ndarray pixel charges threshold : float Minimum average charge in the ``n_pixels`` brightest pixels to apply cleaning fraction : float Pixels below fraction * (average charge in the ``n_pixels`` brightest pixels) will be removed from the cleaned image n_pixels : int Consider this number of the brightest pixels to calculate the mean charge Returns ------- A boolean mask of selected pixels. """ mean_brightest_signal = np.mean(n_largest(n_pixels, image)) if mean_brightest_signal < threshold: return np.ones(image.shape, dtype=bool) threshold_brightest = fraction * mean_brightest_signal mask = image >= threshold_brightest return mask
[docs] def mars_cleaning_1st_pass( geom, image, picture_thresh=7, boundary_thresh=5, keep_isolated_pixels=False, min_number_picture_neighbors=0, ): """ Clean an image by selecting pixels that pass a three-threshold tail-cuts procedure. All thresholds are defined with respect to the pedestal dispersion. All pixels that have a signal higher than the core (picture) threshold will be retained, along with all those above the boundary threshold that are neighbors of a core pixel AND all those above the boundary threshold that are neighbors of a neighbor of a core pixel. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information image : np.ndarray pixel charges picture_thresh : float threshold above which all pixels are retained boundary_thresh : float threshold above which pixels are retained if they have a neighbor already above the ``picture_thresh``; it is then reapplied iteratively to the neighbor of the neighbor keep_isolated_pixels : bool If True, pixels above the picture threshold will be included always, if not they are only included if a neighbor is in the picture or boundary min_number_picture_neighbors : int A picture pixel survives cleaning only if it has at least this number of picture neighbors. This has no effect in case ``keep_isolated_pixels`` is True Returns ------- A boolean mask of selected pixels. """ pixels_from_tailcuts_clean = tailcuts_clean( geom, image, picture_thresh, boundary_thresh, keep_isolated_pixels, min_number_picture_neighbors, ) # this selects any core pixel and any of its first neighbors # At this point we don't know yet which ones should be kept. # In principle, the pixel thresholds should be hierarchical from core to # boundaries (this should be true for every type of particle triggering # the image), so we can just check which pixels have more than # boundary_thresh photo-electrons in the same image, but starting from # the mask we got from 'tailcuts_clean'. pixels_above_2nd_boundary = image >= boundary_thresh # and now it's the same as the last part of 'tailcuts_clean', but without # the core pixels, i.e. we start from the neighbors of the core pixels. pixels_with_previous_neighbors = geom.neighbor_matrix_sparse.dot( pixels_from_tailcuts_clean ) if keep_isolated_pixels: return ( pixels_above_2nd_boundary & pixels_with_previous_neighbors ) | pixels_from_tailcuts_clean else: pixels_with_2ndboundary_neighbors = geom.neighbor_matrix_sparse.dot( pixels_above_2nd_boundary ) return (pixels_above_2nd_boundary & pixels_with_previous_neighbors) | ( pixels_from_tailcuts_clean & pixels_with_2ndboundary_neighbors )
[docs] def dilate(geom, mask): """ Add one row of neighbors to the true values of a pixel mask and return the new mask. This can be used to include extra rows of pixels in a mask that was pre-computed, e.g. via `tailcuts_clean`. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information mask : np.ndarray input mask (array of booleans) to be dilated """ return mask | geom.neighbor_matrix_sparse.dot(mask)
[docs] def apply_time_delta_cleaning( geom, mask, arrival_times, min_number_neighbors, time_limit ): """ Identify all pixels from selection that have less than N neighbors that arrived within a given timeframe. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information mask : np.ndarray boolean mask of selected pixels before `apply_time_delta_cleaning` arrival_times : np.ndarray pixel timing information min_number_neighbors : int a selected pixel needs at least this number of (already selected) neighbors that arrived within a given time_limit to itself to survive the cleaning. time_limit : int | float arrival time limit for neighboring pixels Returns ------- A boolean mask of selected pixels. """ pixels_to_keep = mask.copy() time_diffs = np.abs(arrival_times[mask, None] - arrival_times) # neighboring pixels arriving in the time limit and previously selected valid_neighbors = (time_diffs < time_limit) & geom.neighbor_matrix[mask] & mask enough_neighbors = np.count_nonzero(valid_neighbors, axis=1) >= min_number_neighbors pixels_to_keep[pixels_to_keep] &= enough_neighbors return pixels_to_keep
[docs] def apply_time_average_cleaning( geom, mask, image, arrival_times, picture_thresh, time_limit ): """ Extract all pixels that arrived within a given timeframe with respect to the time average of the pixels on the main island. In order to avoid removing signal pixels of large impact-parameter events, the time limit for bright pixels is doubled. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information mask : np.ndarray boolean mask of selected pixels before `apply_time_delta_cleaning` image : np.ndarray pixel charges arrival_times : np.ndarray pixel timing information picture_thresh : float threshold above which ``time_limit`` is extended twice its value time_limit : int | float arrival time limit w.r.t. the average time of the core pixels Returns ------- A boolean mask of selected pixels. """ mask = mask.copy() if np.count_nonzero(mask) > 0: # use main island (maximum charge) for time average calculation n_islands, island_labels = number_of_islands(geom, mask) mask_main = brightest_island(n_islands, island_labels, image) time_ave = np.average(arrival_times[mask_main], weights=image[mask_main] ** 2) time_diffs = np.abs(arrival_times[mask] - time_ave) time_limit_pixwise = np.where( image < (2 * picture_thresh), time_limit, time_limit * 2 )[mask] mask[mask] &= time_diffs < time_limit_pixwise return mask
[docs] def fact_image_cleaning( geom, image, arrival_times, picture_threshold=4, boundary_threshold=2, min_number_neighbors=2, time_limit=5, ): """Clean an image by selection pixels that pass the fact cleaning procedure. Cleaning contains the following steps: 1: Find pixels containing more photons than a threshold t1 2: Remove pixels with less than N neighbors 3: Add neighbors of the remaining pixels that are above a lower threshold t2 4: Remove pixels with less than N neighbors arriving within a given timeframe 5: Remove pixels with less than N neighbors 6: Remove pixels with less than N neighbors arriving within a given timeframe Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information image : np.ndarray pixel charges arrival_times : np.ndarray pixel timing information picture_threshold : float | np.ndarray threshold above which all pixels are retained boundary_threshold : float | np.ndarray threshold above which pixels are retained if they have a neighbor already above the ``picture_thresh`` min_number_neighbors : int Threshold to determine if a pixel survives cleaning steps. These steps include checks of neighbor arrival time and value time_limit : int | float arrival time limit for neighboring pixels Returns ------- A boolean mask of selected pixels. References ---------- See :cite:p:`phd-temme` and for implementation :cite:p:`fact-tools`. """ # Step 1 pixels_to_keep = image >= picture_threshold # Step 2 number_of_neighbors_above_picture = geom.neighbor_matrix_sparse.dot( (pixels_to_keep).view(np.byte) ) pixels_to_keep = pixels_to_keep & ( number_of_neighbors_above_picture >= min_number_neighbors ) # Step 3 pixels_above_boundary = image >= boundary_threshold pixels_to_keep = dilate(geom, pixels_to_keep) & pixels_above_boundary # nothing else to do if min_number_neighbors <= 0 if min_number_neighbors <= 0: return pixels_to_keep # Step 4 pixels_to_keep = apply_time_delta_cleaning( geom, pixels_to_keep, arrival_times, min_number_neighbors, time_limit ) # Step 5 number_of_neighbors = geom.neighbor_matrix_sparse.dot( (pixels_to_keep).view(np.byte) ) pixels_to_keep = pixels_to_keep & (number_of_neighbors >= min_number_neighbors) # Step 6 pixels_to_keep = apply_time_delta_cleaning( geom, pixels_to_keep, arrival_times, min_number_neighbors, time_limit ) return pixels_to_keep
[docs] def time_constrained_clean( geom, image, arrival_times, picture_thresh=7, boundary_thresh=5, time_limit_core=4.5, time_limit_boundary=1.5, min_number_picture_neighbors=1, ): """ Time constrained cleaning by MAGIC Cleaning contains the following steps: - Find core pixels (containing more photons than a picture threshold) - Remove pixels with less than N neighbors - Keep core pixels whose arrival times are within a time limit of the average time - Find boundary pixels (containing more photons than a boundary threshold) - Remove pixels with less than N neighbors arriving within a given timeframe Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information image : np.ndarray pixel charges arrival_times : np.ndarray pixel timing information picture_threshold : float | np.ndarray threshold above which all pixels are retained boundary_threshold : float | np.ndarray threshold above which pixels are retained if they have a neighbor already above the ``picture_thresh`` time_limit_core : int | float arrival time limit of core pixels w.r.t the average time time_limit_boundary : int | float arrival time limit of boundary pixels w.r.t neighboring core pixels min_number_neighbors : int Threshold to determine if a pixel survives cleaning steps. These steps include checks of neighbor arrival time and value Returns ------- A boolean mask of selected pixels. """ # find core pixels that pass a picture threshold pixels_above_picture = image >= picture_thresh # require at least min_number_picture_neighbors number_of_neighbors_above_picture = geom.neighbor_matrix_sparse.dot( pixels_above_picture.view(np.byte) ) pixels_in_picture = pixels_above_picture & ( number_of_neighbors_above_picture >= min_number_picture_neighbors ) # keep core pixels whose arrival times are within a certain time limit of the average mask_core = apply_time_average_cleaning( geom, pixels_in_picture, image, arrival_times, picture_thresh, time_limit_core ) # find boundary pixels that pass a boundary threshold pixels_above_boundary = image >= boundary_thresh pixels_with_picture_neighbors = geom.neighbor_matrix_sparse.dot(mask_core) mask_boundary = (pixels_above_boundary & pixels_with_picture_neighbors) & np.invert( mask_core ) # keep boundary pixels whose arrival times are within a certain time limit of the neighboring core pixels mask_boundary = mask_boundary.copy() time_diffs = np.abs(arrival_times[mask_boundary, None] - arrival_times) valid_neighbors = ( (time_diffs < time_limit_boundary) & geom.neighbor_matrix[mask_boundary] & mask_core ) enough_neighbors = ( np.count_nonzero(valid_neighbors, axis=1) >= min_number_picture_neighbors ) mask_boundary[mask_boundary] &= enough_neighbors return mask_core | mask_boundary
[docs] def nsb_image_cleaning( geom, image, arrival_times, picture_thresh_min=8, boundary_thresh=4, min_number_picture_neighbors=2, keep_isolated_pixels=False, time_limit=None, time_num_neighbors=1, bright_cleaning_n_pixels=3, bright_cleaning_fraction=0.03, bright_cleaning_threshold=None, largest_island_only=False, pedestal_factor=2.5, pedestal_std=None, ): """ Clean an image in 5 Steps: 1) Get pixelwise picture thresholds for `tailcuts_clean` in step 2) from interleaved pedestal events if ``pedestal_std`` is not None. 2) Apply `tailcuts_clean` algorithm. 3) Apply `apply_time_delta_cleaning` algorithm if ``time_limit`` is not None. 4) Apply `bright_cleaning` if ``bright_cleaning_threshold`` is not None. 5) Get only `ctapipe.image.largest_island` if ``largest_island_only`` is set to true. Parameters ---------- geom : `ctapipe.instrument.CameraGeometry` Camera geometry information image : np.ndarray Pixel charges arrival_times : np.ndarray Pixel timing information picture_thresh_min : float | np.ndarray Defines the minimum value used for the picture threshold for `tailcuts_clean`. The threshold used will be at least this value, or higher if ``pedestal_std`` and ``pedestal_factor`` are set. boundary_thresh : float | np.ndarray Threshold above which pixels are retained if they have a neighbor already above the ``picture_thresh_min``. Used for `tailcuts_clean`. min_number_picture_neighbors : int A picture pixel survives cleaning only if it has at least this number of picture neighbors. This has no effect in case ``keep_isolated_pixels`` is True. Used for `tailcuts_clean`. keep_isolated_pixels : bool If True, pixels above the picture threshold will be included always, if not they are only included if a neighbor is in the picture or boundary. Used for `tailcuts_clean`. time_limit : float Time limit for the `apply_time_delta_cleaning`. Set to None if no `apply_time_delta_cleaning` should be applied. time_num_neighbors : int Used for `apply_time_delta_cleaning`. A selected pixel needs at least this number of (already selected) neighbors that arrived within a given ``time_limit`` to itself to survive this cleaning. bright_cleaning_n_pixels : int Consider this number of the brightest pixels for calculating the mean charge. Pixels below fraction * (mean charge in the ``bright_cleaning_n_pixels`` brightest pixels) will be removed from the cleaned image. Set ``bright_cleaning_threshold`` to None if no `bright_cleaning` should be applied. bright_cleaning_fraction : float Fraction parameter for `bright_cleaning`. Pixels below fraction * (mean charge in the ``bright_cleaning_n_pixels`` brightest pixels) will be removed from the cleaned image. Set ``bright_cleaning_threshold`` to None if no `bright_cleaning` should be applied. bright_cleaning_threshold : float Threshold parameter for `bright_cleaning`. Minimum mean charge in the ``bright_cleaning_n_pixels`` brightest pixels to apply the cleaning. Set to None if no `bright_cleaning` should be applied. largest_island_only : bool Set to true to get only largest island. pedestal_factor : float Factor for interleaved pedestal cleaning. It is multiplied by the pedestal standard deviation for each pixel to calculate pixelwise picture threshold parameters for `tailcuts_clean` considering the current background. Has no effect if ``pedestal_std`` is set to None. pedestal_std : np.ndarray | None Pedestal standard deviation for each pixel. Used to calculate pixelwise picture threshold parameters for `tailcuts_clean` by multiplying it with ``pedestal_factor`` and clip (limit) the product with ``picture_thresh_min``. If set to None, only ``picture_thresh_min`` is used to set the picture threshold for `tailcuts_clean`. Returns ------- A boolean mask of selected pixels. """ # Step 1 picture_thresh = picture_thresh_min if pedestal_std is not None: pedestal_threshold = pedestal_std * pedestal_factor picture_thresh = np.clip(pedestal_threshold, picture_thresh_min, None) # Step 2 mask = tailcuts_clean( geom, image, picture_thresh=picture_thresh, boundary_thresh=boundary_thresh, min_number_picture_neighbors=min_number_picture_neighbors, keep_isolated_pixels=keep_isolated_pixels, ) # Check that at least one pixel survives tailcuts_clean if np.count_nonzero(mask) == 0: return mask # Step 3 if time_limit is not None: mask = apply_time_delta_cleaning( geom, mask, arrival_times, min_number_neighbors=time_num_neighbors, time_limit=time_limit, ) # Step 4 if bright_cleaning_threshold is not None: mask &= bright_cleaning( image, bright_cleaning_threshold, bright_cleaning_fraction, bright_cleaning_n_pixels, ) # Step 5 if largest_island_only: _, island_labels = number_of_islands(geom, mask) mask = largest_island(island_labels) return mask
[docs] class ImageCleaner(TelescopeComponent): """ Abstract class for all configurable Image Cleaning algorithms. Use ``ImageCleaner.from_name()`` to construct an instance of a particular algorithm """
[docs] @abstractmethod def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """ Identify pixels with signal, and reject those with pure noise. Parameters ---------- tel_id : int which telescope id in the subarray is being used (determines which cut is used) image : np.ndarray image pixel data corresponding to the camera geometry arrival_times : np.ndarray image of arrival time (not used in this method) monitoring : `ctapipe.containers.CameraMonitoringContainer` `ctapipe.containers.CameraMonitoringContainer` to make use of additional parameters from monitoring data e.g. sky pedestal std. Returns ------- np.ndarray boolean mask of pixels passing cleaning """ pass
[docs] class TailcutsImageCleaner(ImageCleaner): """ Clean images using the standard picture/boundary technique. See `ctapipe.image.tailcuts_clean`. """ picture_threshold_pe = FloatTelescopeParameter( default_value=10.0, help="top-level threshold in photoelectrons" ).tag(config=True) boundary_threshold_pe = FloatTelescopeParameter( default_value=5.0, help="second-level threshold in photoelectrons" ).tag(config=True) min_picture_neighbors = IntTelescopeParameter( default_value=2, help="Minimum number of neighbors above threshold to consider" ).tag(config=True) keep_isolated_pixels = BoolTelescopeParameter( default_value=False, help="If False, pixels with less neighbors than ``min_picture_neighbors`` are" "removed.", ).tag(config=True)
[docs] def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """ Apply standard picture-boundary cleaning. See `ImageCleaner.__call__()` """ return tailcuts_clean( self.subarray.tel[tel_id].camera.geometry, image, picture_thresh=self.picture_threshold_pe.tel[tel_id], boundary_thresh=self.boundary_threshold_pe.tel[tel_id], min_number_picture_neighbors=self.min_picture_neighbors.tel[tel_id], keep_isolated_pixels=self.keep_isolated_pixels.tel[tel_id], )
[docs] class NSBImageCleaner(TailcutsImageCleaner): """ Clean images based on lstchains image cleaning technique described in :cite:p:`lst1-crab-paper`. See `ctapipe.image.nsb_image_cleaning`. """ time_limit = FloatTelescopeParameter( default_value=2, help="Time limit for the `apply_time_delta_cleaning`. Set to None if no" " `apply_time_delta_cleaning` should be applied.", allow_none=True, ).tag(config=True) time_num_neighbors = IntTelescopeParameter( default_value=1, help="Used for `apply_time_delta_cleaning`." " A selected pixel needs at least this number of (already selected) neighbors" " that arrived within a given `time_limit` to itself to survive this cleaning.", ).tag(config=True) bright_cleaning_n_pixels = IntTelescopeParameter( default_value=3, help="Consider this number of the brightest pixels for calculating the" " mean charge. Pixels below fraction * (mean charge in the" " ``bright_cleaning_n_pixels`` brightest pixels) will be removed from the" " cleaned image. Set ``bright_cleaning_threshold`` to None if no" " `bright_cleaning` should be applied.", ).tag(config=True) bright_cleaning_fraction = FloatTelescopeParameter( default_value=0.03, help="Fraction parameter for `bright_cleaning`. Pixels below" " fraction * (mean charge in the ``bright_cleaning_n_pixels`` brightest pixels)" " will be removed from the cleaned image. Set ``bright_cleaning_threshold`` to" " None if no `bright_cleaning` should be applied.", ).tag(config=True) bright_cleaning_threshold = FloatTelescopeParameter( default_value=267, help="Threshold parameter for `bright_cleaning`. Minimum mean charge" " in the ``bright_cleaning_n_pixels`` brightest pixels to apply the cleaning." " Set to None if no `bright_cleaning` should be applied.", allow_none=True, ).tag(config=True) largest_island_only = BoolTelescopeParameter( default_value=False, help="Set to true to get only largest island" ).tag(config=True) pedestal_factor = FloatTelescopeParameter( default_value=2.5, help="Factor for interleaved pedestal cleaning. It is multiplied by the" " pedestal standard deviation for each pixel to calculate pixelwise upper limit" " picture thresholds and clip them with ``picture_thresh_pe`` of" " `TailcutsImageCleaner` for `tailcuts_clean` considering the current background." " If no pedestal standard deviation is given, interleaved pedestal cleaning is" " not applied and ``picture_thresh_pe`` of `TailcutsImageCleaner` is used alone" " instead.", ).tag(config=True)
[docs] def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """ Apply NSB image cleaning used by lstchain. See `ImageCleaner.__call__()` """ pedestal_std = None if monitoring is not None: pedestal_std = monitoring.pixel_statistics.sky_pedestal_image.std return nsb_image_cleaning( self.subarray.tel[tel_id].camera.geometry, image, arrival_times, picture_thresh_min=self.picture_threshold_pe.tel[tel_id], boundary_thresh=self.boundary_threshold_pe.tel[tel_id], min_number_picture_neighbors=self.min_picture_neighbors.tel[tel_id], keep_isolated_pixels=self.keep_isolated_pixels.tel[tel_id], time_limit=self.time_limit.tel[tel_id], time_num_neighbors=self.time_num_neighbors.tel[tel_id], bright_cleaning_n_pixels=self.bright_cleaning_n_pixels.tel[tel_id], bright_cleaning_fraction=self.bright_cleaning_fraction.tel[tel_id], bright_cleaning_threshold=self.bright_cleaning_threshold.tel[tel_id], largest_island_only=self.largest_island_only.tel[tel_id], pedestal_factor=self.pedestal_factor.tel[tel_id], pedestal_std=pedestal_std, )
[docs] class MARSImageCleaner(TailcutsImageCleaner): """ 1st-pass MARS-like Image cleaner (See `ctapipe.image.mars_cleaning_1st_pass`) """
[docs] def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """ Apply MARS-style image cleaning. See `ImageCleaner.__call__()` """ return mars_cleaning_1st_pass( self.subarray.tel[tel_id].camera.geometry, image, picture_thresh=self.picture_threshold_pe.tel[tel_id], boundary_thresh=self.boundary_threshold_pe.tel[tel_id], min_number_picture_neighbors=self.min_picture_neighbors.tel[tel_id], keep_isolated_pixels=False, )
[docs] class FACTImageCleaner(TailcutsImageCleaner): """ Clean images using the FACT technique. See `ctapipe.image.fact_image_cleaning` for algorithm details. """ time_limit_ns = FloatTelescopeParameter( default_value=5.0, help="arrival time limit for neighboring pixels, in ns" ).tag(config=True)
[docs] def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """Apply FACT-style image cleaning. see ImageCleaner.__call__()""" return fact_image_cleaning( geom=self.subarray.tel[tel_id].camera.geometry, image=image, arrival_times=arrival_times, picture_threshold=self.picture_threshold_pe.tel[tel_id], boundary_threshold=self.boundary_threshold_pe.tel[tel_id], min_number_neighbors=self.min_picture_neighbors.tel[tel_id], time_limit=self.time_limit_ns.tel[tel_id], )
[docs] class TimeConstrainedImageCleaner(TailcutsImageCleaner): """ MAGIC-like Image cleaner with timing information (See `ctapipe.image.time_constrained_clean`). """ time_limit_core_ns = FloatTelescopeParameter( default_value=4.5, help="arrival time limit for neighboring core pixels, in ns", ).tag(config=True) time_limit_boundary_ns = FloatTelescopeParameter( default_value=1.5, help="arrival time limit for neighboring boundary pixels, in ns", ).tag(config=True)
[docs] def __call__( self, tel_id: int, image: np.ndarray, arrival_times: np.ndarray = None, *, monitoring: CameraMonitoringContainer = None, ) -> np.ndarray: """ Apply MAGIC-like image cleaning with timing information. See `ImageCleaner.__call__()` """ return time_constrained_clean( self.subarray.tel[tel_id].camera.geometry, image, arrival_times=arrival_times, picture_thresh=self.picture_threshold_pe.tel[tel_id], boundary_thresh=self.boundary_threshold_pe.tel[tel_id], min_number_picture_neighbors=self.min_picture_neighbors.tel[tel_id], time_limit_core=self.time_limit_core_ns.tel[tel_id], time_limit_boundary=self.time_limit_boundary_ns.tel[tel_id], )