LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
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  }
387 }
388 
392 template<typename MaskPixelT>
394  pexLog::Trace("afw.Mask", 5, boost::format("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>
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>
529 Mask<MaskPixelT>& Mask<MaskPixelT>::operator=(const Mask<MaskPixelT>& rhs) {
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  boost::bind(std::equal_to<int>(),
667  boost::bind(&detail::MaskPlaneDict::value_type::second, _1), _id));
668  if (it != dict->end()) { // mask plane is already in use
669  return;
670  }
671 
672  if (dict->find(_name) == dict->end()) { // not already set
673  dict->add(_name, _id);
674  }
675  }
676 
677  std::string const& _name;
678  int _id;
679  };
680 }
681 
682 template<typename MaskPixelT>
683 std::string Mask<MaskPixelT>::interpret(MaskPixelT value)
684 {
685  std::string result = "";
686  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
687  for (MaskPlaneDict::const_iterator iter = mpd.begin(); iter != mpd.end(); ++iter) {
688  if (value & getBitMask(iter->second)) {
689  if (result.size() > 0) {
690  result += ",";
691  }
692  result += iter->first;
693  }
694  }
695  return result;
696 }
697 
698 template<typename MaskPixelT>
699 int Mask<MaskPixelT>::addMaskPlane(const std::string& name)
700 {
701  int id = getMaskPlaneNoThrow(name); // see if the plane is already available
702 
703  if (id < 0) { // doesn't exist
704  id = _maskPlaneDict()->getUnusedPlane();
705  }
706 
707  // build new entry, adding the plane to all Masks where this is no contradiction
708 
709  if (id >= getNumPlanesMax()) { // Max number of planes is already allocated
710  throw LSST_EXCEPT(pexExcept::RuntimeError,
711  str(boost::format("Max number of planes (%1%) already used") % getNumPlanesMax()));
712  }
713 
714  _state.forEachMaskDict(addPlaneFunctor(name, id));
715 
716  return id;
717 }
718 
724 template<typename MaskPixelT>
726  std::string name,
727  int planeId
728 ) {
729  if (planeId < 0 || planeId >= getNumPlanesMax()) {
730  throw LSST_EXCEPT(pexExcept::RangeError,
731  str(boost::format("mask plane ID must be between 0 and %1%") % (getNumPlanesMax() - 1)));
732  }
733 
734  _maskPlaneDict()->add(name, planeId);
735 
736  return planeId;
737 }
738 
742 template<typename MaskPixelT>
745 {
746  return _maskDict->getMaskPlaneDict();
747 }
748 
749 template<typename MaskPixelT>
750 void Mask<MaskPixelT>::removeMaskPlane(const std::string& name)
751 {
752  if (detail::MaskDict::makeMaskDict()->getMaskPlane(name) < 0) {
753  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
754  str(boost::format("Plane %s doesn't exist in the default Mask") % name));
755  }
756 
757  detail::MaskDict::incrDefaultVersion(); // leave current Masks alone
758  _maskPlaneDict()->erase(name);
759 }
760 
767 template<typename MaskPixelT>
768 void Mask<MaskPixelT>::removeAndClearMaskPlane(const std::string& name,
769  bool const removeFromDefault
770  )
772 {
773  clearMaskPlane(getMaskPlane(name)); // clear this bits in this Mask
774 
775  if (_maskDict == detail::MaskDict::makeMaskDict() && removeFromDefault) { // we are the default
776  ;
777  } else {
778  _maskDict = _maskDict->clone();
779  }
780 
781  _maskDict->erase(name);
782 
783  if (removeFromDefault && detail::MaskDict::makeMaskDict()->getMaskPlane(name) >= 0) {
784  removeMaskPlane(name);
785  }
786 }
787 
791 template<typename MaskPixelT>
792 MaskPixelT Mask<MaskPixelT>::getBitMaskNoThrow(int planeId) {
793  return (planeId >= 0 && planeId < getNumPlanesMax()) ? (1 << planeId) : 0;
794 }
795 
801 template<typename MaskPixelT>
802 MaskPixelT Mask<MaskPixelT>::getBitMask(int planeId) {
803  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
804 
805  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end(); ++i) {
806  if (planeId == i->second) {
807  MaskPixelT const bitmask = getBitMaskNoThrow(planeId);
808  if (bitmask == 0) { // failed
809  break;
810  }
811  return bitmask;
812  }
813  }
814  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
815  str(boost::format("Invalid mask plane ID: %d") % planeId));
816 }
817 
823 template<typename MaskPixelT>
824 int Mask<MaskPixelT>::getMaskPlane(const std::string& name) {
825  int const plane = getMaskPlaneNoThrow(name);
826 
827  if (plane < 0) {
828  throw LSST_EXCEPT(pexExcept::InvalidParameterError,
829  str(boost::format("Invalid mask plane name: %s") % name));
830  } else {
831  return plane;
832  }
833 }
834 
838 template<typename MaskPixelT>
839 int Mask<MaskPixelT>::getMaskPlaneNoThrow(const std::string& name) {
840  return _maskPlaneDict()->getMaskPlane(name);
841 }
842 
848 template<typename MaskPixelT>
849 MaskPixelT Mask<MaskPixelT>::getPlaneBitMask(const std::string& name) {
850  return getBitMask(getMaskPlane(name));
851 }
852 
858 template<typename MaskPixelT>
859 MaskPixelT Mask<MaskPixelT>::getPlaneBitMask(const std::vector<std::string> &name) {
860  MaskPixelT mpix = 0x0;
861  for (std::vector<std::string>::const_iterator it = name.begin(); it != name.end(); ++it) {
862  mpix |= getBitMask(getMaskPlane(*it));
863  }
864  return mpix;
865 }
866 
870 template<typename MaskPixelT>
872 {
873  return _maskPlaneDict()->size();
874 }
875 
879 template<typename MaskPixelT>
881  _maskPlaneDict()->clear();
882 }
883 
887 template<typename MaskPixelT>
889  *this = 0;
890 }
891 
895 template<typename MaskPixelT>
897  *this &= ~getBitMask(planeId);
898 }
899 
911 template<typename MaskPixelT>
913  MaskPlaneDict const &currentPlaneDict
914  )
915 {
916  PTR(detail::MaskDict) currentMD = detail::MaskDict::makeMaskDict(currentPlaneDict);
917 
918  if (*_maskDict == *currentMD) {
919  if (*detail::MaskDict::makeMaskDict() == *_maskDict) {
920  return; // nothing to do
921  }
922  } else {
923  //
924  // Find out which planes need to be permuted
925  //
926  MaskPixelT keepBitmask = 0; // mask of bits to keep
927  MaskPixelT canonicalMask[sizeof(MaskPixelT)*8]; // bits in lsst::afw::image::Mask that should be
928  MaskPixelT currentMask[sizeof(MaskPixelT)*8]; // mapped to these bits
929  int numReMap = 0;
930 
931  for (MaskPlaneDict::const_iterator i = currentPlaneDict.begin(); i != currentPlaneDict.end() ; i++) {
932  std::string const name = i->first; // name of mask plane
933  int const currentPlaneNumber = i->second; // plane number currently in use
934  int canonicalPlaneNumber = getMaskPlaneNoThrow(name); // plane number in lsst::afw::image::Mask
935 
936  if (canonicalPlaneNumber < 0) { // no such plane; add it
937  canonicalPlaneNumber = addMaskPlane(name);
938  }
939 
940  if (canonicalPlaneNumber == currentPlaneNumber) {
941  keepBitmask |= getBitMask(canonicalPlaneNumber); // bit is unchanged, so preserve it
942  } else {
943  canonicalMask[numReMap] = getBitMask(canonicalPlaneNumber);
944  currentMask[numReMap] = getBitMaskNoThrow(currentPlaneNumber);
945  numReMap++;
946  }
947  }
948 
949  // Now loop over all pixels in Mask
950  if (numReMap > 0) {
951  for (int r = 0; r != this->getHeight(); ++r) { // "this->": Meyers, Effective C++, Item 43
952  for (typename Mask::x_iterator ptr = this->row_begin(r), end = this->row_end(r);
953  ptr != end; ++ptr) {
954  MaskPixelT const pixel = *ptr;
955 
956  MaskPixelT newPixel = pixel & keepBitmask; // value of invariant mask bits
957  for (int i = 0; i < numReMap; i++) {
958  if (pixel & currentMask[i]) newPixel |= canonicalMask[i];
959  }
960 
961  *ptr = newPixel;
962  }
963  }
964  }
965  }
966  // We've made the planes match the current mask dictionary
967  _maskDict = detail::MaskDict::makeMaskDict();
968 }
969 
970 /************************************************************************************************************/
971 
975 template<typename MaskPixelT>
977  int x,
978  int y
979 ) {
980  return this->ImageBase<MaskPixelT>::operator()(x, y);
981 }
982 
986 template<typename MaskPixelT>
988  int x,
989  int y,
990  CheckIndices const& check
991 ) {
992  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
993 }
994 
998 template<typename MaskPixelT>
1000  int x,
1001  int y
1002 ) const {
1003  return this->ImageBase<MaskPixelT>::operator()(x, y);
1004 }
1005 
1009 template<typename MaskPixelT>
1011  int x,
1012  int y,
1013  CheckIndices const& check
1014 ) const {
1015  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
1016 }
1017 
1021 template<typename MaskPixelT>
1023  int x,
1024  int y,
1025  int planeId
1026 ) const {
1027  // !! converts an int to a bool
1028  return !!(this->ImageBase<MaskPixelT>::operator()(x, y) & getBitMask(planeId));
1029 }
1030 
1034 template<typename MaskPixelT>
1036  int x,
1037  int y,
1038  int planeId,
1039  CheckIndices const& check
1040 ) const {
1041  // !! converts an int to a bool
1042  return !!(this->ImageBase<MaskPixelT>::operator()(x, y, check) & getBitMask(planeId));
1043 }
1044 
1045 /************************************************************************************************************/
1046 //
1047 // Check that masks have the same dictionary version
1048 //
1049 // @throw lsst::pex::exceptions::RuntimeError
1050 //
1051 template<typename MaskPixelT>
1053  if (*_maskDict != *other._maskDict) {
1054  throw LSST_EXCEPT(pexExcept::RuntimeError, "Mask dictionaries do not match");
1055  }
1056 }
1057 
1058 /************************************************************************************************************/
1059 //
1060 // N.b. We could use the STL, but I find boost::lambda clearer, and more easily extended
1061 // to e.g. setting random numbers
1062 // transform_pixels(_getRawView(), _getRawView(), lambda::ret<PixelT>(lambda::_1 + val));
1063 // is equivalent to
1064 // transform_pixels(_getRawView(), _getRawView(), std::bind2nd(std::plus<PixelT>(), val));
1065 //
1066 namespace bl = boost::lambda;
1067 
1071 template<typename MaskPixelT>
1072 void Mask<MaskPixelT>::operator|=(MaskPixelT const val) {
1073  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 | val));
1074 }
1075 
1079 template<typename MaskPixelT>
1081  checkMaskDictionaries(rhs);
1082 
1083  if (this->getDimensions() != rhs.getDimensions()) {
1084  throw LSST_EXCEPT(pexExcept::LengthError,
1085  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1086  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1087  }
1088  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 | bl::_2));
1089 }
1090 
1094 template<typename MaskPixelT>
1095 void Mask<MaskPixelT>::operator&=(MaskPixelT const val) {
1096  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 & val));
1097 }
1098 
1102 template<typename MaskPixelT>
1104  checkMaskDictionaries(rhs);
1105 
1106  if (this->getDimensions() != rhs.getDimensions()) {
1107  throw LSST_EXCEPT(pexExcept::LengthError,
1108  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1109  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1110  }
1111  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 & bl::_2));
1112 }
1113 
1117 template<typename MaskPixelT>
1118 void Mask<MaskPixelT>::operator^=(MaskPixelT const val) {
1119  transform_pixels(_getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 ^ val));
1120 }
1121 
1125 template<typename MaskPixelT>
1127  checkMaskDictionaries(rhs);
1128 
1129  if (this->getDimensions() != rhs.getDimensions()) {
1130  throw LSST_EXCEPT(pexExcept::LengthError,
1131  str(boost::format("Images are of different size, %dx%d v %dx%d") %
1132  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
1133  }
1134  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(), bl::ret<MaskPixelT>(bl::_1 ^ bl::_2));
1135 }
1136 
1140 template<typename MaskPixelT>
1142  int const x0, int const x1, int const y) {
1143  MaskPixelT const bitMask = getBitMask(planeId);
1144 
1145  for (int x = x0; x <= x1; x++) {
1146  operator()(x, y) = operator()(x, y) | bitMask;
1147  }
1148 }
1149 
1153 template<typename MaskPixelT>
1155  if (!metadata) {
1156  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "Null PTR(PropertySet)");
1157  }
1158 
1159  // First, clear existing MaskPlane metadata
1160  typedef std::vector<std::string> NameList;
1161  NameList paramNames = metadata->paramNames(false);
1162  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1163  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1164  metadata->remove(*i);
1165  }
1166  }
1167 
1168  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
1169 
1170  // Add new MaskPlane metadata
1171  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end() ; ++i) {
1172  std::string const& planeName = i->first;
1173  int const planeNumber = i->second;
1174 
1175  if (planeName != "") {
1176  metadata->add(maskPlanePrefix + planeName, planeNumber);
1177  }
1178  }
1179 }
1180 
1186 template<typename MaskPixelT>
1188  CONST_PTR(dafBase::PropertySet) metadata
1189 ) {
1190  MaskPlaneDict newDict;
1191 
1192  // First, clear existing MaskPlane metadata
1193  typedef std::vector<std::string> NameList;
1194  NameList paramNames = metadata->paramNames(false);
1195  int numPlanesUsed = 0; // number of planes used
1196 
1197  // Iterate over childless properties with names starting with maskPlanePrefix
1198  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
1199  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
1200  // split off maskPlanePrefix to obtain plane name
1201  std::string planeName = i->substr(maskPlanePrefix.size());
1202  int const planeId = metadata->getAsInt(*i);
1203 
1204  MaskPlaneDict::const_iterator plane = newDict.find(planeName);
1205  if (plane != newDict.end() && planeId != plane->second) {
1206  throw LSST_EXCEPT(pexExcept::RuntimeError,
1207  "File specifies plane " + planeName + " twice");
1208  }
1209  for (MaskPlaneDict::const_iterator j = newDict.begin(); j != newDict.end(); ++j) {
1210  if (planeId == j->second) {
1211  throw LSST_EXCEPT(pexExcept::RuntimeError,
1212  str(boost::format("File specifies plane %s has same value (%d) as %s") %
1213  planeName % planeId % j->first));
1214  }
1215  }
1216  // build new entry
1217  if (numPlanesUsed >= getNumPlanesMax()) {
1218  // Max number of planes already allocated
1219  throw LSST_EXCEPT(pexExcept::RuntimeError,
1220  str(boost::format("Max number of planes (%1%) already used") %
1221  getNumPlanesMax()));
1222  }
1223  newDict[planeName] = planeId;
1224  }
1225  }
1226  return newDict;
1227 }
1228 
1232 template<typename MaskPixelT>
1234 {
1235  _maskDict->print();
1236 }
1237 
1238 /*
1239  * Static members of Mask
1240  */
1241 template<typename MaskPixelT>
1242 std::string const Mask<MaskPixelT>::maskPlanePrefix("MP_");
1243 
1244 template<typename MaskPixelT>
1245 PTR(detail::MaskDict) Mask<MaskPixelT>::_maskPlaneDict()
1246 {
1248 }
1249 
1250 //
1251 // Explicit instantiations
1252 //
1253 template class Mask<MaskPixel>;
1254 }}}
int y
int iter
int _dictCounter
Definition: Mask.cc:273
std::vector< std::string > paramNames(bool topLevelOnly=true) const
Definition: PropertySet.cc:142
#define CONST_PTR(...)
Definition: base.h:47
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:1187
static void clearMaskPlaneDict()
Reset the maskPlane dictionary.
Definition: Mask.cc:880
ImageBase< MaskPixelT >::PixelReference operator()(int x, int y)
get a reference to the specified pixel
Definition: Mask.cc:976
HandleList _dicts
Definition: Mask.cc:272
int64_t _id
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:768
std::string const & _name
Definition: Mask.cc:677
afw::table::Key< afw::table::Point< int > > dimensions
MaskPlaneDict const & getMaskPlaneDict() const
Definition: Mask.cc:744
bool operator!=(lsst::afw::coord::Coord const &lhs, lsst::afw::coord::Coord const &rhs)
Inequality; the complement of equality.
Definition: Coord.h:462
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
definition of the Trace messaging facilities
void operator^=(Mask const &rhs)
XOR a Mask into a Mask.
Definition: Mask.cc:1126
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:1154
static int getMaskPlane(const std::string &name)
Return the mask plane number corresponding to a plane name.
Definition: Mask.cc:824
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
#define PTR(...)
Definition: base.h:41
static void removeMaskPlane(const std::string &name)
Definition: Mask.cc:750
lsst::daf::base::PropertyList PropertyList
Definition: Wcs.cc:58
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:699
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:1141
int const x0
Definition: saturated.cc:45
boost::shared_ptr< detail::MaskDict > _maskDict
Definition: Mask.h:342
table::Key< table::Point< int > > pixel
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:802
void clearAllMaskPlanes()
Clear all the pixels.
Definition: Mask.cc:888
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:859
virtual Ptr deepCopy(void) const
Definition: PropertySet.cc:70
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
static std::string interpret(MaskPixelT value)
Interpret a mask value as a comma-separated list of mask plane names.
Definition: Mask.cc:683
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 add(std::string const &name, T const &value)
Definition: PropertySet.cc:619
void _initializePlanes(MaskPlaneDict const &planeDefs)
Initialise mask planes; called by constructors.
Definition: Mask.cc:393
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:1184
void swap(Mask &rhs)
Definition: Mask.cc:516
void operator|=(Mask const &rhs)
OR a Mask into a Mask.
Definition: Mask.cc:1080
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:839
LSST bitmasks.
int x
Mask & operator=(MaskPixelT const rhs)
Definition: Mask.cc:537
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:1103
Mask(unsigned int width, unsigned int height, MaskPlaneDict const &planeDefs=MaskPlaneDict())
Construct a Mask initialized to 0x0.
Definition: Mask.cc:403
void checkMaskDictionaries(Mask const &other)
Definition: Mask.cc:1052
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:896
_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:792
int getAsInt(std::string const &name) const
Definition: PropertySet.cc:333
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:912
virtual void remove(std::string const &name)
Definition: PropertySet.cc:754
afw::table::Key< double > b
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:1233
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
Include files required for standard LSST Exception handling.
std::string const wcsNameForXY0
Definition: Image.h:82
_view_t _getRawView() const
Definition: Image.h:401
static int getNumPlanesUsed()
Reset the maskPlane dictionary.
Definition: Mask.cc:871