Using lsst.afw.detection.Footprint to represent detection areas¶
The fundamental unit of a detection in the LSST pipeline is an instance of the
Footprint class. This class contains the x, y locations for pixels that are
part of a detection, as well as the x, y location and intensity of pixels which
are considered local peaks within the detection area.
Spans¶
Internally the pixel locations of a detection are stored in an instance of a
SpanSet which can be retrieved through the getSpans function (or the
Footprint.spans property in Python). The SpanSet provides methods for
working with the detected area as a mathematical set. Of important note is that
SpanSets are immutable once created. If the area of a Footprint needs
to be updated after initialization a new SpanSet must be created which will
then replace the original SpanSet held by the Footprint instance. This
can be done by calling the setSpans method (or assigning to the
Footprint.spans property in Python). This does not modify the PeakCatalog,
and there may be peaks which no longer fall inside the footprint. Call
removeOrphanPeaks to remove these peaks. Below modifying a SpanSet is
demonstrated.
from lsst.afw.geom import SpanSet
from lsst.afw.detection import Footprint
# Create a SpanSet and use it to construct a Footprint
radius = 5
ss = SpanSet.fromShape(radius, offset=(10, 10))
foot = Footprint(ss)
# Demo the SpanSet is the same
assert(ss == foot.spans)
# Create a new SpanSet and assign it to the Footprint
newRadius = 4
ss2 = SpanSet.fromShape(newRadius, offset=(7, 7))
foot.spans = ss2
# Show that the SpanSet held by the Footprint is no longer the original
assert(ss != foot.spans)
Some common operations which involve calling SpanSet methods, and
possibly setting the results back to a Footprint, have convenience methods
defined in the Footprint class. Unlike the SpanSet class a
Footprint is mutable, such that calling the some convenience methods (e.g.
dilate, erode) modifies the Footprint, as shown below.
from lsst.afw.geom import SpanSet
from lsst.afw.detection import Footprint
# Create a SpanSet and use it to construct a Footprint
radius = 5
ss = SpanSet.fromShape(radius, offset=(10, 10))
foot = Footprint(ss)
# Grab the SpanSet back from the Footprint and show it is the same
ssFromFoot = foot.spans
assert(ss is ssFromFoot)
# Modify the Footprint in place (automatically update the internal reference
# to the SpanSet), show that they are now different
kernelRad = 2
foot.erode(kernelRad)
newSsFromFoot = foot.spans
assert(ss is not newSsFromFoot)
In cases where the location information is all that is needed, it is strongly
suggested to use a SpanSet directly and avoid the overhead of carrying
around an empty PeakCatalog. The constructors for a Footprint have been
structured to remind users of this by first requiring a SpanSet to be created.
Peaks¶
Information on the location and intensity of the detected peaks within a
Footprint are kept in a PeakCatalog which can be retrieved with the
getPeaks method (or the .peaks property within Python). Like with a
Footprint’s SpanSet it is possible to set a Footprint's
PeakCatalog. Unlike with the SpanSet member it is only possible to set a
new PeakCatalog if the existing catalog is empty. It is also possible to
change the schema that defines the PeakCatalog but the existing catalog must
be empty for this operation as well. Another asymmetry between the SpanSet
and PeakCatalog members is in the behavior of the Python property accessor.
In Python the .spans property is both readable and writable, while the .peaks
property is read only. This behavior is intended to make a programmer cognisant
of the fact that the PeakCatalog can only be set if it is currently empty.
The PeakCatalog can be populated by calling methods on the catalog itself,
or with the convenience method addPeak supplied with the Footprint
class. An additional convince method sortPeaks is also provided to increase
the ease of sorting the catalog. The following is an example of using a
Footprint’s PeakCatalog.
from lsst.afw.geom import SpanSet
from lsst.afw.detection import Footprint
# Create a Footprint from a SpanSet
radius = 5
ss = SpanSet.fromShape(radius, offset=(10, 10))
foot = Footprint(ss)
# Add a few peaks to the PeakCatalog (x, y, intensity)
foot.addPeak(7, 7, 95)
foot.addPeak(8, 8, 103)
foot.addPeak(9, 9, 100)
# Sort the peaks according to the intensity
foot.sortPeaks()
# Print the peaks in the Footprint
for peak in foot.peaks:
print(peak.getPeakValue())
# Output:
# 103.0
# 100.0
# 95.0
Regions¶
The Footprint class also contains a few miscellaneous data members and
methods unrelated to the main data containers mentioned above. One such data
member is the``region`` which defines the boundary of the image in which the
detection was made. This property can be retrieved or set with getRegion
and setRegion respectively.
Transformations¶
A method named transform is provided which operates on both the SpanSet
and PeakCatalog transforming the x, y values into a new coordinate system.
The transform method returns a newly
created Footprint.
Handling discontinuous Footprints¶
To split apart a footprint which may have a discontinuous area into continuous
regions which contain only peaks which fall in the region use the split
method. Occasionally, as mentioned above, operations on the SpanSet may
create an area which no longer contains the x, y locations of peaks in the
PeakCatalog. When this occurs the removeOrphanPeaks may be used to trim
peaks which fall outside the new area.