Source code for gammapy.detect.find

# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import absolute_import, division, print_function, unicode_literals
import numpy as np
from astropy.coordinates import SkyCoord
from astropy.table import Table
from ..maps import WcsNDMap

__all__ = ["find_peaks"]


[docs]def find_peaks(image, threshold, min_distance=1): """Find local peaks in an image. This is a very simple peak finder, that finds local peaks (i.e. maxima) in images above a given ``threshold`` within a given ``min_distance`` around each given pixel. If you get multiple spurious detections near a peak, usually it's best to smooth the image a bit, or to compute it using a different method in the first place to result in a smooth image. You can also increase the ``min_distance`` parameter. The output table contains one row per peak and the following columns: - ``x`` and ``y`` are the pixel coordinates (first pixel at zero) - ``ra`` and ``dec`` are the RA / DEC sky coordinates (ICRS frame) - ``value`` is the pixel value It is sorted by peak value, starting with the highest value. If there are no pixel values above the threshold, an empty table is returned. There are more featureful peak finding and source detection methods e.g. in the ``photutils`` or ``scikit-image`` Python packages. Parameters ---------- image : `~gammapy.maps.WcsNDMap` 2D map threshold : float or array-like The data value or pixel-wise data values to be used for the detection threshold. A 2D ``threshold`` must have the same shape as tha map ``data``. min_distance : int Minimum pixel distance between peaks. Smallest possible value and default is 1 pixel. Returns ------- output : `~astropy.table.Table` Table with parameters of detected peaks """ from scipy.ndimage import maximum_filter # Input validation if not isinstance(image, WcsNDMap): raise TypeError("find_peaks only supports WcsNDMap") if not image.geom.is_image: raise ValueError("find_peaks only supports 2D images") size = 2 * min_distance + 1 # Remove non-finite values to avoid warnings or spurious detection data = image.data.copy() data[~np.isfinite(data)] = np.nanmin(data) # Handle edge case of constant data; treat as no peak if np.all(data == data.flat[0]): return Table() # Run peak finder data_max = maximum_filter(data, size=size, mode="constant") mask = (data == data_max) & (data > threshold) y, x = mask.nonzero() value = data[y, x] # Make and return results table if len(value) == 0: return Table() coord = SkyCoord.from_pixel(x, y, wcs=image.geom.wcs).icrs table = Table() table["value"] = value * image.unit table["x"] = x table["y"] = y table["ra"] = coord.ra table["dec"] = coord.dec table["ra"].format = ".5f" table["dec"].format = ".5f" table["value"].format = ".5g" table.sort("value") table.reverse() return table