def main(image_pre, image_post, res_val, max_factor=0.25): """ Verify subtraction by checking quantities in residual images Parameters ---------- image_pre : str Filename of image before selfcal image_post : str Filename of image after selfcal res_val : float Maximum allowed value of peak residual (Jy/beam) max_factor : float Factor by which old peak residual must exceed new peak residual """ imgpre = pim.image(image_pre) maxvalpre = numpy.max(numpy.abs(imgpre.getdata())) imgpost = pim.image(image_post) maxvalpost = numpy.max(numpy.abs(imgpost.getdata())) if (maxvalpost > res_val) or (maxvalpost * max_factor > maxvalpre): return { 'break': False, 'maxvalpost': maxvalpost, 'maxvalpre': maxvalpre } else: return { 'break': True, 'maxvalpost': maxvalpost, 'maxvalpre': maxvalpre }
def main(image_pre, image_post, res_val, max_factor=0.25): """ Verify subtraction by checking quantities in residual images Parameters ---------- image_pre : str Filename of image before selfcal image_post : str Filename of image after selfcal res_val : float Maximum allowed value of peak residual (Jy/beam) max_factor : float Factor by which old peak residual must exceed new peak residual """ imgpre = pim.image(image_pre) maxvalpre = numpy.max(numpy.abs(imgpre.getdata())) imgpost = pim.image(image_post) maxvalpost = numpy.max(numpy.abs(imgpost.getdata())) if (maxvalpost > res_val) or (maxvalpost*max_factor > maxvalpre): return {'break': False, 'maxvalpost': maxvalpost, 'maxvalpre': maxvalpre} else: return {'break': True, 'maxvalpost': maxvalpost, 'maxvalpre': maxvalpre}
def find_imagenoise(imagename): """ Finds noise, dynamic range, and min/max for an image Parameters ---------- imagename : str Filename of image Returns ------- rms : float Noise (Jy/beam) of image dynamic_range : float Dynamic range (max/min) of image minmax : float Ratio of min/max """ im = pim.image(imagename) image = numpy.copy(im.getdata()) mean, rms = meanclip(image) minmax = abs(numpy.min(image) / numpy.max(image)) return rms, numpy.abs(numpy.max(image) / rms), minmax
def find_imagenoise(imagename): """ Finds noise, dynamic range, and min/max for an image Parameters ---------- imagename : str Filename of image Returns ------- rms : float Noise (Jy/beam) of image dynamic_range : float Dynamic range (max/min) of image minmax : float Ratio of min/max """ im = pim.image(imagename) image = numpy.copy(im.getdata()) mean, rms = meanclip(image) minmax = abs(numpy.min(image) / numpy.max(image)) return rms, numpy.abs(numpy.max(image)/rms), minmax
def main(fitsimage, outfilename, force_stokes_i=False): """ Convert a fits image to a CASA image Parameters ---------- fitsimage : str Name of FITS image outfilename : str Name of output CASA image force_stokes_i : bool, optional If True, force Stokes axis to be 'I' """ casaimage = pim.image(fitsimage) casaimage.saveas(outfilename, overwrite=True) if type(force_stokes_i) is str: if force_stokes_i.lower() == 'true': force_stokes_i = True else: force_stokes_i = False if force_stokes_i: coords = casaimage.coordinates().dict() coords['stokes1']['stokes'] = ['I'] freq = coords['spectral2']['wcs']['crval'] coords['spectral2']['restfreqs'] = np.array([freq]) outtable = pt.table(outfilename, readonly=False, ack=False) outtable.putkeywords({'coords': coords}) outtable.done()
def test_CIM_stacking_base(self): ds.cim.CIM_stacking_base([self.CIMPathA, self.CIMPathA], TEST_DIR, 'test_CIM_stacking_base', overwrite=True) assert np.array_equiv(np.multiply(casaimage.image(self.CIMPathA).getdata(),2),casaimage.image('{0:s}/test_CIM_stacking_base'.format(TEST_DIR)).getdata()), \ 'Stacking the same image not equivalent with multiplying with two!'
def main(image, output=None, radius=0.5): """ Zero corners of avgpb images Parameters ---------- image : str avgpb image output : str, optional Output image name. If None, add a 'z' to the end of the input filename radius : float, optional Radius beyond which to zero avgpb values (expressed as fraction of image width) """ if type(radius) is str: radius = float(radius) pb = pim.image(image) pbdata = pb.getdata() (nx, ny) = pbdata.shape[2:] pbrad = radius * nx cy = ny / 2 cx = nx / 2 pbcounter = 0 for j in range(nx, cx, -1): k = ny while np.sqrt((j-cx)**2+(k-cy)**2) > pbrad and k > cy: pbcounter += 1 pbdata[:, :, k-1, j-1] = 0. pbdata[:, :, k-1, nx-j] = 0. pbdata[:, :, ny-k, j-1] = 0. pbdata[:, :, ny-k, nx-j] = 0. k -= 1 if k == ny: break print pbcounter,'x 4 =',pbcounter*4,'zeros replaced' if output is None: while image[-1] == '/': image = image[: -1] outim = image + 'z' else: outim = output pout = pim.image(outim, values=pbdata, coordsys=pb.coordinates())
def pix2radec(image, i, j): """input: (image, i,j) image name as string, pixel coordinates as int, (0,0) is lower left (TBC) output: (ra, dec) sky coordinates as degree in float""" casa_image = images.image(image) world_vals = casa_image.toworld((0,0,j,i)) # in: frequency, stokes (0-3), jpixel, ipixel # out: frequency, stokes (1-4), dec, ra ra = degrees(world_vals[3]) dec = degrees(world_vals[2]) return (ra, dec)
def radec2pix(image, ra, dec): """input: (image, ra, dec) image name as string, sky coordinates as degree in float output: (i,j) pixel coordinates as int, (0,0) is lower left (TBC)""" casa_image = images.image(image) ra = radians(ra) dec = radians(dec) pix_vals = casa_image.topixel((0,1,dec,ra)) # in: frequency, stokes (1-4), dec, ra # out: frequency, stokes (0-3), jpixel, ipixel i = int(floor(pix_vals[3])) j = int(floor(pix_vals[2])) return (i, j)
def getBeam(self): """ Return the beam size of the image """ this_pim = pim.image(self.imagename) info_dict = this_pim.info()['imageinfo']['restoringbeam'] # get beam info bpar_ma = quanta.quantity(info_dict['major']).get_value('arcsec') bpar_mi = quanta.quantity(info_dict['minor']).get_value('arcsec') bpar_pa = quanta.quantity(info_dict['positionangle']).get_value('deg') #print('\n{0} - Beam: maj {1:0.3f} (arcsec), min {2:2.3f} (arcsec), pa {3:0.2f} (deg)'.format(img, bpar_ma, bpar_mi,bpar_pa)) return (bpar_ma,bpar_mi,bpar_pa)
def test_set_CIM_unit(self): test_cim_name = '{0:s}/test_set_CIM_unit'.format(TEST_DIR) template_cim = ds.cim.create_CIM_object(self.CIMPathA) coordsys = template_cim.coordinates() #If shape is given, the data type is automatically set to float! test_cim = casaimage.image(test_cim_name, coordsys=coordsys, values=template_cim.getdata(), overwrite=True) #Need to give a unit that is known to casacore ds.cim.set_CIM_unit(test_cim_name, 'Jy') CIM_with_unit = ds.cim.create_CIM_object( '{0:s}/test_set_CIM_unit'.format(TEST_DIR)) assert CIM_with_unit.unit( ) == 'Jy', 'Unable to add unit to newly created CASAImage!'
def display_image(image): """ Displays image in an external viewer """ global fig, at, selected_direction if options['facet_viewer'] == 'casa': im2 = pim.image(image) im2.view() elif options['facet_viewer'] == 'ds9': if os.path.isdir(image): # Convert casa image to fits if not os.path.exists('{0}.fits'.format(image)): subprocess.call('image2fits in={0} out={0}.fits'.format(image), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) image = '{0}.fits'.format(image) if not haspyds9: os.system('ds9 {} &'.format(image)) else: # use pyds9 if available to re-use an existing ds9 pyds9.ds9_xpans() c = at.get_child() info_last = c.get_text() info = 'Opening image in ds9...' c.set_text(info) fig.canvas.draw() ds9=pyds9.DS9('checkfactor', wait=120) c.set_text(info_last) fig.canvas.draw() ds9.set('file '+image) if options['ds9_limits'] is not None: ds9.set('scale limits '+options['ds9_limits']) if options['ds9_load_regions']: regionfile=os.path.join(selected_direction.working_dir,'regions','facets_ds9.reg') ds9.set('regions delete all') ds9.set('regions load '+regionfile) else: info = 'Unknown facet viewer specified in config file!' c = at.get_child() c.set_text(info) fig.canvas.draw()
from casacore.images import image print("creating image named crash") im = image(imagename='/data/crash', shape=(256, 256))
def on_press(event): """ Handle key presses """ global fig, at, selected_direction, choose_from_list if event.key == 'u': # Update plot choose_from_list = False update_plot() return elif event.key == 'c': # Open selfcal images (if any) choose_from_list = False if selected_direction is None: return selfcal_images = find_selfcal_images(selected_direction) if len(selfcal_images) > 0: info = 'Opening selfcal images for {}...'.format(selected_direction.name) if hasaplpy: # Update the text box as the call below takes a few seconds c = at.get_child() c.set_text(info) fig.canvas.draw() make_selfcal_images.main(selfcal_images, interactive=True, facet_name=selected_direction.name) else: if os.path.exists('/tmp/tempimage'): shutil.rmtree('/tmp/tempimage') im = pim.image(selfcal_images) im.view() else: info = 'No selfcal images exist for {}'.format(selected_direction.name) elif event.key == 'i': # Open full facet images (if any) if selected_direction is None: return facet_images, facetimage_ops = find_facet_images(selected_direction) if len(facet_images) == 0: info = 'No image of facet exists for {}'.format(selected_direction.name) else: info = 'Load facet image from (choose one):' for opindx, (img, fimg_op) in enumerate(zip(facet_images, facetimage_ops)): info += '\n ({0}) {1}'.format(opindx+1, fimg_op) choose_from_list = True elif event.key == 'v': # Open full facet images (if any) choose_from_list = False if selected_direction is None: return facet_verify_images = find_facet_verify_images(selected_direction) if len(facet_verify_images) == 0: info = 'No verify image of facet exists for {}'.format(selected_direction.name) else: info = 'Opening selfcal verification images for {}...'.format(selected_direction.name) display_image(facet_verify_images) elif event.key in [str(num+1) for num in range(9)]: # Open image (from list given on "i" press) if choose_from_list: facet_images, facetimage_ops = find_facet_images(selected_direction) if int(event.key) <= len(facet_images): display_image(facet_images[int(event.key)-1]) return else: return elif event.key == 't': # Open fast TEC selfcal plots (if any) choose_from_list = False if selected_direction is None: return selfcal_plots = find_selfcal_tec_plots(selected_direction) if len(selfcal_plots) > 0: info = 'Opening selfcal TEC solution plots for {}...'.format(selected_direction.name) os.system(options['image_display']+' {} &'.format(' '.join(selfcal_plots))) else: info = 'Final selfcal solutions do not exist for {}'.format(selected_direction.name) elif event.key == 'g': # Open slow Gain selfcal plots (if any) choose_from_list = False if selected_direction is None: return selfcal_plots = find_selfcal_gain_plots(selected_direction) if len(selfcal_plots) > 0: info = 'Opening selfcal Gain solution plots for {}...'.format(selected_direction.name) os.system(options['image_display']+' {} &'.format(' '.join(selfcal_plots))) else: info = 'Final selfcal solutions do not exist for {}'.format(selected_direction.name) elif event.key == 'h': choose_from_list = False info='Reprinting instructions' show_instructions() return else: return # Update info box c = at.get_child() c.set_text(info) fig.canvas.draw()
# This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # #usage: extractbeam.py imagename import casacore.images as pim from casacore import quanta import sys for img in sys.argv[1:]: this_pim = pim.image(img) info_dict = this_pim.info()['imageinfo']['restoringbeam'] # get beam info bpar_ma = quanta.quantity(info_dict['major']).get_value('arcsec') bpar_mi = quanta.quantity(info_dict['minor']).get_value('arcsec') bpar_pa = quanta.quantity(info_dict['positionangle']).get_value('deg') print( '\n{0} - Beam: maj {1:0.3f} (arcsec), min {2:2.3f} (arcsec), pa {3:0.2f} (deg)' .format(img, bpar_ma, bpar_mi, bpar_pa))
def display_image(images): """ Displays images in an external viewer """ global fig, at, selected_direction if not isinstance(images, list): images = [images] if options['facet_viewer'] == 'casa': for image in images: im2 = pim.image(image) im2.view() elif options['facet_viewer'] == 'ds9': for i in range(len(images)): image = images[i] if os.path.isdir(image): # Convert casa image to fits if not os.path.exists('{0}.fits'.format(image)): subprocess.call('image2fits in={0} out={0}.fits'.format(image), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) images[i] = '{0}.fits'.format(image) if not haspyds9: os.system('ds9 -tile {} &'.format(' '.join(images))) else: # use pyds9 if available to re-use an existing ds9 pyds9.ds9_xpans() c = at.get_child() info_last = c.get_text() info = 'Opening image in ds9...' c.set_text(info) fig.canvas.draw() ds9=pyds9.DS9('checkfactor', wait=120) c.set_text(info_last) fig.canvas.draw() for i in range(len(images)): if options['ds9_frames'] == 'current': if len(images) > 1: # For single image, no need to set frame as current one # is used by default. For multiple images, use frame i # for image i ds9.set('frame {:d}'.format(i)) elif options['ds9_frames'] == 'new': ds9.set('frame new') else: log.warning('ds9_frames setting "{}" not understood. Using ' '"new" instead'.format(options['ds9_frames'])) ds9.set('frame new') ds9.set('file '+images[i]) if options['ds9_limits'] is not None: ds9.set('scale limits '+options['ds9_limits']) if options['ds9_load_regions']: regionfile=os.path.join(selected_direction.working_dir,'regions','facets_ds9.reg') ds9.set('regions delete all') ds9.set('regions load '+regionfile) if len(images) > 1: ds9.set('tile') ds9.set('frame match scale and limits') ds9.set('frame match colorbar') ds9.set('frame match wcs') else: info = 'Unknown facet viewer specified in config file!' c = at.get_child() c.set_text(info) fig.canvas.draw()
def main(images, vertices, outfits, maxwidth=0): """ Creates mosaic Parameters ---------- images : str or list of str List of filenames of facet images. May be given as a list or as a string (e.g., '[image1, image2]' vertices : str or list of str List of filenames of facet vertices files. May be given as a list or as a string (e.g., '[vert1, vert2]' outfits : str Filename of output FITS mosaic maxwidth : int, optional Maximum number of pixels to consider for the width of the mosaic [default 0 = unlimited] This can be helpful at high declination. """ if type(images) is str: images = images.strip('[]').split(',') images = [im.strip() for im in images] if type(vertices) is str: vertices = vertices.strip('[]').split(',') vertices = [v.strip() for v in vertices] formstr = '{0:45s} {1:45s} {2:s} {3:s} {4:s} {5:s}' print formstr.format("-----","--------","------------","-------","-------","------") print formstr.format("Image", "FC reg","Norm. weight", "Maj(ac)", "Min(ac)","PA(deg)") print formstr.format("-----","--------","------------","-------","-------","------") psf_fwhm = [] # resolution frequency = [] # frequency of images (should be equal?) for i in range(len(images)): this_pim = pim.image(images[i]) info_dict = this_pim.info()['imageinfo']['restoringbeam'] bpar_ma = quanta.quantity(info_dict['major']).get_value('deg') bpar_mi = quanta.quantity(info_dict['minor']).get_value('deg') bpar_pa = quanta.quantity(info_dict['positionangle']).get_value('deg') psf_fwhm.append([bpar_ma, bpar_mi, bpar_pa]) frequency.append(this_pim.info()['coordinates']['spectral2']['restfreq']) print '{0:45.45s} {1:45.45s} {2:0.2f} {3:0.2f} {4:0.2f} {5:0.2f}'.format(images[i], vertices[i], 0, bpar_ma*60, bpar_mi*60,bpar_pa) psf_fwhm = np.array(psf_fwhm) frequency = np.array(frequency) mean_psf_fwhm = np.mean(psf_fwhm, axis=0) mean_frequency = np.mean(frequency) # Initialize some vectors declims = [] # store the limits of the declination axes raleft = [] raright = [] rainc = [] # store the r.a. increments in case they differ decinc = [] # store the dec increments in case they differ pims = [] # stores the casacore images of the data # Get image frames for input images for im in images: image = pim.image(im) sptcoords = image.coordinates().get_coordinate('spectral') nc = sptcoords.get_axis_size() # Get Stokes axis. Ensure we are working with the Stokes parameter requested. stkcoords = image.coordinates().get_coordinate('stokes') if stkcoords.get_axis_size() == 1: assert(stkcoords.get_stokes()[0] == 'I') else: stks = stkcoords.get_stokes().index('I') image = image.subimage(blc=(0, stks), trc=(nc-1, stks), dropdegenerate=False) ns = 1 dircoords = image.coordinates().get_coordinate('direction') nx = dircoords.get_axis_size(axis=1) ny = dircoords.get_axis_size(axis=0) inc = dircoords.get_increment() ref = dircoords.get_referencepixel() val = dircoords.get_referencevalue() # wsclean image header is weird if val[1]<0: val[1]+=2*np.pi ra_axis = (range(nx)-ref[1])*inc[1]+val[1] dec_axis = (range(ny)-ref[0])*inc[0]+val[0] rainc.append(inc[1]) decinc.append(inc[0]) declims.append(min(dec_axis)) declims.append(max(dec_axis)) mean_ra = np.mean(ra_axis) raleft.append((ra_axis[0]-mean_ra)*np.cos(val[0])+mean_ra) raright.append((ra_axis[-1]-mean_ra)*np.cos(val[0])+mean_ra) pims.append(image) # Generate the mosaic coordinate frame master_dec = np.arange(min(declims),max(declims),min(decinc)) if max(raleft)-min(raright) > 5.*np.pi/3.: # crossed RA=0 for i in range(len(raright)): raright[i] = raright[i]-2.*np.pi master_ra = np.arange(max(raleft),min(raright),max(rainc)) lmra = len(master_ra) if maxwidth != 0: if lmra > maxwidth: xboundary = (lmra-maxwidth)/2 master_ra = master_ra[xboundary:-xboundary] print "Found ra,dec pixel increments (arcsec):" print np.array(rainc)*206265.,np.array(decinc)*206265. ma = pims[-1].coordinates() ma['direction'].set_referencepixel([len(master_dec)/2,len(master_ra)/2]) ma['direction'].set_increment([decinc[np.argmin(np.abs(decinc))],rainc[np.argmin(np.abs(rainc))]]) ma['direction'].set_referencevalue([master_dec[len(master_dec)/2],master_ra[len(master_ra)/2]]) # Initialize the arrays for the output image, sensitivity, and weights master_im = np.zeros((len(master_dec),len(master_ra))) master_mask = np.zeros((len(master_dec),len(master_ra))) # Reproject the images onto the master grid, weight and normalize for i, im in enumerate(pims): print 'doing image',i im, mask = mask_vertices(im, vertices[i]) im = im.regrid([2,3],ma,outshape=(int(nc),int(ns),len(master_dec),len(master_ra))) mask = mask.regrid([2,3],ma,outshape=(int(nc),int(ns),len(master_dec),len(master_ra))) master_im += np.squeeze(im.getdata()) master_mask += np.squeeze(mask.getdata()) blank=np.ones_like(im)*np.nan master_im=np.where(master_mask,master_im,blank) # Write fits files arrax = np.zeros( (1,1, len(master_im[:,0]), len(master_im[0,:])) ) arrax[0,0,:,:] = master_im # Open new casa image for mosaic new_pim = pim.image('',shape=(1,1, len(master_dec),len(master_ra)), coordsys=ma) new_pim.putdata(arrax) # Write fits new_pim.tofits(outfits, overwrite=True) # need to add new beam info (not sure if this is possible with casacore) hdu = pyfits.open(outfits,mode='update') header = hdu[0].header header.update('BMAJ',mean_psf_fwhm[0]) header.update('BMIN',mean_psf_fwhm[1]) header.update('BPA',mean_psf_fwhm[2]) header.update('BUNIT',pims[-1].info()['unit']) header.update('RESTFRQ',mean_frequency) header.update('RESTFREQ',mean_frequency) newhdu = pyfits.PrimaryHDU(data=hdu[0].data, header=header) newhdu.writeto(outfits,clobber=True)
#Cretae an ARL image from the grids sub_grid_real_arlimage = create_ARLimage_from_CASAimage(grid_name_real); sub_grid_imag_arlimage = create_ARLimage_from_CASAimage(grid_name_imag); #Add it to the combined arlimage combined_grid_real_arlimage.data += sub_grid_real_arlimage.data; combined_grid_imag_arlimage.data += sub_grid_imag_arlimage.data; log.info('Normalise combined grids'); #Normnalise the combined image combined_grid_real_arlimage.data /= N_combination; combined_grid_imag_arlimage.data /= N_combination; log.info('Write combined grid back to the grids'); #write this back to the dataset combined_grid_real_casaimage = casaimage.image(combined_grid_name_real); combined_grid_real_casaimage_data = combined_grid_real_casaimage.getdata(); combined_grid_imag_casaimage = casaimage.image(combined_grid_name_imag); combined_grid_imag_casaimage_data = combined_grid_imag_casaimage.getdata(); #Put the arl object to the CASAimage object combined_grid_real_casaimage_data[...] = combined_grid_real_arlimage.data; combined_grid_imag_casaimage_data[...] = combined_grid_imag_arlimage.data; #Write it back to the image combined_grid_real_casaimage.putdata(combined_grid_real_casaimage_data); combined_grid_imag_casaimage.putdata(combined_grid_imag_casaimage_data); #Deleting the variables closes the image, which release the lock #Another soulution would be is to do this inside a function....
def display_image(images): """ Displays images in an external viewer """ global fig, at, selected_direction if not isinstance(images, list): images = [images] if options['facet_viewer'] == 'casa': for image in images: im2 = pim.image(image) im2.view() elif options['facet_viewer'] == 'ds9': for i in range(len(images)): image = images[i] if os.path.isdir(image): # Convert casa image to fits if not os.path.exists('{0}.fits'.format(image)): subprocess.call( 'image2fits in={0} out={0}.fits'.format(image), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) images[i] = '{0}.fits'.format(image) if not haspyds9: os.system('ds9 -tile {} &'.format(' '.join(images))) else: # use pyds9 if available to re-use an existing ds9 pyds9.ds9_xpans() c = at.get_child() info_last = c.get_text() info = 'Opening image in ds9...' c.set_text(info) fig.canvas.draw() ds9 = pyds9.DS9('checkfactor', wait=120) c.set_text(info_last) fig.canvas.draw() for i in range(len(images)): if options['ds9_frames'] == 'current': if len(images) > 1: # For single image, no need to set frame as current one # is used by default. For multiple images, use frame i # for image i ds9.set('frame {:d}'.format(i)) elif options['ds9_frames'] == 'new': ds9.set('frame new') else: log.warning( 'ds9_frames setting "{}" not understood. Using ' '"new" instead'.format(options['ds9_frames'])) ds9.set('frame new') ds9.set('file ' + images[i]) if options['ds9_limits'] is not None: ds9.set('scale limits ' + options['ds9_limits']) if options['ds9_load_regions']: regionfile = os.path.join(selected_direction.working_dir, 'regions', 'facets_ds9.reg') ds9.set('regions delete all') ds9.set('regions load ' + regionfile) if len(images) > 1: ds9.set('tile') ds9.set('frame match scale and limits') ds9.set('frame match colorbar') ds9.set('frame match wcs') else: info = 'Unknown facet viewer specified in config file!' c = at.get_child() c.set_text(info) fig.canvas.draw()
def main(image_name, mask_name, atrous_do=False, threshisl=0.0, threshpix=0.0, rmsbox=None, rmsbox_bright=(35, 7), iterate_threshold=False, adaptive_rmsbox=False, img_format='fits', threshold_format='float', trim_by=0.0, vertices_file=None, atrous_jmax=6, pad_to_size=None, skip_source_detection=False, region_file=None, nsig=1.0, reference_ra_deg=None, reference_dec_deg=None, cellsize_deg=0.000417, use_adaptive_threshold=False, adaptive_thresh=150.0): """ Make a clean mask and return clean threshold Parameters ---------- image_name : str Filename of input image from which mask will be made. If the image does not exist, a template image with center at (reference_ra_deg, reference_dec_deg) will be made internally mask_name : str Filename of output mask image atrous_do : bool, optional Use wavelet module of PyBDSM? threshisl : float, optional Value of thresh_isl PyBDSM parameter threshpix : float, optional Value of thresh_pix PyBDSM parameter rmsbox : tuple of floats, optional Value of rms_box PyBDSM parameter rmsbox_bright : tuple of floats, optional Value of rms_box_bright PyBDSM parameter iterate_threshold : bool, optional If True, threshold will be lower in 20% steps until at least one island is found adaptive_rmsbox : tuple of floats, optional Value of adaptive_rms_box PyBDSM parameter img_format : str, optional Format of output mask image (one of 'fits' or 'casa') threshold_format : str, optional Format of output threshold (one of 'float' or 'str_with_units') trim_by : float, optional Fraction by which the perimeter of the output mask will be trimmed (zeroed) vertices_file : str, optional Filename of file with vertices (must be a pickle file containing a dictionary with the vertices in the 'vertices' entry) atrous_jmax : int, optional Value of atrous_jmax PyBDSM parameter pad_to_size : int, optional Pad output mask image to a size of pad_to_size x pad_to_size skip_source_detection : bool, optional If True, source detection is not run on the input image region_file : str, optional Filename of region file in CASA format. If given, no mask image is made (the region file is used as the clean mask) nsig : float, optional Number of sigma of returned threshold value reference_ra_deg : float, optional RA for center of output mask image reference_dec_deg : float, optional Dec for center of output mask image cellsize_deg : float, optional Size of a pixel in degrees use_adaptive_threshold : bool, optional If True, use an adaptive threshold estimated from the negative values in the image adaptive_thresh : float, optional If adaptive_rmsbox is True, this value sets the threshold above which a source will use the small rms box Returns ------- result : dict Dict with nsig-sigma rms threshold """ if rmsbox is not None and type(rmsbox) is str: rmsbox = eval(rmsbox) if type(rmsbox_bright) is str: rmsbox_bright = eval(rmsbox_bright) if pad_to_size is not None and type(pad_to_size) is str: pad_to_size = int(pad_to_size) if type(atrous_do) is str: if atrous_do.lower() == 'true': atrous_do = True threshisl = 4.0 # override user setting to ensure proper source fitting else: atrous_do = False if type(iterate_threshold) is str: if iterate_threshold.lower() == 'true': iterate_threshold = True else: iterate_threshold = False if type(adaptive_rmsbox) is str: if adaptive_rmsbox.lower() == 'true': adaptive_rmsbox = True else: adaptive_rmsbox = False if type(skip_source_detection) is str: if skip_source_detection.lower() == 'true': skip_source_detection = True else: skip_source_detection = False if type(use_adaptive_threshold) is str: if use_adaptive_threshold.lower() == 'true': use_adaptive_threshold = True else: use_adaptive_threshold = False if reference_ra_deg is not None and reference_dec_deg is not None: reference_ra_deg = float(reference_ra_deg) reference_dec_deg = float(reference_dec_deg) if not os.path.exists(image_name): print('Input image not found. Making empty image...') if not skip_source_detection: print('ERROR: Source detection cannot be done on an empty image') sys.exit(1) if reference_ra_deg is not None and reference_dec_deg is not None: image_name = mask_name + '.tmp' make_template_image(image_name, reference_ra_deg, reference_dec_deg, cellsize_deg=float(cellsize_deg)) else: print( 'ERROR: if image not found, a refernce position must be given') sys.exit(1) trim_by = float(trim_by) atrous_jmax = int(atrous_jmax) threshpix = float(threshpix) threshisl = float(threshisl) nsig = float(nsig) adaptive_thresh = float(adaptive_thresh) threshold = 0.0 if not skip_source_detection: if vertices_file is not None: # Modify the input image to blank the regions outside of the polygon temp_img = pim.image(image_name) image_name += '.blanked' temp_img.saveas(image_name, overwrite=True) input_img = pim.image(image_name) data = input_img.getdata() vertices = read_vertices(vertices_file) RAverts = vertices[0] Decverts = vertices[1] xvert = [] yvert = [] for RAvert, Decvert in zip(RAverts, Decverts): pixels = input_img.topixel( [1, 1, Decvert * np.pi / 180.0, RAvert * np.pi / 180.0]) xvert.append(pixels[2]) # x -> Dec yvert.append(pixels[3]) # y -> RA poly = Polygon(xvert, yvert) # Find masked regions masked_ind = np.where(data[0, 0]) # Find distance to nearest poly edge and set to NaN those that # are outside the facet (dist < 0) dist = poly.is_inside(masked_ind[0], masked_ind[1]) outside_ind = np.where(dist < 0.0) if len(outside_ind[0]) > 0: data[0, 0, masked_ind[0][outside_ind], masked_ind[1][outside_ind]] = np.nan # Save changes input_img.putdata(data) if use_adaptive_threshold: # Get an estimate of the rms img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=adaptive_thresh, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax, stop_at='isl') # Find min and max pixels max_neg_val = abs(np.min(img.ch0_arr)) max_neg_pos = np.where(img.ch0_arr == np.min(img.ch0_arr)) max_pos_val = abs(np.max(img.ch0_arr)) max_pos_pos = np.where(img.ch0_arr == np.max(img.ch0_arr)) # Estimate new thresh_isl from min pixel value's sigma, but don't let # it get higher than 1/2 of the peak's sigma threshisl_neg = 2.0 * max_neg_val / img.rms_arr[max_neg_pos][0] max_sigma = max_pos_val / img.rms_arr[max_pos_pos][0] if threshisl_neg > max_sigma / 2.0: threshisl_neg = max_sigma / 2.0 # Use the new threshold only if it is larger than the user-specified one if threshisl_neg > threshisl: threshisl = threshisl_neg if iterate_threshold: # Start with given threshold and lower it until we get at least one island nisl = 0 while nisl == 0: img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=adaptive_thresh, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax) nisl = img.nisl threshpix /= 1.2 threshisl /= 1.2 if threshpix < 5.0: break else: img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=adaptive_thresh, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax) if img.nisl == 0: if region_file is None or region_file == '[]': print('No islands found. Clean mask cannot be made.') sys.exit(1) else: # Continue on and use user-supplied region file skip_source_detection = True threshold = nsig * img.clipped_rms # Check if there are large islands preset (indicating that multi-scale # clean is needed) has_large_isl = False for isl in img.islands: if isl.size_active > 100: # Assuming normal sampling, a size of 100 pixels would imply # a source of ~ 10 beams has_large_isl = True if (region_file is not None and region_file != '[]' and skip_source_detection): # Copy region file and return if source detection was not done os.system('cp {0} {1}'.format(region_file.strip('[]"'), mask_name)) if threshold_format == 'float': return {'threshold_5sig': threshold} elif threshold_format == 'str_with_units': # This is done to get around the need for quotes around strings in casapy scripts # 'casastr/' is removed by the generic pipeline return {'threshold_5sig': 'casastr/{0}Jy'.format(threshold)} elif not skip_source_detection: img.export_image(img_type='island_mask', mask_dilation=0, outfile=mask_name, img_format=img_format, clobber=True) if (vertices_file is not None or trim_by > 0 or pad_to_size is not None or (region_file is not None and region_file != '[]') or skip_source_detection): # Alter the mask in various ways if skip_source_detection: # Read the image mask_im = pim.image(image_name) else: # Read the PyBDSM mask mask_im = pim.image(mask_name) data = mask_im.getdata() coordsys = mask_im.coordinates() if reference_ra_deg is not None and reference_dec_deg is not None: values = coordsys.get_referencevalue() values[2][0] = reference_dec_deg / 180.0 * np.pi values[2][1] = reference_ra_deg / 180.0 * np.pi coordsys.set_referencevalue(values) imshape = mask_im.shape() del (mask_im) if pad_to_size is not None: imsize = pad_to_size coordsys['direction'].set_referencepixel([imsize / 2, imsize / 2]) pixmin = (imsize - imshape[2]) / 2 if pixmin < 0: print("The padded size must be larger than the original size.") sys.exit(1) pixmax = pixmin + imshape[2] data_pad = np.zeros((1, 1, imsize, imsize), dtype=np.float32) data_pad[0, 0, pixmin:pixmax, pixmin:pixmax] = data[0, 0] new_mask = pim.image('', shape=(1, 1, imsize, imsize), coordsys=coordsys) new_mask.putdata(data_pad) else: new_mask = pim.image('', shape=imshape, coordsys=coordsys) new_mask.putdata(data) data = new_mask.getdata() if skip_source_detection: # Mask all pixels data[:] = 1 if vertices_file is not None: # Modify the clean mask to exclude regions outside of the polygon vertices = read_vertices(vertices_file) RAverts = vertices[0] Decverts = vertices[1] xvert = [] yvert = [] for RAvert, Decvert in zip(RAverts, Decverts): try: pixels = new_mask.topixel([ 0, 1, Decvert * np.pi / 180.0, RAvert * np.pi / 180.0 ]) except: pixels = new_mask.topixel([ 1, 1, Decvert * np.pi / 180.0, RAvert * np.pi / 180.0 ]) xvert.append(pixels[2]) # x -> Dec yvert.append(pixels[3]) # y -> RA poly = Polygon(xvert, yvert) # Find masked regions masked_ind = np.where(data[0, 0]) # Find distance to nearest poly edge and unmask those that # are outside the facet (dist < 0) dist = poly.is_inside(masked_ind[0], masked_ind[1]) outside_ind = np.where(dist < 0.0) if len(outside_ind[0]) > 0: data[0, 0, masked_ind[0][outside_ind], masked_ind[1][outside_ind]] = 0 if trim_by > 0.0: sh = np.shape(data) margin = int(sh[2] * trim_by / 2.0) data[0, 0, 0:sh[2], 0:margin] = 0 data[0, 0, 0:margin, 0:sh[3]] = 0 data[0, 0, 0:sh[2], sh[3] - margin:sh[3]] = 0 data[0, 0, sh[2] - margin:sh[2], 0:sh[3]] = 0 if region_file is not None and region_file != '[]': # Merge the CASA regions with the mask casa_polys = read_casa_polys(region_file.strip('[]"'), new_mask) for poly in casa_polys: # Find unmasked regions unmasked_ind = np.where(data[0, 0] == 0) # Find distance to nearest poly edge and mask those that # are inside the casa region (dist > 0) dist = poly.is_inside(unmasked_ind[0], unmasked_ind[1]) inside_ind = np.where(dist > 0.0) if len(inside_ind[0]) > 0: data[0, 0, unmasked_ind[0][inside_ind], unmasked_ind[1][inside_ind]] = 1 # Save changes new_mask.putdata(data) if img_format == 'fits': new_mask.tofits(mask_name, overwrite=True) elif img_format == 'casa': new_mask.saveas(mask_name, overwrite=True) else: print( 'Output image format "{}" not understood.'.format(img_format)) sys.exit(1) if not skip_source_detection: if threshold_format == 'float': return { 'threshold_5sig': nsig * img.clipped_rms, 'multiscale': has_large_isl } elif threshold_format == 'str_with_units': # This is done to get around the need for quotes around strings in casapy scripts # 'casastr/' is removed by the generic pipeline return { 'threshold_5sig': 'casastr/{0}Jy'.format(nsig * img.clipped_rms), 'multiscale': has_large_isl } else: return {'threshold_5sig': '0.0'}
def main(images, outfits, maxwidth=0): """ Creates mosaic Parameters ---------- images : str or list of str List of filenames of facet images. May be given as a list or as a string (e.g., '[image1, image2]'. Each image must be blanked with zeros outside of the facet region outfits : str Filename of output FITS mosaic maxwidth : int, optional Maximum number of pixels to consider for the width of the mosaic [default 0 = unlimited] This can be helpful at high declination. """ if type(images) is str: images = images.strip('[]').split(',') images = [im.strip() for im in images] formstr = '{0:45s} {1:s} {2:s} {3:s} {4:s}' print formstr.format("-----", "------------", "-------", "-------", "-------") print formstr.format("Image", "Norm. weight", "Maj(ac)", "Min(ac)", "PA(deg)") print formstr.format("-----", "------------", "-------", "-------", "-------") psf_fwhm = [] # resolution frequency = [] # frequency of images (should be equal?) for i in range(len(images)): this_pim = pim.image(images[i]) info_dict = this_pim.info()['imageinfo']['restoringbeam'] bpar_ma = quanta.quantity(info_dict['major']).get_value('deg') bpar_mi = quanta.quantity(info_dict['minor']).get_value('deg') bpar_pa = quanta.quantity(info_dict['positionangle']).get_value('deg') psf_fwhm.append([bpar_ma, bpar_mi, bpar_pa]) frequency.append( this_pim.info()['coordinates']['spectral2']['restfreq']) print '{0:45.45s} {1:0.2f} {2:0.2f} {3:0.2f} {4:0.2f}'.format( images[i], 0, bpar_ma * 60, bpar_mi * 60, bpar_pa) psf_fwhm = np.array(psf_fwhm) frequency = np.array(frequency) mean_psf_fwhm = np.mean(psf_fwhm, axis=0) mean_frequency = np.mean(frequency) # Initialize some vectors declims = [] # store the limits of the declination axes raleft = [] raright = [] rainc = [] # store the r.a. increments in case they differ decinc = [] # store the dec increments in case they differ pims = [] # stores the casacore images of the data # Get image frames for input images for im in images: image = pim.image(im) sptcoords = image.coordinates().get_coordinate('spectral') nc = sptcoords.get_axis_size() # Get Stokes axis. Ensure we are working with the Stokes parameter requested. stkcoords = image.coordinates().get_coordinate('stokes') if stkcoords.get_axis_size() == 1: assert (stkcoords.get_stokes()[0] == 'I') else: stks = stkcoords.get_stokes().index('I') image = image.subimage(blc=(0, stks), trc=(nc - 1, stks), dropdegenerate=False) ns = 1 dircoords = image.coordinates().get_coordinate('direction') nx = dircoords.get_axis_size(axis=1) ny = dircoords.get_axis_size(axis=0) inc = dircoords.get_increment() ref = dircoords.get_referencepixel() val = dircoords.get_referencevalue() # wsclean image header is weird if val[1] < 0: val[1] += 2 * np.pi ra_axis = (range(nx) - ref[1]) * inc[1] + val[1] dec_axis = (range(ny) - ref[0]) * inc[0] + val[0] rainc.append(inc[1]) decinc.append(inc[0]) declims.append(min(dec_axis)) declims.append(max(dec_axis)) mean_ra = np.mean(ra_axis) raleft.append((ra_axis[0] - mean_ra) * np.cos(val[0]) + mean_ra) raright.append((ra_axis[-1] - mean_ra) * np.cos(val[0]) + mean_ra) pims.append(image) # Generate the mosaic coordinate frame master_dec = np.arange(min(declims), max(declims), min(decinc)) if max(raleft) - min(raright) > 5. * np.pi / 3.: # crossed RA=0 for i in range(len(raright)): raright[i] = raright[i] - 2. * np.pi master_ra = np.arange(max(raleft), min(raright), max(rainc)) lmra = len(master_ra) if maxwidth != 0: if lmra > maxwidth: xboundary = (lmra - maxwidth) / 2 master_ra = master_ra[xboundary:-xboundary] print "Found ra,dec pixel increments (arcsec):" print np.array(rainc) * 206265., np.array(decinc) * 206265. ma = pims[-1].coordinates() ma['direction'].set_referencepixel( [len(master_dec) / 2, len(master_ra) / 2]) ma['direction'].set_increment( [decinc[np.argmin(np.abs(decinc))], rainc[np.argmin(np.abs(rainc))]]) ma['direction'].set_referencevalue( [master_dec[len(master_dec) / 2], master_ra[len(master_ra) / 2]]) # Initialize the arrays for the output image, sensitivity, and weights master_im = np.zeros((len(master_dec), len(master_ra))) # Reproject the images onto the master grid, weight and normalize for im in pims: im = im.regrid([2, 3], ma, outshape=(int(nc), int(ns), len(master_dec), len(master_ra))) master_im += np.squeeze(im.getdata()) blank = np.ones_like(master_im) * np.nan master_im = np.where(master_im, master_im, blank) # Write fits files arrax = np.zeros((1, 1, len(master_im[:, 0]), len(master_im[0, :]))) arrax[0, 0, :, :] = master_im # Open new casa image for mosaic new_pim = pim.image('', shape=(1, 1, len(master_dec), len(master_ra)), coordsys=ma) new_pim.putdata(arrax) # Write fits new_pim.tofits(outfits, overwrite=True) # need to add new beam info (not sure if this is possible with casacore) hdu = pyfits.open(outfits, mode='update', memmap=False) header = hdu[0].header header['BMAJ'] = mean_psf_fwhm[0] header['BMIN'] = mean_psf_fwhm[1] header['BPA'] = mean_psf_fwhm[2] header['BUNIT'] = pims[-1].info()['unit'] header['RESTFRQ'] = mean_frequency header['RESTFREQ'] = mean_frequency newhdu = pyfits.PrimaryHDU(data=hdu[0].data, header=header) newhdu.writeto(outfits, clobber=True)
def main(input_image_file, vertices_file, output_image_file, blank_value='zero', img_format='fits', image_is_casa_model=False, nterms=1): """ Blank a region in an image Parameters ---------- input_image_file : str Filename of input image from which mask will be made. If the image does not exist, a template image with center at (reference_ra_deg, reference_dec_deg) will be made internally vertices_file : str, optional Filename of file with vertices (must be a pickle file containing a dictionary with the vertices in the 'vertices' entry) output_image_file : str Filename of output image blank_value : str, optional Value for blanks (one of 'zero' or 'nan') img_format : str, optional Format of output mask image (one of 'fits' or 'casa') image_is_casa_model : bool, optional If True, the input and output image files are treated as the root name of a casa model image (or images) nterms : int, optional If image_is_casa_model is True, this argument sets the number of nterms for the model """ if type(image_is_casa_model) is str: if image_is_casa_model.lower() == 'true': image_is_casa_model = True else: image_is_casa_model = False if type(nterms) is str: nterms = int(nterms) if image_is_casa_model: if nterms == 1: input_image_files = [input_image_file+'.model'] output_image_files = [output_image_file+'.model'] if nterms == 2: input_image_files = [input_image_file+'.model.tt0', input_image_file+'.model.tt1'] output_image_files = [output_image_file+'.model.tt0', output_image_file+'.model.tt1'] if nterms == 3: input_image_files = [input_image_file+'.model.tt0', input_image_file+'.model.tt1', input_image_file+'.model.tt2'] output_image_files = [output_image_file+'.model.tt0', output_image_file+'.model.tt1', output_image_file+'.model.tt2'] else: input_image_files = [input_image_file] output_image_files = [output_image_file] for input_image, output_image in zip(input_image_files, output_image_files): im = pim.image(input_image) data = im.getdata() coordsys = im.coordinates() imshape = im.shape() new_im = pim.image('', shape=imshape, coordsys=coordsys) # Construct polygon vertices = read_vertices(vertices_file) RAverts = vertices[0] Decverts = vertices[1] xvert = [] yvert = [] for RAvert, Decvert in zip(RAverts, Decverts): pixels = new_im.topixel([0, 1, Decvert*np.pi/180.0, RAvert*np.pi/180.0]) xvert.append(pixels[2]) # x -> Dec yvert.append(pixels[3]) # y -> RA poly = Polygon(xvert, yvert) # Find distance to nearest poly edge and blank those that # are outside the facet (dist < 0) pix_ind = np.indices(data[0, 0].shape) dist = poly.is_inside(pix_ind[0], pix_ind[1]) outside_ind = np.where(dist < 0.0) if len(outside_ind[0]) > 0: if blank_value == 'zero': blank_val = 0.0 elif blank_value == 'nan': blank_val = np.nan else: print('Blank value type "{}" not understood.'.format(blank_with)) sys.exit(1) data[0, 0, pix_ind[0][outside_ind], pix_ind[1][outside_ind]] = blank_val # Save changes new_im.putdata(data) if img_format == 'fits': new_im.tofits(output_image, overwrite=True) elif img_format == 'casa': new_im.saveas(output_image, overwrite=True) else: print('Output image format "{}" not understood.'.format(img_format)) sys.exit(1)
def test_create_CIM_diff_array(self): assert np.array_equiv(ds.cim.create_CIM_diff_array(self.CIMPathA,self.CIMPathA), np.zeros((np.shape(casaimage.image(self.CIMPathA).getdata())[2],np.shape(casaimage.image(self.CIMPathA).getdata())[3]))) == True, \ 'Failed to produce a difference image of zeros using CIM A!'
def main(image_name, mask_name, atrous_do=False, threshisl=0.0, threshpix=0.0, rmsbox=None, rmsbox_bright=(35, 7), iterate_threshold=False, adaptive_rmsbox=False, img_format='fits', threshold_format='float', trim_by=0.0, vertices_file=None, atrous_jmax=6, pad_to_size=None, skip_source_detection=False, region_file=None, nsig=1.0, reference_ra_deg=None, reference_dec_deg=None, cellsize_deg=0.000417, use_adaptive_threshold=False): """ Make a clean mask and return clean threshold Parameters ---------- image_name : str Filename of input image from which mask will be made. If the image does not exist, a template image with center at (reference_ra_deg, reference_dec_deg) will be made internally mask_name : str Filename of output mask image atrous_do : bool, optional Use wavelet module of PyBDSM? threshisl : float, optional Value of thresh_isl PyBDSM parameter threshpix : float, optional Value of thresh_pix PyBDSM parameter rmsbox : tuple of floats, optional Value of rms_box PyBDSM parameter rmsbox_bright : tuple of floats, optional Value of rms_box_bright PyBDSM parameter iterate_threshold : bool, optional If True, threshold will be lower in 20% steps until at least one island is found adaptive_rmsbox : tuple of floats, optional Value of adaptive_rms_box PyBDSM parameter img_format : str, optional Format of output mask image (one of 'fits' or 'casa') threshold_format : str, optional Format of output threshold (one of 'float' or 'str_with_units') trim_by : float, optional Fraction by which the perimeter of the output mask will be trimmed (zeroed) vertices_file : str, optional Filename of file with vertices (must be a pickle file containing a dictionary with the vertices in the 'vertices' entry) atrous_jmax : int, optional Value of atrous_jmax PyBDSM parameter pad_to_size : int, optional Pad output mask image to a size of pad_to_size x pad_to_size skip_source_detection : bool, optional If True, source detection is not run on the input image region_file : str, optional Filename of region file in CASA format. If given, no mask image is made (the region file is used as the clean mask) nsig : float, optional Number of sigma of returned threshold value reference_ra_deg : float, optional RA for center of output mask image reference_dec_deg : float, optional Dec for center of output mask image cellsize_deg : float, optional Size of a pixel in degrees use_adaptive_threshold : bool, optional If True, use an adaptive threshold estimated from the negative values in the image Returns ------- result : dict Dict with nsig-sigma rms threshold """ if rmsbox is not None and type(rmsbox) is str: rmsbox = eval(rmsbox) if type(rmsbox_bright) is str: rmsbox_bright = eval(rmsbox_bright) if pad_to_size is not None and type(pad_to_size) is str: pad_to_size = int(pad_to_size) if type(atrous_do) is str: if atrous_do.lower() == 'true': atrous_do = True threshisl = 4.0 # override user setting to ensure proper source fitting else: atrous_do = False if type(iterate_threshold) is str: if iterate_threshold.lower() == 'true': iterate_threshold = True else: iterate_threshold = False if type(adaptive_rmsbox) is str: if adaptive_rmsbox.lower() == 'true': adaptive_rmsbox = True else: adaptive_rmsbox = False if type(skip_source_detection) is str: if skip_source_detection.lower() == 'true': skip_source_detection = True else: skip_source_detection = False if type(use_adaptive_threshold) is str: if use_adaptive_threshold.lower() == 'true': use_adaptive_threshold = True else: use_adaptive_threshold = False if reference_ra_deg is not None and reference_dec_deg is not None: reference_ra_deg = float(reference_ra_deg) reference_dec_deg = float(reference_dec_deg) if not os.path.exists(image_name): print('Input image not found. Making empty image...') if not skip_source_detection: print('ERROR: Source detection cannot be done on an empty image') sys.exit(1) if reference_ra_deg is not None and reference_dec_deg is not None: image_name = mask_name + '.tmp' make_template_image(image_name, reference_ra_deg, reference_dec_deg, cellsize_deg=float(cellsize_deg)) else: print('ERROR: if image not found, a refernce position must be given') sys.exit(1) trim_by = float(trim_by) atrous_jmax = int(atrous_jmax) threshpix = float(threshpix) threshisl = float(threshisl) nsig = float(nsig) threshold = 0.0 if not skip_source_detection: if vertices_file is not None: # Modify the input image to blank the regions outside of the polygon temp_img = pim.image(image_name) image_name += '.blanked' temp_img.saveas(image_name, overwrite=True) input_img = pim.image(image_name) data = input_img.getdata() vertices = read_vertices(vertices_file) RAverts = vertices[0] Decverts = vertices[1] xvert = [] yvert = [] for RAvert, Decvert in zip(RAverts, Decverts): pixels = input_img.topixel([1, 1, Decvert*np.pi/180.0, RAvert*np.pi/180.0]) xvert.append(pixels[2]) # x -> Dec yvert.append(pixels[3]) # y -> RA poly = Polygon(xvert, yvert) # Find masked regions masked_ind = np.where(data[0, 0]) # Find distance to nearest poly edge and set to NaN those that # are outside the facet (dist < 0) dist = poly.is_inside(masked_ind[0], masked_ind[1]) outside_ind = np.where(dist < 0.0) if len(outside_ind[0]) > 0: data[0, 0, masked_ind[0][outside_ind], masked_ind[1][outside_ind]] = np.nan # Save changes input_img.putdata(data) if use_adaptive_threshold: # Get an estimate of the rms img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=150, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax, stop_at='isl') # Find min and max pixels max_neg_val = abs(np.min(img.ch0_arr)) max_neg_pos = np.where(img.ch0_arr == np.min(img.ch0_arr)) max_pos_val = abs(np.max(img.ch0_arr)) max_pos_pos = np.where(img.ch0_arr == np.max(img.ch0_arr)) # Estimate new thresh_isl from min pixel value's sigma, but don't let # it get higher than 1/2 of the peak's sigma threshisl_neg = 2.0 * max_neg_val / img.rms_arr[max_neg_pos][0] max_sigma = max_pos_val / img.rms_arr[max_pos_pos][0] if threshisl_neg > max_sigma / 2.0: threshisl_neg = max_sigma / 2.0 # Use the new threshold only if it is larger than the user-specified one if threshisl_neg > threshisl: threshisl = threshisl_neg if iterate_threshold: # Start with given threshold and lower it until we get at least one island nisl = 0 while nisl == 0: img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=150, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax) nisl = img.nisl threshpix /= 1.2 threshisl /= 1.2 if threshpix < 5.0: break else: img = bdsm.process_image(image_name, mean_map='zero', rms_box=rmsbox, thresh_pix=threshpix, thresh_isl=threshisl, atrous_do=atrous_do, ini_method='curvature', thresh='hard', adaptive_rms_box=adaptive_rmsbox, adaptive_thresh=150, rms_box_bright=rmsbox_bright, rms_map=True, quiet=True, atrous_jmax=atrous_jmax) if img.nisl == 0: if region_file is None or region_file == '[]': print('No islands found. Clean mask cannot be made.') sys.exit(1) else: # Continue on and use user-supplied region file skip_source_detection = True threshold = nsig * img.clipped_rms # Check if there are large islands preset (indicating that multi-scale # clean is needed) has_large_isl = False for isl in img.islands: if isl.size_active > 100: # Assuming normal sampling, a size of 100 pixels would imply # a source of ~ 10 beams has_large_isl = True if (region_file is not None and region_file != '[]' and skip_source_detection): # Copy region file and return if source detection was not done os.system('cp {0} {1}'.format(region_file.strip('[]"'), mask_name)) if threshold_format == 'float': return {'threshold_5sig': threshold} elif threshold_format == 'str_with_units': # This is done to get around the need for quotes around strings in casapy scripts # 'casastr/' is removed by the generic pipeline return {'threshold_5sig': 'casastr/{0}Jy'.format(threshold)} elif not skip_source_detection: img.export_image(img_type='island_mask', mask_dilation=0, outfile=mask_name, img_format=img_format, clobber=True) if (vertices_file is not None or trim_by > 0 or pad_to_size is not None or (region_file is not None and region_file != '[]') or skip_source_detection): # Alter the mask in various ways if skip_source_detection: # Read the image mask_im = pim.image(image_name) else: # Read the PyBDSM mask mask_im = pim.image(mask_name) data = mask_im.getdata() coordsys = mask_im.coordinates() if reference_ra_deg is not None and reference_dec_deg is not None: values = coordsys.get_referencevalue() values[2][0] = reference_dec_deg/180.0*np.pi values[2][1] = reference_ra_deg/180.0*np.pi coordsys.set_referencevalue(values) imshape = mask_im.shape() del(mask_im) if pad_to_size is not None: imsize = pad_to_size coordsys['direction'].set_referencepixel([imsize/2, imsize/2]) pixmin = (imsize - imshape[2]) / 2 if pixmin < 0: print("The padded size must be larger than the original size.") sys.exit(1) pixmax = pixmin + imshape[2] data_pad = np.zeros((1, 1, imsize, imsize), dtype=np.float32) data_pad[0, 0, pixmin:pixmax, pixmin:pixmax] = data[0, 0] new_mask = pim.image('', shape=(1, 1, imsize, imsize), coordsys=coordsys) new_mask.putdata(data_pad) else: new_mask = pim.image('', shape=imshape, coordsys=coordsys) new_mask.putdata(data) data = new_mask.getdata() if skip_source_detection: # Mask all pixels data[:] = 1 if vertices_file is not None: # Modify the clean mask to exclude regions outside of the polygon vertices = read_vertices(vertices_file) RAverts = vertices[0] Decverts = vertices[1] xvert = [] yvert = [] for RAvert, Decvert in zip(RAverts, Decverts): try: pixels = new_mask.topixel([0, 1, Decvert*np.pi/180.0, RAvert*np.pi/180.0]) except: pixels = new_mask.topixel([1, 1, Decvert*np.pi/180.0, RAvert*np.pi/180.0]) xvert.append(pixels[2]) # x -> Dec yvert.append(pixels[3]) # y -> RA poly = Polygon(xvert, yvert) # Find masked regions masked_ind = np.where(data[0, 0]) # Find distance to nearest poly edge and unmask those that # are outside the facet (dist < 0) dist = poly.is_inside(masked_ind[0], masked_ind[1]) outside_ind = np.where(dist < 0.0) if len(outside_ind[0]) > 0: data[0, 0, masked_ind[0][outside_ind], masked_ind[1][outside_ind]] = 0 if trim_by > 0.0: sh = np.shape(data) margin = int(sh[2] * trim_by / 2.0 ) data[0, 0, 0:sh[2], 0:margin] = 0 data[0, 0, 0:margin, 0:sh[3]] = 0 data[0, 0, 0:sh[2], sh[3]-margin:sh[3]] = 0 data[0, 0, sh[2]-margin:sh[2], 0:sh[3]] = 0 if region_file is not None and region_file != '[]': # Merge the CASA regions with the mask casa_polys = read_casa_polys(region_file.strip('[]"'), new_mask) for poly in casa_polys: # Find unmasked regions unmasked_ind = np.where(data[0, 0] == 0) # Find distance to nearest poly edge and mask those that # are inside the casa region (dist > 0) dist = poly.is_inside(unmasked_ind[0], unmasked_ind[1]) inside_ind = np.where(dist > 0.0) if len(inside_ind[0]) > 0: data[0, 0, unmasked_ind[0][inside_ind], unmasked_ind[1][inside_ind]] = 1 # Save changes new_mask.putdata(data) if img_format == 'fits': new_mask.tofits(mask_name, overwrite=True) elif img_format == 'casa': new_mask.saveas(mask_name, overwrite=True) else: print('Output image format "{}" not understood.'.format(img_format)) sys.exit(1) if not skip_source_detection: if threshold_format == 'float': return {'threshold_5sig': nsig * img.clipped_rms, 'multiscale': has_large_isl} elif threshold_format == 'str_with_units': # This is done to get around the need for quotes around strings in casapy scripts # 'casastr/' is removed by the generic pipeline return {'threshold_5sig': 'casastr/{0}Jy'.format(nsig * img.clipped_rms), 'multiscale': has_large_isl} else: return {'threshold_5sig': '0.0'}
def on_press(event): """ Handle key presses """ global fig, at, selected_direction, choose_from_list if event.key == 'u': # Update plot choose_from_list = False update_plot() return elif event.key == 'c': # Open selfcal images (if any) choose_from_list = False if selected_direction is None: return selfcal_images = find_selfcal_images(selected_direction) if len(selfcal_images) > 0: info = 'Opening selfcal images for {}...'.format( selected_direction.name) if hasaplpy: # Update the text box as the call below takes a few seconds c = at.get_child() c.set_text(info) fig.canvas.draw() make_selfcal_images.main(selfcal_images, interactive=True, facet_name=selected_direction.name) else: if os.path.exists('/tmp/tempimage'): shutil.rmtree('/tmp/tempimage') im = pim.image(selfcal_images) im.view() else: info = 'No selfcal images exist for {}'.format( selected_direction.name) elif event.key == 'i': # Open full facet images (if any) if selected_direction is None: return facet_images, facetimage_ops = find_facet_images(selected_direction) if len(facet_images) == 0: info = 'No image of facet exists for {}'.format( selected_direction.name) else: info = 'Load facet image from (choose one):' for opindx, (img, fimg_op) in enumerate( zip(facet_images, facetimage_ops)): info += '\n ({0}) {1}'.format(opindx + 1, fimg_op) choose_from_list = True elif event.key == 'v': # Open full facet images (if any) choose_from_list = False if selected_direction is None: return facet_verify_images = find_facet_verify_images(selected_direction) if len(facet_verify_images) == 0: info = 'No verify image of facet exists for {}'.format( selected_direction.name) else: info = 'Opening selfcal verification images for {}...'.format( selected_direction.name) display_image(facet_verify_images) elif event.key in [str(num + 1) for num in range(9)]: # Open image (from list given on "i" press) if choose_from_list: facet_images, facetimage_ops = find_facet_images( selected_direction) if int(event.key) <= len(facet_images): display_image(facet_images[int(event.key) - 1]) return else: return elif event.key == 't': # Open fast TEC selfcal plots (if any) choose_from_list = False if selected_direction is None: return selfcal_plots = find_selfcal_tec_plots(selected_direction) if len(selfcal_plots) > 0: info = 'Opening selfcal TEC solution plots for {}...'.format( selected_direction.name) os.system(options['image_display'] + ' {} &'.format(' '.join(selfcal_plots))) else: info = 'Final selfcal solutions do not exist for {}'.format( selected_direction.name) elif event.key == 'g': # Open slow Gain selfcal plots (if any) choose_from_list = False if selected_direction is None: return selfcal_plots = find_selfcal_gain_plots(selected_direction) if len(selfcal_plots) > 0: info = 'Opening selfcal Gain solution plots for {}...'.format( selected_direction.name) os.system(options['image_display'] + ' {} &'.format(' '.join(selfcal_plots))) else: info = 'Final selfcal solutions do not exist for {}'.format( selected_direction.name) elif event.key == 'h': choose_from_list = False info = 'Reprinting instructions' show_instructions() return else: return # Update info box c = at.get_child() c.set_text(info) fig.canvas.draw()