There is no universally-adopted standard on how the bits in a mask are to be interpreted, and accordingly the LSST code tries to be flexible.
The mapping name --> bitmask
is defined by a dictionary in the Mask class (e.g. EDGE -> 4 -> 2^4 == 0x10
).
When Mask is created, the dictionary is initialised with a number of useful values; a convenience function is provided to list them:
Plane 0 -> BAD
Plane 3 -> CR
Plane 5 -> DETECTED
Plane 6 -> DETECTED_NEGATIVE
Plane 4 -> EDGE
Plane 2 -> INTRP
Plane 1 -> SAT
>>>
>>> def showMask(msk, msg="???"):
... print
"%-15s" % msg,
" ".join(sorted([str(
x) for
x in msk.getMaskPlaneDict().
items()]))
std::vector< SchemaItem< Flag > > * items
Represent a 2-dimensional array of bitmask pixels.
void printMaskPlanes() const
print the mask plane dictionary to std::cout
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
A base class for image defects.
(where we slipped in a convenient function showMask
to show masks in name-order)
You can add more mask planes:
>>> rhl = msk.addMaskPlane("RHL")
>>> showMask(msk, "msk")
msk ('BAD', 0) ('CR', 3) ('DETECTED', 5) ('DETECTED_NEGATIVE', 6) ('EDGE', 4) ('INTRP', 2) ('RHL', 7) ('SAT', 1)
>>> msk |=
Mask.getPlaneBitMask("RHL")
# set the RHL bits
That last example was a little misleading; I could just as well have written Mask.addMaskPlane("RHL")
as addMaskPlane
is a class static function — it adds the named mask plane to all masks. I can remove a mask plane just as easily with Mask.removeMaskPlane("RHL")
:
showMask(
Mask(),
"default Mask")
default
Mask ('BAD', 0) ('CR', 3) ('DETECTED', 5) ('DETECTED_NEGATIVE', 6) ('EDGE', 4) ('INTRP', 2) ('SAT', 1)
static void removeMaskPlane(const std::string &name)
(note that getMaskPlaneDict
is not static; we needed to create an object to be able to call it).
Unfortunately we have a problem; we set the beloved RHL
bit in msk
, but now it's gone. The resolution is that each mask remembers the version of the mask dictionary that was current when it was created, so:
>>> showMask(msk, "msk")
msk ('BAD', 0) ('CR', 3) ('DETECTED', 5) ('DETECTED_NEGATIVE', 6) ('EDGE', 4) ('INTRP', 2) ('RHL', 7) ('SAT', 1)
If you want to get rid of msk's
RHL
bit, use msk.removeAndClearMaskPlane("RHL")
or msk.removeAndClearMaskPlane("RHL", True)
if you want to drop RHL
from the default mask too. This does two things: It clears any RHL
bits that are set in the Mask (it isn't static, so it can do that), and it removes RHL
from the Mask's dictionary.
It's clear that you can make things inconsistent if you try:
>>> print
"Planes:", p0, p1,
Mask.
addMaskPlane(
"P1") #
a no-op -- re-adding
a plane has no effect
Planes: 0 1 1
>>> showMask(
Mask(),
"default Mask")
>>> showMask(msk, "msk")
msk ('P0', 0) ('P1', 1)
>>> p1 =
Mask.addMaskPlane("P1")
>>> p0 =
Mask.addMaskPlane("P0")
>>>
>>> showMask(msk2, "msk2")
msk2 ('P0', 1) ('P1', 0)
static void clearMaskPlaneDict()
Reset the maskPlane dictionary.
static int addMaskPlane(const std::string &name)
But you can't actually do much harm:
>>> msk |= msk2
File
"<stdin>",
line 1, in <module>
File
"/Users/rhl/LSST/afw/python/lsst/afw/image/imageLib.py",
line 5415, in __ior__
_imageLib.MaskU___ior__(*args)
0: Message:
Mask dictionary versions do not match; 3 v. 6
std::shared_ptr< RecordT > src
def line(points, frame=None, origin=afwImage.PARENT, symbs=False, ctype=None, size=0.5)
The version numbers aren't actually compared directly, rather a hash of the contents is computed, so:
>>> showMask(msk, "msk")
msk ('P0', 0) ('P1', 1)
>>> msk.removeAndClearMaskPlane("P0")
>>> msk.removeAndClearMaskPlane("P1")
>>> p0 =
Mask.addMaskPlane("P0")
>>> p1 =
Mask.addMaskPlane("P1")
>>> showMask(msk, "msk")
msk ('P0', 1) ('P1', 0)
>>> msk |= msk2
(We removed the errant planes from msk
, then re-added the ones that are already defined in the default dictionary)
Adding planes has no such difficulties, so they are added to all pre-existing dictionaries that don't have conflicts:
>>> showMask(msk, "msk")
msk ('P0', 1) ('P1', 0) ('P2', 2)
However, as expected,
>>> msk |= msk2
void removeAndClearMaskPlane(const std::string &name, bool const removeFromDefault=false)
Clear all pixels of the specified mask and remove the plane from the mask plane dictionary; optionall...
will raise an exception.
What did I mean by, "conflicts"? Here's an example:
>>> showMask(msk, "msk")
msk ('P0', 1) ('P1', 0) ('P2', 2)
default
Mask ('P0', 3) ('P1', 0) ('P2', 2) ('P3', 1)
Note that msk
hasn't acquired a P3
plane as plane 1
is already in use.