def make_stamp(size=(100, 100), fwhm=1.0, psfname=None, offset=0.): """Make a postage stamp of the given size, including a PSF :param size: The size in pixels, 2-element tuple :param fwhm: For a single gaussian PSF, the FWHM of the PSF in pixels :param offset: The offset of the position of the object from the stamp center. Useful for playing with subpixel offsets. :param psfname: The path and filename of the gaussian mixture PSF parameters. """ # --- Get a stamp with a give size ---- stamp = PostageStamp() size = np.array(size).astype(int) stamp.nx, stamp.ny = size stamp.npix = int(stamp.nx * stamp.ny) # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- # override the WCS so coordinates are in pixels # The scale matrix D stamp.scale = np.eye(2) # The sky coordinates of the reference pixel stamp.crval = np.zeros([2]) + offset # The pixel coordinates of the reference pixel stamp.crpix = np.zeros([2]) # --- Add the PSF --- if psfname is not None: import pickle with open(psfname, 'rb') as pf: pdat = pickle.load(pf) oversample, pcenter = 8, 504 - 400 answer = pdat[6][2] stamp.psf = pointspread.make_psf(answer, oversample=oversample, center=pcenter) else: stamp.psf = pointspread.PointSpreadFunction() stamp.psf.covariances *= fwhm / 2.355 # --- Add extra information --- #stamp.full_header = dict(hdr) return stamp
def get_stamp(n, dx=1): stamp = PostageStamp() stamp.nx, stamp.ny = n, n stamp.npix = stamp.nx * stamp.ny # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) stamp.scale = np.eye(2) / dx stamp.dpix_dsky = np.eye(2) / dx stamp.crval = np.zeros([2]) stamp.crpix = np.zeros([2]) stamp.psf = PointSpreadFunction() return stamp
def make_stamp(size=(100, 100), fwhm=1.0, psfname=None, offset=0., filtername='dummy', oversample=8, psfcenter=104): """Make a postage stamp of the given size, including a PSF :param size: The size in pixels, 2-element tuple :param fwhm: For a single gaussian PSF, the FWHM of the PSF in pixels :param offset: The offset of the position of the object from the stamp center. Useful for playing with subpixel offsets. :param psfname: The path and filename of the gaussian mixture PSF parameters. """ # --- Get a stamp with a give size ---- stamp = PostageStamp() size = np.array(size).astype(int) stamp.nx, stamp.ny = size # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- # override the WCS so coordinates are in pixels # The scale matrix D stamp.scale = np.eye(2) # The sky coordinates of the reference pixel stamp.crval = np.zeros([2]) + offset # The pixel coordinates of the reference pixel stamp.crpix = np.zeros([2]) # --- Add the PSF --- stamp.psf = get_psf(psfname, fwhm, 2, 6, oversample, psfcenter) # --- Add extra information --- #stamp.full_header = dict(hdr) stamp.filtername = filtername return stamp
def make_stamp(imname, center=(None, None), size=(None, None), center_type='pixels', psfname=None, fwhm=1.0): """Make a postage stamp around the given position using the given image name """ data = fits.getdata(imname) hdr = fits.getheader(imname) crpix = np.array([hdr['CRPIX1'], hdr['CRPIX2']]) crval = np.array([hdr['CRVAL1'], hdr['CRVAL2']]) CD = np.array([[hdr['CD1_1'], hdr['CD1_2']], [hdr['CD2_1'], hdr['CD2_2']]]) # Pull slices and transpose to get to an axis order that makes sense to me # and corresponds with the wcs keyword ordering im = data[0, :, :].T err = data[1, :, :].T # ---- Extract subarray ----- center = np.array(center) # here we get the center coordinates in pixels (accounting for the transpose above) if center_type == 'celestial': world = np.append(center, 0) #hdr.update(NAXIS=2) ast = apy_wcs.WCS(hdr) center = ast.wcs_world2pix(world[None, :], 0)[0, :2] # --- here is much mystery --- size = np.array(size) lo, hi = (center - 0.5 * size).astype(int), (center + 0.5 * size).astype(int) xinds = slice(int(lo[0]), int(hi[0])) yinds = slice(int(lo[1]), int(hi[1])) crpix_stamp = np.floor(0.5 * size) crval_stamp = crpix_stamp + lo W = np.eye(2) if center_type == 'celestial': crval_stamp = ast.wcs_pix2world(np.append(crval_stamp, 0.)[None,:], 0)[0, :2] W[0, 0] = np.cos(np.deg2rad(crval_stamp[-1])) # --- Add image and uncertainty data to Stamp ---- stamp = PostageStamp() stamp.pixel_values = im[xinds, yinds] stamp.ierr = 1./err[xinds, yinds] bad = ~np.isfinite(stamp.ierr) stamp.pixel_values[bad] = 0.0 stamp.ierr[bad] = 0.0 stamp.ierr = stamp.ierr.flatten() stamp.nx, stamp.ny = stamp.pixel_values.shape stamp.npix = stamp.nx * stamp.ny # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- stamp.crpix = crpix_stamp stamp.crval = crval_stamp stamp.scale = np.matmul(np.linalg.inv(CD), W) stamp.pixcenter_in_full = center stamp.lo = lo # --- Add the PSF --- if psfname is not None: import pickle with open(psfname, 'rb') as pf: pdat = pickle.load(pf) oversample, center = 8, 504 - 400 answer = pdat[6][2] stamp.psf = pointspread.make_psf(answer, oversample=oversample, center=center) else: stamp.psf = pointspread.PointSpreadFunction() stamp.psf.covaraniaces *= fwhm/2.355 # --- Add extra information --- stamp.full_header = dict(hdr) return stamp
def xdf_pixel_stamp(imroot, psfname, center, size, fwhm=3.0, background=0.0, filtername="H", base=base): """Make a stamp with pixel coordinate information. """ impath = os.path.join(base, "data", "images") psfpath = os.path.join(base, "data", "psfs", "mixtures") # Values used to produce the MMSE catalog im, wght, rms, cutout, wcs = get_cutout(impath, imroot, mmse_position, mmse_size) # transpose to get x coordinate on the first axis im = im.T err = rms.T CD = wcs.wcs.cd # ---- Extract subarray ----- center = np.array(center) # --- here is much mystery --- size = np.array(size) lo, hi = (center - 0.5 * size).astype(int), (center + 0.5 * size).astype(int) xinds = slice(int(lo[0]), int(hi[0])) yinds = slice(int(lo[1]), int(hi[1])) crpix_stamp = np.floor(0.5 * size) crval_stamp = crpix_stamp + lo W = np.eye(2) # --- MAKE STAMP ------- # --- Add image and uncertainty data to Stamp ---- stamp = PostageStamp() stamp.pixel_values = im[xinds, yinds] - background stamp.ierr = 1. / err[xinds, yinds] bad = ~np.isfinite(stamp.ierr) stamp.pixel_values[bad] = 0.0 stamp.ierr[bad] = 0.0 stamp.ierr = stamp.ierr.flatten() stamp.nx, stamp.ny = stamp.pixel_values.shape # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- stamp.crpix = crpix_stamp stamp.crval = crval_stamp stamp.dpix_dsky = np.eye(2) stamp.scale = np.linalg.inv(CD * 3600.0) # arcsec per pixel stamp.pixcenter_in_full = center stamp.lo = lo stamp.CD = CD stamp.W = W # --- Add the PSF --- stamp.psf = pointspread.get_psf(os.path.join(psfpath, psfname), fwhm) stamp.filtername = filtername return stamp
def xdf_sky_stamp(imroot, psfname, world, wsize, base=base, fwhm=3.0, background=0.0, filtername="H"): """Make a stamp with celestial coordinate information. """ from astropy.coordinates import SkyCoord from astropy import units as u impath = os.path.join(base, "data", "images") psfpath = os.path.join(base, "data", "psfs", "mixtures") position = SkyCoord(world[0], world[1], unit="deg", frame="icrs") size = wsize * u.arcsec hdr = fits.getheader(os.path.join(impath, imroot + "sci.fits")) sci = fits.getdata(os.path.join(impath, imroot + "sci.fits")) wht = fits.getdata(os.path.join(impath, imroot + "wht.fits")) wcs = WCS(hdr) # note size should be (ny, nx) flipped_size = (np.zeros(2) + np.array(wsize))[::-1] * u.arcsec image = Cutout2D(sci, position, size, wcs=wcs) weight = Cutout2D(wht, position, size, wcs=wcs) im = np.ascontiguousarray(image.data) ivar = np.ascontiguousarray(weight.data) # ----------- # --- MAKE STAMP ------- # --- Add image and uncertainty data to Stamp, flipping axis order ---- stamp = PostageStamp() stamp.pixel_values = np.array(im).T - background stamp.ierr = np.sqrt(ivar).T # Clean errors bad = ~np.isfinite(stamp.ierr) stamp.pixel_values[bad] = 0.0 stamp.ierr[bad] = 0.0 stamp.ierr = stamp.ierr.flatten() stamp.nx, stamp.ny = stamp.pixel_values.shape # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- psize = np.array(stamp.pixel_values.shape) stamp.crpix = np.floor(0.5 * psize) stamp.crval = image.wcs.wcs_pix2world(stamp.crpix[None, :], 0)[0, :2] CD = image.wcs.wcs.cd W = np.eye(2) W[0, 0] = np.cos(np.deg2rad(stamp.crval[-1])) stamp.dpix_dsky = np.matmul(np.linalg.inv(CD), W) stamp.scale = np.linalg.inv(CD * 3600.0) stamp.CD = CD stamp.W = W try: stamp.wcs = wcs except: pass # --- Add the PSF --- stamp.psf = pointspread.get_psf(os.path.join(psfpath, psfname), fwhm) # --- Add extra information --- stamp.full_header = dict(hdr) if filtername is None: stamp.filtername = stamp.full_header["FILTER"] else: stamp.filtername = filtername return stamp
def make_real_stamp(imname, center=(None, None), size=(None, None), center_type='pixels', psfname=None, fwhm=1.0, psf_realization=2, fix_header=False, psf_ngauss=6, psfcenter=104, oversample=8): """Make a postage stamp around the given position using the given image name """ data = fits.getdata(imname) hdr = fits.getheader(imname) crpix = np.array([hdr['CRPIX1'], hdr['CRPIX2']]) crval = np.array([hdr['CRVAL1'], hdr['CRVAL2']]) CD = np.array([[hdr['CD1_1'], hdr['CD1_2']], [hdr['CD2_1'], hdr['CD2_2']]]) if fix_header: # because hdr PC/CD/CDELT is sometimes wrong. hdr["CDELT1"] = hdr['CD1_1'] / hdr["PC1_1"] hdr["CDELT2"] = hdr['CD2_2'] / hdr["PC2_2"] # Pull slices and transpose to get to an axis order that makes sense to me # and corresponds with the wcs keyword ordering im = data[0, :, :].T err = data[1, :, :].T # ---- Extract subarray ----- center = np.array(center) # here we get the center coordinates in pixels (accounting for the transpose above) if center_type == 'celestial': world = center.copy() ast = apy_wcs.WCS(hdr, naxis=2) center = ast.wcs_world2pix(world[None, :], 0)[0, :2] # --- here is much mystery --- size = np.array(size) lo, hi = (center - 0.5 * size).astype(int), (center + 0.5 * size).astype(int) xinds = slice(int(lo[0]), int(hi[0])) yinds = slice(int(lo[1]), int(hi[1])) crpix_stamp = np.floor(0.5 * size) crval_stamp = crpix_stamp + lo W = np.eye(2) if center_type == 'celestial': crval_stamp = ast.wcs_pix2world(crval_stamp[None, :], 0)[0, :2] W[0, 0] = np.cos(np.deg2rad(crval_stamp[-1])) # ----------- # --- MAKE STAMP ------- # --- Add image and uncertainty data to Stamp ---- stamp = PostageStamp() stamp.pixel_values = im[xinds, yinds] stamp.ierr = 1. / err[xinds, yinds] bad = ~np.isfinite(stamp.ierr) stamp.pixel_values[bad] = 0.0 stamp.ierr[bad] = 0.0 stamp.ierr = stamp.ierr.flatten() stamp.nx, stamp.ny = stamp.pixel_values.shape # note the inversion of x and y order in the meshgrid call here stamp.ypix, stamp.xpix = np.meshgrid(np.arange(stamp.ny), np.arange(stamp.nx)) # --- Add WCS info to Stamp --- stamp.crpix = crpix_stamp stamp.crval = crval_stamp stamp.dpix_dsky = np.matmul(np.linalg.inv(CD), W) stamp.scale = np.linalg.inv(CD * 3600.0) stamp.pixcenter_in_full = center stamp.lo = lo stamp.CD = CD stamp.W = W try: stamp.wcs = ast except: pass # --- Add the PSF --- stamp.psf = get_psf(psfname, fwhm, psf_realization, psf_ngauss, oversample, psfcenter) # --- Add extra information --- stamp.full_header = dict(hdr) stamp.filtername = stamp.full_header["FILTER"] return stamp