def align_norm(fnlist,uncertlist=None): """Aligns a set of images to each other, as well as normalizing the images to the same average brightness. Both the alignment and normalization are accomplished through stellar photometry using the IRAF routine 'daophot'. The centroids of a handful of stars are found and used to run the IRAF routine 'imalign'. The instrumental magnitudes of the stars are used to determine by how much each image must be scaled for the photometry to match across images. The images are simply updated with their rescaled, shifted selves. This overwrites the previous images and adds the header keyword 'fpphot' to the images. A handful of temporary files are created during this process, which should all be deleted by the routine at the end. But if it is interrupted, they might not be. If the uncertainty images exist, this routine also shifts them by the same amounts as the intensity images, as well as updating the uncertainty values for both the new normalization and the uncertainties in normalizing the images. Inputs: fnlist -> List of strings, each the path to a fits image. uncertlist (optional) -> List of paths to uncertainty images. """ #Fit for the sky background level _skyavg, skysig = fit_sky_level(fnlist) #Get image FWHMs fwhm = np.empty(len(fnlist)) firstimage = openfits(fnlist[0]) toggle = firstimage[0].header.get("fpfwhm") axcen = firstimage[0].header.get("fpaxcen") aycen = firstimage[0].header.get("fpaycen") arad = firstimage[0].header.get("fparad") firstimage.close() if axcen == None: print "Error! Images have not yet been aperture-masked! Do this first!" crash() if toggle == None: print "Warning: FWHMs have not been measured! Assuming 5 pixel FWHM for all images." for i in range(len(fnlist)): fwhm[i] = 5 else: for i in range(len(fnlist)): image = openfits(fnlist[i]) fwhm[i] = image[0].header["fpfwhm"] image.close() #Identify objects in the fields coolist = identify_objects(fnlist,skysig,fwhm) #Match objects between fields coofile = match_objects(coolist) #Do aperture photometry on the matched objects photlist = do_phot(fnlist,coofile,fwhm,skysig) #Read the photometry files x, y, mag, dmag = read_phot(photlist) #Calculate the normalizations norm, dnorm = calc_norm(mag,dmag) #Normalize the images (and optionally, the uncertainty images) for i in range(len(fnlist)): print "Normalizing image "+fnlist[i] image = openfits(fnlist[i],mode="update") if not (uncertlist is None): uncimage = openfits(uncertlist[i],mode="update") uncimage[0].data = np.sqrt(norm[i]**2*uncimage[0].data**2 + dnorm[i]**2*image[0].data**2) uncimage.close() image[0].data *= norm[i] image.close() #Calculate the shifts for i in range(x.shape[1]): x[:,i] = -(x[:,i] - x[0,i]) y[:,i] = -(y[:,i] - y[0,i]) xshifts = np.average(x,axis=1) yshifts = np.average(y,axis=1) #Shift the images (and optionally, the uncertainty images) iraf.images(_doprint=0) iraf.immatch(_doprint=0) for i in range(len(fnlist)): print "Shifting image "+fnlist[i] iraf.geotran(input=fnlist[i], output=fnlist[i], geometry="linear", xshift=xshifts[i], yshift=yshifts[i], database="", verbose="no") if not (uncertlist is None): iraf.geotran(input=uncertlist[i], output=uncertlist[i], geometry="linear", xshift=xshifts[i], yshift=yshifts[i], database="", verbose="no") #Update the image headers for i in range(len(fnlist)): image = openfits(fnlist[i],mode="update") image[0].header["fpphot"]="True" image[0].header["fpxcen"]+=xshifts[i] image[0].header["fpycen"]+=yshifts[i] image[0].header["fpaxcen"]+=xshifts[i] image[0].header["fpaycen"]+=yshifts[i] image.close() #Clean up the coordinate file list clean_files(fnlist) remove(coofile) for i in range(len(photlist)): remove(photlist[i]) return