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
SpanSet
s 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 setSpan
s 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.