LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
Mask.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
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 #include "boost/lambda/lambda.hpp"
51 #pragma clang diagnostic pop
52 #include "boost/format.hpp"
53 #include "boost/filesystem/path.hpp"
54 
55 #include "boost/functional/hash.hpp"
56 
57 #include "boost/bind.hpp"
58 
59 #include "lsst/daf/base.h"
60 #include "lsst/daf/base/Citizen.h"
61 #include "lsst/pex/exceptions.h"
62 #include "lsst/pex/logging/Trace.h"
63 #include "lsst/afw/image/Wcs.h"
64 #include "lsst/afw/image/Mask.h"
65 
67 
68 /************************************************************************************************************/
69 //
70 // for FITS code
71 //
72 #include "boost/mpl/vector.hpp"
73 #include "boost/gil/gil_all.hpp"
76 
77 namespace afwGeom = lsst::afw::geom;
78 namespace dafBase = lsst::daf::base;
79 namespace pexExcept = lsst::pex::exceptions;
80 namespace pexLog = lsst::pex::logging;
81 
82 /************************************************************************************************************/
83 
84 namespace lsst { namespace afw { namespace image {
85  namespace detail {
86  class MaskDict;
87  }
88 
89 namespace {
90  void setInitMaskBits(PTR(detail::MaskDict) dict);
91  /*
92  * A std::map that maintains a hash value of its contents
93  *
94  * We don't simply inherit from the std::map as we need to force the user to use add and remove;
95  * we could inherit, make operator[] private, and never use MapWithHash via a base-class pointer
96  * but it seemed simpler to only forward the functions we wish to support
97  */
98  struct MapWithHash {
99  typedef detail::MaskPlaneDict::value_type value_type;
100  typedef detail::MaskPlaneDict::const_iterator const_iterator;
101 
102  MapWithHash(detail::MaskPlaneDict const& dict=detail::MaskPlaneDict()) :
103  _dict(dict), _hash(_calcHash()) {
104  }
105  ~MapWithHash() { }
106 
107  bool operator==(MapWithHash const& rhs) const {
108  return _hash == rhs._hash;
109  }
110 
111  const_iterator begin() const { return _dict.begin(); }
112  const_iterator end() const { return _dict.end(); }
113  const_iterator find(detail::MaskPlaneDict::key_type const& name) const { return _dict.find(name); }
114 
115  void add(std::string const& str, int val) {
116  _dict[str] = val;
117  _calcHash();
118  }
119 
120  bool empty() const {
121  return _dict.empty();
122  }
123 
124  void clear() {
125  _dict.clear();
126  }
127 
128  std::size_t size() const {
129  return _dict.size();
130  }
131 
132  void erase(std::string const& str) {
133  if (_dict.find(str) != _dict.end()) {
134  _dict.erase(str);
135  _calcHash();
136  }
137  }
138 
139  detail::MaskPlaneDict const& getMaskPlaneDict() const {
140  return _dict;
141  }
142 
143  std::size_t getHash() const {
144  return _hash;
145  }
146  private:
148  std::size_t _hash;
149 
150  // calculate the hash
151  std::size_t _calcHash() {
152  _hash = 0x0;
153  for (const_iterator ptr = begin(); ptr != end(); ++ptr) {
154  _hash = (_hash << 1) ^
155  boost::hash<std::string>()((*ptr).first + str(boost::format("%d") % ptr->second));
156  }
157 
158  return _hash;
159  }
160  };
161 
162  bool operator!=(MapWithHash const& lhs, MapWithHash const& rhs) {
163  return !(lhs == rhs);
164  }
165 
166  class DictState; // forward declaration
167 }
168 
169 namespace detail {
170 /*
171  * A MaskDict is a MapWithHash, but additionally maintains a list of all live MaskDicts (the list is
172  * actually kept in a singleton instance of DictState)
173  */
174 class MaskDict : public MapWithHash {
175  friend class ::lsst::afw::image::DictState; // actually anonymous within lsst::afw::image; g++ is confused
176 
177  MaskDict() : MapWithHash() {}
178  MaskDict(MapWithHash const* dict) : MapWithHash(*dict) {}
179 public:
180  static PTR(MaskDict) makeMaskDict();
181  static PTR(MaskDict) makeMaskDict(detail::MaskPlaneDict const &dict);
182  static PTR(MaskDict) setDefaultDict(PTR(MaskDict) dict);
183 
184  PTR(MaskDict) clone() const;
185 
186  ~MaskDict();
187 
188  int getUnusedPlane() const;
189  int getMaskPlane(const std::string& name) const;
190 
191  void print() const {
192  for (MapWithHash::const_iterator ptr = begin(); ptr != end(); ++ptr) {
193  std::cout << "Plane " << ptr->second << " -> " << ptr->first << std::endl;
194  }
195  }
196 
197  static PTR(MaskDict) incrDefaultVersion();
198  static void listMaskDicts();
199 };
200 }
201 
202 /************************************************************************************************************/
203 
204 namespace {
205  /*
206  * A struct to hold our global state, and for whose components
207  * we can control the order of creation/destruction
208  */
209  class DictState {
210  friend class detail::MaskDict;
211 
212  typedef std::map<MapWithHash *, int> HandleList;
213 
214  public:
215  DictState() {
216  _dictCounter = 0;
219  }
220 
221  ~DictState() {
222  _defaultMaskDict.reset();
223 
224  for (HandleList::iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
225  delete ptr->first;
226  }
227  _dicts.clear();
228  }
229 
230  template<typename FunctorT>
231  void forEachMaskDict(FunctorT func) {
232  for (HandleList::const_iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
233  func(ptr->first);
234  }
235  }
236 
237  private:
238  PTR(detail::MaskDict) getDefaultDict() {
239  static bool first = true;
240 
241  if (first) {
242  setInitMaskBits(_defaultMaskDict);
243 
244  first = false;
245  }
246 
247  return _defaultMaskDict;
248  }
249 
250  PTR(detail::MaskDict) setDefaultDict(PTR(detail::MaskDict) newDefaultMaskDict) {
251  _defaultMaskDict = newDefaultMaskDict;
252 
253  return _defaultMaskDict;
254  }
255 
256  void addDict(MapWithHash *dict) {
257  _dicts[dict] = _dictCounter++;
258  }
259 
260  void eraseDict(MapWithHash *dict) {
261  _dicts.erase(dict);
262  }
263 
264  PTR(detail::MaskDict) incrDefaultVersion() {
265  _defaultMaskDict = PTR(detail::MaskDict)(new detail::MaskDict(*_defaultMaskDict.get()));
266  addDict(_defaultMaskDict.get());
267 
268  return _defaultMaskDict;
269  }
270 
271  PTR(detail::MaskDict) _defaultMaskDict; // default MaskDict to use
272  HandleList _dicts; // all the live MaskDicts
274  };
275 
276  static DictState _state;
277 }
278 
279 /************************************************************************************************************/
280 namespace detail {
281 /*
282  * Implementation of MaskDict
283  */
284 /*
285  * Return the default dictionary, unless you provide mpd in which case you get one of
286  * your very very own
287  */
288 PTR(MaskDict)
290 {
291  return _state.getDefaultDict();
292 }
293 
294 PTR(MaskDict)
295 MaskDict::makeMaskDict(detail::MaskPlaneDict const& mpd)
296 {
297  PTR(MaskDict) dict = _state.getDefaultDict();
298 
299  if (!mpd.empty()) {
300  MapWithHash mwh(mpd);
301  dict = PTR(MaskDict)(new MaskDict(&mwh));
302  _state.addDict(dict.get());
303  }
304 
305  return dict;
306 }
307 
308 PTR(MaskDict)
310 {
311  return _state.setDefaultDict(dict);
312 }
313 
315  PTR(MaskDict) dict(new MaskDict(*this));
316 
317  _state.addDict(dict.get());
318 
319  return dict;
320 }
321 
323  _state.eraseDict(this);
324 }
325 
326 PTR(MaskDict) MaskDict::incrDefaultVersion() {
327  return _state.incrDefaultVersion();
328 }
329 
330 int
332 {
333  if (empty()) {
334  return 0;
335  }
336 
337  MapWithHash::const_iterator const it =
338  std::max_element(begin(), end(), boost::bind(std::less<int>(),
339  boost::bind(&MapWithHash::value_type::second, _1),
340  boost::bind(&MapWithHash::value_type::second, _2)
341  )
342  );
343  assert(it != end());
344  int id = it->second + 1; // The maskPlane to use if there are no gaps
345 
346  for (int i = 0; i < id; ++i) {
347  MapWithHash::const_iterator const it = // is i already used in this Mask?
348  std::find_if(begin(), end(), boost::bind(std::equal_to<int>(),
349  boost::bind(&MapWithHash::value_type::second, _1), i));
350  if (it == end()) { // Not used; so we'll use it
351  return i;
352  }
353  }
354 
355  return id;
356 }
357 
358 int
359 detail::MaskDict::getMaskPlane(const std::string& name) const
360 {
361  MapWithHash::const_iterator i = find(name);
362 
363  return (i == end()) ? -1 : i->second;
364 }
365 }
366 
367 namespace {
368  /*
369  * Definition of the default mask bits
370  *
371  * N.b. this function is in an anonymous namespace, and is invisible to doxygen. ALL mask
372  * planes defined here should be documented with the Mask class in Mask.h
373  */
374  void
375  setInitMaskBits(PTR(detail::MaskDict) dict)
376  {
377  int i = -1;
378  dict->add("BAD", ++i);
379  dict->add("SAT", ++i); // should be SATURATED
380  dict->add("INTRP", ++i); // should be INTERPOLATED
381  dict->add("CR", ++i); //
382  dict->add("EDGE", ++i); //
383  dict->add("DETECTED", ++i); //
384  dict->add("DETECTED_NEGATIVE", ++i);
385  dict->add("SUSPECT", ++i);
386  dict->add("NO_DATA", ++i);
387  }
388 }
389 
393 template<typename MaskPixelT>
395  pexLog::Trace("afw.Mask", 5, boost::format("Number of mask planes: %d") % getNumPlanesMax());
396 
397  _maskDict = detail::MaskDict::makeMaskDict(planeDefs);
398 }
399 
403 template<typename MaskPixelT>
405  unsigned int width,
406  unsigned int height,
407  MaskPlaneDict const& planeDefs
408 ) :
409  ImageBase<MaskPixelT>(afwGeom::ExtentI(width, height)) {
410  _initializePlanes(planeDefs);
411  *this = 0x0;
412 }
413 
417 template<typename MaskPixelT>
419  unsigned int width,
420  unsigned int height,
421  MaskPixelT initialValue,
422  MaskPlaneDict const& planeDefs
423 ) :
424  ImageBase<MaskPixelT>(afwGeom::ExtentI(width, height)) {
425  _initializePlanes(planeDefs);
426  *this = initialValue;
427 }
428 
432 template<typename MaskPixelT>
434  afwGeom::Extent2I const & dimensions,
435  MaskPlaneDict const& planeDefs
436 ) :
437  ImageBase<MaskPixelT>(dimensions) {
438  _initializePlanes(planeDefs);
439  *this = 0x0;
440 }
441 
445 template<typename MaskPixelT>
447  afwGeom::Extent2I const & dimensions,
448  MaskPixelT initialValue,
449  MaskPlaneDict const& planeDefs
450 ) :
451  ImageBase<MaskPixelT>(dimensions) {
452  _initializePlanes(planeDefs);
453  *this = initialValue;
454 }
455 
459 template<typename MaskPixelT>
461  afwGeom::Box2I const & bbox,
462  MaskPlaneDict const& planeDefs
463 ) :
464  ImageBase<MaskPixelT>(bbox) {
465  _initializePlanes(planeDefs);
466  *this = 0x0;
467 }
468 
472 template<typename MaskPixelT>
474  afwGeom::Box2I const & bbox,
475  MaskPixelT initialValue,
476  MaskPlaneDict const& planeDefs
477 ) :
478  ImageBase<MaskPixelT>(bbox) {
479  _initializePlanes(planeDefs);
480  *this = initialValue;
481 }
482 
486 template<typename MaskPixelT>
488  Mask const &rhs,
489  afwGeom::Box2I const &bbox,
490  ImageOrigin const origin,
491  bool const deep
492 ) :
493  ImageBase<MaskPixelT>(rhs, bbox, origin, deep), _maskDict(rhs._maskDict) {
494 }
495 
499 template<typename MaskPixelT>
501  Mask const& rhs,
502  bool deep
503 ) :
504  ImageBase<MaskPixelT>(rhs, deep), _maskDict(rhs._maskDict) {
505 }
506 
507 template<typename MaskPixelT>
509  geom::Point2I const & xy0) :
510  image::ImageBase<MaskPixelT>(array, deep, xy0),
511  _maskDict(detail::MaskDict::makeMaskDict()) {
512 }
513 
514 /************************************************************************************************************/
515 
516 template<typename PixelT>
518  using std::swap; // See Meyers, Effective C++, Item 25
519 
521  swap(_maskDict, rhs._maskDict);
522 }
523 
524 template<typename PixelT>
526  a.swap(b);
527 }
528 
529 template<typename MaskPixelT>
530 Mask<MaskPixelT>& Mask<MaskPixelT>::operator=(const Mask<MaskPixelT>& rhs) {
531  Mask tmp(rhs);
532  swap(tmp); // See Meyers, Effective C++, Item 11
533 
534  return *this;
535 }
536 
537 template<typename MaskPixelT>
539  fill_pixels(_getRawView(), rhs);
540 
541  return *this;
542 }
543 
544 #ifndef DOXYGEN // doc for this section is already in header
545 
546 template<typename MaskPixelT>
548  std::string const & fileName,
549  int hdu,
550  PTR(daf::base::PropertySet) metadata,
551  afw::geom::Box2I const & bbox,
552  ImageOrigin origin,
553  bool conformMasks
554 ) : ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict()) {
555  fits::Fits fitsfile(fileName, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
556  fitsfile.setHdu(hdu);
557  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
558 }
559 
560 template<typename MaskPixelT>
562  fits::MemFileManager & manager,
563  int hdu,
564  PTR(daf::base::PropertySet) metadata,
565  afw::geom::Box2I const & bbox,
566  ImageOrigin origin,
567  bool conformMasks
568 ) : ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict()) {
569 
570  fits::Fits fitsfile(manager, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
571  fitsfile.setHdu(hdu);
572  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
573 }
574 
575 template<typename MaskPixelT>
577  fits::Fits & fitsfile,
578  PTR(daf::base::PropertySet) metadata,
579  afw::geom::Box2I const & bbox,
580  ImageOrigin const origin,
581  bool const conformMasks
582 ) :
583  ImageBase<MaskPixelT>(), _maskDict(detail::MaskDict::makeMaskDict())
584 {
585  // These are the permitted input file types
586  typedef boost::mpl::vector<
587  unsigned char,
588  unsigned short,
589  short
590  >fits_mask_types;
591 
592  if (!metadata) {
594  }
595 
596  fits_read_image<fits_mask_types>(fitsfile, *this, *metadata, bbox, origin);
597 
598  // look for mask planes in the file
599  MaskPlaneDict fileMaskDict = parseMaskPlaneMetadata(metadata);
600  PTR(detail::MaskDict) fileMD = detail::MaskDict::makeMaskDict(fileMaskDict);
601 
602  if (*fileMD == *detail::MaskDict::makeMaskDict()) { // file is already consistent with Mask
603  return;
604  }
605 
606  if (conformMasks) { // adopt the definitions in the file
608  }
609 
610  conformMaskPlanes(fileMaskDict); // convert planes defined by fileMaskDict to the order
611  // defined by Mask::_maskPlaneDict
612 }
613 
614 template<typename MaskPixelT>
616  std::string const & fileName,
618  std::string const & mode
619 ) const {
620  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
621  writeFits(fitsfile, metadata_i);
622 }
623 
624 template<typename MaskPixelT>
626  fits::MemFileManager & manager,
628  std::string const & mode
629 ) const {
630  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
631  writeFits(fitsfile, metadata_i);
632 }
633 
634 template<typename MaskPixelT>
636  fits::Fits & fitsfile,
638 ) const {
639 
640  PTR(dafBase::PropertySet) metadata;
641  if (metadata_i) {
642  metadata = metadata_i->deepCopy();
643  } else {
645  }
646  addMaskPlanesToMetadata(metadata);
647  //
648  // Add WCS with (X0, Y0) information
649  //
651  detail::wcsNameForXY0, this->getX0(), this->getY0()
652  );
653  metadata->combine(wcsAMetadata);
654 
655  fits_write_image(fitsfile, *this, metadata);
656 }
657 
658 #endif // !DOXYGEN
659 
660 namespace {
661  struct addPlaneFunctor {
662  addPlaneFunctor(std::string const& name, int id) : _name(name), _id(id) {}
663 
664  void operator()(MapWithHash *dict) {
665  detail::MaskPlaneDict::const_iterator const it = // is id already used in this Mask?
666  std::find_if(dict->begin(), dict->end(),
667  boost::bind(std::equal_to<int>(),
668  boost::bind(&detail::MaskPlaneDict::value_type::second, _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 
1059 /************************************************************************************************************/
1060 //
1061 // N.b. We could use the STL, but I find boost::lambda clearer, and more easily extended
1062 // to e.g. setting random numbers
1063 // transform_pixels(_getRawView(), _getRawView(), lambda::ret<PixelT>(lambda::_1 + val));
1064 // is equivalent to
1065 // transform_pixels(_getRawView(), _getRawView(), std::bind2nd(std::plus<PixelT>(), val));
1066 //
1067 namespace bl = boost::lambda;
1068 
1072 template<typename MaskPixelT>
1073 void Mask<MaskPixelT>::operator|=(MaskPixelT const val) {
1074  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 | val));
1075 }
1076 
1080 template<typename MaskPixelT>
1082  checkMaskDictionaries(rhs);
1083 
1084  if (this->getDimensions() != rhs.getDimensions()) {
1085  throw LSST_EXCEPT(pexExcept::LengthError,
1086  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1087  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1088  }
1089  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 | bl::_2));
1090 }
1091 
1095 template<typename MaskPixelT>
1096 void Mask<MaskPixelT>::operator&=(MaskPixelT const val) {
1097  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 & val));
1098 }
1099 
1103 template<typename MaskPixelT>
1105  checkMaskDictionaries(rhs);
1106 
1107  if (this->getDimensions() != rhs.getDimensions()) {
1108  throw LSST_EXCEPT(pexExcept::LengthError,
1109  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1110  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1111  }
1112  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 & bl::_2));
1113 }
1114 
1118 template<typename MaskPixelT>
1119 void Mask<MaskPixelT>::operator^=(MaskPixelT const val) {
1120  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 ^ val));
1121 }
1122 
1126 template<typename MaskPixelT>
1128  checkMaskDictionaries(rhs);
1129 
1130  if (this->getDimensions() != rhs.getDimensions()) {
1131  throw LSST_EXCEPT(pexExcept::LengthError,
1132  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1133  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1134  }
1135  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 ^ bl::_2));
1136 }
1137 
1141 template<typename MaskPixelT>
1143  int const x0, int const x1, int const y) {
1144  MaskPixelT const bitMask = getBitMask(planeId);
1145 
1146  for (int x = x0; x <= x1; x++) {
1147  operator()(x, y) = operator()(x, y) | bitMask;
1148  }
1149 }
1150 
1154 template<typename MaskPixelT>
1156  if (!metadata) {
1157  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "Null PTR(PropertySet)");
1158  }
1159 
1160  // First, clear existing MaskPlane metadata
1161  typedef std::vector<std::string> NameList;
1162  NameList paramNames = metadata->paramNames(false);
1163  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1164  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1165  metadata->remove(*i);
1166  }
1167  }
1168 
1169  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
1170 
1171  // Add new MaskPlane metadata
1172  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end() ; ++i) {
1173  std::string const& planeName = i->first;
1174  int const planeNumber = i->second;
1175 
1176  if (planeName != "") {
1177  metadata->add(maskPlanePrefix + planeName, planeNumber);
1178  }
1179  }
1180 }
1181 
1187 template<typename MaskPixelT>
1189  CONST_PTR(dafBase::PropertySet) metadata
1190 ) {
1191  MaskPlaneDict newDict;
1192 
1193  // First, clear existing MaskPlane metadata
1194  typedef std::vector<std::string> NameList;
1195  NameList paramNames = metadata->paramNames(false);
1196  int numPlanesUsed = 0; // number of planes used
1197 
1198  // Iterate over childless properties with names starting with maskPlanePrefix
1199  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1200  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1201  // split off maskPlanePrefix to obtain plane name
1202  std::string planeName = i->substr(maskPlanePrefix.size());
1203  int const planeId = metadata->getAsInt(*i);
1204 
1205  MaskPlaneDict::const_iterator plane = newDict.find(planeName);
1206  if (plane != newDict.end() && planeId != plane->second) {
1207  throw LSST_EXCEPT(pexExcept::RuntimeError,
1208  "File specifies plane " + planeName + " twice");
1209  }
1210  for (MaskPlaneDict::const_iterator j = newDict.begin(); j != newDict.end(); ++j) {
1211  if (planeId == j->second) {
1212  throw LSST_EXCEPT(pexExcept::RuntimeError,
1213  str(boost::format("File specifies plane %s has same value (%d) as %s") %
1214  planeName % planeId % j->first));
1215  }
1216  }
1217  // build new entry
1218  if (numPlanesUsed >= getNumPlanesMax()) {
1219  // Max number of planes already allocated
1220  throw LSST_EXCEPT(pexExcept::RuntimeError,
1221  str(boost::format("Max number of planes (%1%) already used") %
1222  getNumPlanesMax()));
1223  }
1224  newDict[planeName] = planeId;
1225  }
1226  }
1227  return newDict;
1228 }
1229 
1233 template<typename MaskPixelT>
1235 {
1236  _maskDict->print();
1237 }
1238 
1239 /*
1240  * Static members of Mask
1241  */
1242 template<typename MaskPixelT>
1243 std::string const Mask<MaskPixelT>::maskPlanePrefix("MP_");
1244 
1245 template<typename MaskPixelT>
1246 PTR(detail::MaskDict) Mask<MaskPixelT>::_maskPlaneDict()
1247 {
1249 }
1250 
1251 //
1252 // Explicit instantiations
1253 //
1254 template class Mask<MaskPixel>;
1255 }}}
int y
int iter
std::vector< std::string > paramNames(bool topLevelOnly=true) const
Definition: PropertySet.cc:142
int _dictCounter
Definition: Mask.cc:273
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:1188
static void clearMaskPlaneDict()
Reset the maskPlane dictionary.
Definition: Mask.cc:881
ImageBase< MaskPixelT >::PixelReference operator()(int x, int y)
get a reference to the specified pixel
Definition: Mask.cc:977
#define PTR(...)
Definition: base.h:41
table::Key< std::string > name
Definition: ApCorrMap.cc:71
HandleList _dicts
Definition: Mask.cc:272
void swap(ImageBase< PixelT > &a, ImageBase< PixelT > &b)
Definition: Image.cc:291
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
virtual void remove(std::string const &name)
Definition: PropertySet.cc:754
std::string const & _name
Definition: Mask.cc:678
MaskPlaneDict const & getMaskPlaneDict() const
Definition: Mask.cc:745
bool operator!=(lsst::afw::coord::Coord const &lhs, lsst::afw::coord::Coord const &rhs)
Inequality; the complement of equality.
Definition: Coord.h:476
std::map< std::string, int > MaskPlaneDict
Definition: Mask.h:65
PixelReference operator()(int x, int y)
Return a reference to the pixel (x, y)
Definition: Image.cc:236
#define CONST_PTR(...)
Definition: base.h:47
definition of the Trace messaging facilities
void operator^=(Mask const &rhs)
XOR a Mask into a Mask.
Definition: Mask.cc:1127
detail::MaskPlaneDict _dict
Definition: Mask.cc:147
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:1155
static int getMaskPlane(const std::string &name)
Return the mask plane number corresponding to a plane name.
Definition: Mask.cc:825
bool operator==(CoordKey const &lhs, CoordKey const &rhs)
Compare CoordKeys for equality using the constituent Keys.
limited backward compatibility to the DC2 run-time trace facilities
Definition: Trace.h:93
static void removeMaskPlane(const std::string &name)
Definition: Mask.cc:751
lsst::daf::base::PropertyList PropertyList
Definition: Wcs.cc:59
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:194
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: Image.h:115
static int addMaskPlane(const std::string &name)
Definition: Mask.cc:700
Extent< int, 2 > ExtentI
Definition: Extent.h:352
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:1142
int const x0
Definition: saturated.cc:45
boost::shared_ptr< detail::MaskDict > _maskDict
Definition: Mask.h:342
An integer coordinate rectangle.
Definition: Box.h:53
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
static MaskPixelT getBitMask(int plane)
Return the bitmask corresponding to plane ID.
Definition: Mask.cc:803
int getAsInt(std::string const &name) const
Definition: PropertySet.cc:333
afw::table::PointKey< int > dimensions
void clearAllMaskPlanes()
Clear all the pixels.
Definition: Mask.cc:889
int getWidth() const
Return the number of columns in the image.
Definition: Image.h:237
void swap(ImageBase &rhs)
Definition: Image.cc:282
std::size_t _hash
Definition: Mask.cc:148
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
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:93
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:106
int _id
Definition: Mask.cc:679
static std::string interpret(MaskPixelT value)
Interpret a mask value as a comma-separated list of mask plane names.
Definition: Mask.cc:684
int getMaskPlane(const std::string &name) const
Definition: Mask.cc:359
detail::MaskPlaneDict MaskPlaneDict
Definition: Mask.h:97
if(width!=gim.getWidth()||height!=gim.getHeight()||x0!=gim.getX0()||y0!=gim.getY0())
Definition: saturated.cc:47
void _initializePlanes(MaskPlaneDict const &planeDefs)
Initialise mask planes; called by constructors.
Definition: Mask.cc:394
A class used to request that array accesses be checked.
Definition: Image.h:87
boost::shared_ptr< lsst::daf::base::PropertyList > createTrivialWcsAsPropertySet(std::string const &wcsName, int const x0=0, int const y0=0)
Definition: Wcs.cc:1187
void swap(Mask &rhs)
Definition: Mask.cc:517
void operator|=(Mask const &rhs)
OR a Mask into a Mask.
Definition: Mask.cc:1081
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
LSST bitmasks.
int x
Mask & operator=(MaskPixelT const rhs)
Definition: Mask.cc:538
static boost::shared_ptr< MaskDict > setDefaultDict(boost::shared_ptr< MaskDict > dict)
Definition: Mask.cc:309
static const std::string maskPlanePrefix
Definition: Mask.h:346
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
A multidimensional strided array.
Definition: Array.h:47
void operator&=(Mask const &rhs)
AND a Mask into a Mask.
Definition: Mask.cc:1104
Mask(unsigned int width, unsigned int height, MaskPlaneDict const &planeDefs=MaskPlaneDict())
Construct a Mask initialized to 0x0.
Definition: Mask.cc:404
void checkMaskDictionaries(Mask const &other)
Definition: Mask.cc:1053
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.
void clearMaskPlane(int plane)
Clear the specified bit in all pixels.
Definition: Mask.cc:897
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: Image.h:151
Class for storing generic metadata.
Definition: PropertySet.h:82
static MaskPixelT getBitMaskNoThrow(int plane)
Return the bitmask corresponding to a plane ID, or 0 if invalid.
Definition: Mask.cc:793
virtual Ptr deepCopy(void) const
Definition: PropertySet.cc:70
int id
Definition: CR.cc:151
boost::shared_ptr< detail::MaskDict > _defaultMaskDict
Definition: Mask.cc:271
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
afw::table::Key< double > b
table::PointKey< int > pixel
int getHeight() const
Return the number of rows in the image.
Definition: Image.h:239
boost::shared_ptr< MaskDict > clone() const
Definition: Mask.cc:314
void printMaskPlanes() const
print the mask plane dictionary to std::cout
Definition: Mask.cc:1234
void add(std::string const &name, T const &value)
Definition: PropertySet.cc:619
static boost::shared_ptr< MaskDict > incrDefaultVersion()
Definition: Mask.cc:326
static boost::shared_ptr< MaskDict > makeMaskDict()
Definition: Mask.cc:289
Definition of default types for Masks and Variance Images.
ImageT val
Definition: CR.cc:154
MaskDict(MapWithHash const *dict)
Definition: Mask.cc:178
geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: Image.h:298
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
_view_t _getRawView() const
Definition: Image.h:401
Include files required for standard LSST Exception handling.
static int getNumPlanesUsed()
Reset the maskPlane dictionary.
Definition: Mask.cc:872