//# Copyright (C) 1998,1999,2000,2001,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This program is free software; you can redistribute it and/or modify it //# under the terms of the GNU General Public License as published by the Free //# Software Foundation; either version 2 of the License, or (at your option) //# any later version. //# //# This program is distributed in the hope that it will be useful, but WITHOUT //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for //# more details. //# //# You should have received a copy of the GNU General Public License along //# with this program; if not, write to the Free Software Foundation, Inc., //# 675 Massachusetts Ave, Cambridge, MA 02139, USA. //# //# Correspondence concerning AIPS++ should be addressed as follows: //# Internet email: aips2-request@nrao.edu. //# Postal address: AIPS++ Project Office //# National Radio Astronomy Observatory //# 520 Edgemont Road //# Charlottesville, VA 22903-2475 USA //# //# $Id: $ #include <imageanalysis/ImageAnalysis/ImageMaskHandler.h> #include <imageanalysis/ImageAnalysis/ImageFactory.h> #include <casacore/casa/Exceptions/Error.h> #include <casacore/images/Images/ImageExprParse.h> #include <casacore/images/Images/ImageProxy.h> #include <casacore/images/Regions/RegionHandler.h> namespace casa { template <class T> ImageMaskHandler<T>::ImageMaskHandler(SPIIT image) : _image(image) {} template <class T> ImageMaskHandler<T>::~ImageMaskHandler() {} template <class T> void ImageMaskHandler<T>::set(const casacore::String& name) { _image->setDefaultMask(name); } template <class T> casacore::String ImageMaskHandler<T>::defaultMask() const { return _image->getDefaultMask(); } template <class T> void ImageMaskHandler<T>::deleteMasks( const std::set<casacore::String>& masks ) { ThrowIf(masks.empty(), "You have not supplied any mask names"); for (const auto& mask: masks) { _image->removeRegion(mask, casacore::RegionHandler::Masks, false); } } template <class T> void ImageMaskHandler<T>::rename( const casacore::String& oldName, const casacore::String& newName ) { _image->renameRegion(newName, oldName, casacore::RegionHandler::Masks, false); } template <class T> casacore::Vector<casacore::String> ImageMaskHandler<T>::get() const { return _image->regionNames(casacore::RegionHandler::Masks); } template <class T> void ImageMaskHandler<T>::copy( const casacore::String& currentName, const casacore::String& newName ) { ThrowIf(_image->hasRegion( newName, casacore::RegionHandler::Any), "Mask " + newName + " already exists" ); casacore::Vector<casacore::String> mask2 = stringToVector(currentName, ':'); ThrowIf(mask2.size() > 2, "Illegal mask specification " + currentName); auto external = mask2.size() == 2; _image->makeMask(newName, true, false); if (external) { casacore::ImageProxy proxy(casacore::Vector<casacore::String>(1, mask2[0]), 0); ThrowIf( ! proxy.shape().isEqual(_image->shape()), "Images have different shapes" ); auto imagePtrs = ImageFactory::fromFile(mask2[0]); if (auto myImage = std::get<0>(imagePtrs)) { casacore::ImageUtilities::copyMask( *_image, *myImage, newName, mask2[1], casacore::AxesSpecifier() ); } else if (auto myimage = std::get<1>(imagePtrs)) { casacore::ImageUtilities::copyMask( *_image, *myimage, newName, mask2[1], casacore::AxesSpecifier() ); } else { ThrowCc("This image pixel data type not supported"); } } else { casacore::ImageUtilities::copyMask( *_image, *_image, newName, mask2[0], casacore::AxesSpecifier() ); } } template <class T> template<class U> void ImageMaskHandler<T>::copy( const casacore::MaskedLattice<U>& mask ) { auto shape = _image->shape(); ThrowIf ( ! shape.isEqual(mask.shape()), "Mask must be the same shape as the image" ); auto cursorShape = _image->niceCursorShape(4096*4096); casacore::LatticeStepper stepper(shape, cursorShape, casacore::LatticeStepper::RESIZE); if (! _image->hasPixelMask()) { if (ImageMask::isAllMaskTrue(mask)) { // the current image has no pixel mask and the mask is all true, so // there is no point in copying anything. return; } casacore::String maskname = ""; casacore::LogIO log; ImageMaskAttacher::makeMask(*_image, maskname, false, true, log, false); } casacore::Lattice<casacore::Bool>& pixelMask = _image->pixelMask(); casacore::LatticeIterator<casacore::Bool> iter(pixelMask, stepper); casacore::RO_MaskedLatticeIterator<U> miter(mask, stepper); for (iter.reset(); ! iter.atEnd(); ++iter, ++miter) { auto mymask = miter.getMask(); iter.rwCursor() = mymask; } } template <class T> void ImageMaskHandler<T>::calcmask( const casacore::String& mask, casacore::Record& regions, const casacore::String& maskName, const casacore::Bool makeDefault ) { ThrowIf(mask.empty(), "You must specify an expression"); ThrowIf ( ! _image->canDefineRegion(), "Cannot make requested mask for this image type which is " + _image->imageType() ); casacore::Block<casacore::LatticeExprNode> temps; casacore::PtrBlock<const casacore::ImageRegion*> tempRegs; _makeRegionBlock(tempRegs, regions); casacore::LatticeExprNode node = casacore::ImageExprParse::command(mask, temps, tempRegs); // Delete the ImageRegions _makeRegionBlock(tempRegs, casacore::Record()); // Make sure the expression is Boolean DataType type = node.dataType(); ThrowIf(type != TpBool, "The expression type must be Boolean"); _calcmask(node, maskName, makeDefault); } template<class T> void ImageMaskHandler<T>::_calcmask( const casacore::LatticeExprNode& node, const casacore::String& maskName, const casacore::Bool makeDefault ) { // Get the shape of the expression and check it matches that // of the output image. We don't check that the Coordinates // match as that would be an un-necessary restriction. if ( ! node.isScalar() && ! _image->shape().isEqual(node.shape()) ) { ostringstream os; os << "The shape of the expression does not conform " << "with the shape of the output image" << "Expression shape = " << node.shape() << "Image shape = " << _image->shape(); ThrowCc(os.str()); } // Make mask and get hold of its name. Currently new mask is forced to // be default because of other problems. Cannot use the usual ImageMaskAttacher<casacore::Float>::makeMask // function because I cant attach/make it default until the expression // has been evaluated // Generate mask name if not given casacore::String maskName2 = maskName.empty() ? _image->makeUniqueRegionName( casacore::String("mask"), 0 ) : maskName; // Make the mask if it does not exist if (! _image->hasRegion(maskName2, casacore::RegionHandler::Masks)) { _image->makeMask(maskName2, true, false); casacore::LogIO log; log << casacore::LogOrigin("ImageMaskHandler", __func__); log << casacore::LogIO::NORMAL << "Created mask `" << maskName2 << "'" << casacore::LogIO::POST; casacore::ImageRegion iR = _image->getRegion( maskName2, casacore::RegionHandler::Masks ); casacore::LCRegion& mask = iR.asMask(); if (node.isScalar()) { casacore::Bool value = node.getBool(); mask.set(value); } else { mask.copyData(casacore::LatticeExpr<casacore::Bool> (node)); } } else { // Access pre-existing mask. casacore::ImageRegion iR = _image->getRegion( maskName2, casacore::RegionHandler::Masks ); casacore::LCRegion& mask2 = iR.asMask(); if (node.isScalar()) { casacore::Bool value = node.getBool(); mask2.set(value); } else { mask2.copyData(casacore::LatticeExpr<casacore::Bool> (node)); } } if (makeDefault) { _image->setDefaultMask(maskName2); } } template<class T> void ImageMaskHandler<T>::_makeRegionBlock( casacore::PtrBlock<const casacore::ImageRegion*>& regions, const casacore::Record& Regions ) { auto n = regions.size(); for (casacore::uInt j=0; j<n; ++j) { delete regions[j]; } regions.resize(0, true, true); casacore::uInt nreg = Regions.nfields(); if (nreg > 0) { regions.resize(nreg); regions.set(static_cast<casacore::ImageRegion*> (0)); for (casacore::uInt i=0; i<nreg; ++i) { regions[i] = casacore::ImageRegion::fromRecord(Regions.asRecord(i), ""); } } } }