//# Copyright (C) 1998,1999,2000,2001,2003 //# Associated Universities, Inc. Washington DC, USA. //# //# This library is free software; you can redistribute it and/or modify it //# under the terms of the GNU Library General Public License as published by //# the Free Software Foundation; either version 2 of the License, or (at your //# option) any later version. //# //# This library 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 Library General Public //# License for more details. //# //# You should have received a copy of the GNU Library General Public License //# along with this library; 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 //# #include <imageanalysis/ImageAnalysis/SubImageFactory.h> #include <casacore/casa/BasicSL/String.h> #include <casacore/tables/LogTables/NewFile.h> #include <casacore/images/Images/ExtendImage.h> #include <casacore/images/Images/ImageExpr.h> #include <casacore/images/Images/ImageUtilities.h> #include <casacore/images/Images/SubImage.h> #include <casacore/images/Images/PagedImage.h> #include <casacore/images/Regions/WCLELMask.h> #include <casacore/lattices/LRegions/LCMask.h> #include <casacore/lattices/Lattices/LatticeUtilities.h> #include <imageanalysis/ImageAnalysis/ImageMask.h> #include <imageanalysis/ImageAnalysis/ImageMaskAttacher.h> #include <imageanalysis/ImageAnalysis/ImageMaskHandler.h> // debug #include <components/ComponentModels/C11Timer.h> namespace casa { template<class T> std::shared_ptr<casacore::SubImage<T> > SubImageFactory<T>::createSubImageRW( casacore::CountedPtr<casacore::ImageRegion>& outRegion, casacore::CountedPtr<casacore::ImageRegion>& outMask, casacore::ImageInterface<T>& inImage, const casacore::Record& region, const casacore::String& mask, casacore::LogIO *const &os, const casacore::AxesSpecifier& axesSpecifier, casacore::Bool extendMask, casacore::Bool preserveAxesOrder ) { if (! mask.empty()) { _getMask(outMask, mask, extendMask, inImage.shape(), inImage.coordinates()); } std::shared_ptr<casacore::SubImage<T> > subImage; // We can get away with no region processing if the region record // is empty and the user is not dropping degenerate axes if (region.nfields() == 0 && axesSpecifier.keep()) { subImage.reset( ! outMask ? new casacore::SubImage<T>(inImage, true, axesSpecifier, preserveAxesOrder) : new casacore::SubImage<T>( inImage, *outMask, true, axesSpecifier, preserveAxesOrder ) ); } else { outRegion = casacore::ImageRegion::fromRecord( os, inImage.coordinates(), inImage.shape(), region ); if (! outMask) { subImage.reset( new casacore::SubImage<T>( inImage, *outRegion, true, axesSpecifier, preserveAxesOrder ) ); } else { // on the first pass, we need to keep all axes, the second // casacore::SubImage construction after this one will properly account // for the axes specifier casacore::SubImage<T> subImage0( inImage, *outMask, true, casacore::AxesSpecifier(), preserveAxesOrder ); subImage.reset( new casacore::SubImage<T>( subImage0, *outRegion, true, axesSpecifier, preserveAxesOrder ) ); } } return subImage; } template<class T> std::shared_ptr<casacore::SubImage<T> > SubImageFactory<T>::createSubImageRW( casacore::ImageInterface<T>& inImage, const casacore::Record& region, const casacore::String& mask, casacore::LogIO *const &os, const casacore::AxesSpecifier& axesSpecifier, casacore::Bool extendMask, casacore::Bool preserveAxesOrder ) { casacore::CountedPtr<casacore::ImageRegion> pRegion; casacore::CountedPtr<casacore::ImageRegion> pMask; return createSubImageRW( pRegion, pMask, inImage, region, mask, os, axesSpecifier, extendMask, preserveAxesOrder ); } template<class T> std::shared_ptr<const casacore::SubImage<T> > SubImageFactory<T>::createSubImageRO( casacore::CountedPtr<casacore::ImageRegion>& outRegion, casacore::CountedPtr<casacore::ImageRegion>& outMask, const casacore::ImageInterface<T>& inImage, const casacore::Record& region, const casacore::String& mask, casacore::LogIO *const &os, const casacore::AxesSpecifier& axesSpecifier, casacore::Bool extendMask, casacore::Bool preserveAxesOrder ) { if (! mask.empty()) { _getMask(outMask, mask, extendMask, inImage.shape(), inImage.coordinates()); } std::shared_ptr<casacore::SubImage<T> > subImage; // We can get away with no region processing if the region record // is empty and the user is not dropping degenerate axes if (region.nfields() == 0 && axesSpecifier.keep()) { subImage.reset( ! outMask ? new casacore::SubImage<T>(inImage, axesSpecifier, preserveAxesOrder) : new casacore::SubImage<T>( inImage, *outMask, axesSpecifier, preserveAxesOrder ) ); } else { outRegion = casacore::ImageRegion::fromRecord( os, inImage.coordinates(), inImage.shape(), region ); if (! outMask) { subImage.reset( new casacore::SubImage<T>( inImage, *outRegion, axesSpecifier, preserveAxesOrder ) ); } else { // on the first pass, we need to keep all axes, the second // casacore::SubImage construction after this one will properly account // for the axes specifier casacore::SubImage<T> subImage0( inImage, *outMask, casacore::AxesSpecifier(), preserveAxesOrder ); subImage.reset( new casacore::SubImage<T>( subImage0, *outRegion, axesSpecifier, preserveAxesOrder ) ); } } return subImage; } template<class T> std::shared_ptr<const casacore::SubImage<T> > SubImageFactory<T>::createSubImageRO( const casacore::ImageInterface<T>& inImage, const casacore::Record& region, const casacore::String& mask, casacore::LogIO *const &os, const casacore::AxesSpecifier& axesSpecifier, casacore::Bool extendMask, casacore::Bool preserveAxesOrder ) { casacore::CountedPtr<casacore::ImageRegion> pRegion; casacore::CountedPtr<casacore::ImageRegion> pMask; return createSubImageRO( pRegion, pMask, inImage, region, mask, os, axesSpecifier, extendMask, preserveAxesOrder ); } template<class T> SPIIT SubImageFactory<T>::createImage( const casacore::ImageInterface<T>& image, const casacore::String& outfile, const casacore::Record& region, const casacore::String& mask, casacore::Bool dropDegenerateAxes, casacore::Bool overwrite, casacore::Bool list, casacore::Bool extendMask, casacore::Bool attachMask, const casacore::Lattice<T> *const data ) { return createImage( image, outfile, region, mask, casacore::AxesSpecifier(! dropDegenerateAxes), overwrite, list, extendMask, attachMask, data ); } template<class T> SPIIT SubImageFactory<T>::createImage( const casacore::ImageInterface<T>& image, const casacore::String& outfile, const casacore::Record& region, const casacore::String& mask, const casacore::AxesSpecifier& axesSpec, casacore::Bool overwrite, casacore::Bool list, casacore::Bool extendMask, casacore::Bool attachMask, const casacore::Lattice<T> *const data ) { casacore::LogIO log; log << casacore::LogOrigin("SubImageFactory", __func__); // Copy a portion of the image // Verify output file if (! overwrite && ! outfile.empty()) { casacore::NewFile validfile; casacore::String errmsg; if(! validfile.valueOK(outfile, errmsg)) { // CAS-8715 users want a nicer error message in this case if (casacore::File(outfile).exists()) { errmsg = outfile + " already exists"; } ThrowCc(errmsg); } } std::shared_ptr<const casacore::SubImage<T> > x = createSubImageRO( image, region, mask, list ? &log : 0, axesSpec, extendMask, true ); SPIIT outImage; if (outfile.empty()) { outImage.reset( new casacore::TempImage<T>(x->shape(), x->coordinates()) ); } else { outImage.reset( new casacore::PagedImage<T>( x->shape(), x->coordinates(), outfile ) ); if (list) { log << casacore::LogIO::NORMAL << "Creating image '" << outfile << "' of shape " << outImage->shape() << casacore::LogIO::POST; } } casacore::ImageUtilities::copyMiscellaneous(*outImage, *x); if (attachMask || ! ImageMask::isAllMaskTrue(*x)) { // if we don't already have a mask, but the user has specified that one needs to // be present, attach it. This needs to be done prior to the copyDataAndMask() call // because in that implementation, the image to which the mask is to be copied must // have already have a mask; that call does not create one if it does not exist. casacore::String maskName = ""; ImageMaskAttacher::makeMask(*outImage, maskName, false, true, log, list); if (data) { ImageMaskHandler<T> imh(outImage); imh.copy(*x); } } if (data) { outImage->copyData(*data); } else { casacore::LatticeUtilities::copyDataAndMask(log, *outImage, *x); } outImage->flush(); return outImage; } template<class T> void SubImageFactory<T>::_getMask( casacore::CountedPtr<casacore::ImageRegion>& outMask, const casacore::String& mask, casacore::Bool extendMask, const casacore::IPosition& imageShape, const casacore::CoordinateSystem& csys ) { casacore::String mymask = mask; for (casacore::uInt i=0; i<2; i++) { try { outMask = casacore::ImageRegion::fromLatticeExpression(mymask); break; } catch (const casacore::AipsError& x) { if (i == 0) { // not an LEL expression, perhaps it's a clean mask image name mymask += ">=0.5"; continue; } ThrowCc("Input mask specification is incorrect: " + x.getMesg()); } } if (outMask && outMask->asWCRegion().type() == "WCLELMask") { const casacore::ImageExpr<casacore::Bool> *myExpression = dynamic_cast<const casacore::WCLELMask*>( outMask->asWCRegionPtr() )->getImageExpr(); if ( myExpression && ! myExpression->shape().isEqual(imageShape) ) { if (! extendMask) { ostringstream os; os << "The input image shape (" << imageShape << ") and mask shape (" << myExpression->shape() << ") are different, and it was specified " "that the mask should not be extended, so the mask cannot be applied to the " "(sub)image. Specifying that the mask should be extended may resolve the issue"; ThrowCc(os.str()); } try { casacore::ExtendImage<casacore::Bool> exIm(*myExpression, imageShape, csys); outMask = new casacore::ImageRegion(casacore::LCMask(exIm)); } catch ( const std::exception &x ) { ThrowCc( String("Unable to extend mask: ") + x.what() ); } } } } }