################################################ # Task to make masks. # reorganized after diesuccsion on Oct1, 2012 # with Jeurgen and Urvashi # # modified by TT # based on the original code, # v1.0: 2012.03.20, U.Rau # ################################################ # Notes (to self) - TT # 1. expanding one mask to another # e.g.) expanding a continuum mask (both image mask/boolean mask) # channel mask # 2. part of copy mode func.: merging of different types of masks # e.g.) inpimage and inpmask are lists of the mask to be merged # output mask is written to either outimage or outmask as embedded # T/F mask # 3. copying mask to another or create a new one # regrid if necessary (i.e. if the coords are different) # ---------------------------------------------- # basic rules: # for mask image (1/0 mask): as it is # for internal mask : parent_imagename:mask_name # # For input, # inpimage is the casa image # - mode='list': list internal masks of inpimage # - other mode: used as a template for output # if region files are specified -> make mask specifeid with the regions on to inpimage # output is '' => modified inpimage unless overwrite=F else exception # # if inpmask='': use inpimage as input mask # if inpmask='mask0' or other embedded mask name of the inpimage, # use that T/F mask # # =expand= # case1: on the same image (outimage=''), expand mask image from # prev. run etc. No regriding. Use nearest chan mask # image to expand. # 1.a: inpimage is clean image mask (1s and 0s) # i) outimage != inpimage and outmask='' => new expanded mask image to outimage # ii) outimage != inpimage and outmask!='' => convert expanded mask image to T/F mask to store inside outimage # iii) outimage ==inpimage and outmask='' => update input mask image by expanding it # iv) outimage ==inpimage and outmask!=''=> update input image with the expanded T/F mask # 1.b: if inpmask!='', do T/F mask to 1/0 image mask conversion, then do as in 1.a # case2: outimage is in diffirent coords. (need to regrid) # ################# # tests # 1. for input: mask image # 2. for input: mask/or regular image with internal mask # 3. for input: mask image; for output: mask image with different spectral grid # 4. for input: mask/regular image with internal mask; for output: image with # internal mask with different spectral grid ################### from __future__ import absolute_import import os import shutil import numpy as np # get is_CASA6 and is_python3 from casatasks.private.casa_transition import * if is_CASA6: from casatools import image, regionmanager, imager, table, quanta from casatasks import casalog from .imtools import pixelmask2cleanmask else: from taskinit import * from recipes.pixelmask2cleanmask import pixelmask2cleanmask image = iatool regionmanager = rgtool quanta = qatool table = tbtool imager = imtool if is_python3: import subprocess subprocess_getoutput = subprocess.getoutput else: import commands subprocess_getoutput = commands.getoutput _ia = image() _rg = regionmanager() _qa = quanta() pid = str(os.getpid()) debug = False #debug = True def makemask(mode,inpimage, inpmask, output, overwrite, inpfreqs, outfreqs): """ make /manipulate masks """ _ia = image() _rg = regionmanager() _im = imager() casalog.origin('makemask') #casalog.post("params(mode,inpimage,inpmask,output,overwrite)=",mode,inpimage,inpmask,output,overwrite) try: # temp files tmp_maskimage='__tmp_makemaskimage_'+pid tmp_outmaskimage='__tmp_outmakemaskimage_'+pid tmp_regridim='__tmp_regridim_'+pid #intial cleanup to make sure nothing left from previous runs tmplist = [tmp_maskimage,tmp_outmaskimage,tmp_regridim] cleanuptempfiles(tmplist) # do parameter check first # check names of inpimage, inpmask check for existance # inpimage == output (exact match) then check overwrite # => T overwrite inpimage # => F exception # check inpimage if (['list','copy','expand'].count(mode)==1): if inpimage=='': raise ValueError("inpimage is empty") if not os.path.isdir(inpimage): raise RuntimeError("inpimage=%s does not exist" % inpimage) # === list mode === if mode == 'list': inpOK=checkinput(inpimage) if inpOK: if _ia.isopen(): _ia.close() _ia.open(inpimage) inmasklist=_ia.maskhandler('get') # now ia.maskhandler returns ['T'] if no internal mask is there... if inmasklist.count('T')!=0: inmasklist.remove('T') if len(inmasklist) ==0: casalog.post('No internal (T/F) masks were found in %s' % (inpimage),'INFO') else: defaultmaskname=_ia.maskhandler('default')[0] printinmasks='' for mname in inmasklist: if mname==defaultmaskname: printinmasks+='\''+mname+'\''+'(default)' else: printinmasks+='\''+mname+'\'' if mname != inmasklist[-1]: printinmasks+=', ' casalog.post('Internal (T/F) masks in %s: %s' % (inpimage, printinmasks),'INFO') _ia.close() # === setdefaultmask mode === elif mode == 'setdefaultmask': inpOK=checkinput(inpmask) if inpOK: (parentimage,bmask)=extractmaskname(inpmask) if bmask=='': raise RuntimeError("Missing an internal mask name") if _ia.isopen(): _ia.close() _ia.open(parentimage) defaultmaskname=_ia.maskhandler('default')[0] inmasklist=_ia.maskhandler('get') if defaultmaskname==bmask: casalog.post('No change. %s is already a default internal mask' % bmask, 'INFO') else: _ia.maskhandler('set',bmask) casalog.post('Set %s as a default internal mask' % bmask, 'INFO') if len(inmasklist)>1: casalog.post('Current internal masks are %s' % str(inmasklist), 'INFO') _ia.close() # === delete mode === elif mode == 'delete': inpOK=checkinput(inpmask) if inpOK: (parentimage,bmask)=extractmaskname(inpmask) if bmask=='': raise RuntimeError("Missing an internal mask name") _ia.open(parentimage) casalog.post('Deleting the internal mask, %s ' % bmask, 'INFO') defaultmaskname=_ia.maskhandler('default')[0] _ia.maskhandler('delete',bmask) inmasklist=_ia.maskhandler('get') if inmasklist.count('T')!=0: inmasklist.remove('T') if len(inmasklist) !=0 and defaultmaskname==bmask: _ia.maskhandler('set',inmasklist[0]) casalog.post('Set %s as a default internal mask' % inmasklist[0], 'INFO') if len(inmasklist)>1: casalog.post('Current internal masks are %s' % str(inmasklist), 'INFO') _ia.close() else: # PREPROCESS STAGE for mode='copy' and 'expand' #DEBUG #casalog.post("mode=",mode) # copy can have multiple input masks, expand has only one. # check inpimage, inpmask, output, overwrite # storeinmask = False # used to check if output to a new internal mask isNewOutfile = False inpOK=checkinput(inpimage) if inpOK: (immask,inmask)=extractmaskname(inpimage) # seperate text files(region files), images(with full ':'), and direct region # input mask(s) if inpmask=='': raise ValueError("Input errror. The inpmask parameter is not specified.") if type(inpmask)!=list: inpmask=[inpmask] # check if inpmask contains region file or region specification rgfiles=[] imgfiles=[] rglist=[] bmasks=[] for masklet in inpmask: # is text file? if type(masklet)==str: # text file or image if os.path.exists(masklet): # region file or image if (subprocess_getoutput('file '+masklet).count('directory')): if os.path.exists(masklet+'/table.f1'): #casalog.post("%s is not in a recognized format for inpmask, ignored." % masklet, 'WARN') raise ValueError("%s is not in a recognized format for inpmask" % masklet) else: # probably image file (with no mask extension) imgfiles.append(masklet) # text file (CRTF) elif (subprocess_getoutput('file '+masklet).count('text')): rgfiles.append(masklet) else: #casalog.post("%s does not recognized format for inpmask, ignored." % masklet, 'WARN') raise ValueError("%s is not in a recognized format for inpmask" % masklet) else: # direct string specification if masklet.count('[') and masklet.count(']'): # rough check on region specification rglist.append(masklet) # extract internal mask from the input image else: (parentim, mask)=extractmaskname(masklet) if mask!='': bmasks.append(masklet) else: raise ValueError("%s is not an existing file/image or a region format" % masklet) # expand allows only a string for inpmask if mode=='expand': if type(inpmask)==list: inpmask=inpmask[0] # check for overwrite condition if output=='': if overwrite: output=inpimage else: raise ValueError("output is not specified. If you want to overwrite inpimage, please set overwrite=True") if inpimage==output: #if overwrite: # tmp_outmaskimage=tmp_maskimage #else: if not overwrite: raise ValueError("output=inpimage. If you want to overwrite inpimage, please set overwrite=True") outparentim=output outbmask='' if os.path.isdir(output): if not overwrite: raise RuntimeError("output=%s exists. If you want to overwrite it, please set overwrite=True" % output) else: (outparentim, outbmask)=extractmaskname(output) if outbmask!='': (parentimexist,maskexist)=checkinmask(outparentim,outbmask) if parentimexist and maskexist: if not overwrite: raise ValueError("output=%s exists. If you want to overwrite it, please set overwrite=True" % output) else: casalog.post("Will overwrite the existing internal mask, %s in %s" % (outbmask,outparentim)) storeinmask=True #if parentimexist and not maskexist: else: storeinmask = True if not parentimexist: isNewOutfile=True else: outparentim=output #casalog.post("param checks before branching out for mode==========")) #casalog.post("storeinmask = ",storeinmask) #casalog.post("output=",output, " is exist?=",os.path.isdir(output)) #casalog.post("outparentim=",outparentim, " is exist?=",os.path.isdir(outparentim)) # MAIN PROCESS for 'copy' or 'expand' mode # the following code is somewhat duplicated among the modes but keep separated from each mode # for now.... copy now handle merge as well # === old copy mode === NOW combined to 'merge mode' # #if mode=='copy': # #casalog.post("Copy mode") # needregrid=True # #if outimage=='': # #overwrite # # outimage=inpimage # # if not os.path.isdir(outimage): # needregrid=False # # if inpmask!='': # # need to extract the mask and put in tmp_maskimage # pixelmask2cleanmask(imagename=inpimage, maskname=inpmask, maskimage=tmp_maskimage, usemasked=True) # else: # shutil.copytree(inpimage, tmp_maskimage) # if needregrid: # casalog.post("Regridding...",'DEBUG1') # regridmask(tmp_maskimage,outimage,tmp_outmaskimage) # # regrid may produce <1.0 pixels for mask so be sure to its all in 1.0 # #_ia.open(tmp_outmaskimage) # #_ia.calc('iif (%s>0.0 && %s<1.0,1,%s)'%(tmp_outmaskimage,tmp_outmaskimage,tmp_outmaskimage)) # #_ia.close() # #casalog.post("Copying regrid output=",tmp_outmaskimage) # else: # shutil.copytree(tmp_maskimage,tmp_outmaskimage) # if outmask!='': # #convert the image mask to T/F mask # if not os.path.isdir(outimage): # shutil.copytree(inpimage,outimage) # # # _ia.open(outimage) # casalog.post("convert the output image mask to T/F mask") # _ia.calcmask(mask='%s<0.5' % tmp_outmaskimage,name=outmask,asdefault=True) # _ia.done() # else: # # if regridded - tmp_outmaskimage is created by regridmask # # if not, tmp_outmaskimage=outimage # _ia.open(tmp_outmaskimage) # _ia.rename(outimage,overwrite=True) # _ia.done() # === expand mode === if mode=='expand': _rg = regionmanager() needtoregrid=False bychanindx=False try: # These coordsys objects will need to be closed, if created incsys = None inmaskcsys = None ocsys = None #casalog.post("expand mode main processing blocks...") # do not allow list in this mode (for inpimage and inpmask) - maybe this is redundant now if type(inpmask)==list: raise TypeError('A list for inpmask is not allowed for mode=expand') # input image info, actually this will be output coordinates _ia.open(inpimage) inshp = _ia.shape() incsys = _ia.coordsys() _ia.close() #casalog.post("inpimage=",inpimage," is exist?=",os.path.isdir(inpimage)) #casalog.post(" inshp for inpimage=",inshp) # prepare working input mask image (tmp_maskimage) if debug: casalog.post("prepare working input image (tmp_maskimage)...") if inpmask!='': # inpmask is either image mask or T/F mask now # need to extract the mask and put in tmp_maskimage # Note: changed usemasked=F, so that True (unmasked) part to be used. CAS- # ==> tmp_maskimage is an input mask image (parentimage,bmask)=extractmaskname(inpmask) if bmask!='': pixelmask2cleanmask(imagename=parentimage, maskname=bmask, maskimage=tmp_maskimage, usemasked=False) #_ia.open(tmp_maskimage) else: if debug: casalog.post("parentimage=" + parentimage + " exist?=" + os.path.isdir(parentimage)) casalog.post("tmp_maskimage=" + tmp_maskimage + " exist?=" + os.path.isdir(tmp_maskimage)) # copy of inpimage in tmp_maskimage _ia.fromimage(outfile=tmp_maskimage, infile=parentimage) else: raise ValueError("inpmask must be specified") if _ia.isopen(): _ia.close() #setting up the output image (copy from inpimage or template) if not os.path.isdir(outparentim): #shutil.copytree(inpimage,tmp_outmaskimage) _ia.fromshape(outfile=tmp_outmaskimage,shape=inshp, csys=incsys.torecord()) _ia.close() needtoregrid=False else: # if inpimage == output, tmp_outmaskimage is already created... if not os.path.isdir(tmp_outmaskimage): shutil.copytree(outparentim,tmp_outmaskimage) if debug: casalog.post("done setting up the out image=" + tmp_outmaskimage) # if inpfreq/outfreq are channel indices (int) then # regrid in x y coords only and extract specified channel mask # to specified output channels. (no regriding in spectral axis) # if inpfreqs/outfreqs are velocity or freqs, # it assumes it is expressed in the range with minval~maxval # create subimage of the input mask with the range, # do regrid with the subimage to output. # decide to regrid or not # 1. the case all channels are selected for input and output, simply regrid # 2. if inpfreqs and outfreqs are integers (= channel indices), regrid only in # first and second axes (e.g. ra,dec) and no regridding along spectral axis # 3. if inpfreqs and outfreqs are ranges in freq or vel, make subimage and regrid _ia.open(tmp_maskimage) inmaskshp = _ia.shape() inmaskcsys = _ia.coordsys() _ia.close() regridmethod = 'linear' if 'spectral2' in inmaskcsys.torecord(): inspecdelt = inmaskcsys.torecord()['spectral2']['wcs']['cdelt'] _ia.open(tmp_outmaskimage) ocsys=_ia.coordsys() oshp=_ia.shape() _ia.close() outspecdelt = ocsys.torecord()['spectral2']['wcs']['cdelt'] if outspecdelt < inspecdelt: regridmethod='nearest' if inmaskshp[3]!=1 and ((inpfreqs==[] and outfreqs==[]) \ or (inpfreqs=='' and outfreqs=='')): # unless inpimage is continuum, skip chan selection part and regrid needtoregrid=True # detach input(tmp) image and open output tmp image # _ia.open(tmp_outmaskimage) else: # if _ia.isopen(): # if _ia.name(strippath=True)!=tmp_maskimage: # _ia.close() # _ia.open(tmp_maskimage) # else: # _ia.open(tmp_maskimage) #if inshp[3]!=1: casalog.post("inpmask is continuum..","INFO") if inmaskshp[3]==1: casalog.post("inpmask is continuum..","INFO") # selection by channel indices (number) # if both inpfreqs and outfreqs are int skip regridding # if outfreqs is vel or freq ranges, try regridding if inpfreqs==[[]] or inpfreqs==[]: # select all channels for input inpfreqs=list(range(inmaskshp[3])) # check inpfreqs and outfreqs types # index based selmode='bychan' if type(inpfreqs)==list: if type(inpfreqs[0])==int: if type(outfreqs)==list and (len(outfreqs)==0 or type(outfreqs[0])==int): selmode='bychan' elif type(outfreqs)==str: #if inpfreqs[0]==0: #contintuum -allow index-type specification if len(inpfreqs)==1: #contintuum -allow index-type specification selmode='byvf' else: raise TypeError("Mixed types in infreqs and outfreqs are not allowed") else: raise TypeError("Non-integer in inpfreq is not supported") # by velocity or frequency elif type(inpfreqs)==str: if type(outfreqs)!=str: raise TypeError("Mixed types in infreqs and outfreqs") selmode='byvf' else: raise TypeError("Wrong type for infreqs") # inpfreqs and outfreqs are list of int # match literally without regridding. if selmode=='bychan': casalog.post("selection of input and output ranges by channel") if _ia.isopen(): _ia.close() if outfreqs==[] or outfreqs==[[]]: outchans=[] else: outchans=outfreqs expandchanmask(tmp_maskimage,inpfreqs,tmp_outmaskimage,outchans) _ia.open(tmp_outmaskimage) elif selmode=='byvf': # outfreqs are quantities (freq or vel) casalog.post("selection of input/output ranges by frequencies/velocities") # do it for input mask image (not the template ) inpfreqlist = translatefreqrange(inpfreqs,inmaskcsys) #casalog.post("inpfreqlist=",inpfreqlist) # close input image if _ia.isopen(): _ia.close() #regrid to output image coordinates if len(inpfreqlist)==1: # continuum #do not regrid, use input image shutil.copytree(tmp_maskimage,tmp_regridim) else: if debug: casalog.post("regrid the mask,tmp_maskimage=" + tmp_maskimage + " tmp_regridim=" + tmp_regridim) #shutil.copytree(tmp_maskimage,'before_regrid_tmp_maskimage') regridmask(tmp_maskimage,inpimage,tmp_regridim,chanrange=inpfreqlist,method=regridmethod) #regridmask(tmp_maskimage,inpimage,tmp_regridim,chanrange=inpfreqlist) # find edge masks (nonzero planes) ##shutil.copytree(tmp_regridim,'saved_'+tmp_regridim) if _ia.isopen(): _ia.close() _ia.open(tmp_regridim) sh=_ia.shape() chanlist = list(range(sh[3])) indlo=0 indhi=0 for i in chanlist: sl1=[0,0,0,i] sl2=[sh[0]-1,sh[1]-1,sh[2]-1,i] psum = _ia.getchunk(sl1,sl2).sum() pmsum = _ia.getchunk(sl1,sl2,getmask=True).sum() if pmsum!=0 and psum>0.0: indlo=i break chanlist.reverse() for i in chanlist: sl1=[0,0,0,i] sl2=[sh[0]-1,sh[1]-1,sh[2]-1,i] psum = _ia.getchunk(sl1,sl2).sum() if psum>0.0: indhi=i break if indhi < indlo: raise RuntimeError("Incorrectly finding edges of input masks! Probably some logic error in the code!!!") else: casalog.post("Determined non-zero channel range to be "+str(indlo)+"~"+str(indhi), 'DEBUG1') # find channel indices for given outfreqs #_ia.open(tmp_outmaskimage) #ocsys=_ia.coordsys() #oshp=_ia.shape() outfreqlist = translatefreqrange(outfreqs,ocsys) rtn=ocsys.findcoordinate('spectral') px=rtn['pixel'][0] wc=rtn['world'][0] world=ocsys.referencevalue() # assume chanrange are in freqs world['numeric'][wc]=_qa.convert(_qa.quantity(outfreqlist[0]),'Hz')['value'] p1 = ocsys.topixel(world)['numeric'][px] world['numeric'][wc]=_qa.convert(_qa.quantity(outfreqlist[1]),'Hz')['value'] p2 = ocsys.topixel(world)['numeric'][px] casalog.post("translated channel indices:"+_qa.tos(outfreqlist[0])+"->p1="+str(p1)+\ " "+_qa.tos(outfreqlist[0])+"-> p2="+str(p2)) if len(inpfreqs)==1: inpfreqchans=inpfreqs elif inpfreqs.find('~'): inpfreqchans=list(range(indlo,indhi+1)) else: inpfreqchans=[indlo,indhi] outfreqchans=list(range(int(round(p1)),int(round(p2))+1)) #casalog.post("inpfreqchans=",inpfreqchans) #casalog.post("outfreqchans=",outfreqchans) expandchanmask(tmp_regridim,inpfreqchans,tmp_outmaskimage,outfreqchans) #shutil.copytree(tmp_regridim,'my_tmp_regrid') #shutil.copytree(tmp_outmaskimage,'my_tmp_outmaskimage') # usechanims={} # list of input mask to be use for each outpfreq # for i in outfreqchans: # nearestch = findnearest(inpfreqchans,i) # usechanims[i]=nearestch # # put masks from inp image channel by channel # for j in outfreqs: # pix = refchanchunk[usechanims[j]-refchanst] # #_ia.putchunk(pixels=pix,blc=[inshp[0]-1,inshp[1]-1,0,j]) # _ia.putchunk(pixels=pix.transpose(),blc=[0,0,0,j]) needtoregrid=False if _ia.isopen(): _ia.close() _ia.open(tmp_outmaskimage) # if needtoregrid: # closing current output image if _ia.isopen(): _ia.close() _ia.open(tmp_maskimage) #os.system('cp -r %s beforeregrid.im' % tmp_maskimage) if os.path.isdir(tmp_outmaskimage): #casalog.post("Removing %s" % tmp_outmaskimage) shutil.rmtree(tmp_outmaskimage) #regridmask(tmp_maskimage,outparentim,tmp_outmaskimage) regridmask(tmp_maskimage,inpimage,tmp_outmaskimage,method=regridmethod) _ia.remove() #casalog.post("closing after regrid") _ia.open(tmp_outmaskimage) # reopen output tmp image # for debugging #os.system('cp -r '+outparentim+" expandmode-copy-"+outparentim) #os.system('cp -r '+tmp_outmaskimage+" expandmode-copy-"+tmp_outmaskimage) if outbmask!='': #convert the image mask to T/F mask casalog.post("Convert the image mask to T/F mask",'INFO') # regions will be masked if == 0.0 for a new outfile, if outfile exists # the pixel values inside specified mask is preserved and the rest is masked if os.path.isdir(outparentim): _ia.calcmask(mask='%s==1.0' % tmp_outmaskimage,name=outbmask,asdefault=True) else: _ia.calcmask(mask='%s!=0.0' % tmp_outmaskimage,name=outbmask,asdefault=True) if storeinmask: isNewFile=False if not os.path.isdir(outparentim): makeEmptyimage(inpimage,outparentim) isNewFile=True _ia.open(outparentim) if isNewFile: _ia.set(1) # if output image exist its image pixel values will not be normalized the region # outside input mask will be masked. #check curinmasks = _ia.maskhandler('get') if outbmask in curinmasks: if not overwrite: raise RuntimeError("Internal mask,"+outbmask+" exists. Please set overwrite=True.") else: _ia.maskhandler('delete',outbmask) _ia.maskhandler('copy',[tmp_outmaskimage+':'+outbmask, outbmask]) _ia.maskhandler('set',outbmask) _ia.done() casalog.post("Output the mask to %s in %s" % (outbmask,outparentim) ,"INFO") else: ow = False if inpimage==output: casalog.post("Updating "+output+" with new mask","INFO") ow=True else: if os.path.isdir(outparentim): casalog.post(outparentim+" exists, overwriting","INFO") ow=True else: casalog.post("Output the mask to "+outparentim ,"INFO") _ia.rename(outparentim,ow) _ia.done() except Exception as instance: casalog.post("*** Error (1) *** %s" % instance, 'ERROR') if _ia.isopen(): _ia.close() _ia.done() raise finally: if inmaskcsys: inmaskcsys.done() if incsys: incsys.done() if ocsys: ocsys.done() if os.path.exists(tmp_maskimage): shutil.rmtree(tmp_maskimage) if os.path.exists(tmp_regridim): shutil.rmtree(tmp_regridim) if os.path.exists(tmp_outmaskimage): shutil.rmtree(tmp_outmaskimage) # === main process for copy mode: also does merge of masks === # copy is a just special case of merge mode # CHANGE: # all input masks should be specified in inpmask # type of inpmask accepted: 1/0 mask, T/F mask, region file, and region expression in a string # already stored internally in seperate lists # rgfiles - region files (binary or CRTF-format text file) # imgfiles - 1/0 image masks # rglist - region expression in strings # bmasks - T/F internal masks # # avaialble parameters: inpimage (string) , inpmask (list/string), output(string) # input inpimage as a template or image used for defining regions when it is given in inpmask # inpmask as list of all the masks to be merged (image masks, T/F internal masks, regions) if mode=='copy': sum_tmp_outfile='__tmp_outputmask_'+pid tmp_inmask='__tmp_frominmask_'+pid tmp_allrgmaskim='__tmp_fromAllRgn_'+pid tmp_rgmaskim='__tmp_fromRgn_'+pid # making sure to remove pre-existing temp files cleanuptempfiles([sum_tmp_outfile, tmp_inmask, tmp_allrgmaskim, tmp_rgmaskim]) usedimfiles=[] usedbmasks=[] usedrgfiles=[] usedrglist=[] # This coordsys object used in several places below will need to be closed, if created tcsys = None try: # check outparentim - image part of output and set as a template image if not (os.path.isdir(outparentim) or (outparentim==inpimage)): # Output is either a new image or the same as inpimage # figure out which input mask to be used as template # if inpimage is defined use the first one else try the first one # inpmask #if output=='': # if type(inpimage)==list: # raise Exception, "inputimage must be a string" # elif type(inpimage)==str: # outimage=inpimage # casalog.post("No outimage is specified. Will overwrite input image: "+outimage,'INFO') #if type(inpimage)==list and len(inpimage)!=0: # tmp_template=inpimage[0] #elif inpimage!='' and inpimage!=[]: # tmp_template=inpimage # string #tmp_template=inpimage # string #else: # if type(inpmask)==list and len(inpmask)!=0: # fsep=inpmask[0].rfind(':') # if fsep ==-1: # raise IOError, "Cannot resolve inpmask name, check the format" # else: # tmp_template=inpmask[0][:inpmask[0].rfind(':')] # elif inpmask!='' and inpmask!=[]: # # this is equivalent to 'copy' the inpmask # tmp_template=inpmask #string # create an empty image with the coords from inpimage makeEmptyimage(inpimage,sum_tmp_outfile) #casalog.post("making an empty image from inpimage to sum_tmp_outfile") else: #use output image(either the same as the input image or other existing image) # - does not do zeroeing out, so output image is only modified *for outbmask!=''* shutil.copytree(outparentim,sum_tmp_outfile) # temporary clear out the internal masks from the working image if _ia.isopen(): _ia.close() _ia.open(sum_tmp_outfile) if (len(imgfiles) or len(rglist) or len(rgfiles)): # do zeroeing out working base image for masks _ia.set(0) origmasks = _ia.maskhandler('get') _ia.maskhandler('delete',origmasks) _ia.close() if len(imgfiles)>0: # summing all the images casalog.post('Summing all mask images in inpmask and normalized to 1 for mask','INFO') for img in imgfiles: #tmpregrid='__tmp_regrid.'+img dirname = os.path.dirname(img) basename = os.path.basename(img) tmpregrid= dirname+'/'+'__tmp_regrid.'+basename if len(dirname) else '__tmp_regrid.'+basename tmpregrid+='_'+pid if os.path.exists(tmpregrid): shutil.rmtree(tmpregrid) # regrid to output image coords try: regridmask(img,sum_tmp_outfile,tmpregrid) addimagemask(sum_tmp_outfile,tmpregrid) usedimfiles.append(img) finally: shutil.rmtree(tmpregrid) # get boolean masks # will work in image(1/0) masks if debug: casalog.post(("imgfiles=" + imgfiles)) shutil.copytree(sum_tmp_outfile,sum_tmp_outfile+"_imagemaskCombined") if len(bmasks)>0: casalog.post('Summing all T/F mask in inpmask and normalized to 1 for mask','INFO') for msk in bmasks: (imname,mskname) = extractmaskname(msk) #if msk.find(':')<0: # # assume default mask # msk=msk+':mask0' #imname=msk[:msk.rfind(':')] if _ia.isopen(): _ia.close() _ia.open(imname) inmasks=_ia.maskhandler('get') _ia.close() if not inmasks.count(mskname): raise TypeError(mskname+" does not exist in "+imname+" -available masks:"+str(inmasks)) # move T/F mask to image mask # changed to usemasked=False as of CAS-5443 pixelmask2cleanmask(imname, mskname, tmp_inmask, False) cleanuptempfiles(['__tmp_fromTFmask_'+pid]) regridmask(tmp_inmask,sum_tmp_outfile,'__tmp_fromTFmask_'+pid) # for T/F mask do AND operation _ia.open(sum_tmp_outfile) if _ia.statistics()['sum'][0] != 0: multiplyimagemask(sum_tmp_outfile,'__tmp_fromTFmask_'+pid) else: addimagemask(sum_tmp_outfile,'__tmp_fromTFmask_'+pid) _ia.close() usedbmasks.append(msk) # need this temp file for the process later ###shutil.rmtree('__tmp_fromTFmask') if os.path.isdir(tmp_inmask): shutil.rmtree(tmp_inmask) # if overwriting to inpimage and if not writing to in-mask, delete the boolean mask if outparentim==inpimage and inpimage==imname: if outbmask=="": _ia.open(imname) _ia.maskhandler('delete',[mskname]) _ia.close() _ia.open(imname) _ia.close() if debug: casalog.post("check rgfiles and rglist") if len(rgfiles)>0 or len(rglist)>0: # create an empty image with input image coords. #casalog.post("Using %s as a template for regions" % inpimage ) if _ia.isopen(): _ia.close() _ia.open(inpimage) tshp=_ia.shape() tcsys=_ia.coordsys() _ia.fromshape(tmp_allrgmaskim,shape=tshp, csys=tcsys.torecord(),overwrite=True) _ia.done() if os.path.isdir(tmp_rgmaskim): shutil.rmtree(tmp_rgmaskim) shutil.copytree(tmp_allrgmaskim,tmp_rgmaskim) if len(rgfiles)>0: # Here only CRTF format file is expected nrgn=0 for rgn in rgfiles: subnrgn=0 with open(rgn) as f: # check if it has '#CRTF' in the first line firstline=f.readline() if firstline.count('#CRTF')==0: raise Exception("Input text file does not seems to be in a correct format \ (must contains #CRTF in the first line)") else: try: # reset temp mask image if _ia.isopen(): _ia.close() _ia.open(tmp_rgmaskim) _ia.set(pixels=0.0) _ia.close() #casalog.post... "tshp=",tshp #casalog.post... "tcsys.torecord=",tcsys.torecord() inrgn=_rg.fromtextfile(rgn, tshp, tcsys.torecord()) #casalog.post... "inrgn=",inrgn _im.regiontoimagemask(tmp_rgmaskim,region=inrgn) addimagemask(tmp_allrgmaskim,tmp_rgmaskim) #shutil.rmtree(tmp_rgmaskim) subnrgn +=1 nrgn +=1 except: break if subnrgn>0: usedrgfiles.append(rgn) casalog.post("Converted %s regions from %s region files to image mask" % (nrgn,len(rgfiles)),"INFO") if debug: casalog.post("processing rglist...") if len(rglist)>0: #casalog.post( "Has rglist...") nrgn=0 for rgn in rglist: # reset temp mask image if _ia.isopen(): _ia.close() _ia.open(tmp_rgmaskim) _ia.set(pixels=0.0) _ia.close() inrgn=_rg.fromtext(rgn, tshp, tcsys.torecord()) _im.regiontoimagemask(tmp_rgmaskim,region=inrgn) addimagemask(tmp_allrgmaskim,tmp_rgmaskim) #shutil.rmtree(tmp_rgmaskim) usedrglist.append(rgn) nrgn+=1 casalog.post("Converted %s regions to image mask" % (nrgn),"INFO") if debug: casalog.post("Regirdding...") # regrid if necessary regridded_mask='__tmp_regrid_allrgnmask_'+pid regridmask(tmp_allrgmaskim, sum_tmp_outfile,regridded_mask) addimagemask(sum_tmp_outfile,regridded_mask) #shutil.rmtree('__tmp_regridded_allrgnmask') casalog.post("Added mask based on regions to output mask","INFO") #cleanup for tmpfile in [tmp_allrgmaskim,tmp_rgmaskim,regridded_mask]: if os.path.isdir(tmpfile): shutil.rmtree(tmpfile) # merge the bmasks with AND if os.path.exists('__tmp_fromTFmask_'+pid) and len(bmasks)>0: if _ia.isopen(): _ia.close() _ia.open(sum_tmp_outfile) if _ia.statistics()['sum'][0]!=0: multiplyimagemask(sum_tmp_outfile,'__tmp_fromTFmask_'+pid) else: addimagemask(sum_tmp_outfile,'__tmp_fromTFmask_'+pid) _ia.done() shutil.rmtree('__tmp_fromTFmask_'+pid) if outbmask!='': casalog.post('Putting mask in T/F','INFO') if _ia.isopen(): _ia.close() try: _ia.open(sum_tmp_outfile) _ia.calcmask(mask='%s==1.0' % sum_tmp_outfile,name=outbmask,asdefault=True) # mask only pixel == 0.0 (for a new outfile), mask region !=1.0 and preserve # the pixel values if outfile exists #if os.path.isdir(outparentim): # _ia.calcmask(mask='%s==1.0' % sum_tmp_outfile,name=outbmask,asdefault=True) #else: # _ia.calcmask(mask='%s!=0.0' % sum_tmp_outfile,name=outbmask,asdefault=True) finally: _ia.done() if debug: shutil.copytree(sum_tmp_outfile,sum_tmp_outfile+"_afterCoverttoTFmask") # if outfile exists initially outfile is copied to sum_tmp_outfile # if outfile does not exist initially sum_tmp_outfile is a copy of inpimage # so rename it with overwrite=T all the cases #casalog.post("open sum_tmp_outfile=",sum_tmp_outfile) if storeinmask: if debug: casalog.post("Storeinmask......") # by a request in CAS-6912 no setting of 1 for copying mask to the 'in-mask' # (i.e. copy the values of inpimage as well for this mode) # Replace #isNewfile = False #if not os.path.isdir(outparentim): if isNewOutfile: #makeEmptyimage(inpimage,outparentim) #isNewfile=True shutil.copytree(inpimage,outparentim) if _ia.isopen(): _ia.close() _ia.open(outparentim) if isNewOutfile: oldmasklist = _ia.maskhandler('get') if oldmasklist[0]!='T': # clean up existing internal masks for the copied image if outbmask in oldmasklist: _ia.maskhandler('delete',outbmask) if (maskexist and overwrite): if debug: casalog.post("outbmask=" + outbmask + " exists... deleting it") _ia.maskhandler('delete',outbmask) _ia.maskhandler('copy',[sum_tmp_outfile+':'+outbmask, outbmask]) _ia.maskhandler('set',outbmask) _ia.done() outputmsg="to create an output mask: %s in %s" % (outbmask,outparentim) else: if debug: casalog.post("store as an image mask......") if _ia.isopen(): _ia.close() _ia.open(sum_tmp_outfile) _ia.rename(outparentim,overwrite=True) _ia.done() outputmsg="to create an output mask: %s " % outparentim casalog.post("Merged masks from:","INFO") if len(usedimfiles)>0: casalog.post("mask image(s): "+str(usedimfiles),"INFO") if len(usedbmasks)>0: casalog.post("internal mask(s): "+str(usedbmasks),"INFO") if len(usedrgfiles)>0: casalog.post("region txt file(s): "+str(usedrgfiles),"INFO") if len(usedrglist)>0: casalog.post("region(s) from direct input: "+str(usedrglist),"INFO") casalog.post(outputmsg,"INFO") except Exception as instance: raise RuntimeError("*** Error (2), in mode copy: *** %s" % instance) finally: if os.path.exists(sum_tmp_outfile): shutil.rmtree(sum_tmp_outfile) if os.path.exists(tmp_inmask): shutil.rmtree(tmp_inmask) if os.path.exists(tmp_allrgmaskim): shutil.rmtree(tmp_allrgmaskim) if os.path.exists(tmp_rgmaskim): shutil.rmtree(tmp_rgmaskim) if tcsys: tcsys.done() if type(inpimage)==list: for im in inpimage: basename = os.path.basename(im) dirname = os.path.dirname(im) tempregridname = dirname+'/__tmp_regrid.'+basename if len(dirname) else '__tmp_regrid.'+basename tempregridname+='_'+pid if os.path.isdir(tempregridname): shutil.rmtree(tempregridname) # === draw mode === # disabled - drawmaskinimage (working with viewer) a bit flaky # when run in succession. # if mode=='draw': # #call drawmaskinimage # from recipes.drawmaskinimage import drawmaskinimage # drawmaskinimage(inpimage,outmask) finally: # final clean up if os.path.isdir(tmp_maskimage): shutil.rmtree(tmp_maskimage) if os.path.isdir(tmp_outmaskimage): shutil.rmtree(tmp_outmaskimage) if os.path.isdir(tmp_regridim): shutil.rmtree(tmp_regridim) if os.path.exists('__tmp_fromTFmask_'+pid): shutil.rmtree('__tmp_fromTFmask_'+pid) def findnearest(arr, val): if type(arr)==list: arr = np.array(arr) indx = np.abs(arr - val).argmin() return arr[indx] def regridmask(inputmask,template,outputmask,axes=[3,0,1],method='linear',chanrange=None): ''' Regrid input mask (image) to output mask using a template. Currently the template must be a CASA image. The default interpolation method is set to 'linear' (since 'nearest' sometime fails). ''' #casalog.post("Regrid..") #casalog.post("inputmask=",inputmask," template=",template," outputmask=",outputmask) if not os.path.isdir(template): raise OSError("template image %s does not exist" % template) _ia = image() try: _tb = table() inputmaskcopy = "_tmp_copy_"+os.path.basename(inputmask) cleanuptempfiles([inputmaskcopy]) shutil.copytree(inputmask,inputmaskcopy) _ia.open(template) ocsys = _ia.coordsys() oshp = _ia.shape() finally: _ia.done() _tb.open(template) defTelescope = _tb.getkeywords()['coords']['telescope'] _tb.close() _tb.open(inputmaskcopy, nomodify=False) keys = _tb.getkeywords() if keys['coords']['telescope']=="UNKNOWN": if defTelescope =="UNKNOWN": raise ValueError("UNKNOWN Telescope for %s " % inputmask) else: keys['coords']['telescope']=defTelescope _tb.putkeywords(keys) _tb.close() if _ia.isopen(): _ia.close() _ia.open(inputmaskcopy) # check axis order, if necessary re-interprete input axes correctly # assumed order of axes reforder=['Right Ascension', 'Declination', 'Stokes', 'Frequency'] axisorder=_ia.summary(list=False)['axisnames'].tolist() # check if all 4 axes exist errmsg = "" for axname in reforder: if axisorder.count(axname) == 0: errmsg += axname+" " if len(errmsg) != 0: errmsg = "There is no "+errmsg+" axes inpimage. ia.adddegaxis or importfits with defaultaxes=True can solve this problem" raise Exception(errmsg) tmp_axes=[] for axi in axes: tmp_axes.append(axisorder.index(reforder[axi])) axes=tmp_axes if type(chanrange)==list and len(chanrange)==2: incsys=_ia.coordsys() spaxis=incsys.findcoordinate('spectral')['world'] # create subimage based on the inpfreqs range inblc=chanrange[0] intrc=chanrange[1] casalog.post("Regridmask: spaxis=%s, inblc=%s, intrc=%s" % (spaxis,inblc,intrc), 'DEBUG1') rgn = _rg.wbox(blc=inblc,trc=intrc,pixelaxes=spaxis.tolist(),csys=incsys.torecord()) incsys.done() else: rgn={} # for continuum case ir = None if oshp[tmp_axes[0]]==1: axes=[0,1] try: #check for an appropriate decimation factor min_axlen=min(oshp[:2]) if min_axlen < 30: decfactor=min_axlen//3 if decfactor==0: decfactor=1 else: decfactor=10 ir=_ia.regrid(outfile=outputmask,shape=oshp,csys=ocsys.torecord(),axes=axes,region=rgn,method=method,decimate=decfactor) except: pass finally: ocsys.done() _ia.remove() _ia.done() # to ensure to create 1/0 mask image #ir.calc('iif (%s>0.0 && %s<1.0,1,%s)'%(outputmask,outputmask,outputmask)) # treat everything not = 0.0 to be mask if (ir): try: ir.calc('iif (abs("%s")>0.0,1,"%s")'%(outputmask,outputmask),False) finally: ir.done() if os.path.isdir(inputmaskcopy): shutil.rmtree(inputmaskcopy) def addimagemask(sumimage, imagetoadd, threshold=0.0): """ add image masks (assumed the images are already in the same coordinates) """ _ia = image() try: #casalog.post("addimagemask: sumimage=",sumimage," imagetoadd=",imagetoadd) _ia.open(sumimage) _ia.calc('iif ("'+imagetoadd+'">'+str(threshold)+',("'+sumimage+'"+"'+imagetoadd+'")/("'+sumimage+'"+"'+imagetoadd+'"),"'+sumimage+'")',False) # actually should be AND? #_ia.calc('iif ('+imagetoadd+'>'+str(threshold)+','+sumimage+'*'+imagetoadd+','+sumimage+')') #_ia.calc('iif ('+imagetoadd+'>'+str(threshold)+',('+sumimage+'*'+imagetoadd+')/('+sumimage+'*'+imagetoadd+'),'+sumimage+')') finally: _ia.close() def multiplyimagemask(sumimage, imagetomerge): """ multiple image masks (do AND operation, assumed the images are already in the same coordinates) to use for merging of two image masks originated from T/F masks or merging between mask image and a T/F mask originated mask image """ _ia = image() try: _ia.open(sumimage) _ia.calc('iif ("'+imagetomerge+'"!=0.0,("'+sumimage+'"*"'+imagetomerge+'"),0.0 )',False) _ia.calc('iif ("'+sumimage+'"!=0.0,("'+sumimage+'")/("'+sumimage+'"),"'+sumimage+'")',False) finally: _ia.close() def expandchanmask(inimage,inchans,outimage,outchans): """ expand masks in channel direction,and insert then to output image with the same coordinates (post-regridded) only differ by channels """ _ia = image() # input image _ia.open(inimage) inshp=_ia.shape() refchanst=inchans[0] refchanen=inchans[-1] #casalog.post("refchanst=",refchanst," refchanen=",refchanen," inshp=",inshp," inchans=",inchans) slst = [0,0,0,refchanst] slen = [inshp[0]-1,inshp[1]-1,0,refchanen] casalog.post("getting chunk at blc="+str(slst)+" trc="+str(slen),'DEBUG1') refchanchunk=_ia.getchunk(blc=slst,trc=slen) refchanchunk=refchanchunk.transpose() _ia.close() #casalog.post("refchanchunk:shape=",refchanchunk.shape) _ia.open(outimage) # need find nearest inchan # store by chan indices (no regrid) outshp=_ia.shape() if outchans==[]: #select all channels outchans=list(range(outshp[3])) usechanims={} # list of input mask to be use for each outpfreq for i in outchans: nearestch = findnearest(inchans,i) usechanims[i]=nearestch #casalog.post("usechanims=",usechanims) casalog.post("Mapping of channels: usechanims="+str(usechanims),'DEBUG1') for j in outchans: pix = refchanchunk[usechanims[j]-refchanst] #casalog.post("pix=",pix) #casalog.post("pix.shape=",pix.shape) #casalog.post("inshp=",inshp, ' j=',j) #_ia.putchunk(pixels=pix,blc=[inshp[0]-1,inshp[1]-1,0,j]) _ia.putchunk(pixels=pix.transpose(),blc=[0,0,0,j]) #casalog.post("DONE putchunk for j=", j) _ia.done() def translatefreqrange(freqrange,csys): """ convert the range in list mainly for frequeny and velocity range determination """ if type(freqrange)==list and type(freqrange[0])==int: #do nothing return freqrange elif type(freqrange)==str: freqlist=freqrange.split('~') for i in list(range(len(freqlist))): if freqlist[i].find('m/s') > -1: fq = _qa.quantity(freqlist[i]) vf=csys.velocitytofrequency(value=fq['value'],velunit=fq['unit']) freqlist[i]=str(vf[0])+'Hz' return freqlist else: raise TypeError("Cannot understand frequency range") def checkinput(inpname): """ do existance check on image and internal mask """ _ia = image() (parentimage,tfmaskname)=extractmaskname(inpname) (parentimexist,tfmaskexist)=checkinmask(parentimage,tfmaskname) if parentimexist: if tfmaskname=='': return True # only the image else: if not tfmaskexist: _ia.open(parentimage) inmasklist=_ia.maskhandler('get') _ia.close() raise Exception("Cannot find the internal mask, %s. Candidate mask(s) are %s" % (tfmaskname, str(inmasklist))) else: return True # image mask and internal mask else: raise Exception("Cannot find the image=%s" % parentimage) def checkinmask(parentimage,tfmaskname): """ check existance of the internal mask """ _ia = image() if os.path.isdir(parentimage): if tfmaskname!='': _ia.open(parentimage) inmasks=_ia.maskhandler('get') _ia.done() if not any(tfmaskname in msk for msk in inmasks): return (True, False) else: return (True, True) # image mask and internal mask else: return (True, False) else: return (False,False) def extractmaskname(maskname): """ split out imagename and maskname from a maskname string returns (parentimage, internalmask) """ # the image file name may contains ':' some cases # take last one in split list as an internal mask name # Try to avoid issues with ':' included in paths when given absolute paths dirname = None if os.path.isabs(maskname): dirname = os.path.dirname(maskname) maskname = os.path.basename(maskname) indx = maskname.find(':') for i in list(range(len(maskname))): if indx>-1: indx += maskname[indx+1:].find(':') indx +=1 else: break if indx != -1: parentimage = maskname[:indx] maskn = maskname[indx+1:] else: parentimage = maskname maskn = '' if dirname: parentimage = os.path.join(dirname, parentimage) return (parentimage, maskn) def makeEmptyimage(template,outimage): """ make an empty image with the coords from template """ _ia = image() _ia.open(template) inshp=_ia.shape() incsys=_ia.coordsys() _ia.fromshape(outimage,shape=inshp,csys=incsys.torecord()) incsys.done() _ia.done() def cleanuptempfiles(tempfilelist): """ clean up tempfilelist """ for fn in tempfilelist: if os.path.isdir(fn): shutil.rmtree(fn) elif os.path.isfile(fn): os.remove(fn)