LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
Mask.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008-2016 AURA/LSST.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
27 
28 /*
29  * There are a number of classes defined here and in Mask.h
30  *
31  * The fundamental type visible to the user is Mask; a 2-d array of pixels. Each of these pixels should
32  * be thought of as a set of bits, and the names of these bits are given by MaskPlaneDict (which is
33  * implemented as a std::map)
34  *
35  * Internally to this file, we have a MapWithHash which is like a std::map, but maintains a hash of its
36  * contents; this is used to check equality efficiently.
37  *
38  * We also have a MaskDict which isa MapWithHash, but also maintains a list of MaskDicts (or equivalently
39  * MapWithHash) allowing us to iterate over these maps, updating them as needed.
40  *
41  * The list of MaskDicts is actually kept as a singleton of a helper class, DictState
42  */
43 
44 #include <functional>
45 #include <list>
46 #include <string>
47 
48 #pragma clang diagnostic push
49 #pragma clang diagnostic ignored "-Wunused-variable"
50 #pragma clang diagnostic pop
51 #include "boost/format.hpp"
52 #include "boost/filesystem/path.hpp"
53 
54 #include "boost/functional/hash.hpp"
55 
56 #include "lsst/daf/base.h"
57 #include "lsst/daf/base/Citizen.h"
58 #include "lsst/pex/exceptions.h"
59 #include "lsst/log/Log.h"
60 #include "lsst/afw/image/Wcs.h"
61 #include "lsst/afw/image/Mask.h"
62 
64 
65 /************************************************************************************************************/
66 //
67 // for FITS code
68 //
69 #include "boost/mpl/vector.hpp"
70 #include "boost/gil/gil_all.hpp"
73 
74 namespace afwGeom = lsst::afw::geom;
75 namespace dafBase = lsst::daf::base;
76 namespace pexExcept = lsst::pex::exceptions;
77 
78 /************************************************************************************************************/
79 
80 namespace lsst { namespace afw { namespace image {
81  namespace detail {
82  class MaskDict;
83  }
84 
85 namespace {
86  void setInitMaskBits(PTR(detail::MaskDict) dict);
87  /*
88  * A std::map that maintains a hash value of its contents
89  *
90  * We don't simply inherit from the std::map as we need to force the user to use add and remove;
91  * we could inherit, make operator[] private, and never use MapWithHash via a base-class pointer
92  * but it seemed simpler to only forward the functions we wish to support
93  */
94  struct MapWithHash {
95  typedef detail::MaskPlaneDict::value_type value_type;
96  typedef detail::MaskPlaneDict::const_iterator const_iterator;
97 
98  MapWithHash(detail::MaskPlaneDict const& dict=detail::MaskPlaneDict()) :
99  _dict(dict), _hash(_calcHash()) {
100  }
101  ~MapWithHash() { }
102 
103  bool operator==(MapWithHash const& rhs) const {
104  return _hash == rhs._hash;
105  }
106 
107  const_iterator begin() const { return _dict.begin(); }
108  const_iterator end() const { return _dict.end(); }
109  const_iterator find(detail::MaskPlaneDict::key_type const& name) const { return _dict.find(name); }
110 
111  void add(std::string const& str, int val) {
112  _dict[str] = val;
113  _calcHash();
114  }
115 
116  bool empty() const {
117  return _dict.empty();
118  }
119 
120  void clear() {
121  _dict.clear();
122  }
123 
124  std::size_t size() const {
125  return _dict.size();
126  }
127 
128  void erase(std::string const& str) {
129  if (_dict.find(str) != _dict.end()) {
130  _dict.erase(str);
131  _calcHash();
132  }
133  }
134 
135  detail::MaskPlaneDict const& getMaskPlaneDict() const {
136  return _dict;
137  }
138 
139  std::size_t getHash() const {
140  return _hash;
141  }
142  private:
144  std::size_t _hash;
145 
146  // calculate the hash
147  std::size_t _calcHash() {
148  _hash = 0x0;
149  for (const_iterator ptr = begin(); ptr != end(); ++ptr) {
150  _hash = (_hash << 1) ^
151  boost::hash<std::string>()((*ptr).first + str(boost::format("%d") % ptr->second));
152  }
153 
154  return _hash;
155  }
156  };
157 
158  bool operator!=(MapWithHash const& lhs, MapWithHash const& rhs) {
159  return !(lhs == rhs);
160  }
161 
162  class DictState; // forward declaration
163 }
164 
165 namespace detail {
166 /*
167  * A MaskDict is a MapWithHash, but additionally maintains a list of all live MaskDicts (the list is
168  * actually kept in a singleton instance of DictState)
169  */
170 class MaskDict : public MapWithHash {
171  friend class ::lsst::afw::image::DictState; // actually anonymous within lsst::afw::image; g++ is confused
172 
173  MaskDict() : MapWithHash() {}
174  MaskDict(MapWithHash const* dict) : MapWithHash(*dict) {}
175 public:
176  static PTR(MaskDict) makeMaskDict();
177  static PTR(MaskDict) makeMaskDict(detail::MaskPlaneDict const &dict);
178  static PTR(MaskDict) setDefaultDict(PTR(MaskDict) dict);
179 
180  PTR(MaskDict) clone() const;
181 
182  ~MaskDict();
183 
184  int getUnusedPlane() const;
185  int getMaskPlane(const std::string& name) const;
186 
187  void print() const {
188  for (MapWithHash::const_iterator ptr = begin(); ptr != end(); ++ptr) {
189  std::cout << "Plane " << ptr->second << " -> " << ptr->first << std::endl;
190  }
191  }
192 
193  static PTR(MaskDict) incrDefaultVersion();
194  static void listMaskDicts();
195 };
196 }
197 
198 /************************************************************************************************************/
199 
200 namespace {
201  /*
202  * A struct to hold our global state, and for whose components
203  * we can control the order of creation/destruction
204  */
205  class DictState {
206  friend class detail::MaskDict;
207 
208  typedef std::map<MapWithHash *, int> HandleList;
209 
210  public:
211  DictState() {
212  _dictCounter = 0;
215  }
216 
217  ~DictState() {
218  _defaultMaskDict.reset();
219 
220  for (HandleList::iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
221  delete ptr->first;
222  }
223  _dicts.clear();
224  }
225 
226  template<typename FunctorT>
227  void forEachMaskDict(FunctorT func) {
228  for (HandleList::const_iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
229  func(ptr->first);
230  }
231  }
232 
233  private:
234  PTR(detail::MaskDict) getDefaultDict() {
235  static bool first = true;
236 
237  if (first) {
238  setInitMaskBits(_defaultMaskDict);
239 
240  first = false;
241  }
242 
243  return _defaultMaskDict;
244  }
245 
246  PTR(detail::MaskDict) setDefaultDict(PTR(detail::MaskDict) newDefaultMaskDict) {
247  _defaultMaskDict = newDefaultMaskDict;
248 
249  return _defaultMaskDict;
250  }
251 
252  void addDict(MapWithHash *dict) {
253  _dicts[dict] = _dictCounter++;
254  }
255 
256  void eraseDict(MapWithHash *dict) {
257  _dicts.erase(dict);
258  }
259 
260  PTR(detail::MaskDict) incrDefaultVersion() {
261  _defaultMaskDict = PTR(detail::MaskDict)(new detail::MaskDict(*_defaultMaskDict.get()));
262  addDict(_defaultMaskDict.get());
263 
264  return _defaultMaskDict;
265  }
266 
267  PTR(detail::MaskDict) _defaultMaskDict; // default MaskDict to use
268  HandleList _dicts; // all the live MaskDicts
270  };
271 
272  static DictState _state;
273 }
274 
275 /************************************************************************************************************/
276 namespace detail {
277 /*
278  * Implementation of MaskDict
279  */
280 /*
281  * Return the default dictionary, unless you provide mpd in which case you get one of
282  * your very very own
283  */
284 PTR(MaskDict)
286 {
287  return _state.getDefaultDict();
288 }
289 
290 PTR(MaskDict)
291 MaskDict::makeMaskDict(detail::MaskPlaneDict const& mpd)
292 {
293  PTR(MaskDict) dict = _state.getDefaultDict();
294 
295  if (!mpd.empty()) {
296  MapWithHash mwh(mpd);
297  dict = PTR(MaskDict)(new MaskDict(&mwh));
298  _state.addDict(dict.get());
299  }
300 
301  return dict;
302 }
303 
304 PTR(MaskDict)
306 {
307  return _state.setDefaultDict(dict);
308 }
309 
311  PTR(MaskDict) dict(new MaskDict(*this));
312 
313  _state.addDict(dict.get());
314 
315  return dict;
316 }
317 
319  _state.eraseDict(this);
320 }
321 
322 PTR(MaskDict) MaskDict::incrDefaultVersion() {
323  return _state.incrDefaultVersion();
324 }
325 
326 int
328 {
329  if (empty()) {
330  return 0;
331  }
332 
333  MapWithHash::const_iterator const it =
334  std::max_element(begin(), end(), std::bind(std::less<int>(),
335  std::bind(&MapWithHash::value_type::second,
336  std::placeholders::_1),
337  std::bind(&MapWithHash::value_type::second,
338  std::placeholders::_2)
339  )
340  );
341  assert(it != end());
342  int id = it->second + 1; // The maskPlane to use if there are no gaps
343 
344  for (int i = 0; i < id; ++i) {
345  MapWithHash::const_iterator const it = // is i already used in this Mask?
346  std::find_if(begin(), end(), std::bind(std::equal_to<int>(),
347  std::bind(&MapWithHash::value_type::second,
348  std::placeholders::_1), i));
349  if (it == end()) { // Not used; so we'll use it
350  return i;
351  }
352  }
353 
354  return id;
355 }
356 
357 int
358 detail::MaskDict::getMaskPlane(const std::string& name) const
359 {
360  MapWithHash::const_iterator i = find(name);
361 
362  return (i == end()) ? -1 : i->second;
363 }
364 }
365 
366 namespace {
367  /*
368  * Definition of the default mask bits
369  *
370  * N.b. this function is in an anonymous namespace, and is invisible to doxygen. ALL mask
371  * planes defined here should be documented with the Mask class in Mask.h
372  */
373  void
374  setInitMaskBits(PTR(detail::MaskDict) dict)
375  {
376  int i = -1;
377  dict->add("BAD", ++i);
378  dict->add("SAT", ++i); // should be SATURATED
379  dict->add("INTRP", ++i); // should be INTERPOLATED
380  dict->add("CR", ++i); //
381  dict->add("EDGE", ++i); //
382  dict->add("DETECTED", ++i); //
383  dict->add("DETECTED_NEGATIVE", ++i);
384  dict->add("SUSPECT", ++i);
385  dict->add("NO_DATA", ++i);
386  }
387 }
388 
392 template<typename MaskPixelT>
394  LOGL_DEBUG("afw.image.Mask", "Number of mask planes: %d", getNumPlanesMax());
395 
396  _maskDict = detail::MaskDict::makeMaskDict(planeDefs);
397 }
398 
402 template<typename MaskPixelT>
404  unsigned int width,
405  unsigned int height,
406  MaskPlaneDict const& planeDefs
407 ) :
408  ImageBase<MaskPixelT>(afwGeom::ExtentI(width, height)) {
409  _initializePlanes(planeDefs);
410  *this = 0x0;
411 }
412 
416 template<typename MaskPixelT>
418  unsigned int width,
419  unsigned int height,
420  MaskPixelT initialValue,
421  MaskPlaneDict const& planeDefs
422 ) :
423  ImageBase<MaskPixelT>(afwGeom::ExtentI(width, height)) {
424  _initializePlanes(planeDefs);
425  *this = initialValue;
426 }
427 
431 template<typename MaskPixelT>
433  afwGeom::Extent2I const & dimensions,
434  MaskPlaneDict const& planeDefs
435 ) :
436  ImageBase<MaskPixelT>(dimensions) {
437  _initializePlanes(planeDefs);
438  *this = 0x0;
439 }
440 
444 template<typename MaskPixelT>
446  afwGeom::Extent2I const & dimensions,
447  MaskPixelT initialValue,
448  MaskPlaneDict const& planeDefs
449 ) :
450  ImageBase<MaskPixelT>(dimensions) {
451  _initializePlanes(planeDefs);
452  *this = initialValue;
453 }
454 
458 template<typename MaskPixelT>
460  afwGeom::Box2I const & bbox,
461  MaskPlaneDict const& planeDefs
462 ) :
463  ImageBase<MaskPixelT>(bbox) {
464  _initializePlanes(planeDefs);
465  *this = 0x0;
466 }
467 
471 template<typename MaskPixelT>
473  afwGeom::Box2I const & bbox,
474  MaskPixelT initialValue,
475  MaskPlaneDict const& planeDefs
476 ) :
477  ImageBase<MaskPixelT>(bbox) {
478  _initializePlanes(planeDefs);
479  *this = initialValue;
480 }
481 
485 template<typename MaskPixelT>
487  Mask const &rhs,
488  afwGeom::Box2I const &bbox,
489  ImageOrigin const origin,
490  bool const deep
491 ) :
492  ImageBase<MaskPixelT>(rhs, bbox, origin, deep), _maskDict(rhs._maskDict) {
493 }
494 
498 template<typename MaskPixelT>
500  Mask const& rhs,
501  bool deep
502 ) :
503  ImageBase<MaskPixelT>(rhs, deep), _maskDict(rhs._maskDict) {
504 }
505 
506 template<typename MaskPixelT>
507 Mask<MaskPixelT>::Mask(ndarray::Array<MaskPixelT,2,1> const & array, bool deep,
508  geom::Point2I const & xy0) :
509  image::ImageBase<MaskPixelT>(array, deep, xy0),
510  _maskDict(detail::MaskDict::makeMaskDict()) {
511 }
512 
513 /************************************************************************************************************/
514 
515 template<typename PixelT>
517  using std::swap; // See Meyers, Effective C++, Item 25
518 
520  swap(_maskDict, rhs._maskDict);
521 }
522 
523 template<typename PixelT>
525  a.swap(b);
526 }
527 
528 template<typename MaskPixelT>
530  Mask tmp(rhs);
531  swap(tmp); // See Meyers, Effective C++, Item 11
532 
533  return *this;
534 }
535 
536 template<typename MaskPixelT>
538  fill_pixels(_getRawView(), rhs);
539 
540  return *this;
541 }
542 
543 #ifndef DOXYGEN // doc for this section is already in header
544 
545 template<typename MaskPixelT>
547  std::string const & fileName,
548  int hdu,
549  PTR(daf::base::PropertySet) metadata,
550  afw::geom::Box2I const & bbox,
551  ImageOrigin origin,
552  bool conformMasks
553 ) : ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict()) {
554  fits::Fits fitsfile(fileName, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
555  fitsfile.setHdu(hdu);
556  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
557 }
558 
559 template<typename MaskPixelT>
561  fits::MemFileManager & manager,
562  int hdu,
563  PTR(daf::base::PropertySet) metadata,
564  afw::geom::Box2I const & bbox,
565  ImageOrigin origin,
566  bool conformMasks
567 ) : ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict()) {
568 
569  fits::Fits fitsfile(manager, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
570  fitsfile.setHdu(hdu);
571  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
572 }
573 
574 template<typename MaskPixelT>
576  fits::Fits & fitsfile,
577  PTR(daf::base::PropertySet) metadata,
578  afw::geom::Box2I const & bbox,
579  ImageOrigin const origin,
580  bool const conformMasks
581 ) :
582  ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict())
583 {
584  // These are the permitted input file types
585  typedef boost::mpl::vector<
586  unsigned char,
587  unsigned short,
588  short
589  >fits_mask_types;
590 
591  if (!metadata) {
593  }
594 
595  fits_read_image<fits_mask_types>(fitsfile, *this, *metadata, bbox, origin);
596 
597  // look for mask planes in the file
598  MaskPlaneDict fileMaskDict = parseMaskPlaneMetadata(metadata);
599  PTR(detail::MaskDict) fileMD = detail::MaskDict::makeMaskDict(fileMaskDict);
600 
601  if (*fileMD == *detail::MaskDict::makeMaskDict()) { // file is already consistent with Mask
602  return;
603  }
604 
605  if (conformMasks) { // adopt the definitions in the file
607  }
608 
609  conformMaskPlanes(fileMaskDict); // convert planes defined by fileMaskDict to the order
610  // defined by Mask::_maskPlaneDict
611 }
612 
613 template<typename MaskPixelT>
615  std::string const & fileName,
617  std::string const & mode
618 ) const {
619  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
620  writeFits(fitsfile, metadata_i);
621 }
622 
623 template<typename MaskPixelT>
625  fits::MemFileManager & manager,
627  std::string const & mode
628 ) const {
629  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
630  writeFits(fitsfile, metadata_i);
631 }
632 
633 template<typename MaskPixelT>
635  fits::Fits & fitsfile,
637 ) const {
638 
639  PTR(dafBase::PropertySet) metadata;
640  if (metadata_i) {
641  metadata = metadata_i->deepCopy();
642  } else {
644  }
645  addMaskPlanesToMetadata(metadata);
646  //
647  // Add WCS with (X0, Y0) information
648  //
650  detail::wcsNameForXY0, this->getX0(), this->getY0()
651  );
652  metadata->combine(wcsAMetadata);
653 
654  fits_write_image(fitsfile, *this, metadata);
655 }
656 
657 #endif // !DOXYGEN
658 
659 namespace {
660  struct addPlaneFunctor {
661  addPlaneFunctor(std::string const& name, int id) : _name(name), _id(id) {}
662 
663  void operator()(MapWithHash *dict) {
664  detail::MaskPlaneDict::const_iterator const it = // is id already used in this Mask?
665  std::find_if(dict->begin(), dict->end(),
666  std::bind(std::equal_to<int>(),
667  std::bind(&detail::MaskPlaneDict::value_type::second,
668  std::placeholders::_1), _id));
669  if (it != dict->end()) { // mask plane is already in use
670  return;
671  }
672 
673  if (dict->find(_name) == dict->end()) { // not already set
674  dict->add(_name, _id);
675  }
676  }
677 
678  std::string const& _name;
679  int _id;
680  };
681 }
682 
683 template<typename MaskPixelT>
684 std::string Mask<MaskPixelT>::interpret(MaskPixelT value)
685 {
686  std::string result = "";
687  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
688  for (MaskPlaneDict::const_iterator iter = mpd.begin(); iter != mpd.end(); ++iter) {
689  if (value & getBitMask(iter->second)) {
690  if (result.size() > 0) {
691  result += ",";
692  }
693  result += iter->first;
694  }
695  }
696  return result;
697 }
698 
699 template<typename MaskPixelT>
700 int Mask<MaskPixelT>::addMaskPlane(const std::string& name)
701 {
702  int id = getMaskPlaneNoThrow(name); // see if the plane is already available
703 
704  if (id < 0) { // doesn't exist
705  id = _maskPlaneDict()->getUnusedPlane();
706  }
707 
708  // build new entry, adding the plane to all Masks where this is no contradiction
709 
710  if (id >= getNumPlanesMax()) { // Max number of planes is already allocated
711  throw LSST_EXCEPT(pexExcept::RuntimeError,
712  str(boost::format("Max number of planes (%1%) already used") % getNumPlanesMax()));
713  }
714 
715  _state.forEachMaskDict(addPlaneFunctor(name, id));
716 
717  return id;
718 }
719 
725 template<typename MaskPixelT>
727  std::string name,
728  int planeId
729 ) {
730  if (planeId < 0 || planeId >= getNumPlanesMax()) {
731  throw LSST_EXCEPT(pexExcept::RangeError,
732  str(boost::format("mask plane ID must be between 0 and %1%") % (getNumPlanesMax() - 1)));
733  }
734 
735  _maskPlaneDict()->add(name, planeId);
736 
737  return planeId;
738 }
739 
743 template<typename MaskPixelT>
746 {
747  return _maskDict->getMaskPlaneDict();
748 }
749 
750 template<typename MaskPixelT>
751 void Mask<MaskPixelT>::removeMaskPlane(const std::string& name)
752 {
753  if (detail::MaskDict::makeMaskDict()->getMaskPlane(name) < 0) {
754  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
755  str(boost::format("Plane %s doesn't exist in the default Mask") % name));
756  }
757 
758  detail::MaskDict::incrDefaultVersion(); // leave current Masks alone
759  _maskPlaneDict()->erase(name);
760 }
761 
768 template<typename MaskPixelT>
769 void Mask<MaskPixelT>::removeAndClearMaskPlane(const std::string& name,
770  bool const removeFromDefault
771  )
773 {
774  clearMaskPlane(getMaskPlane(name)); // clear this bits in this Mask
775 
776  if (_maskDict == detail::MaskDict::makeMaskDict() && removeFromDefault) { // we are the default
777  ;
778  } else {
779  _maskDict = _maskDict->clone();
780  }
781 
782  _maskDict->erase(name);
783 
784  if (removeFromDefault && detail::MaskDict::makeMaskDict()->getMaskPlane(name) >= 0) {
785  removeMaskPlane(name);
786  }
787 }
788 
792 template<typename MaskPixelT>
793 MaskPixelT Mask<MaskPixelT>::getBitMaskNoThrow(int planeId) {
794  return (planeId >= 0 && planeId < getNumPlanesMax()) ? (1 << planeId) : 0;
795 }
796 
802 template<typename MaskPixelT>
803 MaskPixelT Mask<MaskPixelT>::getBitMask(int planeId) {
804  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
805 
806  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end(); ++i) {
807  if (planeId == i->second) {
808  MaskPixelT const bitmask = getBitMaskNoThrow(planeId);
809  if (bitmask == 0) { // failed
810  break;
811  }
812  return bitmask;
813  }
814  }
815  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
816  str(boost::format("Invalid mask plane ID: %d") % planeId));
817 }
818 
824 template<typename MaskPixelT>
825 int Mask<MaskPixelT>::getMaskPlane(const std::string& name) {
826  int const plane = getMaskPlaneNoThrow(name);
827 
828  if (plane < 0) {
829  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
830  str(boost::format("Invalid mask plane name: %s") % name));
831  } else {
832  return plane;
833  }
834 }
835 
839 template<typename MaskPixelT>
840 int Mask<MaskPixelT>::getMaskPlaneNoThrow(const std::string& name) {
841  return _maskPlaneDict()->getMaskPlane(name);
842 }
843 
849 template<typename MaskPixelT>
850 MaskPixelT Mask<MaskPixelT>::getPlaneBitMask(const std::string& name) {
851  return getBitMask(getMaskPlane(name));
852 }
853 
859 template<typename MaskPixelT>
860 MaskPixelT Mask<MaskPixelT>::getPlaneBitMask(const std::vector<std::string> &name) {
861  MaskPixelT mpix = 0x0;
862  for (std::vector<std::string>::const_iterator it = name.begin(); it != name.end(); ++it) {
863  mpix |= getBitMask(getMaskPlane(*it));
864  }
865  return mpix;
866 }
867 
871 template<typename MaskPixelT>
873 {
874  return _maskPlaneDict()->size();
875 }
876 
880 template<typename MaskPixelT>
882  _maskPlaneDict()->clear();
883 }
884 
888 template<typename MaskPixelT>
890  *this = 0;
891 }
892 
896 template<typename MaskPixelT>
898  *this &= ~getBitMask(planeId);
899 }
900 
912 template<typename MaskPixelT>
914  MaskPlaneDict const &currentPlaneDict
915  )
916 {
917  PTR(detail::MaskDict) currentMD = detail::MaskDict::makeMaskDict(currentPlaneDict);
918 
919  if (*_maskDict == *currentMD) {
920  if (*detail::MaskDict::makeMaskDict() == *_maskDict) {
921  return; // nothing to do
922  }
923  } else {
924  //
925  // Find out which planes need to be permuted
926  //
927  MaskPixelT keepBitmask = 0; // mask of bits to keep
928  MaskPixelT canonicalMask[sizeof(MaskPixelT)*8]; // bits in lsst::afw::image::Mask that should be
929  MaskPixelT currentMask[sizeof(MaskPixelT)*8]; // mapped to these bits
930  int numReMap = 0;
931 
932  for (MaskPlaneDict::const_iterator i = currentPlaneDict.begin(); i != currentPlaneDict.end() ; i++) {
933  std::string const name = i->first; // name of mask plane
934  int const currentPlaneNumber = i->second; // plane number currently in use
935  int canonicalPlaneNumber = getMaskPlaneNoThrow(name); // plane number in lsst::afw::image::Mask
936 
937  if (canonicalPlaneNumber < 0) { // no such plane; add it
938  canonicalPlaneNumber = addMaskPlane(name);
939  }
940 
941  if (canonicalPlaneNumber == currentPlaneNumber) {
942  keepBitmask |= getBitMask(canonicalPlaneNumber); // bit is unchanged, so preserve it
943  } else {
944  canonicalMask[numReMap] = getBitMask(canonicalPlaneNumber);
945  currentMask[numReMap] = getBitMaskNoThrow(currentPlaneNumber);
946  numReMap++;
947  }
948  }
949 
950  // Now loop over all pixels in Mask
951  if (numReMap > 0) {
952  for (int r = 0; r != this->getHeight(); ++r) { // "this->": Meyers, Effective C++, Item 43
953  for (typename Mask::x_iterator ptr = this->row_begin(r), end = this->row_end(r);
954  ptr != end; ++ptr) {
955  MaskPixelT const pixel = *ptr;
956 
957  MaskPixelT newPixel = pixel & keepBitmask; // value of invariant mask bits
958  for (int i = 0; i < numReMap; i++) {
959  if (pixel & currentMask[i]) newPixel |= canonicalMask[i];
960  }
961 
962  *ptr = newPixel;
963  }
964  }
965  }
966  }
967  // We've made the planes match the current mask dictionary
968  _maskDict = detail::MaskDict::makeMaskDict();
969 }
970 
971 /************************************************************************************************************/
972 
976 template<typename MaskPixelT>
978  int x,
979  int y
980 ) {
981  return this->ImageBase<MaskPixelT>::operator()(x, y);
982 }
983 
987 template<typename MaskPixelT>
989  int x,
990  int y,
991  CheckIndices const& check
992 ) {
993  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
994 }
995 
999 template<typename MaskPixelT>
1001  int x,
1002  int y
1003 ) const {
1004  return this->ImageBase<MaskPixelT>::operator()(x, y);
1005 }
1006 
1010 template<typename MaskPixelT>
1012  int x,
1013  int y,
1014  CheckIndices const& check
1015 ) const {
1016  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
1017 }
1018 
1022 template<typename MaskPixelT>
1024  int x,
1025  int y,
1026  int planeId
1027 ) const {
1028  // !! converts an int to a bool
1029  return !!(this->ImageBase<MaskPixelT>::operator()(x, y) & getBitMask(planeId));
1030 }
1031 
1035 template<typename MaskPixelT>
1037  int x,
1038  int y,
1039  int planeId,
1040  CheckIndices const& check
1041 ) const {
1042  // !! converts an int to a bool
1043  return !!(this->ImageBase<MaskPixelT>::operator()(x, y, check) & getBitMask(planeId));
1044 }
1045 
1046 /************************************************************************************************************/
1047 //
1048 // Check that masks have the same dictionary version
1049 //
1050 // @throw lsst::pex::exceptions::RuntimeError
1051 //
1052 template<typename MaskPixelT>
1054  if (*_maskDict != *other._maskDict) {
1055  throw LSST_EXCEPT(pexExcept::RuntimeError, "Mask dictionaries do not match");
1056  }
1057 }
1058 
1062 template<typename MaskPixelT>
1063 void Mask<MaskPixelT>::operator|=(MaskPixelT const val) {
1064  transform_pixels(_getRawView(), _getRawView(),
1065  [&val](MaskPixelT const& l) -> MaskPixelT { return l | val; });
1066 }
1067 
1071 template<typename MaskPixelT>
1073  checkMaskDictionaries(rhs);
1074 
1075  if (this->getDimensions() != rhs.getDimensions()) {
1076  throw LSST_EXCEPT(pexExcept::LengthError,
1077  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1078  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1079  }
1080  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
1081  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l | r; });
1082 }
1083 
1087 template<typename MaskPixelT>
1088 void Mask<MaskPixelT>::operator&=(MaskPixelT const val) {
1089  transform_pixels(_getRawView(), _getRawView(),
1090  [&val](MaskPixelT const& l) { return l & val; });
1091 }
1092 
1096 template<typename MaskPixelT>
1098  checkMaskDictionaries(rhs);
1099 
1100  if (this->getDimensions() != rhs.getDimensions()) {
1101  throw LSST_EXCEPT(pexExcept::LengthError,
1102  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1103  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1104  }
1105  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
1106  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l & r; });
1107 }
1108 
1112 template<typename MaskPixelT>
1113 void Mask<MaskPixelT>::operator^=(MaskPixelT const val) {
1114  transform_pixels(_getRawView(), _getRawView(),
1115  [&val](MaskPixelT const& l) -> MaskPixelT { return l ^ val; });
1116 }
1117 
1121 template<typename MaskPixelT>
1123  checkMaskDictionaries(rhs);
1124 
1125  if (this->getDimensions() != rhs.getDimensions()) {
1126  throw LSST_EXCEPT(pexExcept::LengthError,
1127  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1128  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1129  }
1130  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
1131  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l ^ r; });
1132 }
1133 
1137 template<typename MaskPixelT>
1139  int const x0, int const x1, int const y) {
1140  MaskPixelT const bitMask = getBitMask(planeId);
1141 
1142  for (int x = x0; x <= x1; x++) {
1143  operator()(x, y) = operator()(x, y) | bitMask;
1144  }
1145 }
1146 
1150 template<typename MaskPixelT>
1152  if (!metadata) {
1153  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "Null PTR(PropertySet)");
1154  }
1155 
1156  // First, clear existing MaskPlane metadata
1157  typedef std::vector<std::string> NameList;
1158  NameList paramNames = metadata->paramNames(false);
1159  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1160  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1161  metadata->remove(*i);
1162  }
1163  }
1164 
1165  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
1166 
1167  // Add new MaskPlane metadata
1168  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end() ; ++i) {
1169  std::string const& planeName = i->first;
1170  int const planeNumber = i->second;
1171 
1172  if (planeName != "") {
1173  metadata->add(maskPlanePrefix + planeName, planeNumber);
1174  }
1175  }
1176 }
1177 
1183 template<typename MaskPixelT>
1185  CONST_PTR(dafBase::PropertySet) metadata
1186 ) {
1187  MaskPlaneDict newDict;
1188 
1189  // First, clear existing MaskPlane metadata
1190  typedef std::vector<std::string> NameList;
1191  NameList paramNames = metadata->paramNames(false);
1192  int numPlanesUsed = 0; // number of planes used
1193 
1194  // Iterate over childless properties with names starting with maskPlanePrefix
1195  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1196  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1197  // split off maskPlanePrefix to obtain plane name
1198  std::string planeName = i->substr(maskPlanePrefix.size());
1199  int const planeId = metadata->getAsInt(*i);
1200 
1201  MaskPlaneDict::const_iterator plane = newDict.find(planeName);
1202  if (plane != newDict.end() && planeId != plane->second) {
1203  throw LSST_EXCEPT(pexExcept::RuntimeError,
1204  "File specifies plane " + planeName + " twice");
1205  }
1206  for (MaskPlaneDict::const_iterator j = newDict.begin(); j != newDict.end(); ++j) {
1207  if (planeId == j->second) {
1208  throw LSST_EXCEPT(pexExcept::RuntimeError,
1209  str(boost::format("File specifies plane %s has same value (%d) as %s") %
1210  planeName % planeId % j->first));
1211  }
1212  }
1213  // build new entry
1214  if (numPlanesUsed >= getNumPlanesMax()) {
1215  // Max number of planes already allocated
1216  throw LSST_EXCEPT(pexExcept::RuntimeError,
1217  str(boost::format("Max number of planes (%1%) already used") %
1218  getNumPlanesMax()));
1219  }
1220  newDict[planeName] = planeId;
1221  }
1222  }
1223  return newDict;
1224 }
1225 
1229 template<typename MaskPixelT>
1231 {
1232  _maskDict->print();
1233 }
1234 
1235 /*
1236  * Static members of Mask
1237  */
1238 template<typename MaskPixelT>
1239 std::string const Mask<MaskPixelT>::maskPlanePrefix("MP_");
1240 
1241 template<typename MaskPixelT>
1242 PTR(detail::MaskDict) Mask<MaskPixelT>::_maskPlaneDict()
1243 {
1245 }
1246 
1247 //
1248 // Explicit instantiations
1249 //
1250 template class Mask<MaskPixel>;
1251 }}}
int y
int iter
std::vector< std::string > paramNames(bool topLevelOnly=true) const
Definition: PropertySet.cc:142
int _dictCounter
Definition: Mask.cc:269
static std::string interpret(MaskPixelT value)
Interpret a mask value as a comma-separated list of mask plane names.
Definition: Mask.cc:684
void _initializePlanes(MaskPlaneDict const &planeDefs)
Initialise mask planes; called by constructors.
Definition: Mask.cc:393
static void clearMaskPlaneDict()
Reset the maskPlane dictionary.
Definition: Mask.cc:881
table::Key< std::string > name
Definition: ApCorrMap.cc:71
HandleList _dicts
Definition: Mask.cc:268
static MaskPixelT getBitMaskNoThrow(int plane)
Return the bitmask corresponding to a plane ID, or 0 if invalid.
Definition: Mask.cc:793
#define LOGL_DEBUG(logger, message...)
Definition: Log.h:513
void writeFits(std::string const &fileName, boost::shared_ptr< lsst::daf::base::PropertySet const > metadata=boost::shared_ptr< lsst::daf::base::PropertySet >(), std::string const &mode="w") const
Write a mask to a regular FITS file.
static int getMaskPlane(const std::string &name)
Return the mask plane number corresponding to a plane name.
Definition: Mask.cc:825
virtual void remove(std::string const &name)
Definition: PropertySet.cc:754
std::string const & _name
Definition: Mask.cc:678
bool operator!=(lsst::afw::coord::Coord const &lhs, lsst::afw::coord::Coord const &rhs)
Inequality; the complement of equality.
Definition: Coord.h:492
void operator|=(Mask const &rhs)
OR a Mask into a Mask.
Definition: Mask.cc:1072
void operator&=(Mask const &rhs)
AND a Mask into a Mask.
Definition: Mask.cc:1097
std::map< std::string, int > MaskPlaneDict
Definition: Mask.h:64
Mask & operator=(MaskPixelT const rhs)
Definition: Mask.cc:537
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: Image.h:151
boost::shared_ptr< MaskDict > clone() const
Definition: Mask.cc:310
detail::MaskPlaneDict _dict
Definition: Mask.cc:143
boost::shared_ptr< lsst::daf::base::PropertyList > createTrivialWcsAsPropertySet(std::string const &wcsName, int const x0, int const y0)
Definition: Wcs.cc:1190
detail::MaskPlaneDict MaskPlaneDict
Definition: Mask.h:96
bool operator==(CoordKey const &lhs, CoordKey const &rhs)
Compare CoordKeys for equality using the constituent Keys.
static boost::shared_ptr< MaskDict > setDefaultDict(boost::shared_ptr< MaskDict > dict)
Definition: Mask.cc:305
static int getNumPlanesUsed()
Reset the maskPlane dictionary.
Definition: Mask.cc:872
void swap(Mask< PixelT > &a, Mask< PixelT > &b)
Definition: Mask.cc:524
lsst::daf::base::PropertyList PropertyList
Definition: Wcs.cc:60
#define CONST_PTR(...)
Definition: base.h:47
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:201
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: Image.h:115
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...
Definition: Mask.cc:769
static int getMaskPlaneNoThrow(const std::string &name)
Return the mask plane number corresponding to a plane name, or -1 if not found.
Definition: Mask.cc:840
static const std::string maskPlanePrefix
Definition: Mask.h:345
int const x0
Definition: saturated.cc:45
ImageBase< MaskPixelT >::PixelReference operator()(int x, int y)
get a reference to the specified pixel
Definition: Mask.cc:977
bool val
An integer coordinate rectangle.
Definition: Box.h:53
void operator^=(Mask const &rhs)
XOR a Mask into a Mask.
Definition: Mask.cc:1122
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
static boost::shared_ptr< MaskDict > incrDefaultVersion()
Definition: Mask.cc:322
Mask(unsigned int width, unsigned int height, MaskPlaneDict const &planeDefs=MaskPlaneDict())
Construct a Mask initialized to 0x0.
Definition: Mask.cc:403
int getAsInt(std::string const &name) const
Definition: PropertySet.cc:333
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:42
std::size_t _hash
Definition: Mask.cc:144
static MaskPixelT getBitMask(int plane)
Return the bitmask corresponding to plane ID.
Definition: Mask.cc:803
geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: Image.h:300
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:92
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:105
int _id
Definition: Mask.cc:679
_view_t _getRawView() const
Definition: Image.h:403
void setMaskPlaneValues(const int plane, const int x0, const int x1, const int y)
Set the bit specified by &quot;planeId&quot; for pixels (x0, y) ... (x1, y)
Definition: Mask.cc:1138
static MaskPlaneDict parseMaskPlaneMetadata(boost::shared_ptr< lsst::daf::base::PropertySet const >)
Given a PropertySet that contains the MaskPlane assignments, setup the MaskPlanes.
Definition: Mask.cc:1184
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Definition: saturated.cc:47
A class used to request that array accesses be checked.
Definition: Image.h:87
int getHeight() const
Return the number of rows in the image.
Definition: Image.h:241
static MaskPixelT getPlaneBitMask(const std::vector< std::string > &names)
Return the bitmask corresponding to a vector of plane names OR&#39;d together.
Definition: Mask.cc:860
double x
void swap(ImageBase &rhs)
Definition: Image.cc:306
MaskDict(MapWithHash const *dict)
Definition: Mask.cc:174
Extent< int, 2 > ExtentI
Definition: Extent.h:355
LSST bitmasks.
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
static void removeMaskPlane(const std::string &name)
Definition: Mask.cc:751
static void addMaskPlanesToMetadata(boost::shared_ptr< lsst::daf::base::PropertySet >)
Given a PropertySet, replace any existing MaskPlane assignments with the current ones.
Definition: Mask.cc:1151
void checkMaskDictionaries(Mask const &other)
Definition: Mask.cc:1053
MaskPlaneDict const & getMaskPlaneDict() const
Definition: Mask.cc:745
Class for storing generic metadata.
Definition: PropertySet.h:82
virtual Ptr deepCopy(void) const
Definition: PropertySet.cc:70
#define PTR(...)
Definition: base.h:41
int id
Definition: CR.cc:157
static boost::shared_ptr< MaskDict > makeMaskDict()
Definition: Mask.cc:285
boost::shared_ptr< detail::MaskDict > _defaultMaskDict
Definition: Mask.cc:267
afw::table::Key< double > b
table::PointKey< int > pixel
void swap(Mask &rhs)
Definition: Mask.cc:516
void conformMaskPlanes(const MaskPlaneDict &masterPlaneDict)
Adjust this mask to conform to the standard Mask class&#39;s mask plane dictionary, adding any new mask p...
Definition: Mask.cc:913
Include files required for standard LSST Exception handling.
void add(std::string const &name, T const &value)
Definition: PropertySet.cc:619
boost::shared_ptr< detail::MaskDict > _maskDict
Definition: Mask.h:341
void clearMaskPlane(int plane)
Clear the specified bit in all pixels.
Definition: Mask.cc:897
void printMaskPlanes() const
print the mask plane dictionary to std::cout
Definition: Mask.cc:1230
int getWidth() const
Return the number of columns in the image.
Definition: Image.h:239
Definition of default types for Masks and Variance Images.
void clearAllMaskPlanes()
Clear all the pixels.
Definition: Mask.cc:889
static int addMaskPlane(const std::string &name)
Definition: Mask.cc:700
void fits_write_image(fits::Fits &fitsfile, const ImageT &image, boost::shared_ptr< daf::base::PropertySet const > metadata=boost::shared_ptr< daf::base::PropertySet const >())
Definition: fits_io.h:104
std::string const wcsNameForXY0
Definition: Image.h:82
PixelReference operator()(int x, int y)
Return a reference to the pixel (x, y)
Definition: Image.cc:260
int getMaskPlane(const std::string &name) const
Definition: Mask.cc:358