LSSTApplications  15.0+21,16.0+1,16.0+3,16.0+4,16.0+8,16.0-1-g2115a9e+2,16.0-1-g4515a79+6,16.0-1-g5c6f5ee+4,16.0-1-g7bb14cc,16.0-1-g80120d7+4,16.0-1-g98efed3+4,16.0-1-gb7f560d+1,16.0-14-gb4f0cd2fa,16.0-2-g1ad129e+1,16.0-2-g2ed7261+1,16.0-2-g311bfd2,16.0-2-g568a347+3,16.0-2-g852da13+6,16.0-2-gd4c87cb+3,16.0-3-g099ede0,16.0-3-g150e024+3,16.0-3-g1f513a6,16.0-3-g958ce35,16.0-4-g08dccf71+4,16.0-4-g128aaef,16.0-4-g84f75fb+5,16.0-4-gcfd1396+4,16.0-4-gde8cee2,16.0-4-gdfb0d14+1,16.0-5-g7bc0afb+3,16.0-5-g86fb31a+3,16.0-6-g2dd73041+4,16.0-7-g95fb7bf,16.0-7-gc37dbc2+4,w.2018.28
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 
25 // Implementations of Mask class methods
26 
27 /*
28  * There are a number of classes defined here and in Mask.h
29  *
30  * The fundamental type visible to the user is Mask; a 2-d array of pixels. Each of these pixels should
31  * be thought of as a set of bits, and the names of these bits are given by MaskPlaneDict (which is
32  * implemented as a std::map)
33  *
34  * Internally to this file, we have a MapWithHash which is like a std::map, but maintains a hash of its
35  * contents; this is used to check equality efficiently.
36  *
37  * We also have a MaskDict which isa MapWithHash, but also maintains a list of MaskDicts (or equivalently
38  * MapWithHash) allowing us to iterate over these maps, updating them as needed.
39  *
40  * The list of MaskDicts is actually kept as a singleton of a helper class, DictState
41  */
42 
43 #include <functional>
44 #include <list>
45 #include <string>
46 
47 #pragma clang diagnostic push
48 #pragma clang diagnostic ignored "-Wunused-variable"
49 #pragma clang diagnostic pop
50 #include "boost/format.hpp"
51 #include "boost/filesystem/path.hpp"
52 
53 #include "boost/functional/hash.hpp"
54 
55 #include "lsst/daf/base.h"
56 #include "lsst/daf/base/Citizen.h"
57 #include "lsst/geom.h"
58 #include "lsst/pex/exceptions.h"
59 #include "lsst/log/Log.h"
60 #include "lsst/afw/image/Mask.h"
61 
63 
64 //
65 // for FITS code
66 //
67 #include "boost/mpl/vector.hpp"
68 #include "boost/gil/gil_all.hpp"
71 
72 namespace dafBase = lsst::daf::base;
74 
75 namespace lsst {
76 namespace afw {
77 namespace image {
78 namespace detail {
79 class MaskDict;
80 }
81 
82 namespace {
83 void setInitMaskBits(std::shared_ptr<detail::MaskDict> dict);
84 /*
85  * A std::map that maintains a hash value of its contents
86  *
87  * We don't simply inherit from the std::map as we need to force the user to use add and remove;
88  * we could inherit, make operator[] private, and never use MapWithHash via a base-class pointer
89  * but it seemed simpler to only forward the functions we wish to support
90  */
91 struct MapWithHash {
92  typedef detail::MaskPlaneDict::value_type value_type;
93  typedef detail::MaskPlaneDict::const_iterator const_iterator;
94 
95  MapWithHash(detail::MaskPlaneDict const& dict = detail::MaskPlaneDict())
96  : _dict(dict), _hash(_calcHash()) {}
97  ~MapWithHash() {}
98 
99  bool operator==(MapWithHash const& rhs) const { return _hash == rhs._hash; }
100 
101  const_iterator begin() const { return _dict.begin(); }
102  const_iterator end() const { return _dict.end(); }
103  const_iterator find(detail::MaskPlaneDict::key_type const& name) const { return _dict.find(name); }
104 
105  void add(std::string const& str, int val) {
106  _dict[str] = val;
107  _calcHash();
108  }
109 
110  bool empty() const { return _dict.empty(); }
111 
112  void clear() { _dict.clear(); }
113 
114  std::size_t size() const { return _dict.size(); }
115 
116  void erase(std::string const& str) {
117  if (_dict.find(str) != _dict.end()) {
118  _dict.erase(str);
119  _calcHash();
120  }
121  }
122 
123  detail::MaskPlaneDict const& getMaskPlaneDict() const { return _dict; }
124 
125  std::size_t getHash() const { return _hash; }
126 
127 private:
128  detail::MaskPlaneDict _dict;
129  std::size_t _hash;
130 
131  // calculate the hash
132  std::size_t _calcHash() {
133  _hash = 0x0;
134  for (const_iterator ptr = begin(); ptr != end(); ++ptr) {
135  _hash = (_hash << 1) ^
136  boost::hash<std::string>()((*ptr).first + str(boost::format("%d") % ptr->second));
137  }
138 
139  return _hash;
140  }
141 };
142 
143 bool operator!=(MapWithHash const& lhs, MapWithHash const& rhs) { return !(lhs == rhs); }
144 
145 class DictState; // forward declaration
146 } // namespace
147 
148 namespace detail {
149 /*
150  * A MaskDict is a MapWithHash, but additionally maintains a list of all live MaskDicts (the list is
151  * actually kept in a singleton instance of DictState)
152  */
153 class MaskDict : public MapWithHash {
154  friend class ::lsst::afw::image::DictState; // actually anonymous within lsst::afw::image; g++ is
155  // confused
156 
157  MaskDict() : MapWithHash() {}
158  MaskDict(MapWithHash const* dict) : MapWithHash(*dict) {}
159 
160 public:
164 
166 
167  ~MaskDict();
168 
169  int getUnusedPlane() const;
170  int getMaskPlane(const std::string& name) const;
171 
172  void print() const {
173  for (MapWithHash::const_iterator ptr = begin(); ptr != end(); ++ptr) {
174  std::cout << "Plane " << ptr->second << " -> " << ptr->first << std::endl;
175  }
176  }
177 
179  static void listMaskDicts();
180 };
181 } // namespace detail
182 
183 namespace {
184 /*
185  * A struct to hold our global state, and for whose components
186  * we can control the order of creation/destruction
187  */
188 class DictState {
189  friend class detail::MaskDict;
190 
191  typedef std::map<MapWithHash*, int> HandleList;
192 
193 public:
194  DictState() {
195  _dictCounter = 0;
196  _defaultMaskDict = std::shared_ptr<detail::MaskDict>(new detail::MaskDict);
197  _dicts[_defaultMaskDict.get()] = _dictCounter++;
198  }
199 
200  ~DictState() {
201  _defaultMaskDict.reset();
202 
203  for (HandleList::iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
204  delete ptr->first;
205  }
206  _dicts.clear();
207  }
208 
209  template <typename FunctorT>
210  void forEachMaskDict(FunctorT func) {
211  for (HandleList::const_iterator ptr = _dicts.begin(); ptr != _dicts.end(); ++ptr) {
212  func(ptr->first);
213  }
214  }
215 
216 private:
217  std::shared_ptr<detail::MaskDict> getDefaultDict() {
218  static bool first = true;
219 
220  if (first) {
221  setInitMaskBits(_defaultMaskDict);
222 
223  first = false;
224  }
225 
226  return _defaultMaskDict;
227  }
228 
230  _defaultMaskDict = newDefaultMaskDict;
231 
232  return _defaultMaskDict;
233  }
234 
235  void addDict(MapWithHash* dict) { _dicts[dict] = _dictCounter++; }
236 
237  void eraseDict(MapWithHash* dict) { _dicts.erase(dict); }
238 
240  _defaultMaskDict = std::shared_ptr<detail::MaskDict>(new detail::MaskDict(*_defaultMaskDict.get()));
241  addDict(_defaultMaskDict.get());
242 
243  return _defaultMaskDict;
244  }
245 
246  std::shared_ptr<detail::MaskDict> _defaultMaskDict; // default MaskDict to use
247  HandleList _dicts; // all the live MaskDicts
248  int _dictCounter;
249 };
250 
251 static DictState _state;
252 } // namespace
253 
254 namespace detail {
255 /*
256  * Implementation of MaskDict
257  */
258 /*
259  * Return the default dictionary, unless you provide mpd in which case you get one of
260  * your very very own
261  */
262 std::shared_ptr<MaskDict> MaskDict::makeMaskDict() { return _state.getDefaultDict(); }
263 
265  std::shared_ptr<MaskDict> dict = _state.getDefaultDict();
266 
267  if (!mpd.empty()) {
268  MapWithHash mwh(mpd);
269  dict = std::shared_ptr<MaskDict>(new MaskDict(&mwh));
270  _state.addDict(dict.get());
271  }
272 
273  return dict;
274 }
275 
277  return _state.setDefaultDict(dict);
278 }
279 
281  std::shared_ptr<MaskDict> dict(new MaskDict(*this));
282 
283  _state.addDict(dict.get());
284 
285  return dict;
286 }
287 
288 MaskDict::~MaskDict() { _state.eraseDict(this); }
289 
290 std::shared_ptr<MaskDict> MaskDict::incrDefaultVersion() { return _state.incrDefaultVersion(); }
291 
293  if (empty()) {
294  return 0;
295  }
296 
297  MapWithHash::const_iterator const it = std::max_element(
298  begin(), end(),
300  std::bind(&MapWithHash::value_type::second, std::placeholders::_2)));
301  assert(it != end());
302  int id = it->second + 1; // The maskPlane to use if there are no gaps
303 
304  for (int i = 0; i < id; ++i) {
305  MapWithHash::const_iterator const it = // is i already used in this Mask?
306  std::find_if(
307  begin(), end(),
309  std::bind(&MapWithHash::value_type::second, std::placeholders::_1), i));
310  if (it == end()) { // Not used; so we'll use it
311  return i;
312  }
313  }
314 
315  return id;
316 }
317 
319  MapWithHash::const_iterator i = find(name);
320 
321  return (i == end()) ? -1 : i->second;
322 }
323 } // namespace detail
324 
325 namespace {
326 /*
327  * Definition of the default mask bits
328  *
329  * N.b. this function is in an anonymous namespace, and is invisible to doxygen. ALL mask
330  * planes defined here should be documented with the Mask class in Mask.h
331  */
332 void setInitMaskBits(std::shared_ptr<detail::MaskDict> dict) {
333  int i = -1;
334  dict->add("BAD", ++i);
335  dict->add("SAT", ++i); // should be SATURATED
336  dict->add("INTRP", ++i); // should be INTERPOLATED
337  dict->add("CR", ++i); //
338  dict->add("EDGE", ++i); //
339  dict->add("DETECTED", ++i); //
340  dict->add("DETECTED_NEGATIVE", ++i);
341  dict->add("SUSPECT", ++i);
342  dict->add("NO_DATA", ++i);
343 }
344 } // namespace
345 
346 template <typename MaskPixelT>
347 void Mask<MaskPixelT>::_initializePlanes(MaskPlaneDict const& planeDefs) {
348  LOGL_DEBUG("afw.image.Mask", "Number of mask planes: %d", getNumPlanesMax());
349 
350  _maskDict = detail::MaskDict::makeMaskDict(planeDefs);
351 }
352 
353 template <typename MaskPixelT>
354 Mask<MaskPixelT>::Mask(unsigned int width, unsigned int height, MaskPlaneDict const& planeDefs)
355  : ImageBase<MaskPixelT>(lsst::geom::ExtentI(width, height)) {
356  _initializePlanes(planeDefs);
357  *this = 0x0;
358 }
359 
360 template <typename MaskPixelT>
361 Mask<MaskPixelT>::Mask(unsigned int width, unsigned int height, MaskPixelT initialValue,
362  MaskPlaneDict const& planeDefs)
363  : ImageBase<MaskPixelT>(lsst::geom::ExtentI(width, height)) {
364  _initializePlanes(planeDefs);
365  *this = initialValue;
366 }
367 
368 template <typename MaskPixelT>
370  : ImageBase<MaskPixelT>(dimensions) {
371  _initializePlanes(planeDefs);
372  *this = 0x0;
373 }
374 
375 template <typename MaskPixelT>
377  MaskPlaneDict const& planeDefs)
378  : ImageBase<MaskPixelT>(dimensions) {
379  _initializePlanes(planeDefs);
380  *this = initialValue;
381 }
382 
383 template <typename MaskPixelT>
385  : ImageBase<MaskPixelT>(bbox) {
386  _initializePlanes(planeDefs);
387  *this = 0x0;
388 }
389 
390 template <typename MaskPixelT>
391 Mask<MaskPixelT>::Mask(lsst::geom::Box2I const& bbox, MaskPixelT initialValue, MaskPlaneDict const& planeDefs)
392  : ImageBase<MaskPixelT>(bbox) {
393  _initializePlanes(planeDefs);
394  *this = initialValue;
395 }
396 
397 template <typename MaskPixelT>
399  bool const deep)
400  : ImageBase<MaskPixelT>(rhs, bbox, origin, deep), _maskDict(rhs._maskDict) {}
401 
402 template <typename MaskPixelT>
403 Mask<MaskPixelT>::Mask(Mask const& rhs, bool deep)
404  : ImageBase<MaskPixelT>(rhs, deep), _maskDict(rhs._maskDict) {}
405 // Delegate to copy-constructor for backwards compatibility
406 template <typename MaskPixelT>
407 Mask<MaskPixelT>::Mask(Mask&& rhs) : Mask(rhs, false) {}
408 
409 template <typename MaskPixelT>
410 Mask<MaskPixelT>::~Mask() = default;
411 
412 template <typename MaskPixelT>
413 Mask<MaskPixelT>::Mask(ndarray::Array<MaskPixelT, 2, 1> const& array, bool deep,
414  lsst::geom::Point2I const& xy0)
415  : image::ImageBase<MaskPixelT>(array, deep, xy0), _maskDict(detail::MaskDict::makeMaskDict()) {}
416 
417 template <typename PixelT>
419  using std::swap; // See Meyers, Effective C++, Item 25
420 
422  swap(_maskDict, rhs._maskDict);
423 }
424 
425 template <typename PixelT>
427  a.swap(b);
428 }
429 
430 template <typename MaskPixelT>
432  Mask tmp(rhs);
433  swap(tmp); // See Meyers, Effective C++, Item 11
434 
435  return *this;
436 }
437 // Delegate to copy-assignment for backwards compatibility
438 template <typename MaskPixelT>
440  return *this = rhs;
441 }
442 
443 template <typename MaskPixelT>
445  fill_pixels(_getRawView(), rhs);
446 
447  return *this;
448 }
449 
450 #ifndef DOXYGEN // doc for this section is already in header
451 
452 template <typename MaskPixelT>
454  lsst::geom::Box2I const& bbox, ImageOrigin origin, bool conformMasks)
456  fits::Fits fitsfile(fileName, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
457  fitsfile.setHdu(hdu);
458  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
459 }
460 
461 template <typename MaskPixelT>
464  ImageOrigin origin, bool conformMasks)
466  fits::Fits fitsfile(manager, "r", fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
467  fitsfile.setHdu(hdu);
468  *this = Mask(fitsfile, metadata, bbox, origin, conformMasks);
469 }
470 
471 template <typename MaskPixelT>
473  lsst::geom::Box2I const& bbox, ImageOrigin const origin, bool const conformMasks)
475  // These are the permitted input file types
476  typedef boost::mpl::vector<unsigned char, unsigned short, short, std::int32_t> fits_mask_types;
477 
478  if (!metadata) {
480  }
481 
482  fits_read_image<fits_mask_types>(fitsfile, *this, *metadata, bbox, origin);
483 
484  // look for mask planes in the file
485  MaskPlaneDict fileMaskDict = parseMaskPlaneMetadata(metadata);
487 
488  if (*fileMD == *detail::MaskDict::makeMaskDict()) { // file is already consistent with Mask
489  return;
490  }
491 
492  if (conformMasks) { // adopt the definitions in the file
493  _maskDict = detail::MaskDict::setDefaultDict(fileMD);
494  }
495 
496  conformMaskPlanes(fileMaskDict); // convert planes defined by fileMaskDict to the order
497  // defined by Mask::_maskPlaneDict
498 }
499 
500 template <typename MaskPixelT>
501 void Mask<MaskPixelT>::writeFits(std::string const& fileName,
503  std::string const& mode) const {
504  fits::Fits fitsfile(fileName, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
505  writeFits(fitsfile, metadata_i);
506 }
507 
508 template <typename MaskPixelT>
511  std::string const& mode) const {
512  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
513  writeFits(fitsfile, metadata_i);
514 }
515 
516 template <typename MaskPixelT>
519  writeFits(fitsfile, fits::ImageWriteOptions(*this), metadata);
520 }
521 
522 template <typename MaskPixelT>
524  std::string const& mode,
526  fits::Fits fitsfile(filename, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
527  writeFits(fitsfile, options, header);
528 }
529 
530 template <typename MaskPixelT>
532  std::string const& mode,
534  fits::Fits fitsfile(manager, mode, fits::Fits::AUTO_CLOSE | fits::Fits::AUTO_CHECK);
535  writeFits(fitsfile, options, header);
536 }
537 
538 template <typename MaskPixelT>
539 void Mask<MaskPixelT>::writeFits(fits::Fits& fitsfile, fits::ImageWriteOptions const& options,
542  header ? header->deepCopy() : std::make_shared<dafBase::PropertySet>();
543  addMaskPlanesToMetadata(useHeader);
544  fitsfile.writeImage(*this, options, useHeader);
545 }
546 
547 #endif // !DOXYGEN
548 
549 namespace {
550 struct addPlaneFunctor {
551  addPlaneFunctor(std::string const& name, int id) : _name(name), _id(id) {}
552 
553  void operator()(MapWithHash* dict) {
554  detail::MaskPlaneDict::const_iterator const it = // is id already used in this Mask?
555  std::find_if(dict->begin(), dict->end(),
558  std::placeholders::_1),
559  _id));
560  if (it != dict->end()) { // mask plane is already in use
561  return;
562  }
563 
564  if (dict->find(_name) == dict->end()) { // not already set
565  dict->add(_name, _id);
566  }
567  }
568 
570  int _id;
571 };
572 } // namespace
573 
574 template <typename MaskPixelT>
576  std::string result = "";
577  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
578  for (MaskPlaneDict::const_iterator iter = mpd.begin(); iter != mpd.end(); ++iter) {
579  if (value & getBitMask(iter->second)) {
580  if (result.size() > 0) {
581  result += ",";
582  }
583  result += iter->first;
584  }
585  }
586  return result;
587 }
588 
589 template <typename MaskPixelT>
591  int id = getMaskPlaneNoThrow(name); // see if the plane is already available
592 
593  if (id < 0) { // doesn't exist
594  id = _maskPlaneDict()->getUnusedPlane();
595  }
596 
597  // build new entry, adding the plane to all Masks where this is no contradiction
598 
599  if (id >= getNumPlanesMax()) { // Max number of planes is already allocated
601  str(boost::format("Max number of planes (%1%) already used") % getNumPlanesMax()));
602  }
603 
604  _state.forEachMaskDict(addPlaneFunctor(name, id));
605 
606  return id;
607 }
608 
609 template <typename MaskPixelT>
610 int Mask<MaskPixelT>::addMaskPlane(std::string name, int planeId) {
611  if (planeId < 0 || planeId >= getNumPlanesMax()) {
612  throw LSST_EXCEPT(
614  str(boost::format("mask plane ID must be between 0 and %1%") % (getNumPlanesMax() - 1)));
615  }
616 
617  _maskPlaneDict()->add(name, planeId);
618 
619  return planeId;
620 }
621 
622 template <typename MaskPixelT>
624  return _maskDict->getMaskPlaneDict();
625 }
626 
627 template <typename MaskPixelT>
629  if (detail::MaskDict::makeMaskDict()->getMaskPlane(name) < 0) {
631  str(boost::format("Plane %s doesn't exist in the default Mask") % name));
632  }
633 
634  detail::MaskDict::incrDefaultVersion(); // leave current Masks alone
635  _maskPlaneDict()->erase(name);
636 }
637 
638 template <typename MaskPixelT>
639 void Mask<MaskPixelT>::removeAndClearMaskPlane(const std::string& name, bool const removeFromDefault
640 
641 ) {
642  clearMaskPlane(getMaskPlane(name)); // clear this bits in this Mask
643 
644  if (_maskDict == detail::MaskDict::makeMaskDict() && removeFromDefault) { // we are the default
645  ;
646  } else {
647  _maskDict = _maskDict->clone();
648  }
649 
650  _maskDict->erase(name);
651 
652  if (removeFromDefault && detail::MaskDict::makeMaskDict()->getMaskPlane(name) >= 0) {
653  removeMaskPlane(name);
654  }
655 }
656 
657 template <typename MaskPixelT>
658 MaskPixelT Mask<MaskPixelT>::getBitMaskNoThrow(int planeId) {
659  return (planeId >= 0 && planeId < getNumPlanesMax()) ? (1 << planeId) : 0;
660 }
661 
662 template <typename MaskPixelT>
663 MaskPixelT Mask<MaskPixelT>::getBitMask(int planeId) {
664  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
665 
666  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end(); ++i) {
667  if (planeId == i->second) {
668  MaskPixelT const bitmask = getBitMaskNoThrow(planeId);
669  if (bitmask == 0) { // failed
670  break;
671  }
672  return bitmask;
673  }
674  }
676  str(boost::format("Invalid mask plane ID: %d") % planeId));
677 }
678 
679 template <typename MaskPixelT>
681  int const plane = getMaskPlaneNoThrow(name);
682 
683  if (plane < 0) {
685  str(boost::format("Invalid mask plane name: %s") % name));
686  } else {
687  return plane;
688  }
689 }
690 
691 template <typename MaskPixelT>
693  return _maskPlaneDict()->getMaskPlane(name);
694 }
695 
696 template <typename MaskPixelT>
698  return getBitMask(getMaskPlane(name));
699 }
700 
701 template <typename MaskPixelT>
703  MaskPixelT mpix = 0x0;
704  for (std::vector<std::string>::const_iterator it = name.begin(); it != name.end(); ++it) {
705  mpix |= getBitMask(getMaskPlane(*it));
706  }
707  return mpix;
708 }
709 
710 template <typename MaskPixelT>
712  return _maskPlaneDict()->size();
713 }
714 
715 template <typename MaskPixelT>
717  _maskPlaneDict()->clear();
718 }
719 
720 template <typename MaskPixelT>
722  *this = 0;
723 }
724 
725 template <typename MaskPixelT>
727  *this &= ~getBitMask(planeId);
728 }
729 
730 template <typename MaskPixelT>
731 void Mask<MaskPixelT>::conformMaskPlanes(MaskPlaneDict const& currentPlaneDict) {
733 
734  if (*_maskDict == *currentMD) {
735  if (*detail::MaskDict::makeMaskDict() == *_maskDict) {
736  return; // nothing to do
737  }
738  } else {
739  //
740  // Find out which planes need to be permuted
741  //
742  MaskPixelT keepBitmask = 0; // mask of bits to keep
743  MaskPixelT canonicalMask[sizeof(MaskPixelT) * 8]; // bits in lsst::afw::image::Mask that should be
744  MaskPixelT currentMask[sizeof(MaskPixelT) * 8]; // mapped to these bits
745  int numReMap = 0;
746 
747  for (MaskPlaneDict::const_iterator i = currentPlaneDict.begin(); i != currentPlaneDict.end(); i++) {
748  std::string const name = i->first; // name of mask plane
749  int const currentPlaneNumber = i->second; // plane number currently in use
750  int canonicalPlaneNumber = getMaskPlaneNoThrow(name); // plane number in lsst::afw::image::Mask
751 
752  if (canonicalPlaneNumber < 0) { // no such plane; add it
753  canonicalPlaneNumber = addMaskPlane(name);
754  }
755 
756  if (canonicalPlaneNumber == currentPlaneNumber) {
757  keepBitmask |= getBitMask(canonicalPlaneNumber); // bit is unchanged, so preserve it
758  } else {
759  canonicalMask[numReMap] = getBitMask(canonicalPlaneNumber);
760  currentMask[numReMap] = getBitMaskNoThrow(currentPlaneNumber);
761  numReMap++;
762  }
763  }
764 
765  // Now loop over all pixels in Mask
766  if (numReMap > 0) {
767  for (int r = 0; r != this->getHeight(); ++r) { // "this->": Meyers, Effective C++, Item 43
768  for (typename Mask::x_iterator ptr = this->row_begin(r), end = this->row_end(r); ptr != end;
769  ++ptr) {
770  MaskPixelT const pixel = *ptr;
771 
772  MaskPixelT newPixel = pixel & keepBitmask; // value of invariant mask bits
773  for (int i = 0; i < numReMap; i++) {
774  if (pixel & currentMask[i]) newPixel |= canonicalMask[i];
775  }
776 
777  *ptr = newPixel;
778  }
779  }
780  }
781  }
782  // We've made the planes match the current mask dictionary
783  _maskDict = detail::MaskDict::makeMaskDict();
784 }
785 
786 template <typename MaskPixelT>
788  return this->ImageBase<MaskPixelT>::operator()(x, y);
789 }
790 
791 template <typename MaskPixelT>
793  CheckIndices const& check) {
794  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
795 }
796 
797 template <typename MaskPixelT>
799  return this->ImageBase<MaskPixelT>::operator()(x, y);
800 }
801 
802 template <typename MaskPixelT>
804  int x, int y, CheckIndices const& check) const {
805  return this->ImageBase<MaskPixelT>::operator()(x, y, check);
806 }
807 
808 template <typename MaskPixelT>
809 bool Mask<MaskPixelT>::operator()(int x, int y, int planeId) const {
810  // !! converts an int to a bool
811  return !!(this->ImageBase<MaskPixelT>::operator()(x, y) & getBitMask(planeId));
812 }
813 
814 template <typename MaskPixelT>
815 bool Mask<MaskPixelT>::operator()(int x, int y, int planeId, CheckIndices const& check) const {
816  // !! converts an int to a bool
817  return !!(this->ImageBase<MaskPixelT>::operator()(x, y, check) & getBitMask(planeId));
818 }
819 
820 template <typename MaskPixelT>
822  if (*_maskDict != *other._maskDict) {
823  throw LSST_EXCEPT(pexExcept::RuntimeError, "Mask dictionaries do not match");
824  }
825 }
826 
827 template <typename MaskPixelT>
829  transform_pixels(_getRawView(), _getRawView(),
830  [&val](MaskPixelT const& l) -> MaskPixelT { return l | val; });
831  return *this;
832 }
833 
834 template <typename MaskPixelT>
836  checkMaskDictionaries(rhs);
837 
838  if (this->getDimensions() != rhs.getDimensions()) {
840  str(boost::format("Images are of different size, %dx%d v %dx%d") %
841  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
842  }
843  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
844  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l | r; });
845  return *this;
846 }
847 
848 template <typename MaskPixelT>
850  transform_pixels(_getRawView(), _getRawView(), [&val](MaskPixelT const& l) { return l & val; });
851  return *this;
852 }
853 
854 template <typename MaskPixelT>
856  checkMaskDictionaries(rhs);
857 
858  if (this->getDimensions() != rhs.getDimensions()) {
860  str(boost::format("Images are of different size, %dx%d v %dx%d") %
861  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
862  }
863  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
864  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l & r; });
865  return *this;
866 }
867 
868 template <typename MaskPixelT>
870  transform_pixels(_getRawView(), _getRawView(),
871  [&val](MaskPixelT const& l) -> MaskPixelT { return l ^ val; });
872  return *this;
873 }
874 
875 template <typename MaskPixelT>
877  checkMaskDictionaries(rhs);
878 
879  if (this->getDimensions() != rhs.getDimensions()) {
881  str(boost::format("Images are of different size, %dx%d v %dx%d") %
882  this->getWidth() % this->getHeight() % rhs.getWidth() % rhs.getHeight()));
883  }
884  transform_pixels(_getRawView(), rhs._getRawView(), _getRawView(),
885  [](MaskPixelT const& l, MaskPixelT const& r) -> MaskPixelT { return l ^ r; });
886  return *this;
887 }
888 
889 template <typename MaskPixelT>
890 void Mask<MaskPixelT>::setMaskPlaneValues(int const planeId, int const x0, int const x1, int const y) {
891  MaskPixelT const bitMask = getBitMask(planeId);
892 
893  for (int x = x0; x <= x1; x++) {
894  operator()(x, y) = operator()(x, y) | bitMask;
895  }
896 }
897 
898 template <typename MaskPixelT>
900  if (!metadata) {
901  throw LSST_EXCEPT(pexExcept::InvalidParameterError, "Null std::shared_ptr<PropertySet>");
902  }
903 
904  // First, clear existing MaskPlane metadata
905  typedef std::vector<std::string> NameList;
906  NameList paramNames = metadata->paramNames(false);
907  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
908  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
909  metadata->remove(*i);
910  }
911  }
912 
913  MaskPlaneDict const& mpd = _maskPlaneDict()->getMaskPlaneDict();
914 
915  // Add new MaskPlane metadata
916  for (MaskPlaneDict::const_iterator i = mpd.begin(); i != mpd.end(); ++i) {
917  std::string const& planeName = i->first;
918  int const planeNumber = i->second;
919 
920  if (planeName != "") {
921  metadata->add(maskPlanePrefix + planeName, planeNumber);
922  }
923  }
924 }
925 
926 template <typename MaskPixelT>
929  MaskPlaneDict newDict;
930 
931  // First, clear existing MaskPlane metadata
932  typedef std::vector<std::string> NameList;
933  NameList paramNames = metadata->paramNames(false);
934  int numPlanesUsed = 0; // number of planes used
935 
936  // Iterate over childless properties with names starting with maskPlanePrefix
937  for (NameList::const_iterator i = paramNames.begin(); i != paramNames.end(); ++i) {
938  if (i->compare(0, maskPlanePrefix.size(), maskPlanePrefix) == 0) {
939  // split off maskPlanePrefix to obtain plane name
940  std::string planeName = i->substr(maskPlanePrefix.size());
941  int const planeId = metadata->getAsInt(*i);
942 
943  MaskPlaneDict::const_iterator plane = newDict.find(planeName);
944  if (plane != newDict.end() && planeId != plane->second) {
945  throw LSST_EXCEPT(pexExcept::RuntimeError, "File specifies plane " + planeName + " twice");
946  }
947  for (MaskPlaneDict::const_iterator j = newDict.begin(); j != newDict.end(); ++j) {
948  if (planeId == j->second) {
950  str(boost::format("File specifies plane %s has same value (%d) as %s") %
951  planeName % planeId % j->first));
952  }
953  }
954  // build new entry
955  if (numPlanesUsed >= getNumPlanesMax()) {
956  // Max number of planes already allocated
957  throw LSST_EXCEPT(
959  str(boost::format("Max number of planes (%1%) already used") % getNumPlanesMax()));
960  }
961  newDict[planeName] = planeId;
962  }
963  }
964  return newDict;
965 }
966 
967 template <typename MaskPixelT>
969  _maskDict->print();
970 }
971 
972 /*
973  * Static members of Mask
974  */
975 template <typename MaskPixelT>
977 
978 template <typename MaskPixelT>
981 }
982 
983 //
984 // Explicit instantiations
985 //
986 template class Mask<MaskPixel>;
987 } // namespace image
988 } // namespace afw
989 } // namespace lsst
static std::string interpret(MaskPixelT value)
Interpret a mask value as a comma-separated list of mask plane names.
Definition: Mask.cc:575
afw::table::PointKey< int > dimensions
Definition: GaussianPsf.cc:44
uint64_t * ptr
Definition: RangeSet.cc:88
T empty(T... args)
static void clearMaskPlaneDict()
Reset the maskPlane dictionary.
Definition: Mask.cc:716
std::string const & _name
Definition: Mask.cc:569
def erase(frame=None)
Definition: ds9.py:101
static int getMaskPlane(const std::string &name)
Return the mask plane number corresponding to a plane name.
Definition: Mask.cc:680
T swap(T... args)
Class for storing ordered metadata with comments.
Definition: PropertyList.h:72
int getHeight() const
Return the number of rows in the image.
Definition: ImageBase.h:321
table::Box2IKey bbox
table::Key< int > b
std::map< std::string, int > MaskPlaneDict
Definition: Mask.h:65
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
Options for writing an image to FITS.
Definition: fits.h:218
Mask & operator=(MaskPixelT const rhs)
Definition: Mask.cc:444
T endl(T... args)
py::object result
Definition: schema.cc:284
T max_element(T... args)
_view_t::x_iterator x_iterator
An iterator for traversing the pixels in a row.
Definition: ImageBase.h:135
int y
Definition: SpanSet.cc:44
table::Key< int > a
bool operator!=(CoordKey const &lhs, CoordKey const &rhs)
Compare CoordKeys for equality using the constituent Keys.
bool operator==(CoordKey const &lhs, CoordKey const &rhs)
Compare CoordKeys for equality using the constituent Keys.
ImageT val
Definition: CR.cc:146
T end(T... args)
tuple options
Definition: lsstimport.py:53
static void addMaskPlanesToMetadata(std::shared_ptr< lsst::daf::base::PropertySet >)
Given a PropertySet, replace any existing MaskPlane assignments with the current ones.
Definition: Mask.cc:899
static int getNumPlanesUsed()
Definition: Mask.cc:711
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:296
The base class for all image classed (Image, Mask, MaskedImage, ...)
Definition: ImageBase.h:104
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:639
static MaskPlaneDict parseMaskPlaneMetadata(std::shared_ptr< lsst::daf::base::PropertySet const > metadata)
Given a PropertySet that contains the MaskPlane assignments, setup the MaskPlanes.
Definition: Mask.cc:927
x_iterator row_begin(int y) const
Return an x_iterator to the start of the y&#39;th row.
Definition: ImageBase.h:424
#define LOGL_DEBUG(logger, message...)
Log a debug-level message using a varargs/printf style interface.
Definition: Log.h:513
ImageBase< MaskPixelT >::PixelReference operator()(int x, int y)
get a reference to the specified pixel
Definition: Mask.cc:787
iterator end() const
Return an STL compliant iterator to the end of the image.
Definition: Image.cc:275
STL class.
LSST DM logging module built on log4cxx.
Mask(unsigned int width, unsigned int height, MaskPlaneDict const &planeDefs=MaskPlaneDict())
Construct a Mask initialized to 0x0.
Definition: Mask.cc:354
int getMaskPlane(const std::string &name) const
Definition: Mask.cc:318
A base class for image defects.
Definition: cameraGeom.dox:3
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:84
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:120
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:134
void setMaskPlaneValues(const int plane, const int x0, const int x1, const int y)
Set the bit specified by "planeId" for pixels (x0, y) ...
Definition: Mask.cc:890
T bind(T... args)
A class used to request that array accesses be checked.
Definition: ImageBase.h:76
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:702
void swap(ImageBase &rhs)
Definition: Image.cc:253
double x
MaskPlaneDict const & getMaskPlaneDict() const
Return the Mask&#39;s maskPlaneDict.
Definition: Mask.cc:623
void setHdu(int hdu, bool relative=false)
Set the current HDU.
Definition: fits.cc:478
int id
Definition: CR.cc:143
int _id
Definition: Mask.cc:570
T get(T... args)
static std::shared_ptr< MaskDict > incrDefaultVersion()
Definition: Mask.cc:290
T find(T... args)
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:47
static void removeMaskPlane(const std::string &name)
Definition: Mask.cc:628
static std::shared_ptr< MaskDict > makeMaskDict()
Definition: Mask.cc:262
static int getNumPlanesMax()
Definition: Mask.h:492
T begin(T... args)
Mask & operator &=(Mask const &rhs)
AND a Mask into a Mask.
int getWidth() const
Return the number of columns in the image.
Definition: ImageBase.h:319
Extent< int, 2 > ExtentI
Definition: Extent.h:390
std::shared_ptr< MaskDict > clone() const
Definition: Mask.cc:280
Reports invalid arguments.
Definition: Runtime.h:66
Mask & operator|=(Mask const &rhs)
OR a Mask into a Mask.
Definition: Mask.cc:835
x_iterator row_end(int y) const
Return an x_iterator to the end of the y&#39;th row.
Definition: ImageBase.h:427
T substr(T... args)
table::PointKey< int > pixel
ItemVariant const * other
Definition: Schema.cc:55
void swap(Mask &rhs)
Definition: Mask.cc:418
static std::shared_ptr< MaskDict > setDefaultDict(std::shared_ptr< MaskDict > dict)
Definition: Mask.cc:276
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:731
void writeFits(std::string const &fileName, std::shared_ptr< lsst::daf::base::PropertySet const > metadata=std::shared_ptr< lsst::daf::base::PropertySet >(), std::string const &mode="w") const
Write a mask to a regular FITS file.
lsst::geom::Extent2I getDimensions() const
Return the image&#39;s size; useful for passing to constructors.
Definition: ImageBase.h:379
Mask & operator^=(Mask const &rhs)
XOR a Mask into a Mask.
Definition: Mask.cc:876
void clearMaskPlane(int plane)
Clear the specified bit in all pixels.
Definition: Mask.cc:726
void writeImage(ndarray::Array< T const, N, C > const &array)
Write an ndarray::Array to a FITS image HDU.
Definition: fits.h:476
An integer coordinate rectangle.
Definition: Box.h:54
void clearAllMaskPlanes()
Clear all the pixels.
Definition: Mask.cc:721
Reports when the result of an operation cannot be represented by the destination type.
Definition: Runtime.h:115
static int addMaskPlane(const std::string &name)
Definition: Mask.cc:590
PixelReference operator()(int x, int y)
Definition: Image.cc:190
int end
Definition: BoundedField.cc:99
Reports errors that are due to events beyond the control of the program.
Definition: Runtime.h:104
void printMaskPlanes() const
print the mask plane dictionary to std::cout
Definition: Mask.cc:968