def make_mosaic_wcs(filenames, rot=None, scale=None): """Combine WCSs from all input files into a single meta-WCS Parameters ---------- filenames : list list of filenames to process rot : float desired rotation of meta-WCS. Default value is None. scale : float desired scale of meta-WCS. Default value is None. Returns -------- mosaic_wcs : HSTWCS object the merged composite WCS """ if not isinstance(filenames, list): filenames = [filenames] # Compile list of WCSs for all chips from all input filenames hstwcs_list = [] for f in filenames: hstwcs_list.extend([get_hstwcs(f, extnum) for extnum in get_extns(f)]) # Combine them into a single mosaic WCS output_wcs = utils.output_wcs(hstwcs_list, undistort=True) output_wcs.wcs.cd = make_perfect_cd(output_wcs) mosaic_wcs = mergeWCS(output_wcs, {'rot': rot, 'scale': scale}) return mosaic_wcs
def create_output_wcs(input_images, make_coverage_map=False): """ Calculates a WCS for the final reference frame This function is used to calculate the WCS for the final reference frame for the photometric catalogs, peak map and coverage map. The WCS has the NAXIS keywords set large enough to encompass all input images completely. Parameters ---------- input_images : list List of image filenames (strings). Returns ------- output_wcs : HSTWCS WCS object for the final reference frame. Like an Astropy WCS. """ hst_wcs_list = [] for f in input_images: hdu = fits.open(f) for i, ext in enumerate(hdu): if 'SCI' in ext.name: hst_wcs_list.append(HSTWCS(hdu, ext=i)) output_wcs = utils.output_wcs(hst_wcs_list, undistort=True) output_wcs.wcs.cd = make_perfect_cd(output_wcs) print 'The output WCS is the following: ' print output_wcs return output_wcs
def build_self_reference(filename, wcslist=None): """ This function creates a reference, undistorted WCS that can be used to apply a correction to the WCS of the input file. PARAMETERS ---------- filename : str Filename of image which will be corrected, and which will form the basis of the undistorted WCS wcslist : list, optional List of HSTWCS objects for all SCI extensions in input file. If None, will create using `wcsutil.HSTWCS` on each identified SCI extension identified in `filename` Syntax ------- This function can be used with the following syntax to apply a shift/rot/scale change to the same image: >>> import buildref >>> from drizzlepac import updatehdr >>> filename = "jce501erq_flc.fits" >>> wcslin = buildref.build_self_reference(filename) >>> updatehdr.updatewcs_with_shift(filename,wcslin,xsh=49.5694, ysh=19.2203, rot = 359.998, scale = 0.9999964) """ if 'sipwcs' in filename: sciname = 'sipwcs' else: sciname = 'sci' if wcslist is None: numSci = countExtn(filename, extname=sciname.upper()) wcslist = [] for extnum in range(numSci): wcslist.append(read_hlet_wcs(filename, ext=(sciname, extnum + 1))) wcslin = utils.output_wcs(wcslist) wcsbase = wcslin.wcs customwcs = build_hstwcs(wcsbase.crval[0], wcsbase.crval[1], wcsbase.crpix[0], wcsbase.crpix[1], wcslin._naxis1, wcslin._naxis2, wcslin.pscale, wcslin.orientat) return customwcs
def to_wcs(self): """ Combine `HSTWCS` objects from all `members` and return a new `HSTWCS` object. If no `members`, return `None`. .. warning:: This cannot return WCS of intersection. """ wcs_list = self._indv_mem_wcslist() n = len(wcs_list) if n > 1: wcs = output_wcs(wcs_list) elif n == 1: wcs = wcs_list[0] else: wcs = None return wcs
def make_mosaic_wcs(filenames, rot=None, scale=None): """Combine WCSs from all input files into a single meta-WCS Parameters ---------- filenames : list list of filenames to process rot : float desired rotation of meta-WCS. Default value is None. scale : float desired scale of meta-WCS. Default value is None. Returns -------- mosaic_wcs : HSTWCS object the merged composite WCS """ if not isinstance(filenames, list): filenames = [filenames] # Compile list of WCSs for all chips from all input filenames hstwcs_list = [] for f in filenames: hstwcs_list.extend([get_hstwcs(f, extnum) for extnum in get_extns(f)]) # Combine them into a single mosaic WCS output_wcs = utils.output_wcs(hstwcs_list, undistort=True) output_wcs.wcs.cd = make_perfect_cd(output_wcs) # Apply each parameter in order, as this is effectively what is # done by AstroDrizzle. This insures that all rounding effects # are applied if rot is not None: mosaic_wcs = mergeWCS(output_wcs, {'rot': rot}) else: mosaic_wcs = output_wcs if scale is not None: mosaic_wcs = mergeWCS(mosaic_wcs, {'rot':rot, 'scale': scale}) return mosaic_wcs
def build_reference_wcs(inputs, sciname='sci'): """Create the reference WCS based on all the inputs for a field""" # start by creating a composite field-of-view for all inputs wcslist = [] for img in inputs: nsci = countExtn(img) for num in range(nsci): extname = (sciname, num + 1) if sciname == 'sci': extwcs = wcsutil.HSTWCS(img, ext=extname) else: # Working with HDRLET as input and do the best we can... extwcs = read_hlet_wcs(img, ext=extname) wcslist.append(extwcs) # This default output WCS will have the same plate-scale and orientation # as the first chip in the list, which for WFPC2 data means the PC. # Fortunately, for alignment, this doesn't matter since no resampling of # data will be performed outwcs = utils.output_wcs(wcslist) return outwcs
def build_reference_wcs(inputs, sciname='sci'): """Create the reference WCS based on all the inputs for a field""" # start by creating a composite field-of-view for all inputs wcslist = [] for img in inputs: nsci = countExtn(img) for num in range(nsci): extname = (sciname, num+1) if sciname == 'sci': extwcs = wcsutil.HSTWCS(img, ext=extname) else: # Working with HDRLET as input and do the best we can... extwcs = read_hlet_wcs(img, ext=extname) wcslist.append(extwcs) # This default output WCS will have the same plate-scale and orientation # as the first chip in the list, which for WFPC2 data means the PC. # Fortunately, for alignment, this doesn't matter since no resampling of # data will be performed outwcs = utils.output_wcs(wcslist) return outwcs
def make_outputwcs(imageObjectList, output, configObj=None, perfect=False): """ Computes the full output WCS based on the set of input imageObjects provided as input, along with the pre-determined output name from process_input. The user specified output parameters are then used to modify the default WCS to produce the final desired output frame. The input imageObjectList has the outputValues dictionary updated with the information from the computed output WCS. It then returns this WCS as a WCSObject(imageObject) instance. """ if not isinstance(imageObjectList, list): imageObjectList = [imageObjectList] # Compute default output WCS, replace later if user specifies a refimage hstwcs_list = [] undistort = True for img in imageObjectList: chip_wcs = copy.deepcopy(img.getKeywordList('wcs')) # IF the user turned off use of coeffs (coeffs==False) if not configObj['coeffs']: for cw in chip_wcs: # Turn off distortion model for each input cw.sip = None cw.cpdis1 = None cw.cpdis2 = None cw.det2im = None undistort = False hstwcs_list += chip_wcs if not undistort and len(hstwcs_list) == 1: default_wcs = hstwcs_list[0].deepcopy() else: default_wcs = utils.output_wcs(hstwcs_list, undistort=undistort) if perfect: default_wcs.wcs.cd = make_perfect_cd(default_wcs) # Turn WCS instances into WCSObject instances outwcs = createWCSObject(output, default_wcs, imageObjectList) # Merge in user-specified attributes for the output WCS # as recorded in the input configObj object. final_pars = DEFAULT_WCS_PARS.copy() # More interpretation of the configObj needs to be done here to translate # the input parameter names to those understood by 'mergeWCS' as defined # by the DEFAULT_WCS_PARS dictionary. single_step = configObj[util.getSectionName(configObj, 3)] singleParDict = configObj[util.getSectionName(configObj, '3a')].copy() if single_step['driz_separate'] and singleParDict['driz_sep_wcs']: single_pars = DEFAULT_WCS_PARS.copy() del singleParDict['driz_sep_wcs'] keyname = 'driz_sep_' for key in singleParDict: k = key[len(keyname):] if k != 'refimage': single_pars[k] = singleParDict[key] # Now, account for any user-specified reference image def_wcs = default_wcs.deepcopy() single_ref = singleParDict[keyname + 'refimage'] if single_ref: if isinstance(single_ref, wcs.WCS): default_wcs = single_ref else: default_wcs = wcsutil.HSTWCS(singleParDict[keyname + 'refimage']) # ## Create single_wcs instance based on user parameters outwcs.single_wcs = mergeWCS(default_wcs, single_pars) # restore global default WCS to original value so single_drizzle WCS does not # influence final_drizzle WCS default_wcs = def_wcs.deepcopy() final_step = configObj[util.getSectionName(configObj, 7)] finalParDict = configObj[util.getSectionName(configObj, '7a')].copy() if final_step['driz_combine'] and finalParDict['final_wcs']: del finalParDict['final_wcs'] keyname = 'final_' for key in finalParDict: k = key[len(keyname):] if k != 'refimage': final_pars[k] = finalParDict[key] # Now, account for any user-specified reference image final_ref = finalParDict[keyname + 'refimage'] if final_ref: if isinstance(final_ref, wcs.WCS): default_wcs = final_ref if hasattr(final_ref, 'filename'): rootname = final_ref.filename else: rootname = "" print('Creating OUTPUT WCS from WCS object based on {}'.format(rootname)) else: rootname, extnum = fileutil.parseFilename(finalParDict[keyname + 'refimage']) extnum = util.findWCSExtn(finalParDict[keyname + 'refimage']) print('Creating OUTPUT WCS from {}[{}]'.format(rootname, extnum)) default_wcs = wcsutil.HSTWCS('{}[{}]'.format(rootname, extnum)) # ## Create single_wcs instance based on user parameters outwcs.final_wcs = mergeWCS(default_wcs, final_pars) outwcs.wcs = outwcs.final_wcs.copy() # Apply user settings to create custom output_wcs instances # for each drizzle step updateImageWCS(imageObjectList, outwcs) return outwcs
def make_final_table(input_images, save_peakmap=True, min_detections=3, drizzle=False): """ Wrapper for final photometric matching and averaging. This function wraps around several utility functions to match, organize, and average the hst1pass photometric sources to create a final catalog. It does so by: 1. projecting all sources detected in the input images into a final reference frame creating a map of the detections 2. Matching sources from the catalogs corresponding to the input images 3. Calculates the statistics of photometric quantities from the measurements in the catalogs for each source detected at least the number of times specified by the min_detections parameter. If saved, the peakmap shows how many times a source was detected at certain pixel of the final reference frame in the catalogs. Parameters ---------- input_images : list List of image filenames (strings). Must be fits files. save_peakmap : bool, optional Flag to save the map of detections (peakmap). Default True min_detections : int or float, optional If int: minimum number of images a source must be detected in to be included in the final catalog. If float: minimum fraction of images a source must be detected in to be included in the final catalog. Default is 3. drizzle : bool, optional Make a drizzled image on the same grid as the reference frame? Default False. The image output from this is not optimized so it should only be treated as a simple preview. Returns ------- final_catalog : astropy.table.Table Final averaged photometric catalog. See documentation of collate() for more information. """ # Restructure this to read in tables, get meta info, as well as # HSTWCS objects to flexibly create output WCS, cov map input_catalogs = [] metas = { 'filters': [], 'exptimes': [], 'detchips': [], 'wcss': [], 'apcorrs': [], 'photflams': [] } for f in input_images: hdr = fits.getheader(f) if hdr['INSTRUME'] == 'ACS': filt = hdr['FILTER1'] if filt == 'CLEAR1L' or filt == 'CLEAR1S': filt = hdr['FILTER2'] else: filt = hdr['FILTER'] cat_wildcard = f.replace('.fits', '_sci?_xyrd.cat') im_cats = sorted(glob.glob(cat_wildcard)) exptime = hdr['EXPTIME'] photflam = hdr['PHOTFLAM'] input_catalogs += im_cats metas['filters'] += [filt] * len(im_cats) metas['exptimes'] += [exptime] * len(im_cats) metas['photflams'] += [photflam] * len(im_cats) for i, cat in enumerate(im_cats): im_data = fits.getdata(f, ('sci', i + 1)) metas['apcorrs'].append(get_apcorr(im_data, cat)) det = [hdr['DETECTOR']] det0 = det[0] if det0 != 'IR': # Determine which chip for UVIS or WFC (needed for subarray) det = [det0 + str(fits.getval(f, 'CCDCHIP', 1))] wcslist = [HSTWCS(f, ext=('sci', 1))] if len(im_cats) == 2: det += [det0 + str(fits.getval(f, 'CCDCHIP', ('sci', 2)))] wcslist += [HSTWCS(f, ext=('sci', 2))] else: wcslist = [HSTWCS(f, ext=('sci', 1))] metas['detchips'] += det metas['wcss'] += wcslist outwcs = utils.output_wcs(metas['wcss'], undistort=True) outwcs.wcs.cd = make_perfect_cd(outwcs) peakmap, all_int_coords = make_peakmap(input_images, outwcs, save_peakmap=save_peakmap) cov_map = create_coverage_map(metas['wcss'], outwcs) pri_hdu = fits.PrimaryHDU() im_hdu = fits.hdu.ImageHDU(data=cov_map, header=outwcs.to_header()) hdul = fits.HDUList([pri_hdu, im_hdu]) hdul.writeto('python_coverage_map.fits', overwrite=True) final_catalog = process_peaks(peakmap, all_int_coords, input_catalogs, outwcs, metas, cov_map, min_detections=min_detections) final_catalog.write('{}_final_cat.txt'.format(filt), format='ascii.commented_header', overwrite=True) if drizzle: simple_drizzle(input_images, cov_map, 'python_coverage_map.fits', filt) return final_catalog
def vmosaic(fnames, outwcs=None, ref_wcs=None, ext=None, extname=None, undistort=True, wkey='V', wname='VirtualMosaic', plot=False, clobber=False): """ Create a virtual mosaic using the WCS of the input images. Parameters ---------- fnames: a string or a list a string or a list of filenames, or a list of wcsutil.HSTWCS objects outwcs: an HSTWCS object if given, represents the output tangent plane if None, the output WCS is calculated from the input observations. ref_wcs: an HSTWCS object if output wcs is not given, this will be used as a reference for the calculation of the output WCS. If ref_wcs is None and outwcs is None, then the first observation in th einput list is used as reference. ext: an int, a tuple or a list an int - represents a FITS extension, e.g. 0 is the primary HDU a tuple - uses the notation (extname, extver), e.g. ('sci',1) Can be a list of integers or tuples representing FITS extensions extname: string the value of the EXTNAME keyword for the extensions to be used in the mosaic undistort: boolean (default: True) undistort (or not) the output WCS wkey: string default: 'V' one character A-Z to be used to record the virtual mosaic WCS as an alternate WCS in the headers of the input files. wname: string default: 'VirtualMosaic a string to be used as a WCSNAME value for the alternate WCS representign the virtual mosaic plot: boolean if True and matplotlib is installed will make a plot of the tangent plane and the location of the input observations. clobber: boolean This covers the case when an alternate WCS with the requested key already exists in the header of the input files. if clobber is True, it will be overwritten if False, it will compute the new one but will not write it to the headers. Notes ----- The algorithm is: 1. If output WCS is not given it is calculated from the input WCSes. The first image is used as a reference, if no reference is given. This represents the virtual mosaic WCS. 2. For each input observation/chip, an HSTWCS object is created and its footprint on the sky is calculated (using only the four corners). 3. For each input observation the footprint is projected on the output tangent plane and the virtual WCS is recorded in the header. """ wcsobjects = readWCS(fnames, ext, extname) if outwcs != None: outwcs = outwcs.deepcopy() else: if ref_wcs != None: outwcs = utils.output_wcs(wcsobjects, ref_wcs=ref_wcs, undistort=undistort) else: outwcs = utils.output_wcs(wcsobjects, undistort=undistort) if plot: outc=np.array([[0.,0], [outwcs._naxis1, 0], [outwcs._naxis1, outwcs._naxis2], [0, outwcs._naxis2], [0, 0]]) plt.plot(outc[:,0], outc[:,1]) for wobj in wcsobjects: outcorners = outwcs.wcs_world2pix(wobj.calc_footprint(),1) if plot: plt.plot(outcorners[:,0], outcorners[:,1]) objwcs = outwcs.deepcopy() objwcs.wcs.crpix = objwcs.wcs.crpix - (outcorners[0]) updatehdr(wobj.filename, objwcs,wkey=wkey, wcsname=wname, ext=wobj.extname, clobber=clobber) return outwcs
def create_astrometric_catalog(inputs, **pars): """Create an astrometric catalog that covers the inputs' field-of-view. Parameters =========== input : str Filenames of images to be aligned to astrometric catalog catalog : str, optional Name of catalog to extract astrometric positions for sources in the input images' field-of-view. Default: GSC241. Options available are documented on the catalog web page. output : str, optional Filename to give to the astrometric catalog read in from the master catalog web service. If 'None', no file will be written out. Default: ref.cat gaia_only : bool, optional Specify whether or not to only use sources from GAIA in output catalog Default: False note :: This function will point to astrometric catalog web service defined through the use of the ASTROMETRIC_CATALOG_URL environment variable. Returns ======= ref_table : object Astropy Table object of the catalog """ # interpret input parameters catalog = pars.get("catalog", 'GSC241') output = pars.get("output", 'ref_cat.ecsv') gaia_only = pars.get("gaia_only", False) table_format = pars.get("table_format", 'ascii.ecsv') inputs, _ = parseinput.parseinput(inputs) # start by creating a composite field-of-view for all inputs wcslist = [] for img in inputs: nsci = fu.countExtn(img) for num in range(nsci): extname = '{}[sci,{}]'.format(img, num+1) wcslist.append(stwcs.wcsutil.HSTWCS(extname)) # This default output WCS will have the same plate-scale and orientation # as the first chip in the list, which for WFPC2 data means the PC. # Fortunately, for alignment, this doesn't matter since no resampling of # data will be performed outwcs = utils.output_wcs(wcslist) radius = compute_radius(outwcs) ra, dec = outwcs.wcs.crval # perform query for this field-of-view ref_dict = get_catalog(ra, dec, sr=radius, catalog=catalog) colnames = ('ra','dec', 'mag', 'objID', 'GaiaID') col_types = ('f8', 'f8', 'f4', 'U25', 'U25') ref_table = Table(names = colnames, dtype=col_types) # extract just the columns we want... num_sources = 0 for source in ref_dict: if 'GAIAsourceID' in source: g = source['GAIAsourceID'] if gaia_only and g.strip() is '': continue else: g = -1 # indicator for no source ID extracted r = float(source['ra']) d = float(source['dec']) m = float(source['mag']) o = source['objID'] num_sources += 1 ref_table.add_row((r,d,m,o,g)) # Write out table to a file, if specified if output: ref_table.write(output, format=table_format) print("Created catalog '{}' with {} sources".format(output, num_sources)) return ref_table
def make_outputwcs(imageObjectList, output, configObj=None, perfect=False): """ Computes the full output WCS based on the set of input imageObjects provided as input, along with the pre-determined output name from process_input. The user specified output parameters are then used to modify the default WCS to produce the final desired output frame. The input imageObjectList has the outputValues dictionary updated with the information from the computed output WCS. It then returns this WCS as a WCSObject(imageObject) instance. """ if not isinstance(imageObjectList,list): imageObjectList = [imageObjectList] # Compute default output WCS, replace later if user specifies a refimage hstwcs_list = [] undistort=True for img in imageObjectList: chip_wcs = copy.deepcopy(img.getKeywordList('wcs')) # IF the user turned off use of coeffs (coeffs==False) if not configObj['coeffs']: for cw in chip_wcs: # Turn off distortion model for each input cw.sip = None cw.cpdis1 = None cw.cpdis2 = None cw.det2im = None undistort=False hstwcs_list += chip_wcs if not undistort and len(hstwcs_list) == 1: default_wcs = hstwcs_list[0].deepcopy() else: default_wcs = utils.output_wcs(hstwcs_list, undistort=undistort) if perfect: default_wcs.wcs.cd = make_perfect_cd(default_wcs) # Turn WCS instances into WCSObject instances outwcs = createWCSObject(output, default_wcs, imageObjectList) # Merge in user-specified attributes for the output WCS # as recorded in the input configObj object. final_pars = DEFAULT_WCS_PARS.copy() # More interpretation of the configObj needs to be done here to translate # the input parameter names to those understood by 'mergeWCS' as defined # by the DEFAULT_WCS_PARS dictionary. single_step = configObj[util.getSectionName(configObj, 3)] singleParDict = configObj[util.getSectionName(configObj, '3a')].copy() if single_step['driz_separate'] and singleParDict['driz_sep_wcs']: single_pars = DEFAULT_WCS_PARS.copy() del singleParDict['driz_sep_wcs'] keyname = 'driz_sep_' for key in singleParDict: k = key[len(keyname):] if k != 'refimage': single_pars[k] = singleParDict[key] # Now, account for any user-specified reference image def_wcs = default_wcs.deepcopy() if singleParDict[keyname + 'refimage']: default_wcs = wcsutil.HSTWCS(singleParDict[keyname + 'refimage']) ### Create single_wcs instance based on user parameters outwcs.single_wcs = mergeWCS(default_wcs, single_pars) # restore global default WCS to original value so single_drizzle WCS does not # influence final_drizzle WCS default_wcs = def_wcs.deepcopy() final_step = configObj[util.getSectionName(configObj,7)] finalParDict = configObj[util.getSectionName(configObj,'7a')].copy() if final_step['driz_combine'] and finalParDict['final_wcs']: del finalParDict['final_wcs'] keyname = 'final_' for key in finalParDict: k = key[len(keyname):] if k != 'refimage': final_pars[k] = finalParDict[key] # Now, account for any user-specified reference image if finalParDict[keyname + 'refimage']: rootname,extnum = fileutil.parseFilename(finalParDict[keyname+'refimage']) extnum = util.findWCSExtn(finalParDict[keyname+'refimage']) print('Creating OUTPUT WCS from {}[{}]'.format(rootname,extnum)) default_wcs = wcsutil.HSTWCS('{}[{}]'.format(rootname,extnum)) ### Create single_wcs instance based on user parameters outwcs.final_wcs = mergeWCS(default_wcs, final_pars) outwcs.wcs = outwcs.final_wcs.copy() # Apply user settings to create custom output_wcs instances # for each drizzle step updateImageWCS(imageObjectList, outwcs) return outwcs