def epsf_from_model(input_model, n_images, stars_per_image, fitshape, oversampling=1, σ=0, λ=None, smoothing='quartic', epsf_iters=5, seed=0): size = 128 * int(np.ceil(np.sqrt(stars_per_image))) border = 32 rng = np.random.default_rng(seed) stars = [] for i in range(n_images): img, xy_list = gen_image(input_model, stars_per_image, size, border, 'random', σ, λ, rng) stars += list( extract_stars(NDData(img), Table(xy_list, names=['x', 'y']), size=np.array(fitshape))) stars = EPSFStars(stars) builder = EPSFBuilder(oversampling=oversampling, smoothing_kernel=smoothing, maxiters=epsf_iters) epsf, fitted_stars = builder(stars) return epsf, reference_image(input_model, fitshape, oversampling)
def extract_epsf_stars(image: np.ndarray, image_stats: ImageStats, stars_tbl: InputTable, config: Config) -> EPSFStars: image_no_background = image - image_stats.median stars_tbl_filtered = stars_tbl[ stars_tbl[INPUT_TABLE_NAMES[FLUX]] < config.detector_saturation] stars_tbl_filtered.sort(INPUT_TABLE_NAMES[FLUX], reverse=True) stars = extract_stars(NDData(image_no_background), stars_tbl_filtered, size=config.cutout_size) if len(stars) == 0: warnings.warn('No stars extracted') return stars[:config.max_epsf_stars]
recipe_group = lambda:\ generators.scopesim_groups(N1d=1, jitter=8., border=400, magnitude=lambda N: np.random.normal(19, 1.5, N), group_size=9, group_radius=7 ) img, input_table = generators.read_or_generate_image(recipe_group, name_group) sigma_clipped_stats(img) grid_img_no_background = img_grid - np.median(img_grid) stars = extract_stars(NDData(grid_img_no_background), input_table_grid, size=cutout_size) epsf, _ = EPSFBuilder(oversampling=2, maxiters=6, progress_bar=True, smoothing_kernel=util.make_gauss_kernel(0.5)).build_epsf(stars) mean, median, std = sigma_clipped_stats(img) grouper = DAOGroup(60) finder = DAOStarFinder(threshold=median-2*std, fwhm=2.) phot = BasicPSFPhotometry(grouper, MADStdBackgroundRMS(), epsf, cutout_size+2, finder=finder) phot_nogroup = BasicPSFPhotometry(DAOGroup(0.001), MADStdBackgroundRMS(), epsf, cutout_size+2, finder=finder) init_guess = input_table.copy()
img_grid, tab_grid = read_or_generate_image( 'scopesim_grid_16_perturb2_mag18_24_subpixel') epsf_sources = tab_grid.copy() epsf_sources = epsf_sources[(epsf_sources['m'] > 19.5) & ((1024 - 100) > epsf_sources['x']) & (epsf_sources['x'] > 100) & ((1024 - 100) > epsf_sources['y']) & (epsf_sources['y'] > 100)] epsf_sources.sort('m', reverse=False) fitshape = 41 epsf_stars = extract_stars(NDData(img_grid), epsf_sources[:100], size=(fitshape + 2, fitshape + 2)) builder = EPSFBuilder(oversampling=4, smoothing_kernel=make_gauss_kernel(2.3, N=21), maxiters=5) pre_epsf, _ = cached(lambda: builder.build_epsf(epsf_stars), cache_dir / 'epsf_synthetic', rerun=False) data = pre_epsf.data[9:-9, 9:-9].copy() data /= np.sum(data) / np.sum(pre_epsf.oversampling) epsf = FittableImageModel(data=data, oversampling=pre_epsf.oversampling) epsf.origin = centroid_quadratic(epsf.data) def grid_photometry_epsf(): fit_stages_grid = [
saturation_model = SaturationModel( read_scopesim_linearity(Config.instance().scopesim_working_dir / 'inst_pkgs/MICADO/FPA_linearity.dat')) img = saturation_model.inverse_eval(img) mean, median, std = sigma_clipped_stats(img) finder = DAOStarFinder(threshold=median - 5 * std, fwhm=3.5, sigma_radius=2.7) image_no_background = img - median all_stars = finder(img) stars_tbl = all_stars.copy() stars_tbl.rename_columns(['xcentroid', 'ycentroid'], ['x', 'y']) stars = extract_stars(NDData(image_no_background), stars_tbl[:300], size=11) epsf, fitted_stars = EPSFBuilder( oversampling=2, maxiters=6, progress_bar=True, smoothing_kernel=util.make_gauss_kernel(0.45)).build_epsf(stars) culled = CorrelationCuller(100, image_no_background, epsf)(all_stars) sorted_stars = all_stars.copy() sorted_stars.rename_columns(['xcentroid', 'ycentroid'], ['x', 'y']) sorted_stars['qof'] = sorted_stars['model_chisquare'] / sorted_stars['flux'] sorted_stars.sort('qof') stars_refined = extract_stars(NDData(image_no_background),
def naco_astrometry(image, input_psf, offset, reference_table, use_reference=False, use_psf=False): fwhm = estimate_fwhm(input_psf.psfmodel) mean, median, std = sigma_clipped_stats(image) # todo make configurable # values here are handfudged to get maximum amount of candidates # ommitted peakmax = 10_000 finder = phot.IRAFStarFinder(threshold=median * threshold_factor, fwhm=fwhm * fwhm_factor, brightest=n_brightest, minsep_fwhm=minsep_fwhm, peakmax=peakmax) if np.all(np.isnan(image)): return Table() if use_reference: stars_tbl = reference_table.copy() stars_tbl.rename_columns(['XRAW', 'YRAW'], ['x', 'y']) stars_tbl['x'] -= offset[0] stars_tbl['y'] -= offset[1] cut_x = (stars_tbl['x'] >= 0) & (stars_tbl['x'] <= image.shape[1]) cut_y = (stars_tbl['y'] >= 0) & (stars_tbl['y'] <= image.shape[0]) stars_tbl = stars_tbl[cut_x & cut_y] else: stars_tbl = finder(image) stars_tbl.rename_columns(['xcentroid', 'ycentroid'], ['x', 'y']) if use_psf: psf = input_psf else: image_no_background = image - median stars = phot.extract_stars(NDData(image_no_background), stars_tbl, size=cutout_size) epsf, fitted_stars = phot.EPSFBuilder( oversampling=oversampling, maxiters=epsf_iters, progress_bar=True, smoothing_kernel=smoothing_kernel).build_epsf(stars) psf = phot.prepare_psf_model(epsf, renormalize_psf=False) grouper = phot.DAOGroup(group_radius * fwhm) if use_reference: photometry = phot.BasicPSFPhotometry( group_maker=grouper, finder=finder, bkg_estimator=phot.MMMBackground(), aperture_radius=fwhm, fitshape=fitshape, psf_model=psf) stars_tbl.rename_columns(['x', 'y'], ['x_0', 'y_0']) size = len(stars_tbl) stars_tbl['x_0'] += np.random.uniform( 0.1, 0.2, size) * np.random.choice([-1, 1], size) stars_tbl['y_0'] += np.random.uniform( 0.1, 0.2, size) * np.random.choice([-1, 1], size) result = photometry(image, init_guesses=stars_tbl) else: photometry = phot.IterativelySubtractedPSFPhotometry( group_maker=grouper, finder=finder, bkg_estimator=phot.MMMBackground(), aperture_radius=fwhm, fitshape=fitshape, psf_model=psf, niters=photometry_iters) result = photometry(image) result['x_fit'] += offset[0] result['y_fit'] += offset[1] return result
def astrometry(image: np.ndarray, reference_table: Optional[Table] = None, known_psf: Optional[photutils.EPSFModel] = None): """ All the steps necessary to do basic PSF astrometry with photutils :param image: :param reference_table: :param known_psf: :return: """ if known_psf: fwhm = estimate_fwhm(known_psf) else: fwhm = fwhm_guess # get image stats and build finder mean, median, std = sigma_clipped_stats(image) finder = photutils.DAOStarFinder(threshold=median * threshold_factor, fwhm=fwhm * fwhm_factor, sigma_radius=sigma_radius, brightest=n_brightest, peakmax=peakmax) if reference_table: stars_tbl = reference_table.copy() else: stars_tbl = finder(image) stars_tbl.rename_columns(['xcentroid', 'ycentroid'], ['x', 'y']) # extract star cutouts and fit EPSF from them image_no_background = image - median stars = photutils.extract_stars(NDData(image_no_background), stars_tbl, size=cutout_size) epsf, fitted_stars = photutils.EPSFBuilder(oversampling=oversampling, maxiters=epsf_iters, progress_bar=True, smoothing_kernel=smoothing_kernel).build_epsf(stars) # renormalization is probably important if fluxes are interesting, for positions it does not seem to matter psf = photutils.prepare_psf_model(epsf, renormalize_psf=False) grouper = photutils.DAOGroup(group_radius * fwhm) if reference_table: photometry = photutils.BasicPSFPhotometry( group_maker=grouper, finder=None, bkg_estimator=photutils.MMMBackground(), # Don't really know what kind of background estimator is preferred aperture_radius=fwhm, fitshape=fitshape, psf_model=psf) stars_tbl.rename_columns(['x', 'y'], ['x_0', 'y_0']) size = len(stars_tbl) # randomly perturb guesses to make fit do something stars_tbl['x_0'] += np.random.uniform(0.1, 0.2, size) * np.random.choice([-1, 1], size) stars_tbl['y_0'] += np.random.uniform(0.1, 0.2, size) * np.random.choice([-1, 1], size) result = photometry(image, init_guesses=stars_tbl) else: # it might be a good idea to build another finder/grouper here based on the derived EPSF photometry = photutils.IterativelySubtractedPSFPhotometry( group_maker=grouper, finder=finder, bkg_estimator=photutils.MMMBackground(), aperture_radius=fwhm, fitshape=fitshape, psf_model=psf, niters=photometry_iters ) result = photometry(image) return result
peakmax=10_000, exclude_border=True, brightest=300) epsf_sources = epsf_finder(img_combined) # %% plt.figure() plt.imshow(img_combined, norm=LogNorm()) plt.plot(epsf_sources['xcentroid'], epsf_sources['ycentroid'], 'rx') # %% epsf_sources['x'] = epsf_sources['xcentroid'] epsf_sources['y'] = epsf_sources['ycentroid'] epsf_stars = extract_stars(NDData(img_combined), epsf_sources, size=(fitshape + 2, fitshape + 2)) builder = EPSFBuilder(oversampling=2, smoothing_kernel='quadratic', maxiters=7) initial_epsf, _ = cached(lambda: builder.build_epsf(epsf_stars), cache_dir / 'initial_epsf_naco') # %% plt.figure() plt.imshow(initial_epsf.data, norm=LogNorm()) # %% y, x = np.mgrid[-fitshape / 2:fitshape / 2:1j * fitshape, -fitshape / 2:fitshape / 2:1j * fitshape] psffind = StarFinder(threshold=10, kernel=initial_epsf(x, y), min_separation=20,
residual -= fitted_model(x,y) #fitted_models.append(fitted_model) return residual def normalize(img): return img-img.min()+1 if __name__ == "__main__": img_conv, input_table_conv = convolved_grid(N1d=5, border=100, perturbation=2., kernel=Gaussian2DKernel(x_stddev=10, y_stddev=12, x_size=101, y_size=101), seed=1327) img_conv -= 0.00 img_mod, input_table_mod = model_add_grid(gauss2d(σ_x=10., σ_y=12), N1d=5, border=100, perturbation=2., seed=1327) cutout_size = 181 stars_mod = extract_stars(NDData(img_mod), input_table_mod, size=(cutout_size, cutout_size)) stars_conv = extract_stars(NDData(img_conv), input_table_mod, size=(cutout_size, cutout_size)) epsf_analytic = Gaussian2D() epsf_fit_mod = EPSFBuilder(maxiters=8, oversampling=2, smoothing_kernel='quadratic').build_epsf(stars_mod) epsf_fit_conv = EPSFBuilder(maxiters=8, oversampling=2, smoothing_kernel='quadratic').build_epsf(stars_conv) detections = np.array((input_table_mod['x'], input_table_mod['y'])).T residual_ana_mod = compute_residual(img_mod, epsf_analytic) residual_ana_conv = compute_residual(img_conv, epsf_analytic) residual_epsf_mod = compute_residual(img_mod, epsf_fit_mod)