casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables
task_boxit.py
Go to the documentation of this file.
00001 from taskinit import *
00002 import numpy
00003 import sys
00004 import re
00005 
00006 # Writes out regions above threshold to regionfile+'.box'
00007 
00008 def boxit(imagename, regionfile, threshold, maskname, chanrange, polrange, minsize, diag, boxstretch, overwrite):
00009 
00010     casalog.origin('boxit')
00011 
00012     if not(regionfile):
00013         regionfile = imagename + '.box'
00014     if not regionfile.endswith('.box'):
00015         regionfile = regionfile + '.box'
00016 
00017     if not(overwrite):
00018         if(os.path.exists(regionfile)):
00019             casalog.post('file "' + regionfile + '" already exists.', 'WARN')
00020             return
00021         if(maskname and os.path.exists(maskname)):
00022             casalog.post('output mask "' + maskname + '" already exists.', 'WARN')
00023             return
00024 
00025     # If no units, assume mJy for consistency with auto/clean tasks.
00026     # But convert to Jy, because that's what units the images are in.
00027     threshold = qa.getvalue(qa.convert(qa.quantity(threshold,'mJy'),'Jy'))[0]
00028     casalog.post("Setting threshold to " + str(threshold) + "Jy", "INFO")
00029 
00030     newIsland = numpy.zeros(1, dtype=[('box','4i4'),('npix','i4')])
00031     # Find all pixels above the threshold
00032     ia.open(imagename)
00033     # CAS-2059 escape characters in image name that will confuse the lattice expression processor
00034     escaped_imagename = imagename
00035     for escapeme in ['-', '+', '*', '/' ]:
00036         escaped_imagename = re.sub("[" + escapeme + "]", "\\" + escapeme, escaped_imagename)         
00037     mask = escaped_imagename+'>'+str(threshold)
00038     fullmask = ia.getregion(mask=mask, getmask=True)
00039     if not(fullmask.max()):
00040         casalog.post('Maximum flux in image is below threshold.', 'WARN')
00041         return
00042     writemask = bool(maskname)
00043     csys = ia.coordsys()
00044 
00045     shape = fullmask.shape
00046 
00047     nx = int(shape[0])
00048     ny = int(shape[1])
00049     n2 = n3 = 1
00050     if len(shape)==3:
00051         n2 = int(shape[2])
00052     if len(shape)==4:
00053         n2 = int(shape[2])
00054         n3 = int(shape[3])
00055     #print 'nx:', nx, 'ny:', ny, 'n2:', n2, 'n3:', n3
00056 
00057     #casa generated images always 4d and in order of [ra, dec, stokes, freq]
00058     #other images can be in the order of [ra, dec, freq, stokes]
00059     nms = csys.names()
00060     #axes=[]
00061     #for i in xrange(len(nms)):
00062     #   if nms[i]=='Right Ascension':
00063     #      axes[0]=i
00064     #   if nms[i]=='Declination':
00065     #      axes[1]=i
00066     #   if nms[i]=='Stokes'
00067     #      axes[2]=i
00068     #   if nms[i]=='Frequency':
00069     #      axes[3]=i
00070 
00071     chmax=n3
00072     pomax=n2
00073     chmin=0
00074     pomin=0
00075     if len(nms)==4 and nms[3]=='Stokes':
00076        chmax=n2
00077        pomax=n3
00078 
00079     if chanrange:
00080        try:
00081           if str.count(chanrange, '~') == 1:
00082              ch1=int(str.split(chanrange, '~')[0])
00083              ch2=int(str.split(chanrange, '~')[1])
00084           else:
00085              ch1=int(chanrange)
00086              ch2=ch1
00087           if ch1 > ch2 or ch1 < 0 or ch2 > chmax:
00088              casalog('invalid channel range', "SEVERE")
00089              return
00090           if ch1>chmin:
00091              chmin = ch1
00092           if ch2<chmax:
00093              chmax = ch2
00094        except:
00095           casalog('bad format for chanrange', "SEVERE")
00096           return
00097     #print 'chmin', chmin, 'chmax', chmax
00098           
00099     if polrange:
00100        try:
00101           if str.count(polrange, '~') == 1:
00102              po1=int(str.split(polrange, '~')[0])
00103              po2=int(str.split(polrange, '~')[1])
00104           else:
00105              po1=int(polrange)
00106              po2=po1
00107           if po1 > po2 or po1 < 0 or po2 > pomax:
00108              casalog( 'invalid stokes range', "SEVERE")
00109              return
00110           if po1>pomin:
00111              pomin = po1
00112           if po2<pomax:
00113              pomax = po2
00114        except:
00115           casalog( 'bad format for polrange', "SEVERE")
00116           return
00117     #print 'pomin', pomin, 'pomax', pomax
00118           
00119     n1=pomin
00120     n2=pomax
00121     n3=chmax
00122     n4=chmin
00123     if len(nms)==4 and nms[3]=='Stokes':
00124        n1=chmin
00125        n2=chmax
00126        n3=pomax
00127        n4=pomin
00128     #print 'n1:', n1, 'n2:', n2, 'n4:', n4, 'n3:', n3
00129     
00130     f = open(regionfile, 'w')
00131     totregions = 0
00132     outputmask = []
00133     if writemask:
00134         outputmask = ia.getchunk()
00135         outputmask.fill(False)
00136 
00137     for i3 in xrange(n4, n3):
00138         for i2 in xrange(n1, n2):
00139             regions = {}
00140             boxRecord = {}
00141             if len(shape)==2:
00142                 mask = fullmask
00143             if len(shape)==4:
00144                 mask = fullmask[:,:,i2,i3].reshape(nx, ny)
00145             islands = []
00146             pos = numpy.unravel_index(mask.argmax(), mask.shape)
00147             #print pos
00148             while(mask[pos]):
00149                 # found pixel in new island
00150                 island = {}
00151                 island['box'] = [pos[0], pos[1], pos[0], pos[1]]
00152                 island['npix'] = 1
00153                 find_nearby_island_pixels(island, mask, pos, shape[0], shape[1], diag)
00154                 islands.append(island)
00155                 pos = numpy.unravel_index(mask.argmax(), mask.shape)
00156             for record in islands:
00157                 box = record['box']
00158                 # check size of box
00159                 if record['npix'] < minsize:
00160                     continue
00161                 totregions += 1
00162                 # need pixel corners, not pixel centers
00163                 box[0] -= boxstretch
00164                 box[1] -= boxstretch
00165                 box[2] += boxstretch
00166                 box[3] += boxstretch
00167                 # in case we used boxstretch < 0 and a one-pixel sized box:
00168                 if box[0] > box[2]:
00169                     box[0] += boxstretch
00170                     box[2] -= boxstretch
00171                 if box[1] > box[3]:
00172                     box[1] += boxstretch
00173                     box[3] -= boxstretch
00174                 if writemask:
00175                     # avoid pixels in boxes that have been stretched beyond the image limits
00176                     for ii in range(max(0, box[0]), min(box[2], outputmask.shape[0] - 1)):
00177                         for jj in range(max(0, box[1]), min(box[3], outputmask.shape[1] - 1)):
00178                             outputmask[ii][jj][i2][i3] = True
00179                 blccoord = [box[0]-0.5, box[1]-0.5, i2, i3]
00180                 trccoord = [box[2]+0.5, box[3]+0.5, i2, i3]
00181                 # note that the toworld() calls are likely very expensive for many boxes. But then 
00182                 # again, the box-finding algorithm itself seems pretty inefficient, but resource
00183                 # constraints only permit a band aid fix at this time.
00184                 blc = ia.toworld(blccoord, 'm')['measure']
00185                 trc = ia.toworld(trccoord, 'm')['measure']
00186                 # RA/Dec reference frame
00187                 outstring = "worldbox " + blc['direction']['refer']
00188                 # RA blc/trc
00189                 outstring += " [" + quantity_to_string(blc["direction"]["m0"], "rad") + ", "
00190                 outstring += quantity_to_string(trc["direction"]["m0"], "rad") + "]"
00191                 # Dec blc/trc
00192                 outstring += " [" + quantity_to_string(blc["direction"]["m1"], "rad") + ", "
00193                 outstring += quantity_to_string(trc["direction"]["m1"], "rad") + "]"
00194                 # frequency blc/trc
00195                 freq = blc["spectral"]['frequency']['refer'] + " "
00196                 freq += quantity_to_string(blc["spectral"]["frequency"]["m0"], "Hz", False)
00197                 outstring += " ['" + freq + "', '" + freq + "']"
00198                 # Stokes blc/trc
00199                 outstring += " ['" + blc["stokes"] + "', '" + trc["stokes"] + "']"
00200                 # add the mask flag
00201                 outstring += " " + str(1)
00202                 f.write(outstring + "\n")
00203     casalog.post("Wrote " + str(totregions) + " regions to file " + regionfile, 'INFO')
00204     if writemask:
00205         myia = iatool()
00206         myia.fromimage(infile=imagename, outfile=maskname, overwrite=True)
00207         myia.done()
00208         myia.open(maskname)
00209         myia.putchunk(outputmask)
00210         myia.done()
00211     f.close()
00212     return True
00213 
00214 def quantity_to_string(quantity, unit=None, quotes=True):
00215     if unit != None:
00216         quantity = qa.convert(quantity, unit)
00217     string = str(quantity['value']) + quantity['unit']
00218     if quotes:
00219         string = "'" + string + "'"
00220     return string
00221 
00222 def find_nearby_island_pixels(island, mask, pos, xmax, ymax, diag):
00223     # blank this position so we don't deal with it again
00224     mask[pos] = False
00225     xref = pos[0]
00226     yref = pos[1]
00227     for x in range(max(xref-1, 0), min(xref+2, xmax)):
00228         for y in range(max(yref-1, 0), min(yref+2, ymax)):
00229             if x == xref and y == yref:
00230                 # same position as reference
00231                 continue
00232             if ( (not diag) and (x-xref != 0) and (y-yref != 0)):
00233                 # diagonal pixels only used if diag is true
00234                 continue
00235             if mask[x][y]:
00236                 # found another pixel in this island
00237                 island['box'][0] = min(island['box'][0],x)
00238                 island['box'][1] = min(island['box'][1],y)
00239                 island['box'][2] = max(island['box'][2],x)
00240                 island['box'][3] = max(island['box'][3],y)
00241                 island['npix'] += 1
00242                 # look for island pixels next to this one
00243                 find_nearby_island_pixels(island, mask, (x,y), xmax, ymax, diag)
00244     return
00245 
00246