def LensPlaneWCS(pos): ''' The "local" WCS -- useful when you need to work on the sky, but in small offsets from RA, Dec in arcsec. Initialisation is with the coordinates of the central pixel, which is set to be the origin of the "pixel coordinate" system. Return a WCS object. ''' onearcsec = 1.0 / 3600.0 return tractor.FitsWcs( util.Tan(pos.ra, pos.dec, 1.0, 1.0, -onearcsec, 0.0, 0.0, onearcsec, 0, 0))
def PS1WCS(hdr): ''' Return a WCS object initialised from a PS1 file header. WARNING: PC matrix not being used, determinant may be wrong sign... Need to check with literature image of H1413 ''' t = util.Tan() t.set_crpix(hdr['CRPIX1'], hdr['CRPIX2']) t.set_crval(hdr['CRVAL1'], hdr['CRVAL2']) t.set_cd(hdr['CDELT1'], 0., 0., hdr['CDELT2']) t.set_imagesize(hdr['NAXIS1'], hdr['NAXIS2']) return tractor.FitsWcs(t)
def main(): # In LSST meas-deblend (on lsst6): # python examples/suprimePlot.py --data ~dstn/lsst/ACT-data -v 126969 -c 5 --data-range -100 300 --roi 0 500 0 500 --psf psf.fits --image img.fits --sources srcs.fits from optparse import OptionParser import sys parser = OptionParser(usage=('%prog <img> <psf> <srcs>')) parser.add_option('-v', '--verbose', dest='verbose', action='count', default=0, help='Make more verbose') opt, args = parser.parse_args() if len(args) != 3: parser.print_help() sys.exit(-1) if opt.verbose == 0: lvl = logging.INFO else: lvl = logging.DEBUG logging.basicConfig(level=lvl, format='%(message)s', stream=sys.stdout) imgfn, psffn, srcfn = args pimg = pyfits.open(imgfn) if len(pimg) != 4: print('Image must have 3 extensions') sys.exit(-1) img = pimg[1].data mask = pimg[2].data maskhdr = pimg[2].header var = pimg[3].data del pimg print('var', var.shape) #print var print('mask', mask.shape) #print mask print('img', img.shape) #print img mask = mask.astype(np.int16) for bit in range(16): on = ((mask & (1 << bit)) != 0) print('Bit', bit, 'has', np.sum(on), 'pixels set') ''' MP_BAD = 0 Bit 0 has 2500 pixels set MP_SAT = 1 Bit 1 has 5771 pixels set MP_INTRP= 2 Bit 2 has 11269 pixels set MP_CR = 3 Bit 3 has 136 pixels set MP_EDGE = 4 Bit 4 has 11856 pixels set HIERARCH MP_DETECTED = 5 Bit 5 has 37032 pixels set ''' print('Mask header:', maskhdr) maskplanes = {} print('Mask planes:') for card in maskhdr.ascardlist(): if not card.key.startswith('MP_'): continue print(card.value, card.key) maskplanes[card.key[3:]] = card.value print('Variance range:', var.min(), var.max()) print('Image median:', np.median(img.ravel())) invvar = 1. / var invvar[var == 0] = 0. invvar[var < 0] = 0. sig = np.sqrt(np.median(var)) H, W = img.shape for k, v in maskplanes.items(): plt.clf() I = ((mask & (1 << v)) != 0) rgb = np.zeros((H, W, 3)) clipimg = np.clip((img - (-3. * sig)) / (13. * sig), 0, 1) cimg = clipimg.copy() cimg[I] = 1 rgb[:, :, 0] = cimg cimg = clipimg.copy() cimg[I] = 0 rgb[:, :, 1] = cimg rgb[:, :, 2] = cimg plt.imshow(rgb, interpolation='nearest', origin='lower') plt.title(k) plt.savefig('mask-%s.png' % k.lower()) badmask = sum([(1 << maskplanes[k]) for k in ['BAD', 'SAT', 'INTRP', 'CR']]) # HACK -- left EDGE sucks badmask += (1 << maskplanes['EDGE']) #badmask = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) #badmask |= (1 << 4) print('Masking out: 0x%x' % badmask) invvar[(mask & badmask) != 0] = 0. assert (all(np.isfinite(img.ravel()))) assert (all(np.isfinite(invvar.ravel()))) psf = pyfits.open(psffn)[0].data print('psf', psf.shape) psf /= psf.sum() from tractor.emfit import em_fit_2d from tractor.fitpsf import em_init_params # Create Gaussian mixture model PSF approximation. S = psf.shape[0] # number of Gaussian components K = 3 w, mu, sig = em_init_params(K, None, None, None) II = psf.copy() II /= II.sum() # HIDEOUS HACK II = np.maximum(II, 0) print('Multi-Gaussian PSF fit...') xm, ym = -(S / 2), -(S / 2) em_fit_2d(II, xm, ym, w, mu, sig) print('w,mu,sig', w, mu, sig) mypsf = tractor.GaussianMixturePSF(w, mu, sig) P = mypsf.getPointSourcePatch(S / 2, S / 2) mn, mx = psf.min(), psf.max() ima = dict(interpolation='nearest', origin='lower', vmin=mn, vmax=mx) plt.clf() plt.subplot(1, 2, 1) plt.imshow(psf, **ima) plt.subplot(1, 2, 2) pimg = np.zeros_like(psf) P.addTo(pimg) plt.imshow(pimg, **ima) plt.savefig('psf.png') sig = np.sqrt(np.median(var)) plt.clf() plt.hist(img.ravel(), 100, range=(-3. * sig, 3. * sig)) plt.savefig('imghist.png') srcs = fits_table(srcfn) print('Initial:', len(srcs), 'sources') # Trim sources with x=0 or y=0 srcs = srcs[(srcs.x != 0) * (srcs.y != 0)] print('Trim on x,y:', len(srcs), 'sources left') # Zero out nans & infs for c in ['theta', 'a', 'b']: I = np.logical_not(np.isfinite(srcs.get(c))) srcs.get(c)[I] = 0. # Set sources with flux=NaN to something more sensible... I = np.logical_not(np.isfinite(srcs.flux)) srcs.flux[I] = 1. # Sort sources by flux. srcs = srcs[np.argsort(-srcs.flux)] # Trim sources that are way outside the image. margin = 8. * np.maximum(srcs.a, srcs.b) H, W = img.shape srcs = srcs[(srcs.x > -margin) * (srcs.y > -margin) * (srcs.x < (W + margin) * (srcs.y < (H + margin)))] print('Trim out-of-bounds:', len(srcs), 'sources left') wcs = tractor.FitsWcs(Sip(imgfn, 1)) #wcs = tractor.NullWCS() timg = tractor.Image(data=img, invvar=invvar, psf=mypsf, wcs=wcs, sky=tractor.ConstantSky(0.), photocal=tractor.NullPhotoCal(), name='image') inverr = timg.getInvError() assert (all(np.isfinite(inverr.ravel()))) tsrcs = [] for s in srcs: #pos = tractor.PixPos(s.x, s.y) pos = tractor.RaDecPos(s.ra, s.dec) if s.a > 0 and s.b > 0: eflux = tractor.Flux(s.flux / 2.) dflux = tractor.Flux(s.flux / 2.) re, ab, phi = s.a, s.b / s.a, 90. - s.theta eshape = gal.GalaxyShape(re, ab, phi) dshape = gal.GalaxyShape(re, ab, phi) print('Fluxes', eflux, dflux) tsrc = gal.CompositeGalaxy(pos, eflux, eshape, dflux, dshape) else: flux = tractor.Flux(s.flux) print('Flux', flux) tsrc = tractor.PointSource(pos, flux) tsrcs.append(tsrc) chug = tractor.Tractor([timg]) for src in tsrcs: if chug.getModelPatch(timg, src) is None: print('Dropping non-overlapping source:', src) continue chug.addSource(src) print('Kept a total of', len(chug.catalog), 'sources') ima = dict(interpolation='nearest', origin='lower', vmin=-3. * sig, vmax=10. * sig) chia = dict(interpolation='nearest', origin='lower', vmin=-5., vmax=5.) plt.clf() plt.imshow(img, **ima) plt.colorbar() plt.savefig('img.png') plt.clf() plt.imshow(invvar, interpolation='nearest', origin='lower') plt.colorbar() plt.savefig('invvar.png') mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-0.png') chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-0.png') for step in range(5): cat = chug.getCatalog() for src in cat: if chug.getModelPatch(timg, src) is None: print('Dropping non-overlapping source:', src) chug.removeSource(src) print('Kept a total of', len(chug.catalog), 'sources') #cat = chug.getCatalog() #for i,src in enumerate([]): #for i,src in enumerate(chug.getCatalog()): #for i in range(len(cat)): i = 0 while i < len(cat): src = cat[i] #print 'Step', i #for j,s in enumerate(cat): # x,y = timg.getWcs().positionToPixel(s, s.getPosition()) # print ' ', # if j == i: # print '*', # print '(%6.1f, %6.1f)'%(x,y), s print('Optimizing source', i, 'of', len(cat)) x, y = timg.getWcs().positionToPixel(src.getPosition(), src) print('(%6.1f, %6.1f)' % (x, y), src) # pre = src.getModelPatch(timg) s1 = str(src) print('src1 ', s1) dlnp1, X, a = chug.optimizeCatalogFluxes(srcs=[src]) s2 = str(src) dlnp2, X, a = chug.optimizeCatalogAtFixedComplexityStep(srcs=[src], sky=False) s3 = str(src) #post = src.getModelPatch(timg) print('src1 ', s1) print('src2 ', s2) print('src3 ', s3) print('dlnp', dlnp1, dlnp2) if chug.getModelPatch(timg, src) is None: print('After optimizing, no overlap!') print('Removing source', src) chug.removeSource(src) i -= 1 i += 1 # plt.clf() # plt.subplot(2,2,1) # img = timg.getImage() # (x0,x1,y0,y1) = pre.getExtent() # plt.imshow(img, **ima) # ax = plt.axis() # plt.plot([x0,x0,x1,x1,x0], [y0,y1,y1,y0,y0], 'k-', lw=2) # plt.axis(ax) # plt.subplot(2,2,3) # plt.imshow(pre.getImage(), **ima) # plt.subplot(2,2,4) # plt.imshow(post.getImage(), **ima) # plt.savefig('prepost-s%i-s%03i.png' % (step, i)) # # mod = chug.getModelImages()[0] # plt.clf() # plt.imshow(mod, **ima) # plt.colorbar() # plt.savefig('mod-s%i-s%03i.png' % (step, i)) # chi = chug.getChiImage(0) # plt.clf() # plt.imshow(chi, **chia) # plt.colorbar() # plt.savefig('chi-s%i-s%03i.png' % (step, i)) #dlnp,x,a = chug.optimizeCatalogFluxes() #print 'fluxes: dlnp', dlnp #dlnp,x,a = chug.optimizeCatalogAtFixedComplexityStep() #print 'opt: dlnp', dlnp mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-%i.png' % (step + 1)) chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-%i.png' % (step + 1)) return for step in range(5): chug.optimizeCatalogFluxes() mod = chug.getModelImages()[0] plt.clf() plt.imshow(mod, **ima) plt.colorbar() plt.savefig('mod-s%i.png' % step) chi = chug.getChiImage(0) plt.clf() plt.imshow(chi, **chia) plt.colorbar() plt.savefig('chi-s%i.png' % step)
def read_cfht_coadd(imgfn, weightfn, roi=None, radecroi=None, filtermap=None): ''' Given filenames for CFHT coadd image and weight files, produce a tractor.Image object. *roi*: (x0,x1, y0,y1): a region-of-interest in pixel space; returns the subimage [x0,x1), [y0,y1). *radecroi*: (ra0, ra1, dec0, dec1): a region-of-interest in RA,Dec space; returns the subimage bounding the given RA,Dec box [ra0,ra1], [dec0,dec1]. *filtermap*: dict, eg, { 'i.MP9701': 'i' }, to map from the FILTER header keyword to a standard filter name. ''' P = pyfits.open(imgfn) print 'Read', P[0].data.shape, 'image' img = P[0].data imgheader = P[0].header # WCS: the image file has a WCS header # we should be able to do: #twcs = tractor.FitsWcs(imgfn) # ARGH! Memory issues reading the file; HACK: copy header... f, tempfn = tempfile.mkstemp() os.close(f) pyfits.writeto(tempfn, None, header=imgheader, clobber=True) twcs = tractor.FitsWcs(tempfn) # Cut down to the region-of-interest, if given. if roi is not None: x0, x1, y0, y1 = roi elif radecroi is not None: ralo, rahi, declo, dechi = radecroi xy = [ twcs.positionToPixel(tractor.RaDecPos(r, d)) for r, d in [(ralo, declo), (ralo, dechi), (rahi, declo), (rahi, dechi)] ] xy = np.array(xy) x0, x1 = xy[:, 0].min(), xy[:, 0].max() y0, y1 = xy[:, 1].min(), xy[:, 1].max() print 'RA,Dec ROI', ralo, rahi, declo, dechi, 'becomes x,y ROI', x0, x1, y0, y1 # Clip to image size... H, W = data.shape x0 = max(0, min(x0, W - 1)) x1 = max(0, min(x1, W)) y0 = max(0, min(y0, H - 1)) y1 = max(0, min(y1, H)) print ' clipped to', x0, x1, y0, y1 else: H, W = img.shape x0, x1, y0, y1 = 0, W, 0, H if roi is not None or radecroi is not None: # Actually cut the pixels img = img[y0:y1, x0:x1].copy() # Also tell the WCS to apply an offset. twcs.setX0Y0(x0, y0) print 'Image:', img.shape # HACK, tell the WCS how big the image is... # (needed because of the previous HACK, copying the header) twcs.wcs.set_imagesize(x1 - x0, y1 - y0) print twcs # Argh, this doesn't work: the files are .fz compressed #P = pyfits.open(weightfn) #weight = P[1].data[y0:y1, x0:x1] # HACK: use "imcopy" to uncompress to a temp file! #print 'Writing to temp file', tempfn cmd = "imcopy '%s[%i:%i,%i:%i]' '!%s'" % (weightfn, x0 + 1, x1, y0 + 1, y1, tempfn) print 'running', cmd os.system(cmd) P = pyfits.open(tempfn) weight = P[0].data print 'Read', weight.shape, 'weight image' # PSF model: FAKE IT for now tpsf = tractor.GaussianMixturePSF(np.array([0.9, 0.1]), np.zeros((2, 2)), np.array([1, 2])) # SKY level: assume zero #sky = np.median(img) #print 'Image median value:', sky sky = 0. tsky = tractor.ConstantSky(sky) # Photometric calibration: the FITS header says: ''' FILTER = 'r.MP9601' / Filter PHOTZP = 30.000 / photometric zeropoint COMMENT AB magnitude = -2.5 * log10(flux) + PHOTZP COMMENT r.MP9601=r_SDSS-0.024*(g_SDSS-r_SDSS) ''' # Grab the filter name, and apply the filtermap (if given) filter = imgheader['FILTER'] if filtermap: filter = filtermap.get(filter, filter) zp = imgheader['PHOTZP'] # Simple photocal object photocal = tractor.MagsPhotoCal(filter, zp) # For plotting: find the approximate standard deviation #print 'Median weight:', np.median(weight) sigma1 = 1. / np.sqrt(np.median(weight)) zr = np.array([-3, 10]) * sigma1 + sky name = 'CFHT ' + imgheader.get('OBJECT', '') tim = tractor.Image(data=img, invvar=weight, psf=tpsf, wcs=twcs, sky=tsky, photocal=photocal, name=name, zr=zr) tim.extent = [x0, x1, y0, y1] return tim