Line data Source code
1 : //# SDMaskHandler.cc: Implementation of SDMaskHandler classes
2 : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
3 : //# Associated Universities, Inc. Washington DC, USA.
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id$
27 : #include <stack>
28 : #include <casacore/casa/Arrays/ArrayMath.h>
29 : #include <casacore/casa/OS/HostInfo.h>
30 : #include <components/ComponentModels/SkyComponent.h>
31 : #include <components/ComponentModels/ComponentList.h>
32 : #include <casacore/images/Images/ImageRegrid.h>
33 : #include <casacore/images/Images/TempImage.h>
34 : #include <casacore/images/Images/SubImage.h>
35 : #include <casacore/images/Regions/ImageRegion.h>
36 : #include <casacore/images/Regions/RegionManager.h>
37 : #include <casacore/images/Regions/RegionHandler.h>
38 : #include <casacore/images/Regions/WCBox.h>
39 : #include <casacore/images/Regions/WCUnion.h>
40 : #include <imageanalysis/ImageAnalysis/CasaImageBeamSet.h>
41 : #include <imageanalysis/ImageAnalysis/ImageDecomposer.h>
42 : #include <imageanalysis/ImageAnalysis/ImageStatsCalculator.h>
43 : #include <imageanalysis/ImageAnalysis/Image2DConvolver.h>
44 : #include <imageanalysis/ImageAnalysis/ImageRegridder.h>
45 : #include <casacore/casa/OS/File.h>
46 : #include <casacore/lattices/LEL/LatticeExpr.h>
47 : #include <casacore/lattices/Lattices/TiledLineStepper.h>
48 : #include <casacore/lattices/Lattices/LatticeStepper.h>
49 : #include <casacore/lattices/Lattices/LatticeIterator.h>
50 : #include <casacore/lattices/Lattices/LatticeUtilities.h>
51 : #include <casacore/lattices/LRegions/LCEllipsoid.h>
52 : #include <casacore/lattices/LRegions/LCUnion.h>
53 : #include <casacore/lattices/LRegions/LCExtension.h>
54 : #include <casacore/lattices/LRegions/LCPagedMask.h>
55 : #include <synthesis/TransformMachines/StokesImageUtil.h>
56 : #include <casacore/coordinates/Coordinates/CoordinateUtil.h>
57 : #include <casacore/coordinates/Coordinates/StokesCoordinate.h>
58 : #include <casacore/casa/Exceptions/Error.h>
59 : #include <casacore/casa/BasicSL/String.h>
60 : #include <casacore/casa/Utilities/Assert.h>
61 : #include <casacore/casa/OS/Directory.h>
62 : #include <casacore/tables/Tables/TableLock.h>
63 :
64 : #include <sstream>
65 :
66 : #include <casacore/casa/Logging/LogMessage.h>
67 : #include <casacore/casa/Logging/LogIO.h>
68 : #include <casacore/casa/Logging/LogSink.h>
69 :
70 : #include <imageanalysis/Annotations/RegionTextList.h>
71 : #include <synthesis/ImagerObjects/SDMaskHandler.h>
72 :
73 :
74 : using namespace casacore;
75 : namespace casa { //# NAMESPACE CASA - BEGIN
76 :
77 2126 : SDMaskHandler::SDMaskHandler()
78 : {
79 2126 : itsMax = DBL_MAX;
80 2126 : itsRms = DBL_MAX;
81 2126 : itsSidelobeLevel = 0.0;
82 : //itsPBMaskLevel = 0.0;
83 : //itsTooLongForFname=false;
84 : #ifdef NAME_MAX
85 2126 : itsNAME_MAX = NAME_MAX;
86 : #else
87 : itsNAME_MAX = 255;
88 : #endif
89 :
90 2126 : itsTooLongForFname = false;
91 :
92 2126 : }
93 :
94 :
95 2126 : SDMaskHandler::~SDMaskHandler()
96 : {
97 2126 : }
98 :
99 0 : void SDMaskHandler::resetMask(std::shared_ptr<SIImageStore> imstore)
100 : {
101 0 : imstore->mask()->set(1.0);
102 0 : imstore->mask()->unlock();
103 0 : }
104 :
105 : /***
106 : void SDMaskHandler::fillMask(std::shared_ptr<SIImageStore> imstore, Vector<String> maskStrings)
107 : {
108 : String maskString;
109 : if (maskStrings.nelements()) {
110 : for (uInt imsk = 0; imsk < maskStrings.nelements(); imsk++) {
111 : maskString = maskStrings[imsk];
112 : fillMask(imstore, maskString);
113 : }
114 : }
115 : else {
116 : fillMask(imstore, String(""));
117 : }
118 : }
119 : ***/
120 :
121 63 : void SDMaskHandler::fillMask(std::shared_ptr<SIImageStore> imstore, Vector<String> maskStrings)
122 : {
123 126 : LogIO os( LogOrigin("SDMaskHandler","fillMask",WHERE) );
124 63 : String maskString;
125 : try {
126 126 : TempImage<Float> tempAllMaskImage(imstore->mask()->shape(), imstore->mask()->coordinates(), memoryToUse());
127 63 : tempAllMaskImage.set(0.0);
128 63 : if (maskStrings.nelements()) {
129 : //working temp mask image
130 126 : TempImage<Float> tempMaskImage(imstore->mask()->shape(), imstore->mask()->coordinates(), memoryToUse());
131 63 : copyMask(*(imstore->mask()), tempMaskImage);
132 126 : for (uInt imsk = 0; imsk < maskStrings.nelements(); imsk++) {
133 63 : maskString = maskStrings[imsk];
134 63 : bool isTable(false);
135 63 : bool isCasaImage(false);
136 : // test
137 63 : Path testPath(maskString);
138 63 : if (testPath.baseName()==maskString) {
139 63 : if (int(maskString.length()) > itsNAME_MAX)
140 : // the string is too long if it is file name or could be region text
141 1 : itsTooLongForFname=true;
142 : }
143 63 : if (maskString!="") {
144 63 : if(!itsTooLongForFname)
145 62 : isTable = Table::isReadable(maskString);
146 63 : if (!isTable) {
147 : try {
148 46 : if (ImageOpener::imageType(maskString)==ImageOpener::IMAGECONCAT) isCasaImage=true;
149 : //os <<"IT'S A CONCATImage"<<LogIO::POST;
150 : }
151 0 : catch (AipsError &x) {
152 0 : os <<"cannot find imageType... "<<LogIO::POST;
153 0 : }
154 : }
155 : else {
156 17 : Table imtab = Table(maskString, Table::Old);
157 17 : Vector<String> colnames = imtab.tableDesc().columnNames();
158 17 : if ( colnames[0]=="map" ) isCasaImage=true;
159 17 : }
160 63 : if (isCasaImage) {
161 17 : std::shared_ptr<ImageInterface<Float> > inmaskptr;
162 17 : LatticeBase* latt =ImageOpener::openImage(maskString);
163 17 : inmaskptr.reset(dynamic_cast<ImageInterface<Float>* >(latt));
164 17 : IPosition inShape = inmaskptr->shape();
165 17 : IPosition outShape = imstore->mask()->shape();
166 17 : Int specAxis = CoordinateUtil::findSpectralAxis(inmaskptr->coordinates());
167 17 : Int inNchan = (specAxis==-1? 1: inShape(specAxis) );
168 17 : Int outSpecAxis = CoordinateUtil::findSpectralAxis(imstore->mask()->coordinates());
169 17 : Vector <Stokes::StokesTypes> inWhichPols, outWhichPols;
170 17 : Int stokesAxis = CoordinateUtil::findStokesAxis(inWhichPols, inmaskptr->coordinates());
171 17 : Int inNstokes = (stokesAxis==-1? 1: inShape(stokesAxis) );
172 17 : Int outStokesAxis = CoordinateUtil::findStokesAxis(outWhichPols, imstore->mask()->coordinates());
173 17 : if (inNchan == 1 && outShape(outSpecAxis)>1) {
174 6 : os << "Extending mask image: " << maskString << LogIO::POST;
175 6 : expandMask(*inmaskptr, tempMaskImage);
176 : }
177 11 : else if(inNstokes == 1 && outShape(outStokesAxis) > 1 ) {
178 4 : os << "Extending mask image along Stokes axis: " << maskString << LogIO::POST;
179 4 : expandMask(*inmaskptr, tempMaskImage);
180 : }
181 : else {
182 7 : os << "Copying mask image: " << maskString << LogIO::POST;
183 7 : copyMask(*inmaskptr, tempMaskImage);
184 : }
185 17 : }// end of readable table
186 : else {
187 : //
188 46 : std::unique_ptr<Record> myrec(nullptr);
189 : try {
190 46 : if (!itsTooLongForFname) {
191 135 : myrec.reset(RegionManager::readImageFile(maskString,String("temprgrec")));
192 0 : if (myrec!=0) {
193 0 : Bool ret(false);
194 0 : Matrix<Quantity> dummyqmat;
195 0 : Matrix<Float> dummyfmat;
196 0 : ret=SDMaskHandler::regionToImageMask(tempMaskImage, myrec.get(), dummyqmat, dummyfmat);
197 0 : if (!ret) cout<<"regionToImageMask failed..."<<endl;
198 0 : os << "Reading region record mask: " << maskString << LogIO::POST;
199 0 : }
200 : }
201 : else {
202 : // skip to check the mask as a direct region text input
203 1 : throw(AipsError("Too long for filename. Try the string as a direct region text"));
204 : }
205 : }
206 46 : catch (AipsError &x) {
207 : try {
208 46 : ImageRegion* imageRegion=0;
209 46 : os << LogIO::NORMAL3<< "Reading text mask: " << maskString << LogIO::POST;
210 46 : SDMaskHandler::regionTextToImageRegion(maskString, tempMaskImage, imageRegion);
211 46 : if (imageRegion!=0)
212 46 : SDMaskHandler::regionToMask(tempMaskImage,*imageRegion, Float(1.0));
213 : }
214 0 : catch (AipsError &x) {
215 0 : os << LogIO::WARN << maskString << "is invalid mask. Skipping this mask..." << LogIO::POST;
216 0 : }
217 46 : }
218 46 : }// end of region string
219 : }// end of non-emtpy maskstring
220 :
221 126 : LatticeExpr<Float> addedmask( tempMaskImage + tempAllMaskImage );
222 63 : tempAllMaskImage.copyData( LatticeExpr<Float>( iif(addedmask > 0.0, 1.0, 0.0) ) );
223 63 : }
224 63 : imstore->mask()->copyData(tempAllMaskImage);
225 63 : imstore->mask()->unlock();
226 63 : }
227 63 : } catch( AipsError &x )
228 : {
229 0 : throw(AipsError("Error in constructing "+ imstore->getName() +".mask from " + maskString + " : " + x.getMesg()));
230 0 : }
231 63 : }
232 :
233 :
234 :
235 0 : void SDMaskHandler::fillMask(std::shared_ptr<SIImageStore> imstore, String maskString)
236 : {
237 :
238 : try {
239 :
240 : //// imstore->mask() will return a pointer to an ImageInterface (allocation happens on first access).
241 :
242 : // cout << "Call makeMask here to fill in " << imstore->mask()->name() << " from " << maskString << ". For now, set mask to 1 inside a central box" << endl;
243 :
244 : //interpret maskString
245 0 : if (maskString !="") {
246 0 : bool isTable(false);
247 0 : Path testPath(maskString);
248 0 : if (testPath.baseName() == maskString) {
249 0 : if (int(maskString.length()) > itsNAME_MAX)
250 0 : itsTooLongForFname=true;
251 : }
252 0 : if (!itsTooLongForFname)
253 0 : isTable = Table::isReadable(maskString);
254 : //if (!itsTooLongForFname && Table::isReadable(maskString) ) {
255 0 : if ( isTable ) {
256 0 : Table imtab = Table(maskString, Table::Old);
257 0 : Vector<String> colnames = imtab.tableDesc().columnNames();
258 0 : if ( colnames[0]=="map" ) {
259 :
260 : // looks like a CASA image ... probably should check coord exists in the keyword also...
261 : // cout << "copy this input mask...."<<endl;
262 0 : PagedImage<Float> inmask(maskString);
263 0 : IPosition inShape = inmask.shape();
264 0 : IPosition outShape = imstore->mask()->shape();
265 0 : Int specAxis = CoordinateUtil::findSpectralAxis(inmask.coordinates());
266 0 : Int outSpecAxis = CoordinateUtil::findSpectralAxis(imstore->mask()->coordinates());
267 0 : if (inShape(specAxis) == 1 && outShape(outSpecAxis)>1) {
268 0 : expandMask(inmask, *(imstore->mask()));
269 : }
270 : else {
271 0 : copyMask(inmask, *(imstore->mask()));
272 : }
273 0 : }// end of ''map''
274 0 : }// end of readable table
275 : else {
276 0 : ImageRegion* imageRegion=0;
277 0 : SDMaskHandler::regionTextToImageRegion(maskString, *(imstore->mask()), imageRegion);
278 0 : if (imageRegion!=0)
279 0 : SDMaskHandler::regionToMask(*(imstore->mask()),*imageRegion, Float(1.0));
280 : }// end of region string
281 0 : }
282 : else {
283 : /////// Temporary code to set a mask in the inner quarter.
284 : /////// This is only for testing... should go when 'maskString' can be used to fill it in properly.
285 0 : IPosition imshp = imstore->mask()->shape();
286 0 : AlwaysAssert( imshp.nelements() >=2 , AipsError );
287 :
288 0 : Slicer themask;
289 0 : IPosition blc(imshp.nelements(), 0);
290 0 : IPosition trc = imshp-1;
291 0 : IPosition inc(imshp.nelements(), 1);
292 :
293 0 : blc(0)=int(imshp[0]*0.25);
294 0 : blc(1)=int(imshp[1]*0.25);
295 0 : trc(0)=int(imshp[0]*0.75);
296 0 : trc(1)=int(imshp[1]*0.75);
297 :
298 0 : LCBox::verify(blc, trc, inc, imshp);
299 0 : Slicer imslice(blc, trc, inc, Slicer::endIsLast);
300 :
301 0 : std::shared_ptr<ImageInterface<Float> > referenceImage( new SubImage<Float>(*(imstore->mask()), imslice, true) );
302 0 : referenceImage->set(1.0);
303 0 : }
304 :
305 0 : imstore->mask()->unlock();
306 :
307 0 : } catch( AipsError &x )
308 : {
309 0 : throw(AipsError("Error in constructing "+ imstore->getName() +".mask from " + maskString + " : " + x.getMesg()));
310 0 : }
311 0 : }
312 :
313 : //void SDMaskHandler::makeMask()
314 0 : std::shared_ptr<ImageInterface<Float> > SDMaskHandler::makeMask(const String& maskName, const Quantity threshold,
315 : //void SDMaskHandler::makeMask(const String& maskName, const Quantity threshold,
316 : ImageInterface<Float>& tempim)
317 : // ImageInterface<Float>& tempim,
318 : // ImageInterface<Float> *newMaskImage)
319 : {
320 0 : LogIO os( LogOrigin("SDMaskHandler","makeMask",WHERE) );
321 : //
322 : // create mask from a threshold... Imager::mask()...
323 : //default handling?
324 0 : String maskFileName(maskName);
325 0 : if ( maskFileName=="" ) {
326 0 : maskFileName = tempim.name() + ".mask";
327 : }
328 0 : if (!cloneImShape(tempim, maskFileName)) {
329 0 : throw(AipsError("Cannot make a mask from "+tempim.name()));
330 : }
331 0 : PagedImage<Float> *newMaskImage = new PagedImage<Float>(maskFileName, TableLock::AutoNoReadLocking);
332 : //newMaskImage = PagedImage<Float>(maskFileName, TableLock::AutoNoReadLocking);
333 : //PagedImage<Float>(maskFileName, TableLock::AutoNoReadLocking);
334 0 : StokesImageUtil::MaskFrom(*newMaskImage, tempim, threshold);
335 0 : return std::shared_ptr<ImageInterface<Float> >(newMaskImage);
336 0 : }
337 :
338 : //Bool SDMaskHandler::regionToImageMask(const String& maskName, Record* regionRec, Matrix<Quantity>& blctrcs,
339 0 : Bool SDMaskHandler::regionToImageMask(ImageInterface<Float>& maskImage, const Record* regionRec, const Matrix<Quantity>& blctrcs,
340 : const Matrix<Float>& circles, const Float& value) {
341 :
342 0 : LogIO os(LogOrigin("imager", "regionToImageMask", WHERE));
343 :
344 : try {
345 : //PagedImage<Float> tempmask(TiledShape(maskImage->shape(),
346 : // maskImage->niceCursorShape()), maskImage->coordinates(), tempfname);
347 0 : std::shared_ptr<ImageInterface<Float> > tempmask;
348 0 : tempmask.reset( new TempImage<Float>(TiledShape(maskImage.shape(),maskImage.niceCursorShape()), maskImage.coordinates(), memoryToUse() ) );
349 : //tempmask = new PagedImage<Float>(maskImage.shape(), maskImage.coordinates(),"__tmp_rgmask");
350 0 : tempmask->copyData(maskImage);
351 :
352 0 : CoordinateSystem cSys=tempmask->coordinates();
353 : //maskImage.table().markForDelete();
354 0 : ImageRegion *boxregions=0;
355 0 : ImageRegion *circleregions=0;
356 0 : RegionManager regMan;
357 0 : regMan.setcoordsys(cSys);
358 0 : if (blctrcs.nelements()!=0){
359 0 : boxRegionToImageRegion(*tempmask, blctrcs, boxregions);
360 : }
361 0 : if (circles.nelements()!=0) {
362 0 : circleRegionToImageRegion(*tempmask, circles, circleregions);
363 : }
364 0 : ImageRegion* recordRegion=0;
365 0 : if(regionRec !=0){
366 : //if(regionRec.nfields() !=0){
367 0 : recordRegionToImageRegion(regionRec, recordRegion);
368 : }
369 :
370 0 : ImageRegion *unionReg=0;
371 0 : if(boxregions!=0 && recordRegion!=0){
372 0 : unionReg=regMan.doUnion(*boxregions, *recordRegion);
373 0 : delete boxregions; boxregions=0;
374 0 : delete recordRegion; recordRegion=0;
375 : }
376 0 : else if(boxregions !=0){
377 0 : unionReg=boxregions;
378 : }
379 0 : else if(recordRegion !=0){
380 0 : unionReg=recordRegion;
381 : }
382 :
383 0 : if(unionReg !=0){
384 0 : regionToMask(*tempmask, *unionReg, value);
385 0 : delete unionReg; unionReg=0;
386 : }
387 : //As i can't unionize LCRegions and WCRegions; do circles seperately
388 0 : if(circleregions !=0){
389 0 : regionToMask(*tempmask, *circleregions, value);
390 0 : delete circleregions;
391 0 : circleregions=0;
392 : }
393 : //maskImage.table().unmarkForDelete();
394 0 : maskImage.copyData(*tempmask);
395 0 : }
396 0 : catch (AipsError& x) {
397 0 : os << "Error in regionToMaskImage() : " << x.getMesg() << LogIO::EXCEPTION;
398 0 : }
399 0 : return true;
400 0 : }
401 :
402 46 : Bool SDMaskHandler::regionToMask(ImageInterface<Float>& maskImage, ImageRegion& imageregion, const Float& value)
403 : {
404 46 : SubImage<Float> partToMask(maskImage, imageregion, true);
405 46 : LatticeRegion latReg=imageregion.toLatticeRegion(maskImage.coordinates(), maskImage.shape());
406 46 : ArrayLattice<Bool> pixmask(latReg.get());
407 92 : LatticeExpr<Float> myexpr(iif(pixmask, value, partToMask) );
408 46 : partToMask.copyData(myexpr);
409 46 : return true;
410 46 : }
411 :
412 0 : void SDMaskHandler::boxRegionToImageRegion(const ImageInterface<Float>& maskImage, const Matrix<Quantity>& blctrcs, ImageRegion*& boxImageRegions)
413 : {
414 0 : if(blctrcs.shape()(1) != 4)
415 0 : throw(AipsError("Need a list of 4 elements to define a box"));
416 :
417 0 : CoordinateSystem cSys=maskImage.coordinates();
418 0 : RegionManager regMan;
419 0 : regMan.setcoordsys(cSys);
420 0 : Vector<Quantum<Double> > blc(2);
421 0 : Vector<Quantum<Double> > trc(2);
422 0 : Int nrow=blctrcs.shape()(0);
423 0 : Vector<Int> absRel(2, RegionType::Abs);
424 0 : PtrBlock<const WCRegion *> lesbox(nrow);
425 0 : for (Int k=0; k < nrow; ++k){
426 0 : blc(0) = blctrcs(k,0);
427 0 : blc(1) = blctrcs(k,1);
428 0 : trc(0) = blctrcs(k,2);
429 0 : trc(1) = blctrcs(k,3);
430 0 : lesbox[k]= new WCBox (blc, trc, cSys, absRel);
431 : }
432 0 : boxImageRegions=regMan.doUnion(lesbox);
433 0 : if (boxImageRegions!=0) {
434 : }
435 0 : for (Int k=0; k < nrow; ++k){
436 0 : delete lesbox[k];
437 : }
438 0 : }
439 :
440 0 : void SDMaskHandler::circleRegionToImageRegion(const ImageInterface<Float>& maskImage, const Matrix<Float>& circles,
441 : ImageRegion*& circleImageRegions)
442 : {
443 0 : if(circles.shape()(1) != 3)
444 0 : throw(AipsError("Need a list of 3 elements to define a circle"));
445 :
446 0 : CoordinateSystem cSys=maskImage.coordinates();
447 0 : RegionManager regMan;
448 0 : regMan.setcoordsys(cSys);
449 0 : Int nrow=circles.shape()(0);
450 0 : Vector<Float> cent(2);
451 0 : cent(0)=circles(0,1); cent(1)=circles(0,2);
452 0 : Float radius=circles(0,0);
453 0 : IPosition xyshape(2,maskImage.shape()(0),maskImage.shape()(1));
454 0 : LCEllipsoid *circ= new LCEllipsoid(cent, radius, xyshape);
455 : //Tell LCUnion to delete the pointers
456 0 : LCUnion *elunion= new LCUnion(true, circ);
457 : //now lets do the remainder
458 0 : for (Int k=1; k < nrow; ++k){
459 0 : cent(0)=circles(k,1); cent(1)=circles(k,2);
460 0 : radius=circles(k,0);
461 0 : circ= new LCEllipsoid(cent, radius, xyshape);
462 0 : elunion=new LCUnion(true, elunion, circ);
463 : }
464 : //now lets extend that to the whole image
465 0 : IPosition trc(2);
466 0 : trc(0)=maskImage.shape()(2)-1;
467 0 : trc(1)=maskImage.shape()(3)-1;
468 0 : LCBox lbox(IPosition(2,0,0), trc,
469 0 : IPosition(2,maskImage.shape()(2),maskImage.shape()(3)) );
470 0 : LCExtension linter(*elunion, IPosition(2,2,3),lbox);
471 0 : circleImageRegions=new ImageRegion(linter);
472 0 : delete elunion;
473 0 : }
474 :
475 46 : void SDMaskHandler::recordRegionToImageRegion(const Record* imageRegRec, ImageRegion*& imageRegion )
476 : //void SDMaskHandler::recordRegionToImageRegion(Record& imageRegRec, ImageRegion*& imageRegion )
477 : {
478 46 : if(imageRegRec !=0){
479 46 : TableRecord rec1;
480 46 : rec1.assign(*imageRegRec);
481 46 : imageRegion=ImageRegion::fromRecord(rec1,"");
482 46 : }
483 46 : }
484 :
485 :
486 46 : void SDMaskHandler::regionTextToImageRegion(const String& text, const ImageInterface<Float>& regionImage,
487 : ImageRegion*& imageRegion)
488 : {
489 92 : LogIO os( LogOrigin("SDMaskHandler", "regionTextToImageRegion",WHERE) );
490 :
491 : try {
492 46 : IPosition imshape = regionImage.shape();
493 46 : CoordinateSystem csys = regionImage.coordinates();
494 46 : File fname;
495 : int maxFileName;
496 46 : bool skipfnamecheck(false);
497 : #ifdef NAME_MAX
498 46 : maxFileName=NAME_MAX;
499 : #else
500 : maxFileName=255;
501 : #endif
502 :
503 46 : Path testPath(text);
504 46 : if (testPath.baseName() == text) {
505 46 : if (int(text.length()) > maxFileName)
506 : // could be direct region text
507 1 : skipfnamecheck=true;
508 : }
509 46 : fname=text;
510 46 : Record* imageRegRec=0;
511 46 : Record myrec;
512 :
513 : //Record imageRegRec;
514 46 : if (!skipfnamecheck && fname.exists() && fname.isRegular()) {
515 50 : RegionTextList CRTFList(text, csys, imshape);
516 25 : myrec = CRTFList.regionAsRecord();
517 25 : }
518 : else { // direct text input....
519 42 : Regex rx (Regex::fromPattern("*\\[*\\]*"));
520 21 : if (text.matches(rx)) {
521 42 : RegionTextList CRTFList(csys, text, imshape);
522 21 : myrec = CRTFList.regionAsRecord();
523 : //cerr<<"myrec.nfields()="<<myrec.nfields()<<endl;
524 21 : }
525 : else {
526 0 : throw(AipsError("Input mask, '"+text+"' does not exist if it is inteded as a mask file name."+
527 0 : "Or invalid CRTF syntax if it is intended as a direct region specification."));
528 : }
529 21 : }
530 46 : imageRegRec = new Record();
531 46 : imageRegRec->assign(myrec);
532 46 : recordRegionToImageRegion(imageRegRec, imageRegion);
533 46 : delete imageRegRec;
534 46 : }
535 0 : catch (AipsError& x) {
536 0 : os << LogIO::SEVERE << "Exception: "<< x.getMesg() << LogIO::POST;
537 0 : }
538 46 : }
539 :
540 0 : void SDMaskHandler::copyAllMasks(const Vector< std::shared_ptr<ImageInterface<Float> > > inImageMasks, ImageInterface<Float>& outImageMask)
541 : {
542 0 : LogIO os( LogOrigin("SDMaskHandler", "copyAllMasks", WHERE) );
543 :
544 0 : TempImage<Float> tempoutmask(outImageMask.shape(), outImageMask.coordinates(), memoryToUse());
545 :
546 0 : for (uInt i = 0; i < inImageMasks.nelements(); i++) {
547 0 : copyMask(*inImageMasks(i), tempoutmask);
548 0 : outImageMask.copyData( (LatticeExpr<Float>)(tempoutmask+outImageMask) );
549 : }
550 0 : }
551 :
552 70 : void SDMaskHandler::copyMask(const ImageInterface<Float>& inImageMask, ImageInterface<Float>& outImageMask)
553 : {
554 140 : LogIO os( LogOrigin("SDMaskHandler", "copyMask", WHERE) );
555 :
556 : //output mask coords
557 70 : IPosition outshape = outImageMask.shape();
558 70 : CoordinateSystem outcsys = outImageMask.coordinates();
559 70 : DirectionCoordinate outDirCsys = outcsys.directionCoordinate();
560 70 : SpectralCoordinate outSpecCsys = outcsys.spectralCoordinate();
561 :
562 : // do regrid
563 70 : IPosition axes(3,0,1,2);
564 70 : IPosition inshape = inImageMask.shape();
565 70 : CoordinateSystem incsys = inImageMask.coordinates();
566 70 : DirectionCoordinate inDirCsys = incsys.directionCoordinate();
567 70 : SpectralCoordinate inSpecCsys = incsys.spectralCoordinate();
568 : //Check the conversion layer consistentcy between input and output.
569 : //Change the frame of the convesion layer in incsys to that of outcsys if different.
570 70 : if (inSpecCsys.frequencySystem(True)!=outSpecCsys.frequencySystem(True)) {
571 0 : incsys.setSpectralConversion(MFrequency::showType(outSpecCsys.frequencySystem(True)));
572 : }
573 :
574 70 : Vector<Int> dirAxes = CoordinateUtil::findDirectionAxes(incsys);
575 70 : axes(0) = dirAxes(0);
576 70 : axes(1) = dirAxes(1);
577 70 : axes(2) = CoordinateUtil::findSpectralAxis(incsys);
578 :
579 : //const String outfilename = outImageMask.name()+"_"+String::toString(HostInfo::processID());
580 :
581 : try {
582 : // Since regrid along the spectral axis does not seem to work
583 : // properly, replacing with ImageRegridder
584 : //ImageRegrid<Float> imregrid;
585 : //imregrid.showDebugInfo(1);
586 : //imregrid.regrid(outImageMask, Interpolate2D::LINEAR, axes, inImageMask);
587 : //
588 70 : TempImage<Float>* inImageMaskptr = new TempImage<Float>(inshape,incsys,memoryToUse());
589 70 : ArrayLattice<Bool> inimmask(inImageMask.getMask());
590 70 : inImageMaskptr->copyData((LatticeExpr<Float>)(inImageMask * iif(inimmask,1.0,0.0)) );
591 : //
592 70 : SPCIIF tempim(inImageMaskptr);
593 70 : SPCIIF templateim(new TempImage<Float>(outshape,outcsys, memoryToUse()));
594 70 : Record* dummyrec = 0;
595 : //ImageRegridder regridder(tempim, outfilename, templateim, axes, dummyrec, "", true, outshape);
596 : //TTDEBUG
597 140 : ImageRegridder<Float> regridder(tempim, "", templateim, axes, dummyrec, "", true, outshape);
598 70 : regridder.setMethod(Interpolate2D::LINEAR);
599 70 : SPIIF retim = regridder.regrid();
600 : //outImageMask.copyData( (LatticeExpr<Float>) iif(*retim > 0.1, 1.0, 0.0) );
601 70 : ArrayLattice<Bool> retimmask(retim->getMask());
602 : //LatticeExpr<Float> withmask( (*retim) * iif(retimmask,1.0,0.0) );
603 : //outImageMask.copyData( withmask );
604 70 : outImageMask.copyData( (LatticeExpr<Float>)((*retim) * iif(retimmask,1.0,0.0)) );
605 : //LatticeUtilities::copyDataAndMask(os, outImageMask, *retim );
606 : //} catch (AipsError &x) {
607 : // throw(AipsError("Image regrid error : "+ x.getMesg()));
608 : // }
609 70 : } catch (AipsError &x) {
610 0 : os<<LogIO::WARN <<x.getMesg()<<LogIO::POST;
611 0 : os<<LogIO::WARN <<" Cannot regrid the input mask to output mask, it will be empty."<<LogIO::POST;
612 0 : outImageMask.set(0);
613 0 : }
614 :
615 : // no longer needed (output file in regrid is now set to "" so no need of this clean-up)
616 : //try
617 : // {
618 : // delete the outfilename image on disk
619 : // Directory dd(outfilename);
620 : // dd.removeRecursive();
621 : // }
622 : //catch (AipsError &x) {
623 : // throw(AipsError("Cannot delete temporary mask image : "+ x.getMesg()));
624 : // os << LogIO::WARN << "Cannot delete temporary mask image : " << x.getMesg() << LogIO::POST;
625 : //}
626 :
627 70 : }
628 :
629 10 : void SDMaskHandler::expandMask(const ImageInterface<Float>& inImageMask, ImageInterface<Float>& outImageMask)
630 : {
631 20 : LogIO os( LogOrigin("SDMaskHandler", "expandMask", WHERE) );
632 :
633 : // expand mask with input range (in spectral axis and stokes?) ... to output range on outimage
634 : // currently expand a continuum mask to a cube mask in channels (to all channels)
635 : // or continuum Stokes I mask to multi-Stokes mask
636 : // or continuum with multi-Stokes mask to cube with multi-Stokes mask
637 10 : IPosition inShape = inImageMask.shape();
638 10 : CoordinateSystem inCsys = inImageMask.coordinates();
639 10 : Vector<Int> dirAxes = CoordinateUtil::findDirectionAxes(inCsys);
640 10 : Int inSpecAxis = CoordinateUtil::findSpectralAxis(inCsys);
641 : Int inNchan;
642 10 : if (inSpecAxis==-1) {
643 4 : inNchan=1;
644 : }
645 : else {
646 6 : inNchan = inShape(inSpecAxis);
647 : }
648 :
649 10 : Vector<Stokes::StokesTypes> inWhichPols;
650 10 : Int inStokesAxis = CoordinateUtil::findStokesAxis(inWhichPols,inCsys);
651 : Int inNpol;
652 10 : if (inStokesAxis==-1) {
653 4 : inNpol=1;
654 : }
655 : else {
656 6 : inNpol = inShape(inStokesAxis);
657 : }
658 :
659 : //
660 10 : IPosition outShape = outImageMask.shape();
661 10 : CoordinateSystem outCsys = outImageMask.coordinates();
662 10 : Vector<Int> outDirAxes = CoordinateUtil::findDirectionAxes(outCsys);
663 10 : Int outSpecAxis = CoordinateUtil::findSpectralAxis(outCsys);
664 10 : Int outNchan = outShape(outSpecAxis);
665 10 : Vector<Stokes::StokesTypes> outWhichPols;
666 10 : Int outStokesAxis = CoordinateUtil::findStokesAxis(outWhichPols,outCsys);
667 10 : Int outNpol = outShape(outStokesAxis);
668 :
669 10 : IPosition start(4,0,0,0,0);
670 10 : IPosition length(4,outShape(outDirAxes(0)), outShape(outDirAxes(1)),1,1);
671 : //Slicer sl(start, length);
672 :
673 10 : Int stokesInc = 1;
674 : // for fixing removed degenerate axis
675 10 : Bool addSpecAxis = (inSpecAxis == -1? True: False);
676 : // Do expansion for input mask with single channel (continuum)
677 10 : if (inNchan==1 ) {
678 8 : if (inNpol == 1 ) {
679 6 : stokesInc = 1;
680 : }
681 2 : else if (inShape(inStokesAxis)==outShape(outStokesAxis)) {
682 2 : stokesInc = inShape(inStokesAxis);
683 : }
684 : else {
685 0 : throw(AipsError("Cannot extend the input mask of "+String::toString(inNpol)+
686 0 : " Stokes planes to the output mask of "+String::toString(outNpol)+
687 0 : " Stokes planes. Please modify the input mask to make it a Stokes I mask or a mask with the same number of Stokes planes as the output.") );
688 : }
689 :
690 8 : length(outStokesAxis) = stokesInc;
691 :
692 : // I stokes cont -> cube: regrid ra.dec on the input single plane
693 : // I stokes cont -> cont multi-stokes: regrid ra.dec on the input
694 : // I stokes cont -> cube multi-stokes: regid ra.dec on input
695 :
696 8 : Slicer sl(start, length);
697 : // make a subImage for regridding output
698 8 : SubImage<Float> chanMask(outImageMask, sl, true);
699 8 : ImageRegrid<Float> imregrid;
700 16 : TempImage<Float> tempInImageMask(chanMask.shape(), chanMask.coordinates(),memoryToUse());
701 8 : std::unique_ptr<ImageInterface<Float> > outmaskim_ptr;
702 8 : if ( chanMask.shape().nelements() > inImageMask.shape().nelements() ) {
703 4 : String stokesStr;
704 4 : if (inNpol==1) {
705 3 : stokesStr="I";
706 : }
707 : else {
708 1 : stokesStr="";
709 : //for (uInt ipol=0; ipol < inWhichPols.nelements(); ipol++) {
710 : // stokesStr+=Stokes::name(inWhichPols(ipol));
711 : //}
712 : }
713 : //os<<"Adding degenerate axes: addSpecAxis="<<addSpecAxis<<" stokes="<<stokesStr<<LogIO::POST;
714 4 : casacore::ImageUtilities::addDegenerateAxes(os, outmaskim_ptr, inImageMask,"",False, addSpecAxis, stokesStr, False, False, True);
715 4 : tempInImageMask.copyData(*outmaskim_ptr);
716 4 : }
717 : else {
718 4 : tempInImageMask.copyData(inImageMask);
719 : }
720 :
721 : try {
722 8 : imregrid.regrid(chanMask, Interpolate2D::LINEAR, dirAxes, tempInImageMask);
723 0 : } catch (AipsError& x) {
724 0 : os<<LogIO::WARN<<"Regridding of the input mask image failed: "<<x.getMesg()<<LogIO::POST;
725 0 : }
726 : // extract input mask (first stokes plane)
727 8 : Array<Float> inMaskData;
728 8 : IPosition end2(4,outShape(outDirAxes(0)), outShape(outDirAxes(1)), 1, 1);
729 8 : if ( inNpol==outNpol ) {
730 4 : end2(outStokesAxis) = inNpol;
731 : }
732 8 : chanMask.doGetSlice(inMaskData, Slicer(start,end2));
733 8 : IPosition stride(4,1,1,1,1);
734 : //
735 : // continuum output mask case
736 8 : if (outNchan==1) {
737 : //No copying over channels, just do copying over all Stokes if input mask is a single Stokes
738 2 : if (inNpol == 1 && outNpol > 1) {
739 10 : for (Int ipol = 0; ipol < outNpol; ipol++) {
740 8 : start(outStokesAxis) = ipol;
741 8 : os<<"Copying input mask to Stokes plane="<<ipol<<LogIO::POST;
742 8 : outImageMask.putSlice(inMaskData,start,stride);
743 : }
744 : }
745 : }
746 : else { // for cube
747 24 : for (Int ich = 0; ich < outNchan; ich++) {
748 18 : start(outSpecAxis) = ich;
749 18 : IPosition inStart(4,0,0,0,0);
750 18 : if (inNpol == 1 && outNpol > 1) {
751 : // extend to other Stokes
752 30 : for (Int ipol = 0; ipol < outNpol; ipol++) {
753 24 : os<<"Copying input mask to Stokes plane="<<ipol<<LogIO::POST;
754 24 : start(outStokesAxis) = ipol;
755 24 : outImageMask.putSlice(inMaskData,start,stride);
756 : }
757 6 : }
758 : else {
759 : // copy Stokes plane as is (but expand it to all channels)
760 12 : stride(outStokesAxis) = stokesInc;
761 12 : if (inNpol == outNpol) {
762 42 : for (Int ipol = 0; ipol < outNpol; ipol++) {
763 : // need to slice mask from each stokes plane
764 30 : inMaskData.resize();
765 30 : inStart(outStokesAxis) = ipol;
766 30 : start(outStokesAxis) = ipol;
767 30 : end2(outStokesAxis) = 1;
768 30 : stride(outStokesAxis) = 1;
769 30 : chanMask.doGetSlice(inMaskData, Slicer(inStart,end2));
770 30 : outImageMask.putSlice(inMaskData,start,stride);
771 : }
772 :
773 : }
774 : else {
775 0 : outImageMask.putSlice(inMaskData,start,stride);
776 : }
777 : }
778 18 : } //for loop
779 : } // else
780 8 : }
781 : // Stokes I (a single Stokes plane mask with cube)
782 2 : else if (inNpol == 1) {
783 2 : if (inNpol != 1 ) {
784 0 : if (inShape(inStokesAxis)==outShape(outStokesAxis)) {
785 0 : stokesInc = inShape(inStokesAxis);
786 : }
787 : else {
788 0 : throw(AipsError("Cannot extend the input mask of "+String::toString(inNpol)+
789 0 : " Stokes planes to the output mask of "+String::toString(outNpol)+
790 0 : " Stokes planes. Please modify the input mask to make it a Stokes I mask or a mask with the same number of Stokes planes as the output.") );
791 : }
792 : }
793 2 : length(outStokesAxis) = stokesInc;
794 2 : length(outSpecAxis) = outNchan;
795 2 : Slicer slStokes(start, length);
796 : // make a subImage for regridding output (all channels)
797 2 : SubImage<Float> stokesMask(outImageMask, slStokes, true);
798 2 : ImageRegrid<Float> imregrid2;
799 4 : TempImage<Float> tempInStokesImageMask(stokesMask.shape(), stokesMask.coordinates(),memoryToUse());
800 2 : std::unique_ptr<ImageInterface<Float> > outstokesmaskim_ptr;
801 2 : Vector<Stokes::StokesTypes> outWhichPols;
802 2 : if ( stokesMask.shape().nelements() > inImageMask.shape().nelements() ) {
803 1 : casacore::ImageUtilities::addDegenerateAxes(os, outstokesmaskim_ptr, inImageMask,"",False, addSpecAxis, "I", False, False, True);
804 1 : Vector<Int> outWorldOrder(4);
805 1 : Vector<Int> outPixelOrder(4);
806 1 : outWorldOrder(0)=0;
807 1 : outWorldOrder(1)=1;
808 1 : outWorldOrder(2)=3;
809 1 : outWorldOrder(3)=2;
810 1 : outPixelOrder(0)=0;
811 1 : outPixelOrder(1)=1;
812 1 : outPixelOrder(2)=3;
813 1 : outPixelOrder(3)=2;
814 1 : CoordinateSystem modcsys=tempInStokesImageMask.coordinates();
815 1 : IPosition inMaskShape = inImageMask.shape();
816 1 : Array<Float> inData = outstokesmaskim_ptr->get();
817 1 : IPosition newAxisOrder(4,0,1,3,2);
818 1 : Array<Float> reorderedData = reorderArray(inData, newAxisOrder);
819 1 : IPosition newShape=reorderedData.shape();
820 : //os<< "reoderedData shape="<<reorderedData.shape()<<LogIO::POST;
821 1 : TempImage<Float> modTempInStokesMask(TiledShape(newShape), modcsys);
822 1 : modTempInStokesMask.put(reorderedData);
823 :
824 1 : if (compareSpectralCoordinate(inImageMask,tempInStokesImageMask) ) {
825 1 : tempInStokesImageMask.copyData(modTempInStokesMask);
826 : }
827 1 : }
828 : else {
829 1 : if (compareSpectralCoordinate(inImageMask,tempInStokesImageMask) ) {
830 1 : tempInStokesImageMask.copyData(inImageMask);
831 : }
832 :
833 : }
834 : try {
835 2 : imregrid2.regrid(stokesMask, Interpolate2D::LINEAR, dirAxes, tempInStokesImageMask);
836 0 : } catch (AipsError& x) {
837 0 : os<<LogIO::WARN<<"Regridding of the input mask image failed: "<<x.getMesg()<<LogIO::POST;
838 0 : }
839 2 : os <<"Slicing data..."<<LogIO::POST;
840 2 : Array<Float> inMaskData2;
841 2 : IPosition end3(4,outShape(outDirAxes(0)), outShape(outDirAxes(1)), 1, 1);
842 2 : end3(outStokesAxis) = inNpol;
843 2 : end3(outSpecAxis) = inNchan;
844 2 : stokesMask.doGetSlice(inMaskData2,slStokes);
845 2 : IPosition stride(4,1,1,1,1);
846 2 : IPosition inStart2(4,0,0,0,0);
847 10 : for (Int ipol = 0; ipol < outNpol; ipol++) {
848 : // need to slice mask from each stokes plane
849 8 : inMaskData2.resize();
850 8 : inStart2(outStokesAxis) = 0;
851 8 : start(outStokesAxis) = ipol;
852 8 : end3(outStokesAxis) = 1;
853 8 : stride(outStokesAxis) = 1;
854 8 : stride(outSpecAxis) = 1; // assume here inNchan == outNchan
855 8 : stokesMask.doGetSlice(inMaskData2, Slicer(inStart2,end3));
856 8 : outImageMask.putSlice(inMaskData2,start);
857 : }
858 :
859 2 : }
860 : else {
861 0 : throw(AipsError("Input mask,"+inImageMask.name()+" does not conform with the number of channels in output mask"));
862 : }
863 10 : }
864 :
865 2 : Bool SDMaskHandler::compareSpectralCoordinate(const ImageInterface<Float>& inImage, const ImageInterface<Float>& outImage)
866 : {
867 4 : LogIO os( LogOrigin("SDMaskHandler", "checkSpectralCoord",WHERE) );
868 :
869 2 : SpectralCoordinate outSpecCoord = outImage.coordinates().spectralCoordinate();
870 2 : IPosition inshape = inImage.shape();
871 2 : IPosition outshape = outImage.shape();
872 2 : CoordinateSystem incys = inImage.coordinates();
873 2 : CoordinateSystem outcsys = outImage.coordinates();
874 2 : Int inSpecAxis = CoordinateUtil::findSpectralAxis(incys);
875 2 : Int outSpecAxis = CoordinateUtil::findSpectralAxis(outcsys);
876 2 : Bool nchanMatch(true);
877 2 : if (inSpecAxis != -1 and outSpecAxis != -1 )
878 2 : nchanMatch = inshape(inSpecAxis) == outshape(outSpecAxis)? true: false;
879 2 : if (!nchanMatch) {
880 0 : if (!outSpecCoord.near(inImage.coordinates().spectralCoordinate())) {
881 0 : throw(AipsError("Cannot extend the input mask. Spectral coordiante and the number of channels of the input mask does not match with those of the output mask. Use a single channel mask or a mask that matches the spectral coordiante of the output. "));
882 : }
883 : else {
884 0 : throw(AipsError("Cannot extend the input mask. The number of the channels in Input mask,"+inImage.name()+"does not match with that of the output mask. Use a single channel mask or a mask that matches the spectral coordiante of the output. "));
885 : }
886 : return false;
887 : }
888 : else {
889 2 : if (!outSpecCoord.near(inImage.coordinates().spectralCoordinate())) {
890 0 : throw(AipsError("Cannot extend the input mask. Spectral coordiante of Input mask,"+inImage.name()+"does not match with that of the output mask. Use a single channel mask or a mask that matches the spectral coordiante of the output. "));
891 : return false;
892 : }
893 : }
894 2 : return true;
895 2 : }
896 :
897 :
898 : // was Imager::clone()...
899 : //static Bool cloneImShape(const ImageInterface<Float>& inImage, ImageInterface<Float>& outImage)
900 0 : Bool SDMaskHandler::cloneImShape(const ImageInterface<Float>& inImage, const String& outImageName)
901 : {
902 0 : LogIO os( LogOrigin("SDMaskHandler", "cloneImShape",WHERE) );
903 :
904 : try {
905 0 : PagedImage<Float> newImage(TiledShape(inImage.shape(),
906 0 : inImage.niceCursorShape()), inImage.coordinates(),
907 : // outImage.name());
908 0 : outImageName);
909 0 : newImage.set(0.0);
910 0 : newImage.table().flush(true, true);
911 0 : } catch (AipsError& x) {
912 0 : os << LogIO::SEVERE << "Exception: " << x.getMesg() << LogIO::POST;
913 0 : return false;
914 0 : }
915 0 : return true;
916 0 : }
917 :
918 :
919 0 : Int SDMaskHandler::makeInteractiveMask(std::shared_ptr<SIImageStore>& imstore,
920 : Int& niter, Int& cycleniter,
921 : String& threshold, String& cyclethreshold)
922 : {
923 : Int ret;
924 : // Int niter=1000, ncycles=100;
925 : // String thresh="0.001mJy";
926 0 : String imageName = imstore->getName()+".residual"+(imstore->getNTaylorTerms()>1?".tt0":"");
927 0 : String maskName = imstore->getName() + ".mask";
928 0 : imstore->mask()->unlock();
929 0 : cout << "Before interaction : niter : " << niter << " cycleniter : " << cycleniter << " thresh : " << threshold << " cyclethresh : " << cyclethreshold << endl;
930 : // ret = interactiveMasker_p->interactivemask(imageName, maskName,
931 : // niter, ncycles, threshold);
932 0 : return ret;
933 0 : }
934 :
935 0 : void SDMaskHandler::makeAutoMask(std::shared_ptr<SIImageStore> imstore)
936 : {
937 0 : LogIO os( LogOrigin("SDMaskHandler","makeAutoMask",WHERE) );
938 :
939 0 : Array<Float> localres;
940 : // Modification to be able to work with a cube (TT 2014-12-09)
941 : //imstore->residual()->get( localres , true );
942 0 : imstore->residual()->get( localres );
943 :
944 0 : Array<Float> localmask;
945 : //imstore->mask()->get( localmask , true );
946 0 : imstore->mask()->get( localmask );
947 :
948 0 : Int specAxis = CoordinateUtil::findSpectralAxis(imstore->mask()->coordinates());
949 0 : IPosition maskShape = localmask.shape();
950 0 : Int ndim = maskShape.nelements();
951 0 : IPosition pos(ndim,0);
952 0 : IPosition blc(ndim,0);
953 0 : IPosition trc(ndim,0);
954 0 : trc[0] = maskShape[0]-1;
955 0 : trc[1] = maskShape[1]-1;
956 : // added per channel mask setting
957 0 : for (pos[specAxis] = 0; pos[specAxis]<localmask.shape()[specAxis]; pos[specAxis]++)
958 : {
959 0 : IPosition posMaxAbs( localmask.shape().nelements(), 0);
960 0 : blc[specAxis]=pos[specAxis];
961 0 : trc[specAxis]=pos[specAxis];
962 0 : Float maxAbs=0.0;
963 : Float minVal;
964 0 : IPosition posmin(localmask.shape().nelements(), 0);
965 : //minMax(minVal, maxAbs, posmin, posMaxAbs, localres);
966 0 : minMax(minVal, maxAbs, posmin, posMaxAbs, localres(blc,trc));
967 :
968 : // cout << "Max position : " << posMaxAbs << endl;
969 :
970 0 : Int dist=5;
971 :
972 : //IPosition pos(2,0,0); // Deal with the input shapes properly......
973 0 : for (pos[0]=posMaxAbs[0]-dist; pos[0]<posMaxAbs[0]+dist; pos[0]++)
974 : {
975 0 : for (pos[1]=posMaxAbs[1]-dist; pos[1]<posMaxAbs[1]+dist; pos[1]++)
976 : {
977 0 : if( pos[0]>0 && pos[0]<localmask.shape()[0] && pos[1]>0 && pos[1]<localmask.shape()[1] )
978 : {
979 0 : localmask( pos ) = 1.0;
980 : }
981 : }
982 : }
983 0 : } // over channels
984 : //cout << "Sum of mask : " << sum(localmask) << endl;
985 0 : Float summask = sum(localmask);
986 0 : if( summask==0.0 ) { localmask=1.0; summask = sum(localmask); }
987 0 : os << LogIO::NORMAL1 << "Make Autobox mask with " << summask << " available pixels " << LogIO::POST;
988 :
989 0 : imstore->mask()->put( localmask );
990 :
991 : // imstore->mask()->get( localmask , true );
992 : // cout << "Sum of imstore mask : " << sum( localmask ) << endl;
993 :
994 0 : }
995 :
996 52 : void SDMaskHandler::autoMask(std::shared_ptr<SIImageStore> imstore,
997 : ImageInterface<Float>& posmask,
998 : const Int iterdone,
999 : Vector<Bool>& chanflag,
1000 : Record& robuststatsrec,
1001 : const String& alg,
1002 : const String& threshold,
1003 : const Float& fracofpeak,
1004 : const String& resolution,
1005 : const Float& resbybeam,
1006 : const Int nmask,
1007 : const Bool autoadjust,
1008 : // new params for the multithreshold alg.
1009 : const Float& sidelobethreshold,
1010 : const Float& noisethreshold,
1011 : const Float& lownoisethreshold,
1012 : const Float& negativethreshold,
1013 : const Float& cutthreshold,
1014 : const Float& smoothfactor,
1015 : const Float& minbeamfrac,
1016 : const Int growiterations,
1017 : const Bool dogrowprune,
1018 : const Float& minpercentchange,
1019 : const Bool verbose,
1020 : const Bool fastnoise,
1021 : const Bool isthresholdreached,
1022 : Float pblimit)
1023 : {
1024 104 : LogIO os( LogOrigin("SDMaskHandler","autoMask",WHERE) );
1025 :
1026 : //currently supported alg:
1027 : // onebox: a box around a max (box size +/-5pix around max position)
1028 : // thresh: threshold based auto masking (uses threshold or fracofpeak, and resolution)
1029 : //
1030 : // create a working copy of residual image (including pixel masks)
1031 52 : os << LogIO::NORMAL2 <<"algorithm:"<<alg<<LogIO::POST;
1032 52 : TempImage<Float>* tempres = new TempImage<Float>(imstore->residual()->shape(), imstore->residual()->coordinates(), memoryToUse());
1033 : //Array<Float> maskdata;
1034 : //Array<Float> psfdata;
1035 : {
1036 52 : Array<Float> resdata;
1037 52 : imstore->residual()->get(resdata);
1038 52 : tempres->put(resdata);
1039 52 : tempres->setImageInfo(imstore->residual()->imageInfo());
1040 52 : tempres->attachMask(ArrayLattice<Bool> (imstore->residual()->getMask()));
1041 52 : }
1042 :
1043 52 : TempImage<Float>* tempmask = new TempImage<Float>(imstore->mask()->shape(), imstore->mask()->coordinates(), memoryToUse());
1044 : // get current mask and apply pbmask
1045 : {
1046 52 : Array<Float> maskdata;
1047 52 : imstore->mask()->get(maskdata);
1048 52 : String maskname = imstore->getName()+".mask";
1049 52 : tempmask->put(maskdata);
1050 : //For debug
1051 : //PagedImage<Float> tempmaskInit(tempmask->shape(), tempmask->coordinates(), "tempMaskInit"+String::toString(iterdone));
1052 : //tempmaskInit.copyData(*tempmask);
1053 :
1054 : //
1055 :
1056 52 : if (pblimit>0.0 && imstore->hasPB()) {
1057 : //Determine if there is mask and set pixel mask to True for the mask to check by ntrue
1058 0 : LatticeExpr<Bool> pixmask( iif(*tempmask > 0.0, True, False));
1059 0 : TempImage<Float>* dummy = new TempImage<Float>(tempres->shape(), tempres->coordinates(), memoryToUse());
1060 0 : dummy->attachMask(pixmask);
1061 0 : LatticeExpr<Float> themask;
1062 0 : if (!ntrue(dummy->getMask())) { // initial zero mask
1063 : //os<<"INITIAL Zero Mask ...."<<LogIO::POST;
1064 : //themask = LatticeExpr<Float>( iif( (*(imstore->pb())) > pblimit , 1.0 , 0.0 ));
1065 0 : themask = LatticeExpr<Float>( *tempmask);
1066 : }
1067 : else {
1068 : //os<<"INITIAL NON-Zero Mask ...."<<LogIO::POST;
1069 0 : themask = LatticeExpr<Float>( iif( (*(imstore->pb())) > pblimit, *(imstore->mask()), 0.0));
1070 : }
1071 : // attache pixmask to temp res image to be used in stats etc
1072 0 : tempres->attachMask(LatticeExpr<Bool> ( iif(*(imstore->pb()) > pblimit, True, False)));
1073 0 : imstore->mask()->copyData( themask );
1074 0 : imstore->mask()->get(maskdata);
1075 0 : tempmask->put(maskdata);
1076 0 : delete dummy;
1077 0 : }
1078 52 : }
1079 : //for debug
1080 : //String tempresname="initialRes_"+String::toString(iterdone)+".im";
1081 : //PagedImage<Float> initialRes(tempres->shape(), tempres->coordinates(), tempresname);
1082 : //initialRes.copyData(*tempres);
1083 :
1084 : // Not use this way for now. Got an issue on removing pixel mask from *.mask image
1085 : // retrieve pixelmask (i.e. pb mask)
1086 : //LatticeExpr<Bool> pixmasyyk;
1087 : //if (imstore->mask()->hasPixelMask()) {
1088 : // pixmask = LatticeExpr<Bool> (imstore->mask()->pixelMask());
1089 : //
1090 : // create pixel mask (set to True for the previous selected region(s) to exclude the region from the stats/masking )
1091 : //LatticeExpr<Bool> prevmask( iif(*tempmask > 0.0 || pixmask, True, False) );
1092 : // TempImage<Float>* dummy = new TempImage<Float>(tempres->shape(), tempres->coordinates());
1093 : // dummy->attachMask(pixmask);
1094 : //if (ntrue(dummy->getMask())) tempres->attachMask(pixmask);
1095 : // if (ntrue(dummy->getMask())) {
1096 : //tempmask->removeMask();
1097 : // }
1098 : // else {
1099 : // os<<LogIO::DEBUG1<<"No pixel mask"<<LogIO::POST;
1100 : // }
1101 : // delete dummy; dummy=0;
1102 : //}
1103 : //
1104 : //input
1105 52 : Quantity qthresh(0,"");
1106 52 : Quantity qreso(0,"");
1107 52 : Quantity::read(qreso,resolution);
1108 52 : Float sigma = 0.0;
1109 : // if fracofpeak (fraction of a peak) is specified, use it to set a threshold
1110 52 : if ( fracofpeak != 0.0 ) {
1111 0 : if (fracofpeak > 1.0 )
1112 0 : throw(AipsError("Fracofpeak must be < 1.0"));
1113 0 : sigma = 0.0;
1114 : }
1115 52 : else if(Quantity::read(qthresh,threshold) ) {
1116 : // evaluate threshold input
1117 : //cerr<<"qthresh="<<qthresh.get().getValue()<<" unit="<<qthresh.getUnit()<<endl;
1118 52 : if (qthresh.getUnit()!="") {
1119 : // use qthresh and set sigma =0.0 to ignore
1120 0 : sigma = 0.0;
1121 : }
1122 : else {
1123 52 : sigma = String::toFloat(threshold);
1124 52 : if (sigma==0.0) {
1125 : // default case: threshold, fracofpeak unset => use default (3sigma)
1126 52 : sigma = 3.0;
1127 : }
1128 : }
1129 : }
1130 : else {
1131 0 : if (!sigma) {
1132 0 : throw(AipsError("Unrecognized automask threshold="+threshold));
1133 : }
1134 : }
1135 :
1136 : //TempImage<Float>* resforstats = new TempImage<Float>(imstore->residual()->shape(), imstore->residual()->coordinates());
1137 : //Array<Float> resdata2;
1138 : //imstore->residual()->get(resdata2);
1139 : //resforstats->put(resdata2);
1140 : //resforstats->setImageInfo(imstore->residual()->imageInfo());
1141 : //LatticeExpr<Bool> prevmask( iif(*tempmask > 0.0 , True, False) );
1142 : //resforstats->attachMask(prevmask);
1143 : //std::shared_ptr<casacore::ImageInterface<float> > tempres_ptr(resforstats);
1144 : /**
1145 : std::shared_ptr<casacore::ImageInterface<float> > tempres_ptr(tempres);
1146 : //cerr<<" tempres->hasPixelMask? "<<tempres->hasPixelMask()<<endl;
1147 : ImageStatsCalculator imcalc( tempres_ptr, 0, "", False);
1148 : Vector<Int> axes(2);
1149 : axes[0] = 0;
1150 : axes[1] = 1;
1151 : imcalc.setAxes(axes);
1152 : // for now just for new autobox alg.
1153 : if (alg.contains("newauto") ) {
1154 : imcalc.setRobust(true);
1155 : }
1156 : Record thestats = imcalc.statistics();
1157 : ***/
1158 :
1159 52 : Record* region_ptr=0;
1160 52 : String LELmask("");
1161 : // note: tempres is res image with pblimit applied
1162 52 : Bool robust(false); // robust is false by default (turn it on for 'multithresh')
1163 52 : Bool doAnnulus(false); // turn off stats on an annulus
1164 52 : if (alg.contains("multithresh") ) {
1165 52 : robust=true;
1166 : // define an annulus
1167 52 : Float outerRadius=0.0;
1168 52 : Float innerRadius=1.0;
1169 52 : if (imstore->hasPB()) {
1170 43 : LatticeExpr<Bool> blat;
1171 : //use pb based annulus for statistics
1172 43 : if (doAnnulus) {
1173 0 : outerRadius = 0.2;
1174 0 : innerRadius = 0.3;
1175 0 : blat=LatticeExpr<Bool> (iif(( *imstore->pb() < innerRadius && *imstore->pb() > outerRadius) , True, False) );
1176 : }
1177 : else {
1178 43 : blat=LatticeExpr<Bool> ((*imstore->pb()).pixelMask());
1179 : }
1180 43 : TempImage<Float>* testres = new TempImage<Float>(imstore->residual()->shape(), imstore->residual()->coordinates(), memoryToUse());
1181 43 : testres->set(1.0);
1182 43 : testres->attachMask(blat);
1183 :
1184 43 : if (ntrue(testres->getMask()) > 0 ) {
1185 43 : String pbname = imstore->getName()+".pb";
1186 43 : if (doAnnulus) {
1187 0 : LELmask=pbname+"<"+String::toString(innerRadius)+" && "+pbname+">"+String::toString(outerRadius);
1188 : }
1189 43 : }
1190 43 : delete testres; testres=0;
1191 43 : }
1192 : }
1193 :
1194 : //use new noise calc.
1195 : //Bool useoldstats(False);
1196 :
1197 : // at this point tempres has pbmask applied
1198 52 : LatticeExpr<Bool> pbmask(tempres->pixelMask());
1199 :
1200 52 : Record thestats = calcImageStatistics(*tempres, LELmask, region_ptr, robust);
1201 52 : Array<Double> maxs, mins, rmss, mads;
1202 52 : thestats.get(RecordFieldId("max"), maxs);
1203 52 : thestats.get(RecordFieldId("rms"), rmss);
1204 :
1205 52 : Record thenewstats;
1206 52 : if (!(iterdone==0 && robuststatsrec.nfields()) ) { // this is an indirect way to check if initial stats by nsigma threshold is already run.
1207 48 : if (fastnoise) { // use a faster but less robust noise determination
1208 44 : thenewstats = thestats;
1209 44 : os<< LogIO::DEBUG1 << " *** Using classic image statistics ***"<<LogIO::POST;
1210 44 : os<< LogIO::DEBUG1 << "All rms's on the input image -- rms.nelements()="<<rmss.nelements()<<" rms="<<rmss<<LogIO::POST;
1211 : //os<< LogIO::DEBUG1 << "All max's on the input image -- max.nelements()="<<maxs.nelements()<<" max="<<maxs<<LogIO::POST;
1212 44 : if (alg.contains("multithresh")) {
1213 44 : thestats.get(RecordFieldId("medabsdevmed"), mads);
1214 44 : os<< LogIO::DEBUG1 << "All MAD's on the input image -- mad.nelements()="<<mads.nelements()<<" mad="<<mads<<LogIO::POST;
1215 : }
1216 : }
1217 : else {
1218 : // Revised version of calcRobustImageStatistics (previous one- rename to calcRobustImageStatisticsOld)
1219 : //Record thenewstats = calcRobustImageStatistics(*tempres, *tempmask, pbmask, LELmask, region_ptr, robust, chanflag);
1220 : try{
1221 4 : thenewstats = calcRobustImageStatistics(*tempres, *tempmask, pbmask, LELmask, region_ptr, robust, chanflag);
1222 : }
1223 0 : catch( AipsError &x )
1224 : {
1225 : //now that there are part images that are masked...should just not proceed rather than throw an exception
1226 0 : if(x.getMesg().contains("zero element data"))
1227 0 : return;
1228 : else
1229 0 : throw(x);
1230 0 : }
1231 4 : Array<Double> newmaxs, newmins, newrmss, newmads;
1232 4 : thenewstats.get(RecordFieldId("max"), newmaxs);
1233 4 : thenewstats.get(RecordFieldId("rms"), newrmss);
1234 4 : os<< LogIO::DEBUG1 << "*** Using the new image statistics *** "<<LogIO::POST;
1235 4 : os<< LogIO::DEBUG1 << "All NEW rms's on the input image -- rms.nelements()="<<newrmss.nelements()<<" rms="<<newrmss<<LogIO::POST;
1236 : //os<< LogIO::DEBUG1 << "All NEW max's on the input image -- max.nelements()="<<newmaxs.nelements()<<" max="<<newmaxs<<LogIO::POST;
1237 4 : if (alg.contains("multithresh")) {
1238 4 : thenewstats.get(RecordFieldId("medabsdevmed"), newmads);
1239 4 : os<< LogIO::DEBUG1 << "All NEW MAD's on the input image -- mad.nelements()="<<newmads.nelements()<<" mad="<<newmads<<LogIO::POST;
1240 : }
1241 4 : }
1242 48 : os<<LogIO::NORMAL3<<" set the stats to what is calculated here" <<LogIO::POST;
1243 48 : robuststatsrec=thenewstats;
1244 : }
1245 : else {
1246 4 : thenewstats=robuststatsrec; // use existing
1247 : }
1248 : //os<<" current robuststatsrec nfields="<<robuststatsrec.nfields()<<LogIO::POST;
1249 :
1250 :
1251 52 : os<<LogIO::NORMAL <<"SidelobeLevel = "<<imstore->getPSFSidelobeLevel()<<LogIO::POST;
1252 52 : itsSidelobeLevel = imstore->getPSFSidelobeLevel();
1253 : //os<< "mask algortihm ="<<alg<< LogIO::POST;
1254 52 : if (alg==String("") || alg==String("onebox")) {
1255 : //cerr<<" calling makeAutoMask(), simple 1 cleanbox around the max"<<endl;
1256 0 : makeAutoMask(imstore);
1257 : }
1258 52 : else if (alg==String("thresh")) {
1259 0 : autoMaskByThreshold(*tempmask, *tempres, *imstore->psf(), qreso, resbybeam, qthresh, fracofpeak,
1260 : thestats, sigma, nmask, autoadjust);
1261 : }
1262 52 : else if (alg==String("thresh2")) {
1263 0 : autoMaskByThreshold2(*tempmask, *tempres, *imstore->psf(), qreso, resbybeam, qthresh, fracofpeak, thestats, sigma, nmask);
1264 : }
1265 52 : else if (alg==String("multithresh")) {
1266 52 : autoMaskByMultiThreshold(*tempmask, posmask, *tempres, *imstore->psf(), thestats, thenewstats, iterdone, chanflag, minpercentchange, itsSidelobeLevel, sidelobethreshold, noisethreshold, lownoisethreshold, negativethreshold, cutthreshold, smoothfactor, minbeamfrac, growiterations, dogrowprune, verbose, isthresholdreached);
1267 : }
1268 :
1269 : // this did not work (it won't physically remove the mask from the image
1270 : /***
1271 : if (imstore->mask()->hasPixelMask()) {
1272 : imstore.get()->mask()->removeRegion(fname, RegionHandler::Any, False);
1273 : cerr<<"imstore->mask()->name()="<<imstore->mask()->name()<<endl;
1274 : cerr<<" mask: "<<fname<<" exist on disk? ="<<File(fname).isDirectory()<<endl;
1275 : }
1276 : ***/
1277 : {
1278 52 : Array<Float> updatedMaskData;
1279 52 : tempmask->get(updatedMaskData);
1280 52 : imstore->mask()->put(updatedMaskData);
1281 52 : }
1282 : //tempmask->get(maskdata);
1283 : //imstore->mask()->put(maskdata);
1284 52 : delete tempmask; tempmask=0;
1285 : //delete temppsf; temppsf=0;
1286 52 : delete tempres; tempres=0;
1287 52 : }
1288 :
1289 743 : Record SDMaskHandler::calcImageStatistics(ImageInterface<Float>& res, String& LELmask, Record* regionPtr, const Bool robust )
1290 : {
1291 1486 : LogIO os( LogOrigin("SDMaskHandler","calcImageStatistics",WHERE) );
1292 743 : TempImage<Float>* tempres = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
1293 743 : Array<Float> resdata;
1294 : //
1295 :
1296 743 : res.get(resdata);
1297 743 : tempres->put(resdata);
1298 : // if input image (res) has a pixel mask, make sure to honor it so the region is exclude from statistics
1299 743 : if (res.hasPixelMask()) {
1300 163 : tempres->attachMask(res.pixelMask());
1301 : }
1302 :
1303 743 : tempres->setImageInfo(res.imageInfo());
1304 743 : std::shared_ptr<casacore::ImageInterface<Float> > tempres_ptr(tempres);
1305 :
1306 : // 2nd arg is regionRecord, 3rd is LELmask expression and those will be AND
1307 : // to define a region to be get statistics
1308 : //ImageStatsCalculator imcalc( tempres_ptr, 0, "", False);
1309 : //String lelstring = pbname+">0.92 && "+pbname+"<0.98";
1310 : //cerr<<"lelstring = "<<lelstring<<endl;
1311 : //cerr<<"LELMask="<<LELmask<<endl;
1312 743 : ImageStatsCalculator<Float> imcalc( tempres_ptr, regionPtr, LELmask, False);
1313 743 : Vector<Int> axes(2);
1314 743 : axes[0] = 0;
1315 743 : axes[1] = 1;
1316 743 : imcalc.setAxes(axes);
1317 743 : imcalc.setRobust(robust);
1318 743 : Record thestats = imcalc.statistics();
1319 :
1320 : //cerr<<"thestats="<<thestats<<endl;
1321 : //Array<Double> max, min, rms, mad;
1322 : //thestats.get(RecordFieldId("max"), max);
1323 1486 : return thestats;
1324 743 : }
1325 :
1326 : // robust image statistics for better noise estimation
1327 0 : Record SDMaskHandler::calcRobustImageStatisticsOld(ImageInterface<Float>& res, ImageInterface<Float>& prevmask , LatticeExpr<Bool>& pbmask, String& LELmask, Record* regionPtr, const Bool robust, Vector<Bool>& chanflag )
1328 : {
1329 0 : LogIO os( LogOrigin("SDMaskHandler","calcRobustImageStatisticsOld",WHERE) );
1330 :
1331 : //Bool debugStats(true);
1332 :
1333 0 : Array<Float> wholemaskdata;
1334 0 : IPosition maskshp = prevmask.shape();
1335 0 : IPosition maskstart(4,0);
1336 0 : IPosition masklength(4,maskshp(0),maskshp(1), 1, 1);
1337 0 : Slicer masksl(maskstart, masklength);
1338 0 : prevmask.doGetSlice(wholemaskdata,masksl); // single plane
1339 0 : Float npixwholemask = sum(wholemaskdata);
1340 0 : Bool fullmask(False);
1341 0 : if (npixwholemask == (Float) maskshp(0) * (Float) maskshp(1) ) {
1342 0 : fullmask=True;
1343 0 : os<<LogIO::DEBUG1 <<"Appears to be fully masked! npix for the whole mask ="<<npixwholemask<<LogIO::POST;
1344 : }
1345 : //TempImage<Float>* tempres = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
1346 : //Array<Float> resdata;
1347 :
1348 : //res.get(resdata);
1349 : //tempres->put(resdata);
1350 : // if input image (res) has a pixel mask, make sure to honor it so the region is exclude from statistics
1351 : //if (res.hasPixelMask()) {
1352 : // tempres->attachMask(res.pixelMask());
1353 : //}
1354 0 : if (nfalse(pbmask.getMask())) {
1355 0 : os<<LogIO::DEBUG1<<"has pbmask"<<LogIO::POST;
1356 : }
1357 :
1358 : //check Stokes and spectral axes
1359 : //IPosition shp = tempres->shape();
1360 0 : IPosition shp = res.shape();
1361 : //Int specaxis = CoordinateUtil::findSpectralAxis(tempres->coordinates());
1362 0 : Int specaxis = CoordinateUtil::findSpectralAxis(res.coordinates());
1363 0 : uInt nchan = shp(specaxis);
1364 0 : Vector<Stokes::StokesTypes> whichPols;
1365 : //Int stokesaxis = CoordinateUtil::findStokesAxis(whichPols, tempres->coordinates());
1366 0 : Int stokesaxis = CoordinateUtil::findStokesAxis(whichPols, res.coordinates());
1367 0 : uInt nStokes= shp(stokesaxis);
1368 : uInt iaxis2;
1369 : uInt iaxis3;
1370 :
1371 : //TempImage<Bool> pbmaskim(shp, tempres->coordinates(), memoryToUse());
1372 0 : TempImage<Bool> pbmaskim(shp, res.coordinates(), memoryToUse());
1373 0 : pbmaskim.copyData(pbmask);
1374 :
1375 : //check dimensions of tempres, prevmask, pbmask
1376 0 : if (prevmask.shape()!=shp) {
1377 0 : throw(AipsError("Mismatch in shapes of the previous mask and residual image"));
1378 : }
1379 0 : else if (pbmask.shape()!=shp) {
1380 0 : throw(AipsError("Mismatch in shapes of pbmask and residual image"));
1381 : }
1382 :
1383 : //for stats storage
1384 0 : IPosition statshape(2, shp(2), shp(3));
1385 0 : Array<Double> outMins(statshape);
1386 0 : Array<Double> outMaxs(statshape);
1387 0 : Array<Double> outRmss(statshape);
1388 0 : Array<Double> outMads(statshape);
1389 0 : Array<Double> outMdns(statshape);
1390 :
1391 0 : for (uInt istokes = 0; istokes < nStokes; istokes++) {
1392 0 : std::vector<double> mins, maxs, rmss, mads, mdns;
1393 0 : for (uInt ichan = 0; ichan < nchan; ichan++ ) {
1394 0 : if (stokesaxis==3) {
1395 0 : iaxis2 = ichan;
1396 0 : iaxis3 = istokes;
1397 : }
1398 : else {
1399 0 : iaxis2 = istokes;
1400 0 : iaxis3 = ichan;
1401 : }
1402 0 : if (chanflag.nelements()==0 || !chanflag(ichan)) { // get new stats
1403 : // check if mask is empty (evaulated as the whole input mask )
1404 0 : Array<Float> maskdata;
1405 : //IPosition maskshape = prevmask.shape();
1406 : //Int naxis = maskshape.size();
1407 : //IPosition blc(naxis,0);
1408 : //IPosition trc=maskshape-1;
1409 : //Slicer sl(blc,trc,Slicer::endIsLast);
1410 0 : IPosition start(4, 0, 0, iaxis2, iaxis3);
1411 0 : IPosition length(4, shp(0),shp(1), 1, 1);
1412 0 : Slicer sl(start, length);
1413 : //os<<"slicer for subimage start="<<start<<" length="<<length<<LogIO::POST;
1414 : // create subimage (slice) of tempres
1415 0 : AxesSpecifier aspec(False);
1416 0 : SubImage<Float>* subRes = new SubImage<Float>(res, sl, aspec, True);
1417 0 : TempImage<Float>* tempSubRes = new TempImage<Float>(subRes->shape(), subRes->coordinates(), memoryToUse());
1418 0 : tempSubRes->copyData(*subRes);
1419 0 : SubImage<Float>* subprevmask = new SubImage<Float>(prevmask, sl, aspec, True);
1420 0 : SubImage<Bool>* subpbmask = new SubImage<Bool>(pbmaskim, sl, aspec, True);
1421 :
1422 0 : prevmask.doGetSlice(maskdata,sl); // single plane
1423 0 : Float nmaskpix = sum(maskdata);
1424 0 : Array<Bool> booldata;
1425 0 : pbmask.doGetSlice(booldata,sl); // single plane pbmask
1426 : //os<<"valid pix ntrue(booldata)="<<ntrue(booldata)<<LogIO::POST;
1427 :
1428 0 : if (nmaskpix==0 ) {
1429 0 : if (ntrue(booldata)) {
1430 0 : os<<LogIO::DEBUG1<<"No existing mask but apply pbmask..."<<LogIO::POST;
1431 0 : tempSubRes->attachMask(*subpbmask);
1432 : //os<<"ntrue tempres pixelmask=="<<ntrue(tempres->getMask())<<LogIO::POST;
1433 : }
1434 : }
1435 0 : else if (!fullmask) {
1436 0 : os<<LogIO::DEBUG1<<"Do the image statitistics in a region outside the mask..."<<LogIO::POST;
1437 0 : LatticeExpr<Bool> outsideMaskReg;
1438 : //if (res.hasPixelMask()) {
1439 0 : if (nfalse(booldata)) {
1440 : //LatticeExpr<Bool> pbmask(iif(res.pixelMask());
1441 0 : outsideMaskReg = LatticeExpr<Bool> (iif(*subprevmask == 1.0 || !*subpbmask, False, True));
1442 : // for debug
1443 : //if (debugStats) {
1444 : // PagedImage<Float> pbmaskSave(res.shape(), res.coordinates(), "pbmasksaved.im");
1445 : // LatticeExpr<Float> temppbmasksave(iif(subpbmask, 1.0, 0.0));
1446 : // pbmaskSave.copyData(temppbmasksave);
1447 : //}
1448 : }
1449 : else {
1450 0 : outsideMaskReg = LatticeExpr<Bool> (iif(*subprevmask == 1.0, False, True));
1451 : //LatticeExpr<Bool> outsideMaskReg(iif((*subprevmask == 1.0 || !*subpbmask, False, True));
1452 : }
1453 : //tempres->attachMask(outsideMaskReg);
1454 0 : tempSubRes->attachMask(outsideMaskReg);
1455 0 : }
1456 :
1457 : //DEBUG
1458 : //if(debugStats) {
1459 : // PagedImage<Float> temptempIm(res.shape(), res.coordinates(), "temptempmask.im");
1460 : // temptempIm.copyData(prevmask);
1461 : // PagedImage<Float> temptempResIm(res.shape(), res.coordinates(), "temptempres.im");
1462 : // temptempResIm.copyData(*tempres);
1463 : // temptempResIm.makeMask("maskcopy",True, True);
1464 : // if (tempres->hasPixelMask()) {
1465 : // temptempResIm.pixelMask().put((tempres->pixelMask()).get());
1466 : // }
1467 : //} //for debug
1468 :
1469 0 : std::shared_ptr<casacore::ImageInterface<Float> > tempres_ptr(tempSubRes);
1470 :
1471 : // 2nd arg is regionRecord, 3rd is LELmask expression and those will be AND
1472 : // to define a region to be get statistics
1473 : //ImageStatsCalculator imcalc( tempres_ptr, 0, "", False);
1474 0 : ImageStatsCalculator<Float> imcalc( tempres_ptr, regionPtr, LELmask, True);
1475 0 : Vector<Int> axes(2);
1476 0 : axes[0] = 0;
1477 0 : axes[1] = 1;
1478 0 : imcalc.setAxes(axes);
1479 :
1480 : // for an empty (= no mask) mask, use Chauvenet algorithm with maxiter=5 and zscore=-1
1481 0 : if (nmaskpix==0.0 || fullmask ) {
1482 0 : os<<"Using Chauvenet algorithm for image statistics"<<LogIO::POST;
1483 0 : imcalc.configureChauvenet(Double(-1.0), Int(5));
1484 : }
1485 0 : imcalc.setRobust(robust);
1486 0 : Record thestats = imcalc.statistics();
1487 :
1488 0 : Array<Double> arrmins, arrmaxs, arrrmss, arrmads, arrmdns;
1489 :
1490 : // repack
1491 0 : thestats.get(RecordFieldId("min"), arrmins);
1492 0 : thestats.get(RecordFieldId("max"), arrmaxs);
1493 0 : thestats.get(RecordFieldId("rms"), arrrmss);
1494 : //robust = True only
1495 0 : if (robust) {
1496 0 : thestats.get(RecordFieldId("medabsdevmed"), arrmads);
1497 0 : thestats.get(RecordFieldId("median"), arrmdns);
1498 : }
1499 0 : if (arrmaxs.nelements()==0 ){
1500 0 : throw(AipsError("No image statisitics is returned. Possible the whole image is masked."));
1501 : }
1502 0 : IPosition zeroindx(arrmins.ndim(), 0);
1503 :
1504 0 : mins.push_back(arrmins(zeroindx));
1505 0 : maxs.push_back(arrmaxs(zeroindx));
1506 0 : rmss.push_back(arrrmss(zeroindx));
1507 0 : if (robust) {
1508 0 : mads.push_back(arrmads(zeroindx));
1509 0 : mdns.push_back(arrmdns(zeroindx));
1510 : }
1511 : //os<<"deleting tempSubRes"<<LogIO::POST;
1512 : //delete tempSubRes; tempSubRes=0;
1513 0 : delete subRes; subRes=0;
1514 0 : delete subprevmask; subprevmask=0;
1515 0 : delete subpbmask; subpbmask=0;
1516 :
1517 0 : }// if-ichanflag end
1518 : else {
1519 0 : mins.push_back(Double(0.0));
1520 0 : maxs.push_back(Double(0.0));
1521 0 : rmss.push_back(Double(0.0));
1522 0 : if (robust) {
1523 0 : mads.push_back(Double(0.0));
1524 0 : mdns.push_back(Double(0.0));
1525 : }
1526 : }
1527 : } // chan-for-loop end
1528 : //os<<" rms vector for stokes="<<istokes<<" : "<<rmss<<LogIO::POST;
1529 : //os<<"outMins.shape="<<outMins.shape()<<LogIO::POST;
1530 :
1531 0 : IPosition start(2, istokes, 0);
1532 0 : IPosition length(2, 1, nchan); // slicer per Stokes
1533 : //Slicer sl(blc, trc,Slicer::endIsLast );
1534 0 : Slicer slstokes(start, length);
1535 : //cerr<<"set outMin slstokes="<<slstokes<<" to the mins vector"<<endl;
1536 0 : Vector<Double> minvec(mins);
1537 0 : Vector<Double> maxvec(maxs);
1538 0 : Vector<Double> rmsvec(rmss);
1539 : //os<<"stl vector rmss"<<rmss<<LogIO::POST;
1540 : //os<<"rmsvec.shape="<<rmsvec.shape()<<" rmsvec="<<rmsvec<<LogIO::POST;
1541 0 : Matrix<Double> minmat(minvec);
1542 0 : Matrix<Double> maxmat(maxvec);
1543 : //Matrix<Double> rmsmat((Vector<Double>) rmss);
1544 0 : Matrix<Double> rmsmat(rmsvec);
1545 : //os<<"Intial shape of rmsmat="<<rmsmat.shape()<<LogIO::POST;
1546 : //os<<"Intial content of rmsmat="<<rmsmat<<LogIO::POST;
1547 : // copyValues do not work if there is a degerate axis in front
1548 0 : minmat.resize(IPosition(2, nchan, 1),True);
1549 0 : maxmat.resize(IPosition(2, nchan, 1),True);
1550 0 : rmsmat.resize(IPosition(2, nchan, 1),True);
1551 0 : Array<Double> minarr = transpose(minmat);
1552 0 : Array<Double> maxarr = transpose(maxmat);
1553 0 : Array<Double> rmsarr = transpose(rmsmat);
1554 0 : if (robust) {
1555 0 : Vector<Double> madvec(mads);
1556 0 : Vector<Double> mdnvec(mdns);
1557 0 : Matrix<Double> madmat(madvec);
1558 0 : Matrix<Double> mdnmat(mdnvec);
1559 0 : madmat.resize(IPosition(2, nchan, 1),True);
1560 0 : mdnmat.resize(IPosition(2, nchan, 1),True);
1561 0 : Array<Double> madarr = transpose(madmat);
1562 0 : Array<Double> mdnarr = transpose(mdnmat);
1563 0 : outMads(slstokes) = madarr;
1564 0 : outMdns(slstokes) = mdnarr;
1565 : //os<<"madarr="<<madarr<<LogIO::POST;
1566 : //os<<"mdnarr="<<mdnarr<<LogIO::POST;
1567 0 : }
1568 : //os<<"rmsarr="<<rmsarr<<LogIO::POST;
1569 0 : outMins(slstokes) = minarr;
1570 0 : outMaxs(slstokes) = maxarr;
1571 0 : outRmss(slstokes) = rmsarr;
1572 : //cerr<<"Done setting outMin sltokes="<<slstokes<<" to the mins vector"<<endl;
1573 0 : } // stokes-for-loop end
1574 :
1575 0 : Record theOutStatRec;
1576 0 : if (shp(2) == 1) { //Single Stokes plane
1577 : // remove degenerate axis
1578 0 : theOutStatRec.define("min", outMins.nonDegenerate(IPosition(1,1)));
1579 0 : theOutStatRec.define("max", outMaxs.nonDegenerate(IPosition(1,1)));
1580 0 : theOutStatRec.define("rms", outRmss.nonDegenerate(IPosition(1,1)));
1581 0 : if (robust) {
1582 0 : theOutStatRec.define("medabsdevmed", outMads.nonDegenerate(IPosition(1,1)));
1583 0 : theOutStatRec.define("median", outMdns.nonDegenerate(IPosition(1,1)));
1584 : }
1585 : }
1586 0 : else if(shp(3) == 1) { //Single channel plane
1587 0 : theOutStatRec.define("min", outMins.nonDegenerate(IPosition(1,0)));
1588 0 : theOutStatRec.define("max", outMaxs.nonDegenerate(IPosition(1,0)));
1589 0 : theOutStatRec.define("rms", outRmss.nonDegenerate(IPosition(1,0)));
1590 0 : if (robust) {
1591 0 : theOutStatRec.define("medabsdevmed", outMads.nonDegenerate(IPosition(1,0)));
1592 0 : theOutStatRec.define("median", outMdns.nonDegenerate(IPosition(1,0)));
1593 : }
1594 : }
1595 : else {
1596 0 : theOutStatRec.define("min", outMins);
1597 0 : theOutStatRec.define("max", outMaxs);
1598 0 : theOutStatRec.define("rms", outRmss);
1599 0 : if (robust) {
1600 0 : theOutStatRec.define("medabsdevmed", outMads);
1601 0 : theOutStatRec.define("median", outMdns);
1602 : }
1603 : }
1604 0 : return theOutStatRec;
1605 0 : }
1606 :
1607 : // robust image statistics for better noise estimation - revised for making it faster
1608 : // Modified version to do stats all at once
1609 6 : Record SDMaskHandler::calcRobustImageStatistics(ImageInterface<Float>& res, ImageInterface<Float>& prevmask , LatticeExpr<Bool>& pbmask, String& LELmask, Record* regionPtr, const Bool robust, Vector<Bool>& chanflag )
1610 : {
1611 12 : LogIO os( LogOrigin("SDMaskHandler","calcRobustImageStatistics",WHERE) );
1612 :
1613 : //Bool debugStats(true);
1614 :
1615 6 : Array<Float> wholemaskdata;
1616 6 : IPosition maskshp = prevmask.shape();
1617 6 : IPosition maskstart(4,0);
1618 6 : IPosition masklength(4,maskshp(0),maskshp(1), 1, 1);
1619 6 : Slicer masksl(maskstart, masklength);
1620 6 : prevmask.doGetSlice(wholemaskdata,masksl); // single plane
1621 6 : Float npixwholemask = sum(wholemaskdata);
1622 6 : Bool fullmask(False);
1623 :
1624 6 : if (npixwholemask == (Float) maskshp(0) * (Float) maskshp(1) ) {
1625 0 : fullmask=True;
1626 0 : os<<LogIO::DEBUG1 <<"Appears to be fully masked! npix for the whole mask ="<<npixwholemask<<LogIO::POST;
1627 : }
1628 :
1629 : //res.get(resdata);
1630 : //tempres->put(resdata);
1631 : // if input image (res) has a pixel mask, make sure to honor it so the region is exclude from statistics
1632 : //if (res.hasPixelMask()) {
1633 : // tempres->attachMask(res.pixelMask());
1634 : //}
1635 6 : if (nfalse(pbmask.getMask())) {
1636 0 : os<<LogIO::DEBUG1<<"has pbmask..."<<LogIO::POST;
1637 0 : os<<LogIO::DEBUG1<<"-> nfalse(pbmask)="<<nfalse(pbmask.getMask())<<LogIO::POST;
1638 : }
1639 :
1640 : // do stats on a whole cube at once for each algrithms
1641 : //check Stokes and spectral axes
1642 6 : IPosition shp = res.shape();
1643 6 : Int specaxis = CoordinateUtil::findSpectralAxis(res.coordinates());
1644 6 : uInt nchan = shp(specaxis);
1645 6 : Vector<Stokes::StokesTypes> whichPols;
1646 6 : Int stokesaxis = CoordinateUtil::findStokesAxis(whichPols, res.coordinates());
1647 6 : uInt nStokes= shp(stokesaxis);
1648 : uInt iaxis2;
1649 : uInt iaxis3;
1650 :
1651 : //TempImage<Bool> pbmaskim(shp, tempres->coordinates(), memoryToUse());
1652 : //TempImage<Bool> pbmaskim(shp, res.coordinates(), memoryToUse());
1653 : //pbmaskim.copyData(pbmask);
1654 :
1655 : //check dimensions of tempres, prevmask, pbmask
1656 6 : if (prevmask.shape()!=shp) {
1657 0 : throw(AipsError("Mismatch in shapes of the previous mask and residual image"));
1658 : }
1659 6 : else if (pbmask.shape()!=shp) {
1660 0 : throw(AipsError("Mismatch in shapes of pbmask and residual image"));
1661 : }
1662 :
1663 : //for stats storage
1664 6 : IPosition statshape(2, shp(2), shp(3));
1665 6 : Array<Double> outMins(statshape);
1666 6 : Array<Double> outMaxs(statshape);
1667 6 : Array<Double> outRmss(statshape);
1668 6 : Array<Double> outMads(statshape);
1669 6 : Array<Double> outMdns(statshape);
1670 :
1671 : //do stats for each algortims all at once.
1672 : // 2nd arg is regionRecord, 3rd is LELmask expression and those will be AND
1673 : // to define a region to be get statistics
1674 : //ImageStatsCalculator imcalc( tempres_ptr, 0, "", False);
1675 : // Chauvenet over a full image
1676 : // for an empty (= no mask) mask, use Chauvenet algorithm with maxiter=5 and zscore=-1
1677 6 : TempImage<Float>* tempRes = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
1678 6 : tempRes->copyData(res);
1679 6 : tempRes->attachMask(pbmask);
1680 6 : std::shared_ptr<casacore::ImageInterface<Float> > tempres_ptr(tempRes);
1681 6 : ImageStatsCalculator<Float> imcalc( tempres_ptr, regionPtr, LELmask, False);
1682 6 : Vector<Int> axes(2);
1683 6 : axes[0] = 0;
1684 6 : axes[1] = 1;
1685 6 : imcalc.setAxes(axes);
1686 6 : os<<LogIO::DEBUG1<<"Using Chauvenet algorithm for image statistics for a whole cube"<<LogIO::POST;
1687 6 : imcalc.configureChauvenet(Double(-1.0), Int(5));
1688 6 : imcalc.setRobust(robust);
1689 6 : Record thestatsNoMask = imcalc.statistics();
1690 :
1691 : // do stats outside the mask
1692 : //tempres_ptr.reset();
1693 6 : Record thestatsWithMask;
1694 6 : if(!fullmask) {
1695 6 : TempImage<Float>* tempRes2 = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
1696 6 : tempRes2->copyData(res);
1697 6 : os<<LogIO::DEBUG1<<"Do the image statitistics in a region outside the mask..."<<LogIO::POST;
1698 6 : LatticeExpr<Bool> outsideMaskReg;
1699 6 : outsideMaskReg = LatticeExpr<Bool> (iif(prevmask == 1.0 || !pbmask, False, True));
1700 : // need this case? for no existance of pb mask?
1701 : //outsideMaskReg = LatticeExpr<Bool> (iif(prevmask == 1.0, False, True));
1702 6 : tempRes2->attachMask(outsideMaskReg);
1703 6 : std::shared_ptr<casacore::ImageInterface<Float> > tempres_ptr2(tempRes2);
1704 6 : ImageStatsCalculator<Float> imcalc2( tempres_ptr2, regionPtr, LELmask, False);
1705 6 : imcalc2.setAxes(axes);
1706 6 : imcalc2.setRobust(robust);
1707 6 : thestatsWithMask = imcalc2.statistics();
1708 6 : }
1709 :
1710 6 : Array<Double> arrminsNoMask, arrmaxsNoMask, arrrmssNoMask, arrmadsNoMask, arrmdnsNoMask;
1711 6 : Array<Double> arrmins, arrmaxs, arrrmss, arrmads, arrmdns;
1712 6 : thestatsNoMask.get(RecordFieldId("min"), arrminsNoMask);
1713 6 : thestatsNoMask.get(RecordFieldId("max"), arrmaxsNoMask);
1714 6 : thestatsNoMask.get(RecordFieldId("rms"), arrrmssNoMask);
1715 6 : IPosition statsind(arrmins.ndim(), 0);
1716 : //robust = True only
1717 6 : if (robust) {
1718 6 : thestatsNoMask.get(RecordFieldId("medabsdevmed"), arrmadsNoMask);
1719 6 : thestatsNoMask.get(RecordFieldId("median"), arrmdnsNoMask);
1720 : }
1721 6 : if (!fullmask) { // with Mask stats
1722 6 : thestatsWithMask.get(RecordFieldId("min"), arrmins);
1723 6 : thestatsWithMask.get(RecordFieldId("max"), arrmaxs);
1724 6 : thestatsWithMask.get(RecordFieldId("rms"), arrrmss);
1725 6 : if (robust) {
1726 6 : thestatsWithMask.get(RecordFieldId("medabsdevmed"), arrmads);
1727 6 : thestatsWithMask.get(RecordFieldId("median"), arrmdns);
1728 : }
1729 : }
1730 :
1731 12 : for (uInt istokes = 0; istokes < nStokes; istokes++) {
1732 6 : std::vector<double> mins, maxs, rmss, mads, mdns;
1733 12 : for (uInt ichan = 0; ichan < nchan; ichan++ ) {
1734 6 : if (stokesaxis==3) {
1735 0 : iaxis2 = ichan;
1736 0 : iaxis3 = istokes;
1737 0 : statsind(0) = iaxis2;
1738 0 : if (nStokes>1) {
1739 0 : statsind(1) = iaxis3;
1740 : }
1741 : }
1742 : else {
1743 6 : iaxis2 = istokes;
1744 6 : iaxis3 = ichan;
1745 6 : if (nStokes>1) {
1746 0 : statsind(0) = iaxis2;
1747 0 : statsind(1) = iaxis3;
1748 : }
1749 : else { // Stokes axis is degenerate
1750 6 : statsind(0) = iaxis3;
1751 : }
1752 : }
1753 :
1754 6 : if (chanflag.nelements()==0 || !chanflag(ichan)) { // get new stats
1755 : // check if mask is empty (evaulated as the whole input mask )
1756 6 : Array<Float> maskdata;
1757 6 : IPosition start(4, 0, 0, iaxis2, iaxis3);
1758 6 : IPosition length(4, shp(0),shp(1), 1, 1);
1759 6 : Slicer sl(start, length);
1760 : //os<<"slicer for subimage start="<<start<<" length="<<length<<LogIO::POST;
1761 : // create subimage (slice) of tempres
1762 : //AxesSpecifier aspec(False);
1763 : //SubImage<Float>* subprevmask = new SubImage<Float>(prevmask, sl, aspec, True);
1764 :
1765 : // get chan mask data to evaulate no mask
1766 6 : prevmask.doGetSlice(maskdata,sl); // single plane
1767 6 : Float nmaskpix = sum(maskdata);
1768 6 : Array<Bool> booldata;
1769 :
1770 :
1771 : Double min, max, rms, mad, mdn;
1772 : // for an empty (= no mask) mask, use Chauvenet algorithm with maxiter=5 and zscore=-1
1773 6 : if (nmaskpix==0.0 || fullmask ) {
1774 4 : os<<"[C"<<ichan<<"] Using Chauvenet algorithm for the image statistics "<<LogIO::POST;
1775 4 : if(arrminsNoMask.nelements()==0 || arrmaxsNoMask.nelements() ==0 || arrrmssNoMask.nelements() ==0){
1776 0 : throw(AipsError("No image statistics possible on zero element data"));
1777 : }
1778 4 : min = arrminsNoMask(statsind);
1779 4 : max = arrmaxsNoMask(statsind);
1780 4 : rms = arrrmssNoMask(statsind);
1781 4 : if (robust) {
1782 4 : if(arrmadsNoMask.nelements()==0 || arrmdnsNoMask.nelements() ==0 || arrrmssNoMask.nelements() ==0)
1783 0 : throw(AipsError("No robust image statistics possible on zero element data"));
1784 4 : mad = arrmadsNoMask(statsind);
1785 4 : mdn = arrmdnsNoMask(statsind);
1786 : }
1787 : }
1788 : else {
1789 : //os<<"[C"<<ichan<<"] Using the image statitistics in a region outside the mask"<<LogIO::POST;
1790 2 : min = arrmins(statsind);
1791 2 : max = arrmaxs(statsind);
1792 2 : rms = arrrmss(statsind);
1793 2 : if (robust) {
1794 2 : mad = arrmads(statsind);
1795 2 : mdn = arrmdns(statsind);
1796 : }
1797 : }
1798 :
1799 :
1800 : // repack
1801 : //if (arrmaxs.nelements()==0 ){
1802 : // throw(AipsError("No image statisitics is returned. Possible the whole image is masked."));
1803 : //}
1804 :
1805 6 : mins.push_back(min);
1806 6 : maxs.push_back(max);
1807 6 : rmss.push_back(rms);
1808 6 : if (robust) {
1809 6 : mads.push_back(mad);
1810 6 : mdns.push_back(mdn);
1811 : }
1812 6 : }// if-ichanflag end
1813 : else {
1814 0 : mins.push_back(Double(0.0));
1815 0 : maxs.push_back(Double(0.0));
1816 0 : rmss.push_back(Double(0.0));
1817 0 : if (robust) {
1818 0 : mads.push_back(Double(0.0));
1819 0 : mdns.push_back(Double(0.0));
1820 : }
1821 : }
1822 : } // chan-for-loop end
1823 : //os<<" rms vector for stokes="<<istokes<<" : "<<rmss<<LogIO::POST;
1824 : //os<<"outMins.shape="<<outMins.shape()<<LogIO::POST;
1825 :
1826 6 : IPosition start(2, istokes, 0);
1827 6 : IPosition length(2, 1, nchan); // slicer per Stokes
1828 : //Slicer sl(blc, trc,Slicer::endIsLast );
1829 6 : Slicer slstokes(start, length);
1830 : //cerr<<"set outMin slstokes="<<slstokes<<" to the mins vector"<<endl;
1831 6 : Vector<Double> minvec(mins);
1832 6 : Vector<Double> maxvec(maxs);
1833 6 : Vector<Double> rmsvec(rmss);
1834 : //os<<"stl vector rmss"<<rmss<<LogIO::POST;
1835 : //os<<"rmsvec.shape="<<rmsvec.shape()<<" rmsvec="<<rmsvec<<LogIO::POST;
1836 6 : Matrix<Double> minmat(minvec);
1837 6 : Matrix<Double> maxmat(maxvec);
1838 : //Matrix<Double> rmsmat((Vector<Double>) rmss);
1839 6 : Matrix<Double> rmsmat(rmsvec);
1840 : //os<<"Intial shape of rmsmat="<<rmsmat.shape()<<LogIO::POST;
1841 : //os<<"Intial content of rmsmat="<<rmsmat<<LogIO::POST;
1842 : // copyValues do not work if there is a degerate axis in front
1843 6 : minmat.resize(IPosition(2, nchan, 1),True);
1844 6 : maxmat.resize(IPosition(2, nchan, 1),True);
1845 6 : rmsmat.resize(IPosition(2, nchan, 1),True);
1846 6 : Array<Double> minarr = transpose(minmat);
1847 6 : Array<Double> maxarr = transpose(maxmat);
1848 6 : Array<Double> rmsarr = transpose(rmsmat);
1849 6 : if (robust) {
1850 6 : Vector<Double> madvec(mads);
1851 6 : Vector<Double> mdnvec(mdns);
1852 6 : Matrix<Double> madmat(madvec);
1853 6 : Matrix<Double> mdnmat(mdnvec);
1854 6 : madmat.resize(IPosition(2, nchan, 1),True);
1855 6 : mdnmat.resize(IPosition(2, nchan, 1),True);
1856 6 : Array<Double> madarr = transpose(madmat);
1857 6 : Array<Double> mdnarr = transpose(mdnmat);
1858 6 : outMads(slstokes) = madarr;
1859 6 : outMdns(slstokes) = mdnarr;
1860 : //os<<"madarr="<<madarr<<LogIO::POST;
1861 : //os<<"mdnarr="<<mdnarr<<LogIO::POST;
1862 6 : }
1863 6 : outMins(slstokes) = minarr;
1864 6 : outMaxs(slstokes) = maxarr;
1865 6 : outRmss(slstokes) = rmsarr;
1866 6 : } // stokes-for-loop end
1867 :
1868 6 : Record theOutStatRec;
1869 6 : if (shp(2) == 1) { //Single Stokes plane
1870 : // remove degenerate axis
1871 : //os<<"Stokes axis has a single Stokes"<<LogIO::POST;
1872 6 : theOutStatRec.define("min", outMins.nonDegenerate(IPosition(1,1)));
1873 6 : theOutStatRec.define("max", outMaxs.nonDegenerate(IPosition(1,1)));
1874 6 : theOutStatRec.define("rms", outRmss.nonDegenerate(IPosition(1,1)));
1875 6 : if (robust) {
1876 6 : theOutStatRec.define("medabsdevmed", outMads.nonDegenerate(IPosition(1,1)));
1877 6 : theOutStatRec.define("median", outMdns.nonDegenerate(IPosition(1,1)));
1878 : }
1879 : }
1880 0 : else if(shp(3) == 1) { //Single channel plane
1881 0 : theOutStatRec.define("min", outMins.nonDegenerate(IPosition(1,0)));
1882 0 : theOutStatRec.define("max", outMaxs.nonDegenerate(IPosition(1,0)));
1883 0 : theOutStatRec.define("rms", outRmss.nonDegenerate(IPosition(1,0)));
1884 0 : if (robust) {
1885 0 : theOutStatRec.define("medabsdevmed", outMads.nonDegenerate(IPosition(1,0)));
1886 0 : theOutStatRec.define("median", outMdns.nonDegenerate(IPosition(1,0)));
1887 : }
1888 : }
1889 : else {
1890 0 : theOutStatRec.define("min", outMins);
1891 0 : theOutStatRec.define("max", outMaxs);
1892 0 : theOutStatRec.define("rms", outRmss);
1893 0 : if (robust) {
1894 0 : theOutStatRec.define("medabsdevmed", outMads);
1895 0 : theOutStatRec.define("median", outMdns);
1896 : }
1897 : }
1898 :
1899 12 : return theOutStatRec;
1900 6 : }
1901 :
1902 0 : void SDMaskHandler::autoMaskByThreshold(ImageInterface<Float>& mask,
1903 : const ImageInterface<Float>& res,
1904 : const ImageInterface<Float>& psf,
1905 : const Quantity& resolution,
1906 : const Float& resbybeam,
1907 : const Quantity& qthresh,
1908 : const Float& fracofpeak,
1909 : const Record& stats,
1910 : const Float& sigma,
1911 : const Int nmask,
1912 : const Bool autoadjust)
1913 : {
1914 0 : LogIO os( LogOrigin("SDMaskHandler","autoMaskByThreshold",WHERE) );
1915 0 : Array<Double> rms, max;
1916 : Double rmsthresh, minrmsval, maxrmsval, minmaxval, maxmaxval;
1917 0 : IPosition minrmspos, maxrmspos, minmaxpos, maxmaxpos;
1918 : Int npix;
1919 : //for debug set to True to save intermediate mask images on disk
1920 0 : Bool debug(False);
1921 :
1922 : //automask stage selecitons
1923 0 : Bool dobin(True);
1924 0 : Bool doregrid(True);
1925 0 : Bool doconvolve(True);
1926 :
1927 : // taking account for beam or input resolution
1928 0 : TempImage<Float> tempmask(mask.shape(), mask.coordinates(), memoryToUse());
1929 0 : IPosition shp = mask.shape();
1930 0 : CoordinateSystem incsys = res.coordinates();
1931 0 : Vector<Double> incVal = incsys.increment();
1932 0 : Vector<String> incUnit = incsys.worldAxisUnits();
1933 0 : Quantity qinc(incVal[0],incUnit[0]);
1934 0 : if (resolution.get().getValue() ) {
1935 : //npix = 2*Int(abs( resolution/(qinc.convert(resolution),qinc) ).getValue() );
1936 0 : npix = Int(abs( resolution/(qinc.convert(resolution),qinc) ).getValue() );
1937 0 : os << LogIO::NORMAL2 << "Use the input resolution:"<<resolution<<" fo binning "<< LogIO::POST;
1938 0 : os << LogIO::DEBUG1 << "inc = "<<qinc.getValue(resolution.getUnit())<<LogIO::POST;
1939 : }
1940 : else {
1941 : //use beam from residual or psf
1942 0 : ImageInfo resInfo = res.imageInfo();
1943 0 : ImageInfo psfInfo = psf.imageInfo();
1944 0 : GaussianBeam beam;
1945 0 : if (resInfo.hasBeam() || psfInfo.hasBeam()) {
1946 0 : if (resInfo.hasSingleBeam()) {
1947 0 : beam = resInfo.restoringBeam();
1948 : }
1949 0 : else if (resInfo.hasMultipleBeams()) {
1950 0 : beam = CasaImageBeamSet(resInfo.getBeamSet()).getCommonBeam();
1951 : }
1952 0 : else if (psfInfo.hasSingleBeam()) {
1953 0 : beam = psfInfo.restoringBeam();
1954 : }
1955 : else {
1956 0 : beam = CasaImageBeamSet(psfInfo.getBeamSet()).getCommonBeam();
1957 : }
1958 0 : Quantity bmaj = beam.getMajor();
1959 0 : Quantity bmin = beam.getMinor();
1960 0 : if (resbybeam > 0.0 ) {
1961 : //npix = 2*Int( Double(resbybeam) * abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
1962 0 : npix = Int( Double(resbybeam) * abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
1963 0 : os << LogIO::NORMAL2 << "Use "<< resbybeam <<" x beam size(maj)="<< Double(resbybeam)*bmaj <<" for binning."<< LogIO::POST;
1964 : }
1965 : else {
1966 : //npix = 2*Int( abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
1967 0 : npix = Int( abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
1968 0 : os << LogIO::NORMAL2 << "Use a beam size(maj):"<<bmaj<<" for binning."<< LogIO::POST;
1969 : }
1970 0 : }
1971 : else {
1972 0 : throw(AipsError("No restoring beam(s) in the input image/psf or resolution is given"));
1973 : }
1974 0 : }
1975 0 : os << LogIO::DEBUG1 << "Acutal bin size used: npix="<<npix<< LogIO::POST;
1976 0 : if (npix==0) {
1977 0 : os << "Resolution too small. No binning (nbin=1) is applied input image to evaluate the threshold." << LogIO::POST;
1978 0 : npix=1;
1979 : }
1980 :
1981 : // Determine threshold from input image stats
1982 0 : stats.get(RecordFieldId("max"), max);
1983 0 : stats.get(RecordFieldId("rms"), rms);
1984 0 : minMax(minmaxval,maxmaxval,minmaxpos, maxmaxpos, max);
1985 0 : minMax(minrmsval,maxrmsval,minrmspos, maxrmspos, rms);
1986 0 : os << LogIO::DEBUG1 <<"stats on the image: max="<<maxmaxval<<" rms="<<maxrmsval<<endl;
1987 0 : if (fracofpeak) {
1988 0 : rmsthresh = maxmaxval * fracofpeak;
1989 : //os << LogIO::NORMAL <<"Threshold by fraction of the peak(="<<fracofpeak<<") * max: "<<rmsthresh<< LogIO::POST;
1990 0 : os << LogIO::DEBUG1 <<"max at "<<maxmaxpos<<", dynamic range = "<<maxmaxval/rms(maxmaxpos) << LogIO::POST;
1991 : }
1992 0 : else if (sigma) {
1993 : //cerr<<"minval="<<minval<<" maxval="<<maxval<<endl;
1994 0 : rmsthresh = maxrmsval * sigma;
1995 : //os << LogIO::NORMAL <<"Threshold by sigma(="<<sigma<<")* rms (="<<maxrmsval<<") :"<<rmsthresh<< LogIO::POST;
1996 0 : os << LogIO::DEBUG1 <<"max rms at "<<maxrmspos<<", dynamic range = "<<max(maxrmspos)/maxrmsval << LogIO::POST;
1997 : }
1998 : else {
1999 0 : rmsthresh = qthresh.getValue(Unit("Jy"));
2000 0 : if ( rmsthresh==0.0 )
2001 0 : { throw(AipsError("Threshold for automask is not set"));}
2002 : }
2003 : //os << LogIO::NORMAL2 <<" thresh="<<rmsthresh<<LogIO::POST;
2004 :
2005 :
2006 0 : TempImage<Float>* tempIm2 = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
2007 0 : TempImage<Float>* tempIm = new TempImage<Float>(res.shape(), res.coordinates(), memoryToUse());
2008 0 : tempIm->copyData(res);
2009 :
2010 0 : SPCIIF tempIm2_ptr(tempIm2);
2011 0 : SPIIF tempIm3_ptr(tempIm);
2012 0 : SPIIF tempIm_ptr;
2013 : //
2014 : //binning stage
2015 0 : if (dobin) {
2016 0 : tempIm_ptr = makeMaskFromBinnedImage(res, npix, npix, fracofpeak, sigma, nmask, autoadjust, rmsthresh);
2017 : //for debugging: save the mask at this stage
2018 0 : if (debug) {
2019 0 : PagedImage<Float> tempBinIm(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(), "binnedThresh.Im");
2020 0 : tempBinIm.copyData(*(tempIm_ptr.get()));
2021 0 : }
2022 : }
2023 0 : if (doregrid) {
2024 : //regrid
2025 0 : os << LogIO::DEBUG1 <<" now regridding..."<<LogIO::POST;
2026 0 : IPosition axes(3,0, 1, 2);
2027 0 : Vector<Int> dirAxes = CoordinateUtil::findDirectionAxes(incsys);
2028 0 : axes(0) = dirAxes(0);
2029 0 : axes(1) = dirAxes(1);
2030 0 : axes(2) = CoordinateUtil::findSpectralAxis(incsys);
2031 0 : Record* dummyrec = 0;
2032 0 : SPCIIF inmask_ptr(tempIm_ptr);
2033 0 : ImageRegridder<Float> regridder(inmask_ptr, "", tempIm2_ptr, axes, dummyrec, "", True, shp);
2034 0 : regridder.setMethod(Interpolate2D::LINEAR);
2035 0 : tempIm_ptr = regridder.regrid();
2036 : //for debugging: save the mask at this stage
2037 0 : if (debug) {
2038 0 : PagedImage<Float> tempGridded(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(), "binAndGridded.Im");
2039 0 : tempGridded.copyData(*(tempIm_ptr.get()));
2040 0 : }
2041 0 : }
2042 : else {
2043 0 : tempIm_ptr = tempIm3_ptr;
2044 : }
2045 0 : if (doconvolve) {
2046 : //
2047 0 : SPIIF outmask = convolveMask(*(tempIm_ptr.get()), npix, npix);
2048 0 : tempIm_ptr = outmask;
2049 : //
2050 : //for debugging: save the mask at this stage
2051 0 : if (debug) {
2052 0 : PagedImage<Float> tempconvIm(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(),"convolved.Im");
2053 0 : tempconvIm.copyData(*(tempIm_ptr.get()));
2054 0 : }
2055 : //os<<"done convolving the mask "<<LogIO::POST;
2056 0 : }
2057 :
2058 : //os <<"Final thresholding with rmsthresh/afactor="<< rmsthresh/afactor <<LogIO::POST;
2059 : //LatticeExpr<Float> themask( iif( *(tempIm_ptr.get()) > rmsthresh/afactor, 1.0, 0.0 ));
2060 : // previous 1/0 mask (regridded), max pix value should be <1.0, take arbitary cut off at 0.1
2061 0 : LatticeExpr<Float> themask( iif( *(tempIm_ptr.get()) > 0.1, 1.0, 0.0 ));
2062 0 : if (res.hasPixelMask()) {
2063 0 : LatticeExpr<Bool> pixmask(res.pixelMask());
2064 0 : mask.copyData( (LatticeExpr<Float>)( iif((mask + themask) > 0.0 && pixmask, 1.0, 0.0 ) ) );
2065 0 : os <<LogIO::DEBUG1 <<"add previous mask, pbmask and the new mask.."<<LogIO::POST;
2066 0 : }
2067 : else {
2068 : //for debug
2069 : /***
2070 : PagedImage<Float> tempthemask(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(),"tempthemask.Im");
2071 : tempthemask.copyData(themask);
2072 : ***/
2073 :
2074 : //os <<"Lattice themask is created..."<<LogIO::POST;
2075 : //LatticeExpr<Float> themask( iif( tempconvim > rmsthresh/afactor, 1.0, 0.0 ));
2076 0 : mask.copyData( (LatticeExpr<Float>)( iif((mask + themask) > 0.0, 1.0, 0.0 ) ) );
2077 0 : os <<LogIO::DEBUG1 <<"add previous mask and the new mask.."<<LogIO::POST;
2078 : }
2079 0 : }
2080 :
2081 0 : void SDMaskHandler::autoMaskByThreshold2(ImageInterface<Float>& mask,
2082 : const ImageInterface<Float>& res,
2083 : const ImageInterface<Float>& psf,
2084 : const Quantity& resolution,
2085 : const Float& resbybeam,
2086 : const Quantity& qthresh,
2087 : const Float& fracofpeak,
2088 : const Record& stats,
2089 : const Float& sigma,
2090 : const Int nmask)
2091 : {
2092 0 : LogIO os( LogOrigin("SDMaskHandler","autoMaskByThreshold2",WHERE) );
2093 0 : Array<Double> rms, max;
2094 : Double rmsthresh, minrmsval, maxrmsval, minmaxval, maxmaxval;
2095 0 : IPosition minrmspos, maxrmspos, minmaxpos, maxmaxpos;
2096 : Int npix;
2097 : Int beampix;
2098 :
2099 : //for debug set to True to save intermediate mask images on disk
2100 : //Bool debug(False);
2101 :
2102 : // taking account for beam or input resolution
2103 0 : TempImage<Float> tempmask(mask.shape(), mask.coordinates(), memoryToUse());
2104 0 : IPosition shp = mask.shape();
2105 0 : CoordinateSystem incsys = res.coordinates();
2106 0 : Vector<Double> incVal = incsys.increment();
2107 0 : Vector<String> incUnit = incsys.worldAxisUnits();
2108 0 : Quantity qinc(incVal[0],incUnit[0]);
2109 0 : if (resolution.get().getValue() ) {
2110 0 : npix = Int(abs( resolution/(qinc.convert(resolution),qinc) ).getValue() );
2111 0 : beampix = Int( C::pi * npix * npix /(4.*C::ln2));
2112 0 : os << LogIO::NORMAL2 << "Use the input resolution:"<<resolution<<" for pruning "<< LogIO::POST;
2113 0 : os << LogIO::DEBUG1 << "inc = "<<qinc.getValue(resolution.getUnit())<<LogIO::POST;
2114 : }
2115 : else {
2116 : //use beam from residual or psf
2117 0 : ImageInfo resInfo = res.imageInfo();
2118 0 : ImageInfo psfInfo = psf.imageInfo();
2119 0 : GaussianBeam beam;
2120 : Int npixmin;
2121 0 : if (resInfo.hasBeam() || psfInfo.hasBeam()) {
2122 0 : if (resInfo.hasSingleBeam()) {
2123 0 : beam = resInfo.restoringBeam();
2124 : }
2125 0 : else if (resInfo.hasMultipleBeams()) {
2126 0 : beam = CasaImageBeamSet(resInfo.getBeamSet()).getCommonBeam();
2127 : }
2128 0 : else if (psfInfo.hasSingleBeam()) {
2129 0 : beam = psfInfo.restoringBeam();
2130 : }
2131 : else {
2132 0 : beam = CasaImageBeamSet(psfInfo.getBeamSet()).getCommonBeam();
2133 : }
2134 0 : Quantity bmaj = beam.getMajor();
2135 0 : Quantity bmin = beam.getMinor();
2136 0 : if (resbybeam > 0.0 ) {
2137 0 : npix = Int( Double(resbybeam) * abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
2138 0 : npixmin = Int( Double(resbybeam) * abs( (bmin/(qinc.convert(bmin),qinc)).get().getValue() ) );
2139 0 : beampix = Int(C::pi * npix * npixmin / (4. * C::ln2));
2140 :
2141 0 : os << LogIO::NORMAL2 << "Use "<< resbybeam <<" x beam size(maj)="<< Double(resbybeam)*bmaj <<" for pruning."<< LogIO::POST;
2142 : }
2143 : else {
2144 0 : npix = Int( abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
2145 0 : npixmin = Int( abs( (bmin/(qinc.convert(bmin),qinc)).get().getValue() ) );
2146 0 : beampix = Int(C::pi * npix * npixmin / (4. * C::ln2));
2147 0 : os << LogIO::NORMAL2 << "Use a beam size(maj):"<<bmaj<<" for pruning."<< LogIO::POST;
2148 : }
2149 0 : }
2150 : else {
2151 0 : throw(AipsError("No restoring beam(s) in the input image/psf or resolution is given"));
2152 : }
2153 0 : }
2154 0 : os << LogIO::DEBUG1 << "Acutal bin size used: npix="<<npix<< LogIO::POST;
2155 :
2156 : // Determine threshold from input image stats
2157 0 : stats.get(RecordFieldId("max"), max);
2158 0 : stats.get(RecordFieldId("rms"), rms);
2159 0 : minMax(minmaxval,maxmaxval,minmaxpos, maxmaxpos, max);
2160 0 : minMax(minrmsval,maxrmsval,minrmspos, maxrmspos, rms);
2161 0 : os << LogIO::DEBUG1 <<"stats on the image: max="<<maxmaxval<<" rms="<<maxrmsval<<endl;
2162 0 : if (fracofpeak) {
2163 0 : rmsthresh = maxmaxval * fracofpeak;
2164 0 : os << LogIO::NORMAL <<"Threshold by fraction of the peak(="<<fracofpeak<<") * max: "<<rmsthresh<< LogIO::POST;
2165 0 : os << LogIO::DEBUG1 <<"max at "<<maxmaxpos<<", dynamic range = "<<maxmaxval/rms(maxmaxpos) << LogIO::POST;
2166 : }
2167 0 : else if (sigma) {
2168 : //cerr<<"minval="<<minval<<" maxval="<<maxval<<endl;
2169 0 : rmsthresh = maxrmsval * sigma;
2170 0 : os << LogIO::NORMAL <<"Threshold by sigma(="<<sigma<<")* rms (="<<maxrmsval<<") :"<<rmsthresh<< LogIO::POST;
2171 0 : os << LogIO::DEBUG1 <<"max rms at "<<maxrmspos<<", dynamic range = "<<max(maxrmspos)/maxrmsval << LogIO::POST;
2172 : }
2173 : else {
2174 0 : rmsthresh = qthresh.getValue(Unit("Jy"));
2175 0 : if ( rmsthresh==0.0 )
2176 0 : { throw(AipsError("Threshold for automask is not set"));}
2177 : }
2178 0 : os << LogIO::NORMAL2 <<" thresh="<<rmsthresh<<LogIO::POST;
2179 :
2180 0 : std::shared_ptr<ImageInterface<Float> > tempIm_ptr = pruneRegions(res, rmsthresh, nmask, beampix);
2181 0 : LatticeExpr<Float> themask( iif( *(tempIm_ptr.get()) > rmsthresh, 1.0, 0.0 ));
2182 :
2183 : //for debug
2184 : /***
2185 : PagedImage<Float> tempthemask(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(),"tempthemask.Im");
2186 : tempthemask.copyData(themask);
2187 : ***/
2188 0 : if (res.hasPixelMask()) {
2189 0 : LatticeExpr<Bool> pixmask(res.pixelMask());
2190 0 : mask.copyData( (LatticeExpr<Float>)( iif((mask + themask) > 0.0 && pixmask, 1.0, 0.0 ) ) );
2191 0 : mask.clearCache();
2192 0 : mask.unlock();
2193 0 : mask.tempClose();
2194 0 : os <<LogIO::DEBUG1 <<"Add previous mask, pbmask and the new mask.."<<LogIO::POST;
2195 0 : }
2196 : else {
2197 : //os <<"Lattice themask is created..."<<LogIO::POST;
2198 : //LatticeExpr<Float> themask( iif( tempconvim > rmsthresh/afactor, 1.0, 0.0 ));
2199 0 : mask.copyData( (LatticeExpr<Float>)( iif((mask + themask) > 0.0, 1.0, 0.0 ) ) );
2200 0 : os <<LogIO::DEBUG1 <<"Add previous mask and the new mask.."<<LogIO::POST;
2201 : }
2202 0 : }//end of makeAutoMaskByThreshold2
2203 :
2204 : // *** auto-multithresh ***
2205 : // for implemtation of Amanda's algorithm
2206 52 : void SDMaskHandler::autoMaskByMultiThreshold(ImageInterface<Float>& mask,
2207 : ImageInterface<Float>& posmask,
2208 : const ImageInterface<Float>& res,
2209 : const ImageInterface<Float>& psf,
2210 : const Record& stats,
2211 : const Record& robuststats,
2212 : const Int iterdone,
2213 : Vector<Bool>& chanFlag,
2214 : const Float& minPercentChange,
2215 : const Float& sidelobeLevel,
2216 : const Float& sidelobeThresholdFactor,
2217 : const Float& noiseThresholdFactor,
2218 : const Float& lowNoiseThresholdFactor,
2219 : const Float& negativeThresholdFactor,
2220 : const Float& cutThreshold,
2221 : const Float& smoothFactor,
2222 : const Float& minBeamFrac,
2223 : const Int growIterations,
2224 : const Bool doGrowPrune,
2225 : const Bool verbose,
2226 : const Bool isthresholdreached)
2227 : {
2228 104 : LogIO os( LogOrigin("SDMaskHandler","autoMaskByMultiThreshold",WHERE) );
2229 52 : Array<Double> rmss, maxs, mins, mads, mdns;
2230 52 : Array<Double> resRmss;
2231 52 : IPosition minrmspos, maxrmspos, minmaxpos, maxmaxpos, minmadpos, maxmadpos;
2232 : Int nxpix, nypix;
2233 :
2234 : // % min mask pixel change (to trigger new automask creation per chan plane) to a fractional change
2235 52 : Float fracChange = minPercentChange/100.0;
2236 :
2237 : //store summary info
2238 52 : Record summaryRec;
2239 52 : summaryRec.define("sidelobelevel",sidelobeLevel);
2240 :
2241 : //for debug set to True to save intermediate mask images on disk
2242 52 : Bool debug(false); // create additional temp masks for debugging
2243 52 : Bool debug2(false); // debug2 saves masks before/after prune and binary dilation
2244 :
2245 : //set true to use calcImageStatistics2 and thresholds adjusted for the location (median)
2246 : //Bool newstats(True); // turn on new stats definition of threshold calc.
2247 :
2248 : //Timer
2249 52 : Timer timer;
2250 :
2251 : //debug
2252 52 : if (debug2) {
2253 0 : PagedImage<Float> tempcurinmask(mask.shape(), mask.coordinates(), "currrent-in-mask-"+String::toString(iterdone)+".im");
2254 0 : tempcurinmask.copyData(mask);
2255 0 : }
2256 :
2257 : // tempmsk: working image for the curret mask
2258 104 : TempImage<Float> tempmask(mask.shape(), mask.coordinates(), memoryToUse());
2259 52 : tempmask.set(0);
2260 : // prevmask: mask from previous iter.
2261 104 : TempImage<Float> prevmask(mask.shape(), mask.coordinates(), memoryToUse());
2262 : // use positive only previous mask
2263 : //prevmask.copyData(LatticeExpr<Float>(mask) );
2264 52 : prevmask.copyData(LatticeExpr<Float>(posmask) );
2265 : // set up a container for a full cube negative mask
2266 : //if (negativeThresholdFactor > 0) {
2267 104 : TempImage<Float> thenegmask(mask.shape(), mask.coordinates(), memoryToUse());
2268 52 : thenegmask.set(0);
2269 : //}
2270 : // taking account for beam or input resolution
2271 : //IPosition shp = mask.shape();
2272 52 : CoordinateSystem incsys = res.coordinates();
2273 52 : Vector<Double> incVal = incsys.increment();
2274 52 : Vector<String> incUnit = incsys.worldAxisUnits();
2275 52 : Quantity qinc(incVal[0],incUnit[0]);
2276 : //use beam from residual or psf
2277 52 : ImageInfo resInfo = res.imageInfo();
2278 52 : ImageInfo psfInfo = psf.imageInfo();
2279 :
2280 52 : GaussianBeam beam, modbeam; // modbeam for smooth
2281 : Double pruneSize;
2282 52 : if (resInfo.hasBeam() || psfInfo.hasBeam()) {
2283 52 : if (resInfo.hasSingleBeam()) {
2284 0 : beam = resInfo.restoringBeam();
2285 : }
2286 52 : else if (resInfo.hasMultipleBeams()) {
2287 0 : beam = CasaImageBeamSet(resInfo.getBeamSet()).getCommonBeam();
2288 : }
2289 52 : else if (psfInfo.hasSingleBeam()) {
2290 40 : beam = psfInfo.restoringBeam();
2291 : }
2292 : else {
2293 12 : beam = CasaImageBeamSet(psfInfo.getBeamSet()).getCommonBeam();
2294 : }
2295 : // check
2296 52 : if(std::isinf( beam.getMajor(Unit("arcsec"))) || std::isinf( beam.getMinor(Unit("arcsec"))) ){
2297 0 : throw(AipsError("A bad common beam, which is used to set smoothing and pruning sizes for automask. At least one of the axes of the beam is infinite."));
2298 : }
2299 52 : Quantity bmaj = beam.getMajor();
2300 52 : Quantity bmin = beam.getMinor();
2301 : //for pruning for now
2302 : // minBeamFrac * beamarea
2303 52 : Double beamfrac=1.0;
2304 52 : if (minBeamFrac > 0.0) {
2305 52 : beamfrac = (Double) minBeamFrac;
2306 : }
2307 52 : Double beampix = pixelBeamArea(beam, incsys);
2308 52 : pruneSize = beamfrac * beampix;
2309 : //beam in pixels
2310 52 : nxpix = Int( Double(smoothFactor) * abs( (bmaj/(qinc.convert(bmaj),qinc)).get().getValue() ) );
2311 52 : nypix = Int( Double(smoothFactor) * abs( (bmin/(qinc.convert(bmin),qinc)).get().getValue() ) );
2312 52 : modbeam.setMajorMinor(Double(smoothFactor) * bmaj, Double(smoothFactor) * bmin);
2313 52 : modbeam.setPA(beam.getPA());
2314 :
2315 52 : os<<LogIO::DEBUG1<<"beam in pixels: B_maj="<<nxpix<<" B_min="<<nypix<<" beam area="<<beampix<<LogIO::POST;
2316 52 : os<<LogIO::NORMAL <<"prune size="<<pruneSize<<"(minbeamfrac="<<minBeamFrac<<" * beampix="<<beampix<<")"<<LogIO::POST;
2317 52 : summaryRec.define("pruneregionsize",pruneSize);
2318 52 : }
2319 : else {
2320 0 : throw(AipsError("No restoring beam(s) in the input image/psf"));
2321 : }
2322 :
2323 :
2324 : //One time parameter checks
2325 52 : if (!iterdone) {
2326 31 : if (cutThreshold >=0.2) {
2327 1 : os<<LogIO::WARN<<"Faint regions may not be included in the final mask. Consider decreasing cutthreshold."<<LogIO::POST;
2328 : }
2329 : }
2330 :
2331 : // Determine threshold from input image stats
2332 52 : stats.get(RecordFieldId("max"), maxs);
2333 52 : stats.get(RecordFieldId("min"), mins);
2334 : // robuststats may contains only robustrms and medians if it is filled by calcRobustRMS
2335 52 : if (robuststats.isDefined("rms")) {
2336 48 : robuststats.get(RecordFieldId("rms"), rmss);
2337 48 : robuststats.get(RecordFieldId("medabsdevmed"), mads);
2338 48 : resRmss = mads * 1.4826;
2339 48 : os<<LogIO::DEBUG1<<" rms from MAD (mads*1.4826)= "<<resRmss<<LogIO::POST;
2340 : }
2341 4 : else if (robuststats.isDefined("robustrms") ) {
2342 4 : robuststats.get(RecordFieldId("robustrms"),resRmss); // already converted from MAD to rms
2343 4 : os<<LogIO::DEBUG1<<" robustrms from MAD (mads*1.4826)= "<<resRmss<<LogIO::POST;
2344 : }
2345 52 : os<<LogIO::DEBUG1<<"get mdns"<<LogIO::POST;
2346 52 : robuststats.get(RecordFieldId("median"), mdns);
2347 :
2348 : //check for pbmask
2349 52 : IPosition imshp=res.shape();
2350 52 : IPosition imstart(4, 0, 0, 0, 0);
2351 52 : IPosition imlength(4, imshp(0),imshp(1), imshp(2), imshp(3));
2352 :
2353 : Float sidelobeThreshold;
2354 : Float noiseThreshold;
2355 : Float lowNoiseThreshold;
2356 : Float negativeThreshold;
2357 : //
2358 : //determine shape, nchan, npol from residual image
2359 52 : CoordinateSystem imcoord = res.coordinates();
2360 52 : Int specAxis = CoordinateUtil::findSpectralAxis(imcoord);
2361 52 : Vector <Stokes::StokesTypes> whichPols;
2362 52 : Int polAxis = CoordinateUtil::findStokesAxis(whichPols, imcoord);
2363 52 : Int nchan = -1;
2364 52 : Int npol = -1;
2365 52 : if (specAxis != -1) {
2366 52 : nchan = imshp(specAxis);
2367 : }
2368 52 : if (polAxis != -1 ) {
2369 52 : npol = imshp(polAxis);
2370 : }
2371 : //Int specAxis = CoordinateUtil::findSpectralAxis(res.coordinates());
2372 : // here, now chindx really means index to extract per-plane
2373 : //
2374 52 : IPosition statshp = mdns.shape();
2375 52 : IPosition chindx = statshp;
2376 52 : Int poldim = (npol == -1? 1:npol);
2377 52 : Int chandim = (nchan == -1? 1:nchan);
2378 52 : Matrix<Float> maskThreshold(poldim, chandim);
2379 52 : Matrix<Float> lowMaskThreshold(poldim, chandim);
2380 52 : Matrix<Float> negativeMaskThreshold(poldim, chandim);
2381 52 : Matrix<String> ThresholdType(poldim, chandim);
2382 52 : Matrix<Bool> pruned(poldim, chandim);
2383 :
2384 : //for (uInt ich=0; ich < mads.nelements(); ich++) {
2385 260 : for (uInt ich=0; ich < (uInt)nchan; ich++) {
2386 : // for loop for Stokes as well?
2387 440 : for (uInt ipol=0; ipol < (uInt)npol; ipol++) {
2388 232 : if (nchan!=-1) {
2389 232 : if(npol==-1 || npol==1) {
2390 200 : chindx(0) = ich;
2391 : }
2392 : else {
2393 32 : chindx(0) = ipol;
2394 32 : chindx(1) = ich;
2395 : }
2396 : }
2397 : else { // pol only
2398 0 : chindx(0) = ipol;
2399 : }
2400 :
2401 : // turn on a new definition for new stats --- remove old one once tested
2402 : //if (newstats) {
2403 : // os<<LogIO::DEBUG1<<"Using the new statistics ..."<<LogIO::POST;
2404 : // sidelobeThreshold = (Float)mdns(chindx) + sidelobeLevel * sidelobeThresholdFactor * (Float)maxs(chindx);
2405 : //}
2406 : //else {
2407 : // sidelobeThreshold = sidelobeLevel * sidelobeThresholdFactor * (Float)maxs(chindx);
2408 : //}
2409 :
2410 : // turn on a new definition for new stats --- remove old one once tested
2411 : //if (newstats) {
2412 : // noiseThreshold = (Float)mdns(chindx) + noiseThresholdFactor * (Float)resRmss(chindx);
2413 : // lowNoiseThreshold = (Float)mdns(chindx) + lowNoiseThresholdFactor * (Float)resRmss(chindx);
2414 : // negativeThreshold = (Float)mdns(chindx) + negativeThresholdFactor * (Float)resRmss(chindx);
2415 : //}
2416 : //else {
2417 : // noiseThreshold = noiseThresholdFactor * (Float)resRmss(chindx);
2418 : // lowNoiseThreshold = lowNoiseThresholdFactor * (Float)resRmss(chindx);
2419 : // negativeThreshold = negativeThresholdFactor * (Float)resRmss(chindx);
2420 : //}
2421 :
2422 : // include location (=median) for both fastnoise=true and false
2423 232 : Double absmax = max(abs(maxs(chindx)), abs(mins(chindx)));
2424 : // start with no offset
2425 232 : sidelobeThreshold = sidelobeLevel * sidelobeThresholdFactor * (Float)absmax;
2426 232 : noiseThreshold = noiseThresholdFactor * (Float)resRmss(chindx);
2427 232 : lowNoiseThreshold = lowNoiseThresholdFactor * (Float)resRmss(chindx);
2428 232 : negativeThreshold = negativeThresholdFactor * (Float)resRmss(chindx);
2429 : //negativeMaskThreshold(ich) = (-1.0)*max(sidelobeThreshold, negativeThreshold) + (Float)mdns(chindx);
2430 232 : negativeMaskThreshold(ipol, ich) = (-1.0)*max(sidelobeThreshold, negativeThreshold) + (Float)mdns(chindx);
2431 : // add the offset
2432 232 : sidelobeThreshold += (Float)mdns(chindx);
2433 232 : noiseThreshold += (Float)mdns(chindx);
2434 232 : lowNoiseThreshold += (Float)mdns(chindx);
2435 232 : negativeThreshold += (Float)mdns(chindx);
2436 : //maskThreshold(ich) = max(sidelobeThreshold, noiseThreshold);
2437 232 : maskThreshold(ipol, ich) = max(sidelobeThreshold, noiseThreshold);
2438 : //lowMaskThreshold(ich) = max(sidelobeThreshold, lowNoiseThreshold);
2439 232 : lowMaskThreshold(ipol, ich) = max(sidelobeThreshold, lowNoiseThreshold);
2440 : //ThresholdType(ich) = (maskThreshold(ich) == sidelobeThreshold? "sidelobe": "noise");
2441 232 : ThresholdType(ipol, ich) = (maskThreshold(ipol, ich) == sidelobeThreshold? "sidelobe": "noise");
2442 :
2443 232 : os << LogIO::DEBUG1 <<" sidelobeTreshold="<<sidelobeThreshold<<" noiseThreshold="<<noiseThreshold<<" lowNoiseThreshold="<<lowNoiseThreshold<<LogIO::POST;
2444 232 : os << LogIO::DEBUG1 <<" negativeThreshold(abs)="<<negativeThreshold<<", all thresholds include location ="<<(Float)mdns(chindx)<<LogIO::POST;
2445 : //os << LogIO::DEBUG1 <<" Using "<<ThresholdType(ich)<<" threshold for chan "<<String::toString(ich)<<" threshold="<<maskThreshold(ich)<<LogIO::POST;
2446 232 : os << LogIO::DEBUG1 <<" Using "<<ThresholdType(ipol, ich)<<" threshold for pol "<<String::toString(ipol)<<", chan "<< String::toString(ich)<<" threshold="<<maskThreshold(ipol, ich)<<LogIO::POST;
2447 : } // for-ipol
2448 : } // for-ich
2449 :
2450 :
2451 : //main per plane loop start here
2452 52 : IPosition planeshp(imshp.nelements(), 1);
2453 52 : planeshp(0) = imshp(0);
2454 52 : planeshp(1) = imshp(1);
2455 :
2456 : // store in matrix instead of vector to support full pols
2457 52 : Matrix<uInt> nreg(poldim, chandim,0);
2458 52 : Matrix<uInt> npruned(poldim, chandim, 0);
2459 52 : Vector<Float> dummysizes;
2460 52 : Matrix<uInt> ngrowreg(poldim, chandim, 0);
2461 52 : Matrix<uInt> ngrowpruned(poldim, chandim, 0);
2462 52 : Matrix<Float> negmaskpixs(poldim, chandim ,0);
2463 52 : Matrix<Bool> allPruned(poldim, chandim, False);
2464 : // for timing info storage
2465 52 : Vector<Double> timeInitThresh(3,0.0);
2466 52 : Vector<Double> timePrune(3,0.0);
2467 52 : Vector<Double> timeSmooth(3,0.0);
2468 52 : Vector<Double> timeGrow(3,0.0);
2469 52 : Vector<Double> timePruneGrow(3,0.0);
2470 52 : Vector<Double> timeSmoothGrow(3,0.0);
2471 52 : Vector<Double> timeNegThresh(3,0.0);
2472 :
2473 52 : Bool perplanetiming(True);
2474 :
2475 260 : for (uInt ich=0; ich < (uInt)nchan; ich++) {
2476 208 : if (npol==1) {
2477 200 : os << LogIO::NORMAL<< "*** Start auto-multithresh processing for Channel "<<ich<<"***"<<LogIO::POST;
2478 : }
2479 440 : for (uInt ipol=0; ipol < (uInt)npol; ipol++ ) {
2480 232 : if (npol!=1) {
2481 32 : os << LogIO::NORMAL<< "*** Start auto-multithresh processing for Channel "<<ich<<", Polarization "<<ipol<<"***"<<LogIO::POST;
2482 : }
2483 : // channel skip check
2484 232 : if (chanFlag(ich)) {
2485 0 : os << LogIO::NORMAL<<" Skip this channel "<<LogIO::POST;
2486 : }
2487 : else {
2488 : // Below corresponds to createThresholdMask in Amanda's Python code.
2489 232 : IPosition start(planeshp.nelements(),0);
2490 232 : if (specAxis != -1) {
2491 232 : start(specAxis)=ich;
2492 : }
2493 232 : if (polAxis != -1) {
2494 232 : start(polAxis)=ipol;
2495 : }
2496 :
2497 232 : IPosition length(planeshp.nelements(), planeshp(0), planeshp(1), 1, 1);
2498 232 : Slicer sl(start, length);
2499 232 : AxesSpecifier aspec(True); // keep degenerate axes
2500 232 : SubImage<Float> planeResImage(res, sl, aspec, true);
2501 464 : TempImage<Float> planeTempMask(planeResImage.shape(), planeResImage.coordinates(), memoryToUse());
2502 232 : planeTempMask.set(0); // initialize
2503 : //SubImage<Float> subprevmask(prevmask, sl, true, aspec, true);
2504 : // working copy of per-plane previous total mask to be modified. Started with en empty mask.
2505 : // For an un-touched version of per-plane previous mask, subMask is created at the grow mask step.
2506 232 : TempImage<Float> subprevmask(planeshp, planeResImage.coordinates(), memoryToUse());
2507 232 : subprevmask.set(0);
2508 232 : SubImage<Float> subposmask(posmask, sl, true, aspec, true);
2509 : //Vector<Bool> allPruned(nchan);
2510 : // sigle element vectors for input
2511 232 : Vector<Bool> chanFlag1elem(1);
2512 232 : chanFlag1elem(0) = chanFlag(ich);
2513 232 : Vector<Float> maskThreshold1elem(1);
2514 232 : maskThreshold1elem(0) = maskThreshold(ipol,ich);
2515 232 : Vector<Float> lowMaskThreshold1elem(1);
2516 232 : lowMaskThreshold1elem(0) = lowMaskThreshold(ipol,ich);
2517 232 : Vector<Float> negativeMaskThreshold1elem(1);
2518 232 : negativeMaskThreshold1elem(0) = negativeMaskThreshold(ipol,ich);
2519 :
2520 : // *** Pruning ***
2521 232 : if (minBeamFrac > 0.0 ) {
2522 : // do pruning...
2523 : //os<<LogIO::NORMAL<<"Pruning the current mask"<<LogIO::POST;
2524 232 : os << LogIO::NORMAL3 << "Start thresholding: create an initial mask by threshold" << LogIO::POST;
2525 232 : timer.mark();
2526 : // make temp mask image consist of the original pix value and below the threshold is set to 0
2527 : //TempImage<Float> maskedRes(res.shape(), res.coordinates(), memoryToUse());
2528 : // single plane
2529 232 : TempImage<Float> maskedRes(planeshp, planeResImage.coordinates(), memoryToUse());
2530 232 : maskedRes.set(0);
2531 : //makeMaskByPerChanThreshold(res, chanFlag, maskedRes, maskThreshold, dummysizes);
2532 232 : makeMaskByPerChanThreshold(planeResImage, chanFlag1elem, maskedRes, maskThreshold1elem, dummysizes);
2533 232 : timeInitThresh(0)+=timer.real(); timeInitThresh(1)+=timer.user(); timeInitThresh(2)+=timer.system();
2534 232 : if (perplanetiming) {
2535 : os << LogIO::NORMAL3 << "End thresholding: time to create the initial threshold mask: real "<< timer.real()
2536 232 : << "s ( user " << timer.user() <<"s, system "<< timer.system() << "s)" << LogIO::POST;
2537 : }
2538 : //if (res.hasPixelMask()) {
2539 232 : if (planeResImage.hasPixelMask()) {
2540 : //os << LogIO::DEBUG1 <<" HAS MASK....ich="<<ich<<LogIO::POST;
2541 232 : ArrayLattice<Bool> pixmasklat(planeResImage.getMask());
2542 232 : maskedRes.copyData( (LatticeExpr<Float>)( iif(pixmasklat, maskedRes, 0.0 ) ) );
2543 : //for debug
2544 : //Array<Float> testdata;
2545 : //maskedRes.get(testdata);
2546 : //os<<" current total of pix values="<<sum(testdata)<<LogIO::POST;
2547 232 : }
2548 : //TODO MOVE THIS SECTION outside the for-loop -DONE
2549 : //this section need to be move to the end of automask outside of the main chan loop
2550 : //Vector<Bool> allPruned(nchan);
2551 : //if (!iterdone) noMaskCheck(maskedRes, ThresholdType(ipol,ich));
2552 232 : if (debug2) {
2553 0 : os<<LogIO::DEBUG2<<"Saving intermediate masks for this cycle: with name tmp****-"<<iterdone<<".im"<<LogIO::POST;
2554 0 : String tmpfname1="tmpInitThresh-ch"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2555 0 : PagedImage<Float> savedPreMask(planeResImage.shape(),planeResImage.coordinates(),tmpfname1);
2556 0 : savedPreMask.copyData(maskedRes);
2557 0 : }
2558 :
2559 232 : os << LogIO::NORMAL3 << "Start pruning: the initial threshold mask" << LogIO::POST;
2560 232 : timer.mark();
2561 : //std::shared_ptr<ImageInterface<Float> > tempIm_ptr = pruneRegions2(maskedRes, tempthresh, -1, pruneSize);
2562 : //temporary storage for single plane results
2563 232 : Vector<uInt> nreg1elem, npruned1elem;
2564 232 : Vector<Bool> allPruned1elem(1);
2565 232 : std::shared_ptr<ImageInterface<Float> > tempIm_ptr = YAPruneRegions(maskedRes, chanFlag1elem, allPruned1elem, nreg1elem, npruned1elem, pruneSize, false);
2566 232 : nreg(ipol,ich) = nreg1elem(0);
2567 232 : npruned(ipol, ich) = npruned1elem(0);
2568 232 : allPruned(ipol, ich) = allPruned1elem(0);
2569 : //tempmask.copyData(*(tempIm_ptr.get()));
2570 232 : planeTempMask.copyData(*(tempIm_ptr.get()));
2571 : // now this timing for single plane... need to accumlate and report it later????
2572 232 : timePrune(0)+=timer.real(); timePrune(1)+=timer.user(); timePrune(2)+=timer.system();
2573 232 : if (perplanetiming) {
2574 : os << LogIO::NORMAL3 << "End pruning: time to prune the initial threshold mask: real "
2575 232 : << timer.real()<< "s (user " << timer.user() <<"s, system "<< timer.system() << "s)" << LogIO::POST;
2576 : }
2577 :
2578 : //if (debug2) {
2579 : // String tmpfname2="tmpAfterPrune-"+String::toString(iterdone)+".im";
2580 : // PagedImage<Float> savedPrunedPreThreshMask(res.shape(),res.coordinates(),tmpfname2);
2581 : // savedPrunedPreThreshMask.copyData(*(tempIm_ptr.get()));
2582 : //}
2583 : //themask = LatticeExpr<Float> ( iif( *(tempIm_ptr.get()) > maskThreshold, 1.0, 0.0 ));
2584 : // Need this?
2585 : //makeMaskByPerChanThreshold(*(tempIm_ptr.get()), tempmask, maskThreshold, dummysizes);
2586 : //if (debug) {
2587 : // PagedImage<Float> savedPostPrunedMask(res.shape(),res.coordinates(),"tmp-postPruningPostThreshMask.im");
2588 : // savedPostPrunedMask.copyData(tempmask);
2589 : //}
2590 232 : }
2591 : else { // ***** No pruning case ******
2592 0 : os << LogIO::NORMAL3 << "Start thresholding: create an initial threshold mask" << LogIO::POST;
2593 0 : timer.mark();
2594 : //tempmask.set(0);
2595 0 : planeTempMask.set(0);
2596 : //makeMaskByPerChanThreshold(res, chanFlag, tempmask, maskThreshold, dummysizes);
2597 0 : makeMaskByPerChanThreshold(planeResImage, chanFlag1elem, planeTempMask, maskThreshold1elem, dummysizes);
2598 0 : if (debug2) {
2599 0 : String tmpnopruneinitmask="tmpInitThreshNoprune-ch"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2600 0 : PagedImage<Float> savedThreshmask(planeResImage.shape(), planeResImage.coordinates(), tmpnopruneinitmask);
2601 0 : savedThreshmask.copyData(planeTempMask);
2602 0 : }
2603 :
2604 : //if (!iterdone) noMaskCheck(tempmask, ThresholdType);
2605 0 : timePrune(0)+=timer.real(); timePrune(1)+=timer.user(); timePrune(2)+=timer.system();
2606 0 : if (perplanetiming) {
2607 : os << LogIO::NORMAL3 << "End trehsholding: time to create the initial threshold mask: real "
2608 0 : << timer.real()<<"s (user " << timer.user() <<"s, system "<< timer.system() << "s)" << LogIO::POST;
2609 : }
2610 : //tempmask.copyData(themask);
2611 : } // DONE PRUNING STAGE
2612 :
2613 : // ***** SMOOTHING *******
2614 232 : os << LogIO::NORMAL3 << "Start smoothing: the initial threshold mask" << LogIO::POST;
2615 232 : timer.mark();
2616 232 : SPIIF outmask = convolveMask(planeTempMask, modbeam );
2617 232 : if (debug2 ) {
2618 0 : String tmpfname3="tmp-postSmoothMask-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2619 0 : PagedImage<Float> savedSmoothedMask(planeResImage.shape(),planeResImage.coordinates(),tmpfname3);
2620 0 : savedSmoothedMask.copyData(*(outmask.get()));
2621 0 : }
2622 :
2623 :
2624 : //clean up (appy cutThreshold to convolved mask image)
2625 232 : String lelmask("");
2626 : //use standard stats
2627 232 : Record smmaskstats = calcImageStatistics(*outmask, lelmask, 0, false);
2628 232 : Array<Double> smmaskmaxs;
2629 232 : smmaskstats.get(RecordFieldId("max"),smmaskmaxs);
2630 232 : Vector<Float> cutThresholdValue(1);
2631 :
2632 : //if (npol<=1) {
2633 : // chindx(0) = 0;
2634 : //}
2635 : //else {
2636 : // chindx(1) = 0;
2637 : //}
2638 : // cutThresholdValue(ich) = cutThreshold * smmaskmaxs(chindx);
2639 232 : cutThresholdValue(0) = cutThreshold * smmaskmaxs(IPosition(1,0));
2640 : //os<<LogIO::DEBUG1<<" cutThreshVal("<<ich<<")="<<cutThresholdValue(ich)<<LogIO::POST;
2641 :
2642 : //TempImage<Float> thenewmask(res.shape(),res.coordinates(), memoryToUse());
2643 : //thenewmask.set(0);
2644 232 : TempImage<Float> thenewmask(planeshp,planeResImage.coordinates(), memoryToUse());
2645 232 : thenewmask.set(0);
2646 : //makeMaskByPerChanThreshold(*outmask, chanFlag, thenewmask, cutThresholdValue, dummysizes);
2647 232 : makeMaskByPerChanThreshold(*outmask, chanFlag1elem, thenewmask, cutThresholdValue, dummysizes);
2648 : // Per-plane timing
2649 232 : timeSmooth(0) += timer.real(); timeSmooth(1) += timer.user(); timeSmooth(2) += timer.system();
2650 232 : if (perplanetiming) {
2651 : os << LogIO::NORMAL3 << "End smoothing: time to create the smoothed initial threshold mask: real "<< timer.real()
2652 232 : <<"s (user " << timer.user() <<"s, system "<< timer.system() << "s)" << LogIO::POST;
2653 : }
2654 :
2655 : /***
2656 : if (!iterdone) {
2657 : if (!isEmptyMask(*(outmask.get())) && isEmptyMask(thenewmask)) os<<LogIO::WARN<<"Removed all regions based by cutthreshold applied to the smoothed mask."<<LogIO::POST;
2658 : }
2659 : ***/
2660 232 : if (debug2 ) {
2661 0 : String tmpnewmask="tmp-AfterSmooth-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2662 0 : PagedImage<Float> savedthenewmask(planeResImage.shape(), planeResImage.coordinates(), tmpnewmask);
2663 0 : savedthenewmask.copyData(thenewmask);
2664 0 : }
2665 :
2666 : // ***** GROW STAGE *****
2667 : //
2668 : // take stats on the current mask for setting flags for grow mask : if max < 1 for any spectral plane it will grow the previous mask
2669 : //
2670 : // Mod: 2017.07.26: modified get stats for prev mask, if channel contains no mask in prev mask it will set flag to skip the channel
2671 : //Record maskstats = calcImageStatistics(thenewmask, thenewmask, lelmask, 0, false);
2672 : //
2673 232 : SubImage<Float> subMask(mask,sl, true, aspec, true);
2674 232 : if(debug2) {
2675 0 : String tmpsubmaskName = "tmp-submask-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2676 0 : PagedImage<Float> tmpsubmask(planeResImage.shape(), planeResImage.coordinates(), tmpsubmaskName);
2677 0 : tmpsubmask.copyData(subMask);
2678 0 : }
2679 : //Record maskstats = calcImageStatistics(mask, lelmask, 0, false);
2680 : // per-plane stats now
2681 232 : Record maskstats = calcImageStatistics(subMask, lelmask, 0, false);
2682 232 : Array<Double> maskmaxs;
2683 232 : maskstats.get(RecordFieldId("max"),maskmaxs);
2684 232 : IPosition arrshape = maskmaxs.shape();
2685 232 : uInt naxis=arrshape.size();
2686 232 : IPosition indx(naxis,0);
2687 : //os<<LogIO::NORMAL<<"arrshape="<<arrshape<<" indx="<<indx<<LogIO::POST;
2688 : //os<<LogIO::NORMAL<<"statshp="<<statshp<<LogIO::POST;
2689 : // ignoring corr for now and assume first axis is channel
2690 232 : Array<Bool> dogrow(arrshape);
2691 232 : dogrow.set(false);
2692 464 : for (uInt i=0; i < arrshape(0); i++) {
2693 232 : indx(0) = i;
2694 232 : if (maskmaxs(indx) == 1.0 && !chanFlag1elem(0)) {
2695 79 : dogrow(indx) = true;
2696 : }
2697 : //For debug
2698 : //if (chanFlag(i)) {
2699 : // os<<LogIO::NORMAL<<"For dogrow: skipping channel: "<<i<<" chanFlag(i)="<<chanFlag(i)<<" dogrow("<< indx << ")=" <<dogrow(indx)<<LogIO::POST;
2700 : //}
2701 : // set dogrow true for all chans (contraintMask should be able to handle skipping channels )
2702 : // dogrow(indx) = true;
2703 : }
2704 :
2705 232 : if (iterdone && growIterations>0) { // enter to acutal grow process
2706 : //per-plane timing
2707 111 : os << LogIO::NORMAL3 << "Start grow mask: growing the previous mask " << LogIO::POST;
2708 111 : timer.mark();
2709 : //call growMask
2710 : // corresponds to calcThresholdMask with lowNoiseThreshold...
2711 : //TempImage<Float> constraintMaskImage(res.shape(), res.coordinates(), memoryToUse());
2712 : // per-plane constraint mask image
2713 111 : TempImage<Float> constraintMaskImage(planeshp, planeResImage.coordinates(), memoryToUse());
2714 111 : constraintMaskImage.set(0);
2715 : // constrainMask is 1/0 mask
2716 : //makeMaskByPerChanThreshold(res, chanFlag, constraintMaskImage, lowMaskThreshold, dummysizes);
2717 111 : makeMaskByPerChanThreshold(planeResImage, chanFlag1elem, constraintMaskImage, lowMaskThreshold1elem, dummysizes);
2718 111 : if(debug2 && ipol==0 && ich==0) {
2719 0 : os<< LogIO::NORMAL3<<"saving constraint mask " << LogIO::POST;
2720 0 : PagedImage<Float> beforepruneconstIm(planeResImage.shape(), planeResImage.coordinates(),"tmpConstraint-"+String::toString(iterdone)+".im");
2721 0 : beforepruneconstIm.copyData(constraintMaskImage);
2722 0 : }
2723 :
2724 : // 2017.05.05: should done after multiply by binary dilation
2725 : //
2726 : // prune the constraintImage
2727 : //if (minBeamFrac > 0.0 ) {
2728 : // //Double thethresh=0.1;
2729 : // os<<LogIO::NORMAL << "Pruning the constraint mask "<<LogIO::POST;
2730 : // //std::shared_ptr<ImageInterface<Float> > tempPrunedMask_ptr = pruneRegions2(constraintMaskImage, thethresh, -1, pruneSize);
2731 : // Vector<Bool> dummy(0);
2732 : // std::shared_ptr<ImageInterface<Float> > tempPrunedMask_ptr = YAPruneRegions(constraintMaskImage, dummy, pruneSize);
2733 : // constraintMaskImage.copyData( *(tempPrunedMask_ptr.get()) );
2734 : //}
2735 : //if(debug2) {
2736 : // PagedImage<Float> afterpruneconstIm(res.shape(), res.coordinates(),"tmpAfterPruneConstraint-"+String::toString(iterdone)+".im");
2737 : // afterpruneconstIm.copyData(constraintMaskImage);
2738 : //}
2739 :
2740 : // for mask in binaryDilation, translate it to T/F (if T it will grow the mask region (NOTE currently binary dilation
2741 : // does opposite T/F interpretation NEED to CHANGE)
2742 : //TempImage<Bool> constraintMask(res.shape(),res.coordinates(), memoryToUse());
2743 : //constraintMask.copyData( LatticeExpr<Bool> (iif(constraintMaskImage > 0, true, false)) );
2744 111 : TempImage<Bool> constraintMask(planeshp, planeResImage.coordinates(), memoryToUse());
2745 111 : constraintMask.copyData( LatticeExpr<Bool> (iif(constraintMaskImage > 0, true, false)) );
2746 : // simple structure element for binary dilation
2747 111 : IPosition axislen(2, 3, 3);
2748 111 : Array<Float> se(axislen);
2749 111 : se.set(0);
2750 111 : se(IPosition(2,1,0))=1.0;
2751 111 : se(IPosition(2,0,1))=1.0;
2752 111 : se(IPosition(2,1,1))=1.0;
2753 111 : se(IPosition(2,2,1))=1.0;
2754 111 : se(IPosition(2,1,2))=1.0;
2755 111 : if(debug2 && ich==0 && ipol == 0) {
2756 0 : String tmpbeforeBD="tmp-BeforeBD-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2757 0 : PagedImage<Float> beforeBinaryDilationIm(planeResImage.shape(), planeResImage.coordinates(),tmpbeforeBD);
2758 : //`beforeBinaryDilationIm.copyData(constraintMaskImage);
2759 0 : beforeBinaryDilationIm.copyData(subMask);
2760 0 : }
2761 : // CHECK THIS works for a single plane but 4 dim image
2762 :
2763 111 : subprevmask.set(0);
2764 111 : binaryDilation(subMask, se, growIterations, constraintMask, dogrow, subprevmask);
2765 111 : if(debug2) {
2766 0 : PagedImage<Float> afterBinaryDilationIm(planeResImage.shape(), planeResImage.coordinates(),"tmpAfterBinaryDilation-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im");
2767 0 : afterBinaryDilationIm.copyData(subprevmask);
2768 0 : }
2769 : // multiply binary dilated mask by constraintmask
2770 : //prevmask.copyData( LatticeExpr<Float> (constraintMaskImage*prevmask));
2771 111 : subprevmask.copyData( LatticeExpr<Float> (constraintMaskImage*subprevmask));
2772 111 : if(debug2) {
2773 0 : PagedImage<Float> beforepruneconstIm(planeResImage.shape(), planeResImage.coordinates(),"tmpBeforePruneGrowMask-"+String::toString(ich)+"ipol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im");
2774 0 : beforepruneconstIm.copyData(subprevmask);
2775 0 : }
2776 111 : timeGrow(0) += timer.real(); timeGrow(1) += timer.user(); timeGrow(2) += timer.system();
2777 111 : if (perplanetiming) {
2778 : os << LogIO::NORMAL3 << "End grow mask: time to grow the previous mask: real "
2779 111 : << timer.real() <<"s (user "<< timer.user() << "s, system " << timer.system() << "s)" << LogIO::POST;
2780 : }
2781 :
2782 : // **** pruning on grow mask ****
2783 111 : if (minBeamFrac > 0.0 && doGrowPrune) {
2784 : //os<<LogIO::NORMAL << "Pruning the growed previous mask "<<LogIO::POST;
2785 111 : os << LogIO::NORMAL3 << "Start pruning: on the grow mask "<< LogIO::POST;
2786 111 : timer.mark();
2787 111 : Vector<Bool> dummy(0);
2788 111 : Vector<uInt> ngrowreg1elem, ngrowpruned1elem;
2789 : //std::shared_ptr<ImageInterface<Float> > tempPrunedMask_ptr = YAPruneRegions(prevmask, chanFlag, dummy, ngrowreg, ngrowpruned, pruneSize);
2790 :
2791 111 : std::shared_ptr<ImageInterface<Float> > tempPrunedMask_ptr = YAPruneRegions(subprevmask, chanFlag1elem, dummy, ngrowreg1elem, ngrowpruned1elem, pruneSize, false);
2792 111 : ngrowreg(ipol,ich) = ngrowreg1elem(0);
2793 111 : ngrowpruned(ipol,ich) = ngrowpruned1elem(0);
2794 : //prevmask.copyData( *(tempPrunedMask_ptr.get()) );
2795 111 : subprevmask.copyData( *(tempPrunedMask_ptr.get()) );
2796 111 : timePruneGrow(0) += timer.real(); timePruneGrow(1) += timer.user(); timePruneGrow(2) += timer.system();
2797 111 : if (perplanetiming) {
2798 : os << LogIO::NORMAL3 << "End pruning: time to prune the grow mask: real "
2799 111 : << timer.real() <<"s (user "<< timer.user() << "s, system "<< timer.system() << "s)" << LogIO::POST;
2800 : }
2801 111 : if(debug2) {
2802 0 : String tmpafterprunegrowname="tmpAfterPruneGrowMask-"+String::toString(ich)+"pol"+String::toString(ipol)+"iter"+String::toString(iterdone)+".im";
2803 0 : PagedImage<Float> afterpruneconstIm(planeResImage.shape(), planeResImage.coordinates(),tmpafterprunegrowname);
2804 0 : afterpruneconstIm.copyData(subprevmask);
2805 0 : }
2806 111 : }
2807 :
2808 : // ***** smoothing on grow mask *****
2809 111 : os << LogIO::NORMAL3 << "Start smoothing: the grow mask " << LogIO::POST;
2810 111 : timer.mark();
2811 : ///SPIIF outprevmask = convolveMask( prevmask, modbeam);
2812 111 : SPIIF outprevmask = convolveMask( subprevmask, modbeam);
2813 : //if (debug) {
2814 : // PagedImage<Float> postSmoothGrowedMask(res.shape(), res.coordinates(),"tmpPostSmoothGrowMask-"+String::toString(iterdone)+".im");
2815 : // postSmoothGrowedMask.copyData(*outprevmask);
2816 : //}
2817 : //prevmask.copyData( LatticeExpr<Float> (iif( *(outprevmask.get()) > cutThreshold, 1.0, 0.0 )) );
2818 : // single plane
2819 111 : Record constmaskstats = calcImageStatistics(*outprevmask, lelmask, 0, false);
2820 111 : Array<Double> constmaskmaxs;
2821 111 : constmaskstats.get(RecordFieldId("max"),constmaskmaxs);
2822 : //Vector<Float> constCutThresholdValue(nchan);
2823 111 : Vector<Float> constCutThresholdValue(1);
2824 : // stats on a single plane now, so no need of chindx
2825 : //if (npol <=1) {
2826 : // chindx(0) = 0;
2827 : //}
2828 : //else {
2829 : // chindx(1) = 0;
2830 : //}
2831 : //constCutThresholdValue(0) = cutThreshold * constmaskmaxs(chindx);
2832 111 : constCutThresholdValue(0) = cutThreshold * constmaskmaxs(IPosition(1,0));
2833 : //prevmask.set(0);
2834 111 : subprevmask.set(0);
2835 : //makeMaskByPerChanThreshold(*outprevmask, chanFlag, prevmask, constCutThresholdValue, dummysizes);
2836 111 : makeMaskByPerChanThreshold(*outprevmask, chanFlag1elem, subprevmask, constCutThresholdValue, dummysizes);
2837 : //if (debug) {
2838 : // PagedImage<Float> smoothedGrowedMask(res.shape(), res.coordinates(),"tmpSmoothedGrowMask-"+String::toString(iterdone)+".im");
2839 : // smoothedGrowedMask.copyData(prevmask);
2840 : //}
2841 111 : timeSmoothGrow(0) += timer.real(); timeSmoothGrow(1) += timer.user(); timeSmoothGrow(2) += timer.system();
2842 111 : if (perplanetiming) {
2843 : os << LogIO::NORMAL3 << "End smoothing: time to create the smoothed grow mask: real "
2844 111 : << timer.real() <<"s (user "<< timer.user() << "s, system " << timer.system() << "s)" << LogIO::POST;
2845 : }
2846 111 : } //end - GROW (iterdone && dogrowiteration)
2847 :
2848 : // ****** save positive (emission) mask only ******
2849 :
2850 : // temporary save negative mask from the previous one
2851 : //TempImage<Float> prevnegmask(res.shape(), res.coordinates(), memoryToUse());
2852 : //prevnegmask.copyData( (LatticeExpr<Float>)( iif( (mask - posmask ) > 0.0, 1.0, 0.0 ) ) );
2853 :
2854 : //
2855 232 : if (debug2 ) {
2856 0 : String beforesumSPmaskname= "beforesumSPmask-ch"+String::toString(ich)+"pol"+String::toString(ipol)+"-iter"+String::toString(iterdone)+".im";
2857 0 : PagedImage<Float> tempsubposmask(TiledShape(subposmask.shape()), subposmask.coordinates(), beforesumSPmaskname);
2858 0 : tempsubposmask.copyData(subposmask);
2859 0 : String beforesumSPrevmaskname = "beforesumSPrevmask-ch"+String::toString(ich)+"pol"+String::toString(ipol)+"-iter"+String::toString(iterdone)+".im";
2860 0 : PagedImage<Float> tempsubprevmask(TiledShape(subposmask.shape()), subposmask.coordinates(), beforesumSPrevmaskname);
2861 0 : tempsubprevmask.copyData(subprevmask);
2862 0 : }
2863 :
2864 :
2865 :
2866 232 : if (planeResImage.hasPixelMask()) {
2867 : //LatticeExpr<Bool> pixmask(res.pixelMask());
2868 232 : LatticeExpr<Bool> pixmask(planeResImage.pixelMask());
2869 : // add all positive masks (previous one, grow mask, current thresh mask)
2870 : // mask = untouched prev mask, prevmask=modified prev mask by the grow func, thenewmask=mask by thresh on current residual
2871 : //posmask.copyData( (LatticeExpr<Float>)( iif((posmask + prevmask + thenewmask ) > 0.0 && pixmask, 1.0, 0.0 ) ) );
2872 232 : subposmask.copyData( (LatticeExpr<Float>)( iif((subposmask + subprevmask + thenewmask ) > 0.0 && pixmask, 1.0, 0.0 ) ) );
2873 232 : os <<LogIO::DEBUG1 <<"Add positive previous mask, pbmask and the new mask for this plane"<<LogIO::POST;
2874 232 : }
2875 : else {
2876 : //posmask.copyData( (LatticeExpr<Float>)( iif((posmask + prevmask + thenewmask ) > 0.0, 1.0, 0.0 ) ) );
2877 0 : subposmask.copyData( (LatticeExpr<Float>)( iif((subposmask + subprevmask + thenewmask ) > 0.0, 1.0, 0.0 ) ) );
2878 0 : os <<LogIO::DEBUG1 <<"Add positive previous mask and the new mask.."<<LogIO::POST;
2879 : }
2880 :
2881 : // **** NEGATIVE MASK creation *****
2882 : //TempImage<Float> thenegmask(res.shape(),res.coordinates(), memoryToUse());
2883 232 : TempImage<Float> subnegmask(planeshp, planeResImage.coordinates(), memoryToUse());
2884 232 : subnegmask.set(0);
2885 : //Vector<Float> negmaskpixs;
2886 232 : Vector<Float> negmaskpixs1elem;
2887 232 : if (negativeThresholdFactor > 0) {
2888 5 : os << LogIO::NORMAL3 << "Start thresholding: create a negative mask" << LogIO::POST;
2889 5 : timer.mark();
2890 : //os<<LogIO::NORMAL<<"Creating a mask for negative features. "<<LogIO::POST;
2891 : //TempImage<Float> negativeMaskImage(res.shape(), res.coordinates(), memoryToUse());
2892 5 : TempImage<Float> negativeSubMaskImage(planeshp, planeResImage.coordinates(), memoryToUse());
2893 5 : negativeSubMaskImage.set(0);
2894 : //makeMaskByPerChanThreshold(res, chanFlag, negativeMaskImage , negativeMaskThreshold, dummysizes);
2895 5 : makeMaskByPerChanThreshold(planeResImage, chanFlag1elem, negativeSubMaskImage, negativeMaskThreshold1elem, dummysizes);
2896 : // SPIIF negmask = convolveMask( negativeMaskImage, modbeam);
2897 5 : SPIIF negmask = convolveMask( negativeSubMaskImage, modbeam);
2898 : // determine the cutthreshold value for negative mask
2899 5 : Record negmaskstats = calcImageStatistics(*negmask, lelmask, 0, false);
2900 5 : Array<Double> negmaskmaxs;
2901 5 : negmaskstats.get(RecordFieldId("max"),negmaskmaxs);
2902 : //Vector<Float> negCutThresholdValue(nchan);
2903 5 : Vector<Float> negCutThresholdValue(1);
2904 : // 1 dim stats now, so no need of chindx
2905 : //if (npol <= 1) {
2906 : // chindx(0) = 0;
2907 : //}
2908 : //else {
2909 : // chindx(1) = 0;
2910 : //}
2911 5 : negCutThresholdValue(0) = cutThreshold * negmaskmaxs(IPosition(1,0));
2912 : //makeMaskByPerChanThreshold(*negmask, chanFlag, thenegmask, negCutThresholdValue, negmaskpixs);
2913 5 : makeMaskByPerChanThreshold(*negmask, chanFlag1elem, subnegmask, negCutThresholdValue, negmaskpixs1elem);
2914 5 : negmaskpixs(ipol,ich) = negmaskpixs1elem(0);
2915 5 : if (isEmptyMask(subnegmask) ){
2916 1 : os<<"No negative region was found by auotmask."<<LogIO::POST;
2917 : }
2918 : //if (debug) {
2919 : // PagedImage<Float> temppresmoothnegmask(TiledShape(negativeMaskImage.shape()), negativeMaskImage.coordinates(),"tmpPreSmoNegMask.im");
2920 : // temppresmoothnegmask.copyData(negativeMaskImage);
2921 : //PagedImage<Float> tempnegmask(TiledShape(thenegmask.shape()), thenegmask.coordinates(),"tmpNegMask.im");
2922 : // tempnegmask.copyData(thenegmask);
2923 : // PagedImage<Float> tempsmonegmask(TiledShape(thenegmask.shape()), thenegmask.coordinates(),"tmpSmoNegMask.im");
2924 : // tempsmonegmask.copyData(*negmask);
2925 : //}
2926 5 : timeNegThresh(0) += timer.real(); timeNegThresh(1) += timer.user(); timeNegThresh(2) += timer.system();
2927 5 : if (perplanetiming) {
2928 : os << LogIO::NORMAL3 << "End thresholding: time to create the negative mask: real "
2929 5 : << timer.real() <<"s (user " << timer.user() << "s, system " << timer.system() << "s)" << LogIO::POST;
2930 : }
2931 5 : }
2932 :
2933 : // store per plane masks to full cube mask images
2934 : // subMask to mask, posmask, thenegmask
2935 232 : Array<Float> maskdata, posmaskdata, negmaskdata;
2936 : // all images are single planes
2937 232 : IPosition stride(4,1,1,1,1);
2938 232 : IPosition plstart(4,0,0,0,0);
2939 232 : Slicer plsl(plstart, length);
2940 232 : subMask.doGetSlice(maskdata, plsl);
2941 232 : subposmask.doGetSlice(posmaskdata, plsl);
2942 232 : subnegmask.getSlice(negmaskdata, plsl);
2943 : // put to full mask images
2944 232 : mask.putSlice(maskdata,start,stride);
2945 232 : posmask.putSlice(posmaskdata,start,stride);
2946 232 : thenegmask.putSlice(negmaskdata,start,stride);
2947 232 : if (debug2) {
2948 0 : PagedImage<Float> tempfinalmask(TiledShape(mask.shape()), mask.coordinates(), "tmpfinalmask"+String::toString(iterdone)+".im");
2949 0 : tempfinalmask.copyData(mask);
2950 0 : }
2951 232 : } // if not chanFlag=True
2952 : } // ipol iter
2953 : } // the main per plane for-loop end for-ich
2954 :
2955 : //print tot. timing for each step
2956 52 : if (npol*nchan > 1) {
2957 12 : os << LogIO::NORMAL << "*** Timing summary for whole planes ***" << LogIO::POST;
2958 24 : os << LogIO::NORMAL << "Total time to create the initial threshold mask: real "<< timeInitThresh(0)
2959 12 : << "s ( user " << timeInitThresh(1) <<"s, system "<< timeInitThresh(2) << "s)" << LogIO::POST;
2960 : os << LogIO::NORMAL << "Total time to prune the initial threshold mask: real "
2961 12 : << timePrune(0)<< "s (user " << timePrune(1) <<"s, system "<< timePrune(2) << "s)" << LogIO::POST;
2962 24 : os << LogIO::NORMAL << "Total time to create the smoothed initial threshold mask: real "<< timeSmooth(0)
2963 12 : <<"s (user " << timeSmooth(1)<<"s, system "<< timeSmooth(2) << "s)" << LogIO::POST;
2964 : os << LogIO::NORMAL << "Total time to grow the previous mask: real "
2965 12 : << timeGrow(0) <<"s (user "<< timeGrow(1) << "s, system " << timeGrow(2) << "s)" << LogIO::POST;
2966 : os << LogIO::NORMAL << "Total time to prune the grow mask: real "
2967 12 : << timePruneGrow(0) <<"s (user "<< timePruneGrow(1) << "s, system "<< timePruneGrow(2) << "s)" << LogIO::POST;
2968 : os << LogIO::NORMAL << "Total time to create the smoothed grow mask: real "
2969 12 : << timeSmoothGrow(0) <<"s (user "<< timeSmoothGrow(1) << "s, system " << timeSmoothGrow(2) << "s)" << LogIO::POST;
2970 : }
2971 :
2972 52 : if (!iterdone) noMaskCheck(posmask, ThresholdType);
2973 : // "Allpruned check here"
2974 52 : Int nAllPruned=ntrue(allPruned);
2975 : // pruning is done only on positive mask
2976 52 : if(!iterdone && isEmptyMask(posmask) && nAllPruned) {
2977 : os<<LogIO::WARN<<nAllPruned<<" of "<<nchan<<" channels had all regions removed by pruning."
2978 0 : <<" Try decreasing minbeamfrac to remove fewer regions"<<LogIO::POST;
2979 : }
2980 :
2981 : //for debug
2982 : /***
2983 : PagedImage<Float> tempthemask(TiledShape(tempIm_ptr.get()->shape()), tempIm_ptr.get()->coordinates(),"tempthemask.Im");
2984 : tempthemask.copyData(themask);
2985 : ***/
2986 :
2987 : // In the initial iteration, if no mask is created (all spectral planes) by automask it will fall back to full clean mask
2988 : /***
2989 : if (!iterdone) {
2990 : Array<Float> maskdata;
2991 : IPosition maskshape = thenewmask.shape();
2992 : Int naxis = maskshape.size();
2993 : IPosition blc(naxis,0);
2994 : IPosition trc=maskshape-1;
2995 : Slicer sl(blc,trc,Slicer::endIsLast);
2996 : thenewmask.doGetSlice(maskdata,sl);
2997 : if (sum(maskdata)==0.0) {
2998 : mask.set(1);
2999 : //os<<LogIO::WARN<<"No mask was created by automask, set a clean mask to the entire image."<<LogIO::POST;
3000 : os<<LogIO::WARN<<"No mask was created by automask."<<LogIO::POST;
3001 : }
3002 : }
3003 : ***/
3004 52 : if (debug) {
3005 : //saved prev unmodified mask
3006 0 : PagedImage<Float> tmpUntouchedPrevMask(res.shape(), res.coordinates(),"tmpUnmodPrevMask"+String::toString(iterdone)+".im");
3007 0 : tmpUntouchedPrevMask.copyData(mask);
3008 :
3009 0 : }
3010 : // make a copy of unmodified previous mask
3011 104 : TempImage<Float> unmodifiedprevmask(res.shape(),res.coordinates(), memoryToUse());
3012 52 : unmodifiedprevmask.copyData(mask);
3013 :
3014 52 : if (res.hasPixelMask()) {
3015 52 : LatticeExpr<Bool> pixmask(res.pixelMask());
3016 : //mask.copyData( (LatticeExpr<Float>)( iif((mask + thenewmask) > 0.0 && pixmask, 1.0, 0.0 ) ) );
3017 : // add all masks (previous one, grow mask, current thresh mask)
3018 : // mask = untouched prev mask, prevmask=modified prev mask by the grow func, thenewmask=mask by thresh on current residual
3019 : //mask.copyData( (LatticeExpr<Float>)( iif((mask+prevmask + thenewmask + thenegmask) > 0.0 && pixmask, 1.0, 0.0 ) ) );
3020 52 : if(debug) {
3021 0 : PagedImage<Float> savedUnmod(res.shape(), res.coordinates(), "savedUmmod"+String::toString(iterdone)+".im");
3022 0 : savedUnmod.copyData(mask);
3023 0 : PagedImage<Float> savedPosmask(res.shape(), res.coordinates(), "savedPosmask"+String::toString(iterdone)+".im");
3024 0 : savedPosmask.copyData(posmask);
3025 0 : PagedImage<Float> savedNegmask(res.shape(), res.coordinates(), "savedNegmask"+String::toString(iterdone)+".im");
3026 0 : savedPosmask.copyData(thenegmask);
3027 0 : }
3028 52 : mask.copyData( (LatticeExpr<Float>)( iif((mask + posmask + thenegmask ) > 0.0 && pixmask, 1.0, 0.0 ) ) );
3029 :
3030 52 : mask.clearCache();
3031 52 : mask.unlock();
3032 52 : mask.tempClose();
3033 52 : os <<LogIO::DEBUG1 <<"Add previous mask, pbmask and the new mask.."<<LogIO::POST;
3034 52 : }
3035 : else {
3036 : //os <<"Lattice themask is created..."<<LogIO::POST;
3037 : //LatticeExpr<Float> themask( iif( tempconvim > rmsthresh/afactor, 1.0, 0.0 ));
3038 :
3039 : //mask.copyData( (LatticeExpr<Float>)( iif((mask + prevmask + thenewmask + thenegmask ) > 0.0, 1.0, 0.0 ) ) );
3040 0 : mask.copyData( (LatticeExpr<Float>)( iif((mask + posmask + thenegmask ) > 0.0, 1.0, 0.0 ) ) );
3041 :
3042 0 : os <<LogIO::DEBUG1 <<"Add previous mask and the new mask.."<<LogIO::POST;
3043 : }
3044 : // test the curent final mask with the previous mask
3045 52 : Vector<Bool> zeroChanMask;
3046 52 : skipChannels(fracChange,unmodifiedprevmask, mask, ThresholdType, isthresholdreached, chanFlag, zeroChanMask);
3047 :
3048 52 : if (verbose)
3049 4 : printAutomaskSummary(resRmss, maxs, mins, mdns, maskThreshold, ThresholdType, chanFlag, zeroChanMask, nreg, npruned, ngrowreg, ngrowpruned, negmaskpixs, summaryRec);
3050 52 : }//end of autoMaskByMultiThreshold
3051 :
3052 186 : Bool SDMaskHandler::isEmptyMask(ImageInterface<Float>& mask)
3053 : {
3054 186 : Array<Float> maskdata;
3055 186 : IPosition maskshape = mask.shape();
3056 186 : Int naxis = maskshape.size();
3057 186 : IPosition blc(naxis,0);
3058 186 : IPosition trc=maskshape-1;
3059 186 : Slicer sl(blc,trc,Slicer::endIsLast);
3060 186 : mask.doGetSlice(maskdata,sl);
3061 372 : return (sum(maskdata)==0.0);
3062 :
3063 186 : }
3064 :
3065 : //void SDMaskHandler::noMaskCheck(ImageInterface<Float>& mask, Vector<String>& thresholdType)
3066 31 : void SDMaskHandler::noMaskCheck(ImageInterface<Float>& mask, Matrix<String>& thresholdType)
3067 : {
3068 : // checkType and thresholdType will determine the exact messages to print out in the log
3069 62 : LogIO os( LogOrigin("SDMaskHandler","autoMaskByMultiThreshold",WHERE) );
3070 : // for waring messsages
3071 : /***
3072 : Array<Float> maskdata;
3073 : IPosition maskshape = mask.shape();
3074 : Int naxis = maskshape.size();
3075 : IPosition blc(naxis,0);
3076 : IPosition trc=maskshape-1;
3077 : Slicer sl(blc,trc,Slicer::endIsLast);
3078 : mask.doGetSlice(maskdata,sl);
3079 : ***/
3080 : //if (sum(maskdata)==0.0) {
3081 31 : if (isEmptyMask(mask)) {
3082 1 : os << LogIO::WARN <<"No regions found by automasking" <<LogIO::POST;
3083 : // checktype
3084 : //Int nThresholdType = thresholdType.nelements();
3085 1 : Int nrow = thresholdType.nrow();
3086 1 : Int ncol = thresholdType.ncolumn();
3087 : //Int nThresholdType = thresholdType.nelements();
3088 1 : Int nThresholdType = nrow*ncol;
3089 1 : Int nsidelobethresh=0;
3090 1 : Int nnoisethresh=0;
3091 1 : if (nThresholdType>1 ) {
3092 : //for (uInt j=0; j<(uInt) nThresholdType; j++) {
3093 0 : for (uInt j=0; j<(uInt) ncol; j++) {
3094 0 : for (uInt i=0; i<(uInt) nrow; i++) {
3095 0 : if (thresholdType(i,j)=="sidelobe") {
3096 0 : nsidelobethresh++;
3097 : }
3098 0 : if (thresholdType(i,j)=="noise") {
3099 0 : nnoisethresh++;
3100 : }
3101 : }
3102 : }
3103 0 : if (nsidelobethresh) {
3104 : os << LogIO::WARN <<nsidelobethresh<<" of "<<nThresholdType
3105 : <<" channels used the sidelobe threshold to mask, but no emission was found."
3106 0 : <<" Try decreasing your sidelobethreshold parameter if you want to capture emission in these channels."<< LogIO::POST;
3107 : }
3108 0 : if (nnoisethresh) {
3109 : os << LogIO::WARN <<nnoisethresh<<" of "<<nThresholdType<<" channels used the noise threshold to mask, but no emission was found."
3110 0 : << " Try decreasing your noisethreshold parameter if you want to capture emission in these channels."<< LogIO::POST;
3111 : }
3112 : }
3113 : else {
3114 :
3115 2 : os << LogIO::WARN << "Used "<<thresholdType(0,0)<<" threshold to mask, but no emission was found."
3116 1 : << "Try decreasing your "<<thresholdType(0,0)<<"threshold parameter if you want to capture emission in these channels."<< LogIO::POST;
3117 : }
3118 : }
3119 31 : }
3120 :
3121 52 : void SDMaskHandler::skipChannels(const Float& fracChange,
3122 : ImageInterface<Float>& prevmask,
3123 : ImageInterface<Float>& curmask,
3124 : //const Vector<String>& thresholdtype,
3125 : const Matrix<String>& thresholdtype,
3126 : const Bool isthresholdreached,
3127 : Vector<Bool>& chanFlag,
3128 : Vector<Bool>& zeroChanMask)
3129 : {
3130 104 : LogIO os( LogOrigin("SDMaskHandler","skipChannels",WHERE) );
3131 : // debug
3132 52 : os<<LogIO::DEBUG1<<"Inside skipChannels...."<<LogIO::POST;
3133 52 : IPosition shp = curmask.shape();
3134 52 : Int naxis = shp.size();
3135 52 : CoordinateSystem csys = curmask.coordinates();
3136 52 : Int specaxis = CoordinateUtil::findSpectralAxis(csys);
3137 52 : Int nchan = shp(specaxis);
3138 : // Assumption here is skipChannels applied to stokes I only to keep track which channels
3139 : // to skip for new automasking
3140 52 : IPosition blc(naxis,0);
3141 52 : IPosition trc=shp-1;
3142 52 : zeroChanMask.resize(nchan);
3143 52 : os<<LogIO::DEBUG1<<"Inside skipChannels....after zeroChanMask init"<<LogIO::POST;
3144 260 : for (Int ichan=0; ichan<nchan; ichan++) {
3145 208 : blc(specaxis)=ichan;
3146 208 : trc(specaxis)=ichan;
3147 208 : Slicer sl(blc,trc,Slicer::endIsLast);
3148 208 : Array<Float> curmaskdata;
3149 208 : curmask.doGetSlice(curmaskdata,sl);
3150 208 : Float curmaskpix = sum(curmaskdata);
3151 : // sepearately store zero channel mask info maybe combined in future to streamline
3152 208 : if (curmaskpix==0) {
3153 65 : zeroChanMask(ichan) = True;
3154 : }
3155 : else {
3156 143 : zeroChanMask(ichan) = False;
3157 : }
3158 :
3159 : //if (thresholdtype(ichan).contains("noise") && isthresholdreached && !chanFlag(ichan)) {
3160 208 : if (thresholdtype(0, ichan).contains("noise") && !chanFlag(ichan)) {
3161 4 : Array<Float> prevmaskdata;
3162 4 : prevmask.doGetSlice(prevmaskdata,sl);
3163 4 : Float prevmaskpix = sum(prevmaskdata);
3164 : //cerr<<"prevmaskpix="<<prevmaskpix<<" curemaskpix="<<curmaskpix<<endl;
3165 : //cerr<<"fracChnage="<<fracChange<<endl;
3166 4 : Float diffpix = abs(curmaskpix-prevmaskpix);
3167 : // stopmask is true if one of the followings is satified
3168 : // 1) if current mask is zero (curmaskpix==0.0)
3169 : // 2) if cyclethreshold==threshold (i.e. isthresholdreached=True) and diffpix is zero or
3170 : // less than user-specified fractinal change
3171 : //if ( curmaskpix==0.0 || (diffpix == 0.0 && prevmaskpix!=0.0) || diffpix < fracChange*prevmaskpix) {
3172 : //if ( curmaskpix==0.0 || (isthresholdreached && ((diffpix == 0.0 && prevmaskpix!=0.0) || diffpix < fracChange*prevmaskpix)) ) {
3173 4 : if ( curmaskpix==0.0 ||
3174 4 : (fracChange >=0.0 && isthresholdreached && ( diffpix == 0.0 || diffpix < fracChange*prevmaskpix) ) ) {
3175 0 : chanFlag(ichan) = True;
3176 0 : os<<LogIO::NORMAL<<"Stopping masking for chan="<<ichan<<LogIO::POST;
3177 : }
3178 4 : }
3179 208 : } // for loop end
3180 52 : }
3181 :
3182 0 : std::shared_ptr<ImageInterface<Float> > SDMaskHandler::makeMaskFromBinnedImage(const ImageInterface<Float>& image,
3183 : const Int nx,
3184 : const Int ny,
3185 : const Float& fracofpeak,
3186 : const Float& sigma,
3187 : const Int nmask,
3188 : const Bool autoadjust,
3189 : Double thresh)
3190 : {
3191 0 : Bool debug(False);
3192 0 : Bool firstrun(False);
3193 0 : LogIO os( LogOrigin("SDMaskHandler","makeMaskfromBinnedImage",WHERE) );
3194 0 : RebinImage<Float> tempRebinnedIm( image, IPosition(4,nx, ny,1,1) );
3195 : // for debug
3196 0 : if (debug) {
3197 0 : PagedImage<Float> copyRebinnedIm(TiledShape(tempRebinnedIm.shape()), tempRebinnedIm.coordinates(), "binned.Im");
3198 0 : copyRebinnedIm.copyData(tempRebinnedIm);
3199 0 : }
3200 :
3201 : // modified threshold
3202 : // original algortihm
3203 : //thresh = 3.0*thresh / sqrt(npix);
3204 : // modified by bin size only
3205 : //thresh = thresh / sqrt(nx);
3206 :
3207 : //stats on the binned image (the info not used for mask criteria yet)
3208 0 : Array<Double> rmses, maxes, mins;
3209 : // vars to store min,max values of extrema and rms in all planes
3210 : Double minRmsVal, maxRmsVal, minMaxVal, maxMaxVal, minMinVal, maxMinVal;
3211 0 : IPosition minRmsPos, maxRmsPos, minMaxPos, maxMaxPos, minMinPos, maxMinPos;
3212 0 : TempImage<Float>* tempImForStat = new TempImage<Float>(tempRebinnedIm.shape(), tempRebinnedIm.coordinates(), memoryToUse() );
3213 0 : tempImForStat->copyData(tempRebinnedIm);
3214 0 : std::shared_ptr<casacore::ImageInterface<float> > temprebin_ptr(tempImForStat);
3215 : //os<<" temprebin_ptr.get()->hasPixelMask()="<<temprebin_ptr.get()->hasPixelMask()<<LogIO::POST;
3216 0 : ImageStatsCalculator<Float> imcalc( temprebin_ptr, 0, "", False);
3217 0 : Vector<Int> stataxes(2);
3218 0 : stataxes[0] = 0;
3219 0 : stataxes[1] = 1;
3220 0 : imcalc.setAxes(stataxes);
3221 0 : Record imstats = imcalc.statistics();
3222 0 : imstats.get(RecordFieldId("rms"),rmses);
3223 0 : imstats.get(RecordFieldId("max"),maxes);
3224 0 : imstats.get(RecordFieldId("min"),mins);
3225 0 : minMax(minRmsVal,maxRmsVal,minRmsPos, maxRmsPos,rmses);
3226 0 : minMax(minMaxVal,maxMaxVal,minMaxPos, maxMaxPos,maxes);
3227 0 : minMax(minMinVal,maxMinVal,minMinPos, maxMinPos,mins);
3228 :
3229 :
3230 : //os << LogIO::NORMAL <<"Statistics on binned image: max="<<maxMaxVal<<" rms="<<maxRmsVal<<LogIO::POST;
3231 : os << LogIO::NORMAL <<"Statistics on binned image: Peak (max)="<<maxMaxVal<<"@"<<maxMaxPos
3232 0 : <<"rms (max) ="<<maxRmsVal<<"@"<<maxRmsPos<<LogIO::POST;
3233 : //os << LogIO::NORMAL <<"Statistics on binned image: min of Max="<<minMaxVal<<"@"<<minMaxPos<<LogIO::POST;
3234 : //os << LogIO::NORMAL <<"Statistics on binned image: min of rms="<<minRmsVal<<"@"<<minRmsPos<<LogIO::POST;
3235 :
3236 0 : TempImage<Float>* tempMask = new TempImage<Float> (tempRebinnedIm.shape(), tempRebinnedIm.coordinates(), memoryToUse() );
3237 :
3238 :
3239 : //Double dr = maxMaxVal/rmses(maxMaxPos);
3240 :
3241 : // save only the first time
3242 0 : if (itsMax==DBL_MAX) {
3243 0 : itsMax = maxMaxVal;
3244 0 : firstrun = True;
3245 : }
3246 : else {
3247 0 : firstrun = False;
3248 : }
3249 :
3250 0 : Float adjFact = 0.0;
3251 :
3252 : //Float fracDiffMax = (itsMax - maxMaxVal)/itsMax;
3253 0 : Float fracDiffRms = (itsRms - maxRmsVal)/itsRms;
3254 : //os<<"fractional changes in max:"<<fracDiffMax<<" in rms:"<<fracDiffRms<<LogIO::POST;
3255 0 : os<<LogIO::DEBUG1<<"fractional changes in rms from previous one:"<<fracDiffRms<<LogIO::POST;
3256 0 : if (autoadjust) {
3257 : //os <<"autoAdjust is on "<<LogIO::POST;
3258 : // automatically adjust threshold for the initial round and when fractional rms change is
3259 : // is less than 10%
3260 0 : if (fracDiffRms < 0.1 ) {
3261 0 : adjFact = (Float) Int(log(1.0/abs(fracDiffRms))-1.0);
3262 : }
3263 : // else if (dr < 10.0) {
3264 : // os<<LogIO::DEBUG1<<"dynamic range:max/rms = "<<dr<<LogIO::POST;
3265 : // adjFact = sigma!=0 && sigma <= 3.0? 2: 0;
3266 : // }
3267 0 : else if (firstrun) {
3268 0 : adjFact = 3;
3269 : }
3270 : }
3271 0 : if (fracofpeak) {
3272 0 : thresh = fracofpeak * maxMaxVal;
3273 0 : Double prevthresh = thresh;
3274 0 : if (adjFact >0.0 ) {
3275 0 : thresh = max((adjFact + 3) * maxRmsVal,thresh);
3276 0 : if (firstrun) {
3277 : // adjustment at 1st iteration cycle, if threshold is too big, make cutoff at 50% peak
3278 0 : if (thresh < itsMax) {
3279 0 : if (prevthresh != thresh) {
3280 0 : os << LogIO::NORMAL <<"first iteration automatically adjusted thresh="<<thresh<<"( "<<" * (adj fact.="<<adjFact+3<<") * rms )"<<LogIO::POST;
3281 : }
3282 : }
3283 : else {
3284 0 : thresh=prevthresh;
3285 : }
3286 : }
3287 : else {
3288 0 : if (prevthresh != thresh) {
3289 0 : os << LogIO::NORMAL <<"thresh="<<thresh<<" ( adj fact.="<<adjFact+3<<") * rms )"<<LogIO::POST;
3290 : }
3291 : }
3292 : }
3293 : // if sidelobe level is set and if it is larger than the current thresh use that value
3294 : //thresh = max( itsSidelobeLevel*itsMax, thresh );
3295 0 : if (adjFact != 0.0) {
3296 : }
3297 : else {
3298 0 : os << LogIO::NORMAL <<"thresh="<<thresh<<" ( "<<fracofpeak<<"* max peak )"<<LogIO::POST;
3299 : }
3300 : }
3301 0 : else if (sigma) {
3302 0 : thresh = (sigma + adjFact)* maxRmsVal;
3303 : // if sidelobe level is set and if it is larger than the current thresh use that value
3304 : //thresh = max( itsSidelobeLevel*itsMax, thresh);
3305 0 : if (firstrun && adjFact != 0.0) {
3306 0 : if (thresh < itsMax) {
3307 : os << LogIO::NORMAL <<"first iteration automatically adjusted thresh="<<thresh
3308 0 : <<" ( "<<sigma<<"+adjustment factor:"<<adjFact<<")* rms )"<<LogIO::POST;
3309 : }
3310 : else {
3311 0 : thresh = 0.5*itsMax;
3312 : os << LogIO::NORMAL <<"first iteration automatically adjusted thresh="<<thresh
3313 0 : <<" (0.5*peak )"<<LogIO::POST;
3314 : }
3315 : }
3316 0 : if (adjFact != 0.0) {
3317 0 : os << LogIO::NORMAL <<"thresh="<<thresh<<" ( "<<sigma<<"+adjustment factor:"<<adjFact<<")* rms )"<<LogIO::POST;
3318 : }
3319 : else {
3320 0 : os << LogIO::NORMAL <<"thresh="<<thresh<<" ( "<<sigma<<"* rms )"<<LogIO::POST;
3321 : }
3322 : }
3323 :
3324 :
3325 0 : itsRms = maxRmsVal;
3326 :
3327 0 : if (thresh > maxMaxVal) {
3328 0 : os << LogIO::WARN <<" The threshold value,"<<thresh<<" for making a mask is greater than max value in the image. No new mask will be added by automask."<< LogIO::POST;
3329 0 : tempMask->set(0.0);
3330 : }
3331 : else {
3332 :
3333 : // apply threshold to rebinned image to generate a temp image mask
3334 : // first run pruning by limiting n masks (npix=1 as it is already binned)
3335 0 : std::shared_ptr<ImageInterface<Float> > dummyim = pruneRegions(tempRebinnedIm, thresh, nmask, 1);
3336 :
3337 0 : os << LogIO::DEBUG1<<" threshold applied ="<<thresh<<LogIO::POST;
3338 : //cerr<<"dummyim shape="<<dummyim.get()->shape()<<endl;
3339 : //cerr<<"temprebinned shape="<<tempRebinnedIm.shape()<<endl;
3340 : //
3341 : //LatticeExpr<Float> tempthresh( iif( abs(tempRebinnedIm) > thresh, 1.0, 0.0) );
3342 0 : LatticeExpr<Float> tempthresh( iif( abs( *(dummyim.get()) ) > thresh, 1.0, 0.0) );
3343 : //os << LogIO::DEBUG1<<" copying the threshold image....."<<LogIO::POST;
3344 0 : tempMask->copyData(tempthresh);
3345 0 : }
3346 0 : return std::shared_ptr<ImageInterface<Float> >(tempMask);
3347 0 : }
3348 :
3349 348 : std::shared_ptr<ImageInterface<Float> > SDMaskHandler::convolveMask(const ImageInterface<Float>& inmask, const GaussianBeam& beam)
3350 : {
3351 696 : LogIO os( LogOrigin("SDMaskHandler","convolveMask",WHERE) );
3352 348 : TempImage<Float>* tempIm = new TempImage<Float>(inmask.shape(), inmask.coordinates(), memoryToUse() );
3353 348 : tempIm->copyData(inmask);
3354 348 : std::shared_ptr<casacore::ImageInterface<float> > tempIm2_ptr(tempIm);
3355 : //DEBUG will be removed
3356 :
3357 348 : Vector<Quantity> convbeam(3);
3358 348 : convbeam[0] = beam.getMajor();
3359 348 : convbeam[1] = beam.getMinor();
3360 348 : convbeam[2] = beam.getPA();
3361 348 : os << LogIO::DEBUG1<<"convolve with a gaussian: bmaj="<<convbeam[0]<<"bmin="<<convbeam[1]<<" pa="<<convbeam[2]<<LogIO::POST;
3362 348 : Record dammyRec=Record();
3363 : //String convimname("temp_convim");
3364 696 : Image2DConvolver<Float> convolver(tempIm2_ptr, &dammyRec, String(""), String(""), True);
3365 348 : convolver.setKernel("GAUSSIAN", convbeam[0], convbeam[1], convbeam[2]);
3366 348 : convolver.setAxes(std::make_pair(0,1));
3367 348 : convolver.setScale(Double(-1.0));
3368 348 : convolver.setSuppressWarnings(True);
3369 348 : auto outmask = convolver.convolve();
3370 696 : return outmask;
3371 348 : }
3372 :
3373 0 : std::shared_ptr<ImageInterface<Float> > SDMaskHandler::convolveMask(const ImageInterface<Float>& inmask, Int nxpix, Int nypix)
3374 : {
3375 0 : LogIO os( LogOrigin("SDMaskHandler","convolveMask",WHERE) );
3376 0 : TempImage<Float>* tempIm = new TempImage<Float>(inmask.shape(), inmask.coordinates(), memoryToUse() );
3377 0 : tempIm->copyData(inmask);
3378 0 : std::shared_ptr<casacore::ImageInterface<float> > tempIm2_ptr(tempIm);
3379 : //DEBUG will be removed
3380 0 : os << LogIO::DEBUG1<<"convolve with "<<nxpix<<" pix x "<<nypix<<" pix gaussian"<<LogIO::POST;
3381 :
3382 0 : Vector<Quantity> convbeam(3);
3383 0 : convbeam[0] = Quantity(nxpix, "pix");
3384 0 : convbeam[1] = Quantity(nypix, "pix");
3385 0 : convbeam[2] = Quantity(0.0, "deg");
3386 0 : Record dammyRec=Record();
3387 : //String convimname("temp_convim");
3388 0 : Image2DConvolver<Float> convolver(tempIm2_ptr, &dammyRec, String(""), String(""), True);
3389 0 : convolver.setKernel("GAUSSIAN", convbeam[0], convbeam[1], convbeam[2]);
3390 0 : convolver.setAxes(std::make_pair(0,1));
3391 0 : convolver.setScale(Double(-1.0));
3392 0 : convolver.setSuppressWarnings(True);
3393 0 : auto outmask = convolver.convolve();
3394 0 : return outmask;
3395 0 : }
3396 :
3397 0 : std::shared_ptr<casacore::ImageInterface<Float> > SDMaskHandler::pruneRegions(const ImageInterface<Float>& image, Double& thresh, Int nmask, Int npix)
3398 : {
3399 0 : LogIO os( LogOrigin("SDMaskHandler", "pruneRegions",WHERE) );
3400 0 : Bool debug(False);
3401 :
3402 0 : IPosition fullimShape=image.shape();
3403 0 : TempImage<Float>* fullIm = new TempImage<Float>(TiledShape(fullimShape, image.niceCursorShape()), image.coordinates(), memoryToUse());
3404 :
3405 0 : if (nmask==0 && npix==0 ) {
3406 : //No-op
3407 0 : os<<LogIO::DEBUG1<<"Skip pruning of mask regions"<<LogIO::POST;
3408 0 : fullIm->copyData(image);
3409 0 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3410 : }
3411 0 : os <<LogIO::DEBUG1<< "pruneRegions with nmask="<<nmask<<", size="<<npix<<" is applied"<<LogIO::POST;
3412 :
3413 0 : IPosition shp = image.shape();
3414 : //cerr<<"shp = "<<shp<<endl;
3415 0 : IPosition blc(4,0);
3416 0 : IPosition trc = shp-1;
3417 0 : Slicer sl(blc,trc,Slicer::endIsLast);
3418 0 : AxesSpecifier aspec(False);
3419 : // decomposer can only work for 2 and 3-dim images so need
3420 : // some checks the case for stokes axis > 1
3421 : // following works if stokes axis dim = 1
3422 0 : SubImage<Float>* subIm = new SubImage<Float>(image, sl, aspec, True);
3423 0 : RegionManager regMan;
3424 0 : CoordinateSystem cSys=subIm->coordinates();
3425 0 : regMan.setcoordsys(cSys);
3426 : //String strReg = "box[["+String::toString(blc[0])+"pix,"+String::toString(blc[1])+"pix], ["+String::toString(shp[0])+"pix,"+String::toString(shp[1])+"pix]]";
3427 : //cerr<<"strReg="<<strReg<<endl;
3428 : //RegionTextList CRTFList(cSys, strReg, shp);
3429 : //Record regRec = CRTFList.regionAsRecord();
3430 : //std::shared_ptr<casacore::SubImage<Float> > subIm = SubImageFactory<Float>::createSubImageRW(image, regRec, "", &os, aspec, False, False);
3431 :
3432 : //cerr <<" subIm.shape="<<subIm->shape()<<endl;
3433 0 : IPosition subimShape=subIm->shape();
3434 0 : uInt ndim = subimShape.nelements();
3435 : //std::shared_ptr<casacore::ImageInterface<float> > tempIm_ptr(subIm);
3436 0 : TempImage<Float>* tempIm = new TempImage<Float> (TiledShape(subIm->shape(), subIm->niceCursorShape()), subIm->coordinates(), memoryToUse() );
3437 : // to search for both positive and negative components
3438 0 : tempIm->copyData(LatticeExpr<Float> (abs(*subIm)));
3439 0 : os << LogIO::NORMAL2 <<"Finding regions by ImageDecomposer..."<<LogIO::POST;
3440 : //use ImageDecomposer
3441 0 : Matrix<Quantity> blctrcs;
3442 0 : ImageDecomposer<Float> id(*tempIm);
3443 0 : id.setDeblend(True);
3444 0 : os << LogIO::DEBUG1<< "Deblend threshold="<<thresh<<LogIO::POST;
3445 0 : id.setDeblendOptions(thresh, 3, 1, 2); //nContour=3
3446 : //id.setDeblendOptions(thresh, 3, 1, 1); //nContour=3, naxis=1
3447 0 : id.setFit(False);
3448 0 : os << LogIO::DEBUG1<<"Now calling decomposeImage()..."<<LogIO::POST;
3449 0 : id.decomposeImage();
3450 0 : if (debug)
3451 0 : id.printComponents();
3452 0 : uInt nRegion = id.numRegions();
3453 0 : os << "Found " << nRegion <<" regions"<<LogIO::POST;
3454 0 : Block<IPosition> blcs(nRegion);
3455 0 : Block<IPosition> trcs(nRegion);
3456 0 : id.boundRegions(blcs, trcs);
3457 : //os << "Get comp list.."<<LogIO::POST;
3458 0 : Matrix<Float> clmat=id.componentList();
3459 : //os << "Get peaks.."<<LogIO::POST;
3460 0 : Vector<Float> peaks = clmat.column(0);
3461 : //cerr<<"peaks="<<peaks<<endl;
3462 0 : os << LogIO::DEBUG1<< "Sorting by peak fluxes..."<<LogIO::POST;
3463 : // sort
3464 0 : Vector<uInt> sortedindx;
3465 0 : Sort sorter;
3466 : //cerr<<"Setup sortKey..."<<endl;
3467 0 : sorter.sortKey(peaks.data(),TpFloat,0, Sort::Descending);
3468 : //cerr<<"do sort..."<<endl;
3469 0 : sorter.sort(sortedindx, peaks.nelements());
3470 : //os << "Sorting py peak flux DONE..."<<LogIO::POST;
3471 0 : os<< LogIO::DEBUG1<<"sortedindx="<<sortedindx<<LogIO::POST;
3472 : // FOR DEBUGGING
3473 0 : for (uInt j = 0; j < blcs.nelements(); j++) {
3474 0 : os<<" j="<<j<<" blcs="<<blcs[j]<<" trcs="<<trcs[j]<<LogIO::POST;
3475 : }
3476 0 : Vector<Int> absRel(ndim, RegionType::Abs);
3477 0 : PtrBlock<const WCRegion *> wbox;
3478 0 : uInt iSubComp=0;
3479 0 : uInt removeByNMask=0;
3480 0 : uInt removeBySize=0;
3481 0 : for (uInt icomp=0; icomp < sortedindx.nelements(); icomp++) {
3482 0 : Bool removeit(False);
3483 0 : Vector<Quantum<Double> > qblc(ndim);
3484 0 : Vector<Quantum<Double> > qtrc(ndim);
3485 0 : Vector<Double> wblc(ndim);
3486 0 : Vector<Double> wtrc(ndim);
3487 0 : Vector<Double> pblc(ndim);
3488 0 : Vector<Double> ptrc(ndim);
3489 : // pixel blcs and trcs
3490 0 : for (uInt i=0; i < ndim; i++) {
3491 0 : pblc[i] = (Double) blcs[sortedindx[icomp]][i];
3492 0 : ptrc[i] = (Double) trcs[sortedindx[icomp]][i];
3493 : }
3494 : // get blcs and trcs in world coord.
3495 0 : cSys.toWorld(wblc,pblc);
3496 0 : cSys.toWorld(wtrc,ptrc);
3497 0 : for (uInt i=0; i < ndim; i++) {
3498 0 : qblc[i] = Quantum<Double>(wblc[i], cSys.worldAxisUnits()(cSys.pixelAxisToWorldAxis(i)));
3499 0 : qtrc[i] = Quantum<Double>(wtrc[i], cSys.worldAxisUnits()(cSys.pixelAxisToWorldAxis(i)));
3500 : }
3501 :
3502 0 : if (npix > 0) {
3503 : //npix = area
3504 : //os<<"pruning regions by size < "<<npix<<LogIO::POST;
3505 0 : Int xboxdim = ptrc[0] - pblc[0];
3506 0 : Int yboxdim = ptrc[1] - pblc[1];
3507 : //if (( xboxdim < npix || yboxdim < npix ) && xboxdim*yboxdim < npix*npix ) {
3508 0 : if ( xboxdim*yboxdim < npix ) {
3509 0 : removeit = True;
3510 0 : removeBySize++;
3511 : }
3512 : }
3513 0 : if (nmask > 0 && icomp >= (uInt)nmask ) {
3514 0 : removeit=True;
3515 0 : removeByNMask++;
3516 : }
3517 :
3518 0 : if (removeit) {
3519 0 : wbox.resize(iSubComp+1);
3520 0 : wbox[iSubComp]= new WCBox (qblc, qtrc, cSys, absRel);
3521 0 : iSubComp++;
3522 0 : os << LogIO::DEBUG1<<"*** Removed region: "<<icomp<<" pblc="<<pblc<<" ptrc="<<ptrc<<LogIO::POST;
3523 : }
3524 : else {
3525 0 : os << LogIO::DEBUG1<<"Saved region: "<<icomp<<" pblc="<<pblc<<" ptrc="<<ptrc<<LogIO::POST;
3526 : }
3527 0 : } // for icomp
3528 :
3529 : //cerr<<"iSubComp="<<iSubComp<<endl;
3530 : //cerr<<"wbox.nelements="<<wbox.nelements()<<endl;
3531 0 : if (iSubComp>0) {
3532 0 : ImageRegion* boxImageRegion=regMan.doUnion(wbox);
3533 : //cerr<<"regionToMask ..."<<endl;
3534 0 : tempIm->copyData(*subIm);
3535 0 : regionToMask(*tempIm,*boxImageRegion, Float(0.0));
3536 : //cerr<<"Done regionToMask..."<<endl;
3537 0 : os <<"pruneRegions removed "<<iSubComp<<" regions from the mask image"<<LogIO::POST;
3538 0 : os <<" (reasons: "<< removeBySize<<" by size "<<", "<<removeByNMask<<" by nmask)" <<LogIO::POST;
3539 0 : for (uInt k=0; k < wbox.nelements(); k++) {
3540 0 : delete wbox[k];
3541 : }
3542 : }
3543 : else {
3544 0 : os <<"No regions are removed by pruning" << LogIO::POST;
3545 : }
3546 : // Debug
3547 0 : if (debug) {
3548 0 : PagedImage<Float> debugPrunedIm(tempIm->shape(),tempIm->coordinates(),"prunedSub.Im");
3549 0 : debugPrunedIm.copyData(*tempIm);
3550 0 : }
3551 : //
3552 : // Inserting pruned result image to the input image
3553 0 : Array<Float> subimData;
3554 : //IPosition fullimShape=image.shape();
3555 : //TempImage<Float>* fullIm = new TempImage<Float>(TiledShape(fullimShape, image.niceCursorShape()), image.coordinates());
3556 0 : fullIm->set(0);
3557 0 : IPosition start(fullimShape.nelements(),0);
3558 0 : IPosition stride(fullimShape.nelements(),1);
3559 0 : if (ndim ==3) {
3560 0 : IPosition substart(3,0);
3561 0 : IPosition subshape(3,subimShape(0),subimShape(1),1);
3562 0 : IPosition substride(3,1,1,1);
3563 0 : uInt nchan=subimShape(2);
3564 : //cerr<<"shape tempIm ="<<tempIm->shape()<<endl;
3565 : //cerr<<"shape fullIm ="<<fullIm->shape()<<endl;
3566 0 : for (uInt ich=0; ich < nchan; ich++) {
3567 0 : substart(2) = ich;
3568 : //tempIm->getSlice(subimData,Slicer(substart,subend),True);
3569 0 : tempIm->getSlice(subimData,substart,subshape,substride,True);
3570 0 : start(3) = ich;
3571 0 : fullIm->putSlice(subimData,start,stride);
3572 : }
3573 0 : }
3574 0 : else if (ndim==2) {
3575 0 : subimData = tempIm->get();
3576 : //cerr<<"subimData shape="<<subimData.shape()<<endl;
3577 : //cerr<<"shape tempIm ="<<tempIm->shape()<<endl;
3578 0 : fullIm->putSlice(subimData,start,stride);
3579 : //cerr<<"shape fullIm ="<<fullIm->shape()<<endl;
3580 : }
3581 0 : delete subIm; subIm=0;
3582 0 : delete tempIm; tempIm=0;
3583 0 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3584 0 : }
3585 :
3586 :
3587 0 : std::shared_ptr<casacore::ImageInterface<Float> > SDMaskHandler::pruneRegions2(const ImageInterface<Float>& image, Double& thresh, Int nmask, Double prunesize)
3588 : {
3589 0 : LogIO os( LogOrigin("SDMaskHandler", "pruneRegions2",WHERE) );
3590 0 : Bool debug(False);
3591 :
3592 0 : IPosition fullimShape=image.shape();
3593 0 : TempImage<Float>* fullIm = new TempImage<Float>(TiledShape(fullimShape, image.niceCursorShape()), image.coordinates(), memoryToUse());
3594 0 : fullIm->set(0);
3595 :
3596 0 : if (nmask==0 && prunesize==0.0 ) {
3597 : //No-op
3598 0 : os<<LogIO::DEBUG1<<"Skip pruning of mask regions"<<LogIO::POST;
3599 0 : fullIm->copyData(image);
3600 0 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3601 : }
3602 0 : os <<LogIO::NORMAL<< "pruneRegions with nmask="<<nmask<<", size="<<prunesize<<" is applied"<<LogIO::POST;
3603 :
3604 0 : IPosition shp = image.shape();
3605 0 : IPosition trc = shp-1;
3606 0 : Int specaxis = CoordinateUtil::findSpectralAxis(image.coordinates());
3607 0 : uInt nchan = shp(specaxis);
3608 : // do a single channel plane at time
3609 0 : for (uInt ich = 0; ich < nchan; ich++) {
3610 0 : IPosition start(4, 0, 0, 0,ich);
3611 0 : IPosition length(4, shp(0),shp(1),shp(2),1);
3612 0 : Slicer sl(start, length);
3613 : //cerr<<"slicer sl ="<<sl<<endl;
3614 0 : AxesSpecifier aspec(False);
3615 : // decomposer can only work for 2 and 3-dim images so need
3616 : // some checks the case for stokes axis > 1
3617 : // following works if stokes axis dim = 1
3618 0 : SubImage<Float>* subIm = new SubImage<Float>(image, sl, aspec, True);
3619 0 : RegionManager regMan;
3620 0 : CoordinateSystem cSys=subIm->coordinates();
3621 0 : regMan.setcoordsys(cSys);
3622 0 : IPosition subimShape=subIm->shape();
3623 0 : uInt ndim = subimShape.nelements();
3624 0 : TempImage<Float>* tempIm = new TempImage<Float> (TiledShape(subIm->shape(), subIm->niceCursorShape()), subIm->coordinates(), memoryToUse() );
3625 : // to search for both positive and negative components
3626 0 : tempIm->copyData(LatticeExpr<Float> (abs(*subIm)));
3627 : //use ImageDecomposer
3628 0 : Matrix<Quantity> blctrcs;
3629 0 : ImageDecomposer<Float> id(*tempIm);
3630 0 : id.setDeblend(True);
3631 0 : os << LogIO::DEBUG1<< "Deblend threshold="<<thresh<<LogIO::POST;
3632 0 : id.setDeblendOptions(thresh, 3, 1, 2); //nContour=3
3633 0 : id.setFit(False);
3634 0 : os << LogIO::DEBUG1<<"Now calling decomposeImage()..."<<LogIO::POST;
3635 0 : id.decomposeImage();
3636 0 : if (debug)
3637 0 : id.printComponents();
3638 0 : uInt nRegion = id.numRegions();
3639 0 : os << "Found " << nRegion <<" regions for channel plane "<<ich<<LogIO::POST;
3640 0 : if (nRegion) {
3641 0 : Block<IPosition> blcs(nRegion);
3642 0 : Block<IPosition> trcs(nRegion);
3643 0 : id.boundRegions(blcs, trcs);
3644 : //os << "Get comp list.."<<LogIO::POST;
3645 0 : Matrix<Float> clmat=id.componentList();
3646 : //os << "Get peaks.."<<LogIO::POST;
3647 0 : Vector<Float> peaks = clmat.column(0);
3648 : //cerr<<"peaks="<<peaks<<endl;
3649 0 : os << LogIO::DEBUG1<< "Sorting by peak fluxes..."<<LogIO::POST;
3650 : // sort
3651 0 : Vector<uInt> sortedindx;
3652 0 : Sort sorter;
3653 0 : sorter.sortKey(peaks.data(),TpFloat,0, Sort::Descending);
3654 0 : sorter.sort(sortedindx, peaks.nelements());
3655 : //os << "Sorting py peak flux DONE..."<<LogIO::POST;
3656 0 : os<< LogIO::DEBUG1<<"sortedindx="<<sortedindx<<LogIO::POST;
3657 : // FOR DEBUGGING
3658 0 : if (debug) {
3659 0 : for (uInt j = 0; j < blcs.nelements(); j++) {
3660 0 : os<<" j="<<j<<" blcs="<<blcs[j]<<" trcs="<<trcs[j]<<LogIO::POST;
3661 : }
3662 : }
3663 0 : Vector<Int> absRel(ndim, RegionType::Abs);
3664 0 : PtrBlock<const WCRegion *> wbox;
3665 0 : uInt iSubComp=0;
3666 0 : uInt removeByNMask=0;
3667 0 : uInt removeBySize=0;
3668 0 : for (uInt icomp=0; icomp < sortedindx.nelements(); icomp++) {
3669 0 : Bool removeit(False);
3670 0 : if (debug) {
3671 0 : cerr<<"sortedindx="<<sortedindx[icomp]<<" comp="<<clmat.row(sortedindx[icomp])<<endl;
3672 : }
3673 0 : Vector<Quantum<Double> > qblc(ndim);
3674 0 : Vector<Quantum<Double> > qtrc(ndim);
3675 0 : Vector<Double> wblc(ndim);
3676 0 : Vector<Double> wtrc(ndim);
3677 0 : Vector<Double> pblc(ndim);
3678 0 : Vector<Double> ptrc(ndim);
3679 : // pixel blcs and trcs
3680 0 : for (uInt i=0; i < ndim; i++) {
3681 0 : pblc[i] = (Double) blcs[sortedindx[icomp]][i];
3682 0 : ptrc[i] = (Double) trcs[sortedindx[icomp]][i];
3683 : }
3684 : // get blcs and trcs in world coord.
3685 0 : cSys.toWorld(wblc,pblc);
3686 0 : cSys.toWorld(wtrc,ptrc);
3687 0 : if (debug) {
3688 0 : cerr<<"cSys.workdAxisUnits=="<<cSys.worldAxisUnits()<<endl;
3689 0 : cerr<<"cSys increment = "<<cSys.increment()<<endl;
3690 : }
3691 0 : for (uInt i=0; i < ndim; i++) {
3692 0 : qblc[i] = Quantum<Double>(wblc[i], cSys.worldAxisUnits()(cSys.pixelAxisToWorldAxis(i)));
3693 0 : qtrc[i] = Quantum<Double>(wtrc[i], cSys.worldAxisUnits()(cSys.pixelAxisToWorldAxis(i)));
3694 : }
3695 0 : if (prunesize > 0.0) {
3696 : //npix = area
3697 0 : Int xboxdim = ptrc[0] - pblc[0] +1;
3698 0 : Int yboxdim = ptrc[1] - pblc[1] +1;
3699 : // get size from component : these seem to be in deg
3700 0 : Double ax1 = clmat.row(sortedindx[icomp])[3];
3701 0 : Double ax2 = ax1*clmat.row(sortedindx[icomp])[4];
3702 0 : Quantity qax1(ax1,"deg");
3703 0 : Quantity qax2(ax2,"deg");
3704 0 : Vector<Double> incVal = cSys.increment();
3705 0 : Vector<String> incUnit = cSys.worldAxisUnits();
3706 0 : Quantity qinc1(incVal[0],incUnit[0]);
3707 0 : Quantity qinc2(incVal[1],incUnit[1]);
3708 0 : Double pixAreaInRad = abs(qinc1.get(Unit("rad")).getValue() * qinc2.get(Unit("rad")).getValue());
3709 0 : Double regionInSR = C::pi * qax1.get(Unit("rad")).getValue() * qax2.get(Unit("rad")).getValue() / (4. * C::ln2);
3710 0 : Double regpix = regionInSR/pixAreaInRad;
3711 : //Double axpix1 = ceil(abs(qax1/(qinc1.convert(qax1),qinc1)).get().getValue());
3712 : //Double axpix2 = ceil(abs(qax2/(qinc2.convert(qax2),qinc2)).get().getValue());
3713 : //Int regpix = Int(C::pi * axpix1 * axpix2 /(4. * C::ln2));
3714 0 : if (debug) {
3715 0 : cerr<<"regpix="<<regpix<<" prunesize="<<prunesize<<" xboxdim="<<xboxdim<<" yboxdim="<<yboxdim<<endl;
3716 : }
3717 : // regpix seems to be a bit too small ..., try pruning by blc, trc ...
3718 0 : if ( xboxdim*yboxdim < Int(ceil(prunesize)) ) {
3719 : //if ( regpix < prunesize ) {
3720 0 : removeit = True;
3721 0 : removeBySize++;
3722 : }
3723 0 : }
3724 0 : if (nmask > 0 && icomp >= (uInt)nmask ) {
3725 0 : removeit=True;
3726 0 : removeByNMask++;
3727 : }
3728 :
3729 0 : if (removeit) {
3730 0 : wbox.resize(iSubComp+1);
3731 0 : wbox[iSubComp]= new WCBox (qblc, qtrc, cSys, absRel);
3732 0 : iSubComp++;
3733 0 : os << LogIO::DEBUG1<<"*** Removed region: "<<icomp<<" pblc="<<pblc<<" ptrc="<<ptrc<<LogIO::POST;
3734 : }
3735 : else {
3736 0 : os << LogIO::DEBUG1<<"Saved region: "<<icomp<<" pblc="<<pblc<<" ptrc="<<ptrc<<LogIO::POST;
3737 : }
3738 0 : } // for icomp
3739 :
3740 : //cerr<<"iSubComp="<<iSubComp<<endl;
3741 : //cerr<<"wbox.nelements="<<wbox.nelements()<<endl;
3742 0 : if (iSubComp>0) {
3743 0 : ImageRegion* boxImageRegion=regMan.doUnion(wbox);
3744 : //cerr<<"regionToMask ..."<<endl;
3745 0 : tempIm->copyData(*subIm);
3746 0 : regionToMask(*tempIm,*boxImageRegion, Float(0.0));
3747 : //cerr<<"Done regionToMask..."<<endl;
3748 0 : os <<"pruneRegions removed "<<iSubComp<<" regions from the mask image"<<LogIO::POST;
3749 0 : os <<" (reasons: "<< removeBySize<<" by size "<<", "<<removeByNMask<<" by nmask)" <<LogIO::POST;
3750 0 : for (uInt k=0; k < wbox.nelements(); k++) {
3751 0 : delete wbox[k];
3752 : }
3753 : }
3754 : else {
3755 0 : os <<"No regions are removed by pruning" << LogIO::POST;
3756 : }
3757 : // Debug
3758 0 : if (debug) {
3759 0 : PagedImage<Float> debugPrunedIm(tempIm->shape(),tempIm->coordinates(),"tmp-prunedSub.im");
3760 0 : debugPrunedIm.copyData(*tempIm);
3761 0 : }
3762 : //
3763 : // Inserting pruned result image to the input image
3764 0 : Array<Float> subimData;
3765 : //IPosition fullimShape=image.shape();
3766 : //TempImage<Float>* fullIm = new TempImage<Float>(TiledShape(fullimShape, image.niceCursorShape()), image.coordinates());
3767 :
3768 : //IPosition start(fullimShape.nelements(),0);
3769 : //IPosition stride(fullimShape.nelements(),1);
3770 : //IPosition substart(3,0);
3771 : //IPosition subshape(3,subimShape(0),subimShape(1),1);
3772 : //IPosition substride(3,1,1,1);
3773 : //tempIm->getSlice(subimData,Slicer(substart,subend),True);
3774 0 : tempIm->getSlice(subimData,IPosition(2,0), tempIm->shape(), IPosition(2,1,1));
3775 0 : fullIm->putSlice(subimData,start,IPosition(4,1,1,1,1));
3776 0 : delete tempIm; tempIm=0;
3777 0 : delete subIm; subIm=0;
3778 0 : }// if(nRegion) end
3779 0 : }
3780 0 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3781 0 : }
3782 :
3783 : //yet another pruneRegions - using connect component labelling with depth first search alogirthm ..
3784 343 : std::shared_ptr<casacore::ImageInterface<Float> > SDMaskHandler::YAPruneRegions(const ImageInterface<Float>& image, Vector<Bool>& chanflag, Vector<Bool>& allpruned, Vector<uInt>& nreg, Vector<uInt>& npruned, Double prunesize, Bool showchanlabel)
3785 : {
3786 686 : LogIO os( LogOrigin("SDMaskHandler", "YAPruneRegions",WHERE) );
3787 343 : Timer timer;
3788 343 : Bool debug(False);
3789 343 : Bool recordPruned(False);
3790 343 : if (allpruned.nelements()>0) {
3791 232 : recordPruned=True;
3792 232 : allpruned.set(False);
3793 : }
3794 :
3795 343 : IPosition fullimShape=image.shape();
3796 343 : TempImage<Float>* fullIm = new TempImage<Float>(TiledShape(fullimShape, image.niceCursorShape()), image.coordinates(), memoryToUse());
3797 343 : fullIm->set(0);
3798 :
3799 343 : if (prunesize==0.0 ) {
3800 : //No-op
3801 0 : os<<LogIO::DEBUG1<<"Skip pruning of mask regions"<<LogIO::POST;
3802 0 : fullIm->copyData(image);
3803 0 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3804 : }
3805 343 : os <<LogIO::DEBUG1<< "pruneRegions with size="<<prunesize<<" is applied"<<LogIO::POST;
3806 :
3807 343 : IPosition shp = image.shape();
3808 343 : Int specaxis = CoordinateUtil::findSpectralAxis(image.coordinates());
3809 343 : uInt nchan = shp(specaxis);
3810 343 : nreg.resize(nchan);
3811 343 : npruned.resize(nchan);
3812 : // do a single channel plane at time
3813 : // - assumes standard CASA image axis ordering (ra,dec,stokes,chan)
3814 686 : for (uInt ich = 0; ich < nchan; ich++) {
3815 343 : if (!chanflag(ich)) {
3816 343 : IPosition start(4, 0, 0, 0,ich);
3817 343 : IPosition length(4, shp(0),shp(1),shp(2),1);
3818 343 : Slicer sl(start, length);
3819 : //cerr<<"ich="<<ich<<" slicer sl ="<<sl<<endl;
3820 343 : AxesSpecifier aspec(False);
3821 : // following works if stokes axis dim = 1
3822 343 : SubImage<Float>* subIm = new SubImage<Float>(image, sl, aspec, True);
3823 :
3824 343 : IPosition subimShape=subIm->shape();
3825 343 : TempImage<Float>* tempIm = new TempImage<Float> (TiledShape(subIm->shape(), subIm->niceCursorShape()), subIm->coordinates(), memoryToUse() );
3826 : // to search for both positive and negative components
3827 343 : tempIm->copyData(LatticeExpr<Float> (abs(*subIm)));
3828 :
3829 343 : TempImage<Float>* blobMap = new TempImage<Float> (TiledShape(subIm->shape(), subIm->niceCursorShape()), subIm->coordinates(), memoryToUse() );
3830 343 : blobMap->set(0);
3831 :
3832 : // connected componet labelling
3833 343 : os<<LogIO::DEBUG1<<"Calling labelRegions..."<<LogIO::POST;
3834 343 : Array<Float> tempImarr;
3835 343 : tempIm->get(tempImarr);
3836 343 : Float sumMaskVal=sum(tempImarr);
3837 343 : uInt removeBySize=0;
3838 343 : uInt nBlob=0;
3839 343 : os<<LogIO::DEBUG1<<" total pix of 1s="<< sumMaskVal <<LogIO::POST;
3840 343 : if ( sumMaskVal !=0.0 ) {
3841 309 : timer.mark();
3842 309 : labelRegions(*tempIm, *blobMap);
3843 309 : os<< LogIO::DEBUG1 << "Processing time for labelRegions: real "<< timer.real()<< "s ; user "<< timer.user() <<"s"<< LogIO::POST;
3844 309 : Array<Float> tempblobarr;
3845 309 : blobMap->get(tempblobarr);
3846 309 : os<<LogIO::DEBUG1<<" total pix of 1s="<< sum(tempblobarr) <<LogIO::POST;
3847 309 : os<<LogIO::DEBUG1<<"Calling findBlobSize..."<<LogIO::POST;
3848 : // get blobsizes (the vector contains each labeled region size (label # = ith element+1)
3849 : //timer.mark();
3850 309 : Vector<Float> blobsizes = findBlobSize(*blobMap);
3851 : //cerr<<"blobsizes="<<blobsizes<<endl;
3852 : //use ImageDecomposer
3853 : // book keeping of no of removed components`
3854 : //cerr<<"blobsizes.nelements()="<<blobsizes.nelements()<<endl;
3855 : //removing operations
3856 309 : nBlob = blobsizes.nelements();
3857 309 : if (blobsizes.nelements()) {
3858 309 : if (prunesize > 0.0) {
3859 622 : for (uInt icomp = 0; icomp < blobsizes.nelements(); ++icomp) {
3860 313 : if ( blobsizes[icomp] < prunesize ) {
3861 64 : Float blobid = Float(icomp+1);
3862 64 : removeBySize++;
3863 64 : tempIm->copyData( (LatticeExpr<Float>)( iif(*blobMap == blobid, 0.0, *tempIm ) ) );
3864 : }
3865 : }//for-loop
3866 : }
3867 : }
3868 309 : } // if-sumMaskVal!=0
3869 : // log reporting ...
3870 343 : String chanlabel("");
3871 343 : if (showchanlabel) {
3872 0 : chanlabel = "[C"+String::toString(ich)+"]";
3873 : }
3874 343 : if (removeBySize>0) {
3875 64 : os <<LogIO::DEBUG1<<chanlabel<<" pruneRegions removed "<<removeBySize<<" regions (out of "<<nBlob<<" ) from the mask image. "<<LogIO::POST;
3876 64 : if (recordPruned) {
3877 64 : if (removeBySize==nBlob) allpruned(ich) = True;
3878 : }
3879 : }
3880 : else {
3881 279 : if (sumMaskVal!=0.0) {
3882 245 : os <<LogIO::NORMAL<<chanlabel<<" No regions are removed in pruning process." << LogIO::POST;
3883 : }
3884 : else {
3885 34 : os <<LogIO::NORMAL<<chanlabel<<" No regions are found in this plane."<< LogIO::POST;
3886 : }
3887 : }
3888 343 : nreg[ich] = nBlob;
3889 343 : npruned[ich] = removeBySize;
3890 : // Debug
3891 343 : if (debug) {
3892 0 : PagedImage<Float> tempBlobMap(blobMap->shape(), blobMap->coordinates(), "tmp-Blob.map");
3893 0 : tempBlobMap.copyData(*blobMap);
3894 0 : }
3895 343 : Array<Float> subimData;
3896 343 : tempIm->getSlice(subimData,IPosition(2,0), tempIm->shape(), IPosition(2,1,1));
3897 343 : fullIm->putSlice(subimData,start,IPosition(4,1,1,1,1));
3898 343 : delete tempIm; tempIm=0;
3899 343 : delete subIm; subIm=0;
3900 343 : delete blobMap; blobMap=0;
3901 343 : } // if-skipmask
3902 : else {
3903 0 : nreg[ich] = 0;
3904 0 : npruned[ich] = 0;
3905 0 : if (showchanlabel) {
3906 0 : os<<LogIO::DEBUG1<<"Skipping chan "<<ich<<" from pruning"<<LogIO::POST;
3907 : }
3908 : else {
3909 0 : os<<LogIO::DEBUG1<<"Skipping this plane from pruning"<<LogIO::POST;
3910 : }
3911 :
3912 : }
3913 : }
3914 343 : return std::shared_ptr<ImageInterface<Float> >(fullIm);
3915 343 : }
3916 :
3917 :
3918 52 : Float SDMaskHandler::pixelBeamArea(const GaussianBeam& beam, const CoordinateSystem& csys)
3919 : {
3920 :
3921 52 : Quantity bmaj = beam.getMajor();
3922 52 : Quantity bmin = beam.getMinor();
3923 52 : Vector<Double> incVal = csys.increment();
3924 52 : Vector<String> incUnit = csys.worldAxisUnits();
3925 52 : Quantity qinc1(incVal[0],incUnit[0]);
3926 52 : Quantity qinc2(incVal[1],incUnit[1]);
3927 : // should in rad but make sure...
3928 52 : Double pixArea = abs(qinc1.get(Unit("rad")).getValue() * qinc2.get(Unit("rad")).getValue());
3929 52 : Double solidAngle = C::pi * bmaj.get(Unit("rad")).getValue() * bmin.get(Unit("rad")).getValue()/(4.* C::ln2);
3930 52 : return (Float) solidAngle/pixArea;
3931 :
3932 52 : }
3933 :
3934 20 : void SDMaskHandler::makePBMask(std::shared_ptr<SIImageStore> imstore, Float pblimit, Bool combinemask)
3935 : {
3936 40 : LogIO os( LogOrigin("SDMaskHandler","makePBMask",WHERE) );
3937 :
3938 20 : if( imstore->hasPB() ) // Projection algorithms will have this.
3939 : {
3940 19 : LatticeExpr<Float> themask;
3941 19 : if (combinemask && imstore->hasMask()) {
3942 7 : os<<"MAKE combined PB mask"<<LogIO::POST;
3943 7 : themask = LatticeExpr<Float> ( iif( (*(imstore->pb())) > pblimit, *(imstore->mask()), 0.0 ) );
3944 : }
3945 : else {
3946 12 : os<<"MAKE PB mask"<<LogIO::POST;
3947 24 : themask = LatticeExpr<Float> ( iif( (*(imstore->pb())) > pblimit , 1.0, 0.0 ) );
3948 : }
3949 15 : imstore->mask()->copyData( themask );
3950 19 : }
3951 : else // Calculate it here...
3952 : {
3953 : // Get antenna diameter
3954 : // Get frequency
3955 : // Assuming a Gaussian, construct a circle region at pblimit.
3956 :
3957 : // But for now...
3958 1 : throw(AipsError("Need PB/Sensitivity/Weight image before a PB-based mask can be made for "+imstore->getName()));
3959 :
3960 : }
3961 : // Also add option to just use the vpmanager or whatever centralized PB repository there will be (sometime in the distant future...).
3962 :
3963 20 : }// end of makePBMask
3964 :
3965 : //apply per channel plane threshold
3966 696 : void SDMaskHandler::makeMaskByPerChanThreshold(const ImageInterface<Float>& image, Vector<Bool>& chanflag, ImageInterface<Float>& mask, Vector<Float>& thresholds, Vector<Float>& masksizes)
3967 : {
3968 696 : IPosition imshape = image.shape();
3969 :
3970 696 : CoordinateSystem imcsys = image.coordinates();
3971 696 : Vector<Int> diraxes = CoordinateUtil::findDirectionAxes(imcsys);
3972 696 : Int specaxis = CoordinateUtil::findSpectralAxis(imcsys);
3973 696 : uInt nchan = imshape (specaxis);
3974 696 : masksizes.resize(nchan);
3975 696 : if (nchan != thresholds.nelements()) {
3976 0 : throw(AipsError("Mismatch in the number of threshold values and the number of chan planes."));
3977 : }
3978 1392 : for (uInt ich=0; ich < nchan; ich++) {
3979 696 : if (!chanflag(ich)) {
3980 696 : IPosition start(4, 0, 0, 0,ich);
3981 696 : IPosition length(4, imshape(diraxes(0)),imshape(diraxes(1)),imshape(2),1);
3982 696 : Slicer sl(start, length);
3983 :
3984 : // make a subImage for a channel slice
3985 696 : AxesSpecifier aspec(False);
3986 696 : SubImage<Float> chanImage(image, sl, aspec, true);
3987 696 : TempImage<Float>* tempChanImage = new TempImage<Float> (chanImage.shape(), chanImage.coordinates(), memoryToUse() );
3988 696 : Array<Float> chanImageArr;
3989 696 : LatticeExpr<Float> chanMask;
3990 696 : if (thresholds(ich) < 0) {
3991 : //LatticeExpr<Float> chanMask(iif(chanImage < thresholds(ich),1.0, 0.0));
3992 5 : chanMask = LatticeExpr<Float> (iif(chanImage < thresholds(ich),1.0, 0.0));
3993 : }
3994 : else {
3995 : //LatticeExpr<Float> chanMask(iif(chanImage > thresholds(ich),1.0, 0.0));
3996 691 : chanMask = LatticeExpr<Float> (iif(chanImage > thresholds(ich),1.0, 0.0));
3997 : }
3998 696 : tempChanImage->copyData(chanMask);
3999 : //tempChanImage->getSlice(chanImageArr, IPosition(4,0), chanImage.shape(),IPosition(4,1,1,1,1));
4000 696 : tempChanImage->getSlice(chanImageArr, IPosition(2,0), chanImage.shape(),IPosition(2,1,1));
4001 696 : mask.putSlice(chanImageArr,start,IPosition(4,1,1,1,1));
4002 696 : masksizes[ich]=sum(chanImageArr);
4003 696 : delete tempChanImage; tempChanImage=0;
4004 696 : }
4005 : else {
4006 0 : masksizes[ich]=0;
4007 : // cerr<<"makeMaskByPerChanThresh: skipping chan="<<ich<<endl;
4008 : }
4009 : } // loop over chans
4010 696 : }
4011 :
4012 119 : void SDMaskHandler::binaryDilationCore(Lattice<Float>& inlattice,
4013 : Array<Float>& structure,
4014 : Lattice<Bool>& mask,
4015 : Array<Bool>& chanmask,
4016 : Lattice<Float>& outlattice)
4017 : {
4018 238 : LogIO os( LogOrigin("SDMaskHandler", "binaryDilation", WHERE) );
4019 : //
4020 : //IPosition cursorShape=inlattice.niceCursorShape();
4021 119 : IPosition inshape = inlattice.shape();
4022 119 : Int nx = inshape(0);
4023 119 : Int ny = inshape(1);
4024 : // assume here 3x3 structure elements (connectivity of either 1 or 2)
4025 119 : IPosition seshape = structure.shape();
4026 119 : Int se_nx =seshape(0);
4027 119 : Int se_ny =seshape(1);
4028 :
4029 119 : if (mask.shape()!=inshape) {
4030 0 : throw(AipsError("Incompartible mask shape. Need to be the same as the input image."));
4031 : }
4032 : // assume the origin of structure element is the center se(1,1)
4033 119 : IPosition cursorShape(4, nx, ny, 1, 1);
4034 119 : IPosition axisPath(4, 0, 1, 3, 2);
4035 : //cerr<<"cursorShape="<<cursorShape<<endl;
4036 : //cerr<<"structure="<<structure<<endl;
4037 119 : LatticeStepper tls(inlattice.shape(), cursorShape, axisPath);
4038 119 : RO_LatticeIterator<Float> li(inlattice, tls);
4039 119 : RO_LatticeIterator<Bool> mi(mask, tls);
4040 119 : LatticeIterator<Float> oli(outlattice,tls);
4041 : Int ich;
4042 119 : IPosition ipch(chanmask.shape().size(),0);
4043 :
4044 : // for debug
4045 : //Array<Float> initarr=inlattice.get();
4046 : //cerr<<"initarr sum pix="<<sum(initarr)<<endl;
4047 :
4048 238 : for (li.reset(), mi.reset(), oli.reset(), ich=0; !li.atEnd(); li++, mi++, oli++, ich++) {
4049 : //Array<Float> planeImage(li.cursor());
4050 119 : Array<Float> inMask(li.cursor());
4051 : //cerr<<"sum of inMask="<<sum(inMask)<<endl;
4052 119 : Array<Float> planeImage(inMask.shape());
4053 119 : planeImage.set(0);
4054 119 : planeImage=inMask;
4055 : //cerr<<"sum of planeImage before grow ="<<sum(planeImage)<<endl;
4056 119 : Array<Bool> planeMask(mi.cursor());
4057 119 : ipch(0)=ich;
4058 : // if masks are true do binary dilation...
4059 119 : if (ntrue(planeMask)>0 && chanmask(ipch)) {
4060 : //cerr<<"planeImage.shape()="<<planeImage.shape()<<endl;
4061 9687 : for (Int i=0; i < nx; i++) {
4062 1869600 : for (Int j=0; j < ny; j++) {
4063 1860000 : if (planeImage(IPosition(4,i,j,0,0))==1.0 && planeMask(IPosition(4,i,j,0,0)) ) {
4064 : //cerr<<"if planeImage ==1 i="<<i<<" j="<<j<<endl;
4065 : // Set the value for se(1,1)
4066 5780 : planeImage(IPosition(4,i,j,0,0)) = 2.0;
4067 23120 : for (Int ise=0; ise < se_nx; ise++) {
4068 69360 : for (Int jse = 0; jse < se_ny; jse++) {
4069 52020 : Int relx_se = ise - 1;
4070 52020 : Int rely_se = jse - 1;
4071 52020 : if (structure(IPosition(2,ise,jse)) && !(ise==1.0 && jse==1.0)) {
4072 : //cerr<<"structure("<<ise<<","<<jse<<")="<<structure(IPosition(2,ise,jse))<<endl;
4073 23120 : if ((i + relx_se) >= 0 && (i + relx_se) < nx &&
4074 23120 : (j + rely_se) >= 0 && (j + rely_se) < ny) {
4075 23120 : if (planeImage(IPosition(4,i+relx_se,j+rely_se,0,0))==0 ) {
4076 : // set to 2.0 to make distinction with the orignal 1.0 pixels
4077 106 : planeImage(IPosition(4, i+relx_se, j+rely_se,0,0))=2.0;
4078 : //cerr<<" i+relx_se="<<i+relx_se<<" j+rely_se="<<j+rely_se<<endl;
4079 : }
4080 : }
4081 : } // if(se(ise,jse)
4082 : } // if planeImage(i,j)=1.0
4083 : } // S.E. col loop
4084 : } // S.E. row loop
4085 : } // image col loop
4086 : } //inage row loop
4087 :
4088 :
4089 9687 : for (Int ii=0; ii < nx; ii++) {
4090 1869600 : for (Int jj=0; jj < ny; jj++) {
4091 1860000 : if (planeImage(IPosition(4,ii,jj,0,0))==2)
4092 5886 : planeImage(IPosition(4,ii,jj,0,0))=1;
4093 : }
4094 : }
4095 : } // if ntrure() ...
4096 119 : oli.woCursor() = planeImage;
4097 119 : }
4098 : //For debug
4099 : //Array<Float> afterinarr=inlattice.get();
4100 : //cerr<<"afaterinarr sum pix ="<<sum(afterinarr)<<endl;
4101 : //Array<Float> outarr = outlattice.get();
4102 : //cerr<<"outlattice sum pix ="<<sum(outarr)<<endl;
4103 119 : }
4104 :
4105 111 : void SDMaskHandler::binaryDilation(ImageInterface<Float>& inImage,
4106 : Array<Float>& structure,
4107 : Int niteration,
4108 : Lattice<Bool>& mask,
4109 : Array<Bool>& chanmask,
4110 : ImageInterface<Float>& outImage)
4111 : {
4112 222 : LogIO os( LogOrigin("SDMaskHandler", "binaryDilation", WHERE) );
4113 111 : ArrayLattice<Float> templattice(inImage.shape());
4114 111 : templattice.copyData(inImage);
4115 222 : TempImage<Float> diffTempImage(outImage.shape(), outImage.coordinates(), memoryToUse());
4116 111 : diffTempImage.set(1);
4117 : // initial grow mask
4118 111 : binaryDilationCore(inImage,structure,mask,chanmask,outImage);
4119 222 : LatticeExpr<Float> diffIm0( abs(templattice - outImage ) );
4120 :
4121 : // if the initial grow does not change mask (i.e. diffIm0 = 0)
4122 : // then it won't enter the while loop below.
4123 111 : diffTempImage.copyData(diffIm0);
4124 111 : Int iter = 1;
4125 119 : while (iter < niteration && !isEmptyMask(diffTempImage)) {
4126 8 : templattice.copyData(outImage);
4127 8 : binaryDilationCore(templattice,structure,mask,chanmask,outImage);
4128 16 : LatticeExpr<Float> diffIm( abs(templattice - outImage ) );
4129 8 : diffTempImage.copyData(diffIm);
4130 : /***
4131 : if (isEmptyMask(diffTempImage)) {
4132 : cerr<<"current iter"<<iter<<" diffim is 0 "<<endl;
4133 : }
4134 : else {
4135 : cerr<<"current iter"<<iter<<endl;
4136 : }
4137 : ***/
4138 8 : iter++;
4139 8 : }
4140 111 : os<<"grow iter done="<<iter<<LogIO::POST;
4141 111 : }
4142 :
4143 :
4144 0 : void SDMaskHandler::autoMaskWithinPB(std::shared_ptr<SIImageStore> imstore,
4145 : ImageInterface<Float>& posmask,
4146 : const Int iterdone,
4147 : Vector<Bool>& chanflag,
4148 : Record& robuststatsrec,
4149 : const String& alg,
4150 : const String& threshold,
4151 : const Float& fracofpeak,
4152 : const String& resolution,
4153 : const Float& resbybeam,
4154 : const Int nmask,
4155 : const Bool autoadjust,
4156 : const Float& sidelobethreshold,
4157 : const Float& noisethreshold,
4158 : const Float& lownoisethreshold,
4159 : const Float& negativethreshold,
4160 : const Float& cutthreshold,
4161 : const Float& smoothfactor,
4162 : const Float& minbeamfrac,
4163 : const Int growiterations,
4164 : const Bool dogrowprune,
4165 : const Float& minpercentchange,
4166 : const Bool verbose,
4167 : const Bool fastnoise,
4168 : const Bool isthresholdreached,
4169 : Float pblimit)
4170 : {
4171 0 : LogIO os( LogOrigin("SDMaskHandler","autoMaskWithinPB",WHERE) );
4172 : //Bool debug(False);
4173 :
4174 0 : os <<LogIO::DEBUG1<<"Calling autoMaskWithinPB .."<<LogIO::POST;
4175 : // changed to do automask ater pb mask is generated so automask do stats within pb mask
4176 0 : autoMask( imstore, posmask, iterdone, chanflag, robuststatsrec, alg, threshold, fracofpeak, resolution, resbybeam, nmask, autoadjust,
4177 : sidelobethreshold, noisethreshold, lownoisethreshold, negativethreshold, cutthreshold, smoothfactor,
4178 : minbeamfrac, growiterations, dogrowprune, minpercentchange, verbose, fastnoise, isthresholdreached, pblimit);
4179 :
4180 0 : if( imstore->hasPB() )
4181 : {
4182 0 : LatticeExpr<Float> themask( iif( (*(imstore->pb())) > pblimit , (*(imstore->mask())), 0.0 ) );
4183 0 : imstore->mask()->copyData( themask );
4184 :
4185 : /****
4186 : // apply pb mask as pixel mask for now. This will be converted to 1/0 image later
4187 : LatticeExpr<Bool> mask( iif(*(imstore->pb()) > pblimit, True, False));
4188 : os <<"calling MakeMask, hasPixelMask? "<<imstore->mask()->hasPixelMask()<<LogIO::POST;
4189 : os <<"calling MakeMask, hasRegion mask0? "<<imstore->mask()->hasRegion("mask0")<<LogIO::POST;
4190 : os <<"defaultMask "<<imstore->mask()->getDefaultMask()<<LogIO::POST;
4191 : //ImageRegion outreg=imstore->mask()->makeMask("mask0", False, True);
4192 : ImageRegion outreg=imstore.get()->mask()->makeMask("mask0", True, True);
4193 : LCRegion& outmask=outreg.asMask();
4194 : outmask.copyData(mask);
4195 : os <<"Before defineRegion"<<LogIO::POST;
4196 : imstore.get()->mask()->defineRegion("mask0", outreg, RegionHandler::Masks, True);
4197 : os <<"setDefMask"<<LogIO::POST;
4198 : imstore.get()->mask()->setDefaultMask("mask0");
4199 : imstore.get()->releaseImage(imstore.get()->mask());
4200 : if (debug) {
4201 : cerr<<"Make a copy"<<endl;
4202 : PagedImage<Float> temppb(imstore->mask()->shape(), imstore->mask()->coordinates(),"tempPB.Im");
4203 : temppb.copyData(*(imstore->mask()));
4204 : temppb.defineRegion("mask0", outreg, RegionHandler::Masks, True);
4205 : temppb.setDefaultMask("mask0");
4206 : }
4207 : ***/
4208 :
4209 0 : }
4210 : //autoMask( imstore, alg, threshold, fracofpeak, resolution, resbybeam, nmask);
4211 :
4212 : // else... same options as makePBMask (put it into a helper function)
4213 0 : }// end of autoMaskWithinPB
4214 :
4215 : //region labelling code
4216 0 : void SDMaskHandler::depthFirstSearch(Int x,
4217 : Int y,
4218 : Int cur_label,
4219 : Array<Float>& inlatarr,
4220 : Array<Float>& lablatarr)
4221 : {
4222 0 : Vector<Int> dx(4);
4223 0 : Vector<Int> dy(4);
4224 : // 4-direction connectivity
4225 0 : dx(0) = 1; dx(1)=0;dx(2)=-1;dx(3)=0;
4226 0 : dy(0) = 0; dy(1)=1;dy(2)=0;dy(3)=-1;
4227 : //IPosition inshape = inlat.shape();
4228 0 : IPosition inshape = inlatarr.shape();
4229 0 : Int nrow = inshape(0);
4230 0 : Int ncol = inshape(1);
4231 : // out of bound condition
4232 0 : if(x < 0 || x == nrow) return;
4233 0 : if(y < 0 || y == ncol) return;
4234 : //2d lattice is assumed
4235 0 : IPosition loc(2,x,y);
4236 : // already labelled or not value 1 pixel
4237 0 : if(lablatarr(loc) || !inlatarr(loc)) return;
4238 :
4239 : //cerr<<"cur_label="<<cur_label<<" loc="<<loc<<endl;
4240 :
4241 0 : lablatarr(loc) = Float(cur_label);
4242 : //lablat.putAt(Float(cur_label), loc);
4243 : //
4244 : //
4245 : //recursively check the neighbor
4246 0 : for (uInt inc = 0; inc < 4; ++inc)
4247 0 : depthFirstSearch(x + dx[inc], y + dy[inc], cur_label, inlatarr, lablatarr);
4248 0 : }
4249 :
4250 313 : void SDMaskHandler::depthFirstSearch2(Int x,
4251 : Int y,
4252 : Int cur_label,
4253 : Array<Float>& inlatarr,
4254 : Array<Float>& lablatarr)
4255 :
4256 : {
4257 313 : std::stack<IPosition> mystack;
4258 313 : IPosition inshape = inlatarr.shape();
4259 313 : Int nrow = inshape(0);
4260 313 : Int ncol = inshape(1);
4261 : // out of bound condition
4262 313 : if(x < 0 || x == nrow) return;
4263 313 : if(y < 0 || y == ncol) return;
4264 : //2d lattice is assumed
4265 313 : IPosition loc(2,x,y);
4266 : // if already visited or not mask region, return
4267 313 : if(lablatarr(loc) || !inlatarr(loc)) return;
4268 :
4269 313 : IPosition curloc;
4270 313 : mystack.push(loc);
4271 27995 : while (!mystack.empty()) {
4272 27682 : curloc = mystack.top();
4273 27682 : mystack.pop( );
4274 : //cerr<<"curloc="<<curloc<<" cur_label="<<cur_label<<endl;
4275 27682 : lablatarr(curloc) = Float(cur_label);
4276 27682 : Vector<IPosition> loclist = defineNeighbors(curloc, nrow, ncol);
4277 : //cerr<<"defineNeighbors done nelements="<<loclist.nelements()<<endl;
4278 27682 : if (loclist.nelements()) {
4279 138410 : for (uInt i=0; i < loclist.nelements(); ++i)
4280 : {
4281 110728 : if (inlatarr(loclist(i)) == 1 && lablatarr(loclist(i)) == 0 )
4282 : {
4283 27369 : mystack.push(loclist(i));
4284 : }
4285 : }
4286 : }
4287 27682 : }
4288 313 : }
4289 :
4290 27682 : Vector<IPosition> SDMaskHandler::defineNeighbors(IPosition& pos, Int nx, Int ny)
4291 : {
4292 27682 : Vector<IPosition> neighbors(0);
4293 27682 : Int nelement=0;
4294 : // 4-direction connectivity
4295 27682 : Vector<Int> dx(4);
4296 27682 : Vector<Int> dy(4);
4297 27682 : dx(0) = 1; dx(1)=0;dx(2)=-1;dx(3)=0;
4298 27682 : dy(0) = 0; dy(1)=1;dy(2)=0;dy(3)=-1;
4299 138410 : for (uInt inc = 0; inc < 4; ++inc) {
4300 110728 : IPosition newpos(2,0);
4301 110728 : newpos(0) = pos(0)+dx(inc);
4302 110728 : newpos(1) = pos(1)+dy(inc);
4303 110728 : if (newpos(0) >= 0 && newpos(0) < nx && newpos(1) >= 0 && newpos(1) < ny)
4304 : {
4305 110728 : nelement++;
4306 110728 : neighbors.resize(nelement,True);
4307 110728 : neighbors(nelement-1)=newpos;
4308 : }
4309 110728 : }
4310 55364 : return neighbors;
4311 27682 : }
4312 :
4313 309 : void SDMaskHandler::labelRegions(Lattice<Float>& inlat, Lattice<Float>& lablat)
4314 : {
4315 309 : Int blobId = 0;
4316 309 : IPosition inshape = inlat.shape();
4317 309 : Int nrow = inshape(0);
4318 309 : Int ncol = inshape(1);
4319 309 : Array<Float> inlatarr;
4320 309 : Array<Float> lablatarr;
4321 309 : inlat.get(inlatarr);
4322 309 : lablat.get(lablatarr);
4323 : //cerr<<"IN labelRegions:: inlat.shape="<<inlat.shape()<<" lablat.shape="<<lablat.shape()<<" nrow="<<nrow<<" ncol="<<ncol<<endl;
4324 :
4325 309 : if ( sum(inlatarr) !=0.0 ) {
4326 34809 : for (Int i = 0; i < nrow; ++i)
4327 : {
4328 7084500 : for (Int j = 0; j < ncol; ++j)
4329 : {
4330 : // evaluating elements with lattice seems to be very slow...
4331 : // changed to use Arrarys
4332 : //if (!lablat(IPosition(2,i,j)) && inlat(IPosition(2,i,j) ) )
4333 7050000 : if (!lablatarr(IPosition(2,i,j)) && inlatarr(IPosition(2,i,j) ) )
4334 : //depthFirstSearch(i, j, ++blobId, inlatarr, lablatarr);
4335 : // Use non-recursive version
4336 313 : depthFirstSearch2(i, j, ++blobId, inlatarr, lablatarr);
4337 : }
4338 : }
4339 309 : lablat.put(lablatarr);
4340 : }
4341 : //cerr<<"done blobId="<<blobId<<endl;
4342 309 : }
4343 :
4344 309 : Vector<Float> SDMaskHandler::findBlobSize(Lattice<Float>& lablat)
4345 : {
4346 : // iterate through lablat (2D)
4347 : // find max label in lablat
4348 : // create groupsize list vector gsize(max-1)
4349 : // get val at each pixel in lablat (ival=lablat.get(loc)) and add 1 to gsize(ival-1)
4350 : // print each labelled comp's size...
4351 :
4352 618 : LogIO os( LogOrigin("SDMaskHandler","findBlobSize",WHERE) );
4353 309 : IPosition inshape = lablat.shape();
4354 309 : Int nrow = inshape(0);
4355 309 : Int ncol = inshape(1);
4356 : // getting max value via LatticeExprNode seems to be slower
4357 : //LatticeExprNode leMax=max(lablat);
4358 : //Float maxlab = leMax.getFloat();
4359 309 : Array<Float> lablatarr;
4360 309 : lablat.get(lablatarr);
4361 309 : Float maxlab = max(lablatarr);
4362 : //os<<LogIO::DEBUG1<<"maxlab="<<maxlab<<LogIO::POST;
4363 :
4364 309 : if (maxlab < 1.0) {
4365 0 : return Vector<Float>();
4366 : }
4367 309 : Vector<Float> blobsizes(Int(maxlab),0);
4368 34809 : for (Int i = 0; i < nrow; ++i)
4369 : {
4370 7084500 : for (Int j =0; j < ncol; ++j)
4371 : {
4372 : //IPosition loc(4, i, j, 0, 0);
4373 7050000 : IPosition loc(2, i, j);
4374 : //os<<LogIO::DEBUG1<<"i="<<i<<" j="<<j<<" labelat(loc)="<<lablat(loc)<<LogIO::POST;
4375 : //if (lablat(loc)) blobsizes[Int(lablat(loc))-1]+=1;
4376 7050000 : if (lablatarr(loc)) blobsizes[Int(lablatarr(loc))-1]+=1;
4377 7050000 : }
4378 : }
4379 :
4380 : //for debug
4381 622 : for (Int k = 0;k < maxlab; ++k)
4382 : {
4383 313 : os<<LogIO::DEBUG1<<"blobsizes["<<k<<"]="<<blobsizes[k]<<LogIO::POST;
4384 : }
4385 :
4386 309 : return blobsizes;
4387 309 : }
4388 :
4389 4 : void SDMaskHandler::printAutomaskSummary (const Array<Double>& rmss,
4390 : const Array<Double>& maxs,
4391 : const Array<Double>& mins,
4392 : const Array<Double>& mdns,
4393 : //const Vector<Float>& maskthreshold,
4394 : const Matrix<Float>& maskthreshold,
4395 : //const Vector<String>& thresholdtype,
4396 : const Matrix<String>& thresholdtype,
4397 : //const Vector<Bool>& chanflag,
4398 : const Vector<Bool>& chanflag,
4399 : //const Vector<Bool>& /* zeroChanMask */,
4400 : const Matrix<Bool>& /* zeroChanMask */,
4401 : //const Vector<uInt>& nreg,
4402 : const Matrix<uInt>& nreg,
4403 : //const Vector<uInt>& npruned,
4404 : const Matrix<uInt>& npruned,
4405 : //const Vector<uInt>& ngrowreg,
4406 : const Matrix<uInt>& ngrowreg,
4407 : //const Vector<uInt>& ngrowpruned,
4408 : const Matrix<uInt>& ngrowpruned,
4409 : //const Vector<Float>& negmaskpixs,
4410 : const Matrix<Float>& negmaskpixs,
4411 : const Record& miscSummaryInfo)
4412 :
4413 : {
4414 8 : LogIO os( LogOrigin("SDMaskHandler","printAutomaskSummary",WHERE) );
4415 :
4416 : // miscSummaryInfo currently contains sidelobe level and pruneregionsize
4417 : // but these won't be printed out here now (these are printed out in the beginning).
4418 : // or alll the arguments maybe packed into record...
4419 : Float sidelobelevel;
4420 4 : miscSummaryInfo.get("sidelobelevel", sidelobelevel);
4421 : Float prunesize;
4422 4 : miscSummaryInfo.get("pruneregionsize", prunesize);
4423 :
4424 4 : os << LogIO::NORMAL <<"========== automask summary ==========" << LogIO::POST;
4425 : os << LogIO::NORMAL <<"chan masking? median RMS"<<" "
4426 : <<"peak thresh_type thresh_value "
4427 4 : <<"N_reg N_pruned N_grow N_grow_pruned N_neg_pix"<<LogIO::POST;
4428 :
4429 : //use maskthreshold shape to find npol and nchan. Maskthreshold(npol, nchan)
4430 4 : Int npol = maskthreshold.nrow();
4431 4 : Int nchan = maskthreshold.ncolumn();
4432 4 : os << LogIO::DEBUG1 << "npol="<<npol<< " nchan="<<nchan<<LogIO::POST;
4433 4 : IPosition statshp = rmss.shape();
4434 : // Note: stats record collapse the axis with 1
4435 4 : os<<LogIO::DEBUG1 <<"rmss shape="<< String::toString(statshp) <<LogIO::POST;
4436 : // For the historical reason it is called chanidx but it is an index for a single plane stats
4437 4 : IPosition chanidx = statshp;
4438 : //uInt ndim = rmss.ndim();
4439 :
4440 : //Int nchan = maskthreshold.nelements();
4441 12 : for (uInt ich = 0; ich < (uInt) nchan; ich++) {
4442 8 : if (chanidx.nelements()==1 ) {
4443 2 : chanidx(0) = ich;
4444 : }
4445 6 : else if(chanidx.nelements()==2) {
4446 : // to include stats in all stokes in a single line
4447 6 : chanidx(1) = ich;
4448 6 : chanidx(0) =0;
4449 : }
4450 8 : Vector<Double> peaks(npol);
4451 40 : for (uInt ipol = 0; ipol < (uInt) npol; ipol++) {
4452 : //Double peak = abs(maxs(chanidx))> abs( mins(chanidx))? maxs(chanidx): mins(chanidx);
4453 32 : if (npol!=1) {
4454 32 : chanidx(0) = ipol;
4455 : }
4456 32 : peaks(ipol) = abs(maxs(chanidx))> abs( mins(chanidx))? maxs(chanidx): mins(chanidx);
4457 : //os << LogIO::DEBUG1 << "chanidx="<<chanidx<< " peaks("<<ipol<<")="<<peaks(ipol)<<LogIO::POST;
4458 :
4459 : }
4460 8 : String peakStr = npol==1? String::toString(peaks(0)):String::toString(peaks);
4461 : // only tested for single pol (normally stokes I)
4462 8 : String domasking = chanflag(ich)==0? "T":"F";
4463 : //String domasking = zeroChanMask[ich]==1? "F":"T";
4464 8 : String mdnsStr, rmssStr, maskthresholdStr;
4465 8 : String Nreg, Npruned, Ngrowreg, NgrowPruned, Nnegpix;
4466 8 : String NAstr("--");
4467 :
4468 : //if masking is skipped median, rms, thresholdvalue are
4469 : //set to ---
4470 8 : if (domasking=="F") {
4471 0 : mdnsStr=NAstr;
4472 0 : rmssStr=NAstr;
4473 0 : maskthresholdStr=NAstr;
4474 : }
4475 : else {
4476 : //mdnsStr=String::toString(mdns(chanidx));
4477 : //rmssStr=String::toString(rmss(chanidx));
4478 : //maskthresholdStr=String::toString(maskthreshold[ich]);
4479 : //reset pol axis of chanidx
4480 8 : IPosition trc = chanidx;
4481 8 : if (npol > 1) {
4482 8 : chanidx(0)=0;
4483 8 : trc(0)=npol-1;
4484 : }
4485 :
4486 8 : os<<LogIO::DEBUG1<<" mdns.shape="<<mdns.shape()<<"chanidx="<<chanidx<<" trc="<<trc<<LogIO::POST;
4487 8 : if (chanidx.nelements()==1) {
4488 2 : if (nchan==1) {
4489 2 : mdnsStr=String::toString(mdns);
4490 2 : rmssStr=String::toString(rmss);
4491 : }
4492 : else {
4493 0 : mdnsStr=String::toString(mdns(chanidx));
4494 0 : rmssStr=String::toString(rmss(chanidx));
4495 : }
4496 : }
4497 : else {
4498 6 : Matrix<Double> mdnsChan=mdns(chanidx, trc);
4499 6 : Matrix<Double> rmssChan=rmss(chanidx, trc);
4500 : //mdnsStr=String::toString(mdns(chanidx,trc));
4501 : //rmssStr=String::toString(rmss(chanidx,trc));
4502 6 : mdnsStr=String::toString(mdnsChan.column(0));
4503 6 : rmssStr=String::toString(rmssChan.column(0));
4504 6 : }
4505 8 : Vector<Float> maskthreshvec = maskthreshold.column(ich);
4506 8 : if (maskthreshvec.nelements()==1) {
4507 0 : maskthresholdStr=String::toString(maskthreshvec(0));
4508 : }
4509 : else {
4510 8 : maskthresholdStr=String::toString(maskthreshvec);
4511 : }
4512 8 : }
4513 :
4514 8 : if (!nreg.nelements()) {
4515 0 : Nreg = NAstr;
4516 : }
4517 : else {
4518 : //Nreg = String::toString(nreg[ich]);
4519 8 : Vector<uInt> nregvec = nreg.column(ich);
4520 8 : if (nregvec.nelements()==1) {
4521 0 : Nreg = String::toString(nregvec(0));
4522 : }
4523 : else {
4524 8 : Nreg = String::toString(nregvec);
4525 : }
4526 8 : }
4527 8 : if (!npruned.nelements()) {
4528 0 : Npruned = NAstr;
4529 : }
4530 : else {
4531 : //Npruned = String::toString(npruned[ich]);
4532 8 : Vector<uInt> nprunedvec = npruned.column(ich);
4533 8 : if (nprunedvec.nelements()==1) {
4534 0 : Npruned = String::toString(nprunedvec(0));
4535 : }
4536 : else {
4537 8 : Npruned = String::toString(nprunedvec);
4538 : }
4539 8 : }
4540 8 : if (!ngrowreg.nelements()) {
4541 0 : Ngrowreg = NAstr;
4542 : }
4543 : else {
4544 : //Ngrowreg = String::toString(ngrowreg[ich]);
4545 8 : Vector<uInt> ngrowregvec = ngrowreg.column(ich);
4546 8 : if (ngrowregvec.nelements()==1) {
4547 0 : Ngrowreg = String::toString(ngrowregvec(0));
4548 : }
4549 : else {
4550 8 : Ngrowreg = String::toString(ngrowreg.column(ich));
4551 : }
4552 8 : }
4553 8 : if (!ngrowpruned.nelements()) {
4554 0 : NgrowPruned = NAstr;
4555 : }
4556 : else {
4557 : //NgrowPruned = String::toString(ngrowpruned[ich]);
4558 8 : Vector<uInt> ngrowprunedvec=ngrowpruned.column(ich);
4559 8 : if (ngrowprunedvec.nelements()==1) {
4560 0 : NgrowPruned = String::toString(ngrowprunedvec(0));
4561 : }
4562 : else {
4563 8 : NgrowPruned = String::toString(ngrowprunedvec);
4564 : }
4565 8 : }
4566 8 : if (!negmaskpixs.nelements()) {
4567 0 : Nnegpix = NAstr;
4568 : }
4569 : else {
4570 : //Nnegpix = String::toString(negmaskpixs[ich]);
4571 8 : Vector<Float> negmaskpixsvec=negmaskpixs.column(ich);
4572 8 : if (negmaskpixsvec.nelements()==1) {
4573 0 : Nnegpix = String::toString(negmaskpixsvec(0));
4574 : }
4575 : else {
4576 8 : Nnegpix = String::toString(negmaskpixsvec);
4577 : }
4578 8 : }
4579 8 : Vector<String> threshtypevec=thresholdtype.column(ich);
4580 8 : String threshtypeStr;
4581 8 : if (threshtypevec.nelements()==1) {
4582 0 : threshtypeStr=threshtypevec(0);
4583 : }
4584 : else {
4585 8 : threshtypeStr=String::toString(threshtypevec);
4586 : }
4587 :
4588 : os << LogIO::NORMAL << "[C" << ich << "] "
4589 : << domasking << " "
4590 : //<< mdns(chanidx) << " "
4591 : //<< rmss(chanidx) << " "
4592 : << mdnsStr << " "
4593 : << rmssStr << " "
4594 : << peakStr << " "
4595 : << threshtypeStr << " "
4596 : //<< maskthreshold[ich] << " "
4597 : << maskthresholdStr << " "
4598 : << Nreg << " "
4599 : << Npruned << " "
4600 : << Ngrowreg << " "
4601 : << NgrowPruned << " "
4602 : << Nnegpix
4603 8 : << LogIO::POST;
4604 8 : }
4605 4 : os << LogIO::NORMAL <<"========== END of automask summary ==========" << LogIO::POST;
4606 4 : }
4607 :
4608 143 : void SDMaskHandler::setPBMaskLevel (const Float pbmasklevel) {
4609 143 : itsPBMaskLevel = pbmasklevel;
4610 143 : }
4611 :
4612 0 : Float SDMaskHandler::getPBMaskLevel() {
4613 0 : return itsPBMaskLevel;
4614 : }
4615 :
4616 : } //# NAMESPACE CASA - END
|