def centroid_com(self): """ This function ... :return: """ return centroid_com(self._data)
def get_centroids(cube): p = progbar(15, "computing centroids") tot = cube.shape[0] s = tot / 15 im = cube[0] x0 = y0 = 12 x1 = y1 = 19 mask = np.repeat(True, im.size).reshape(im.shape) mask[x0:x1,y0:y1] = False centroid = [] for k,im in enumerate(cube): ma = np.ma.masked_array(im, mask) masked = ma.filled(0) centroid.append(centroid_com(masked)) if (k+1) % s == 0: p.write() p.close() centroid = np.array(centroid) return centroid
def recenter(image, pos, window_size=15, method="2dg"): """ Recenter each star in each frame of the image cube before performing aperture photometry to take care of slight misalignments between frames because of atmospheric turbulence and tracking/pointing errors. Parameters ---------- image : numpy array 2D image pos : list List of (x,y) tuples for star positions window_size : int Window size in which to fit the gaussian to the star to calculate new center method : string Method used to find center of the star. Options are 1d Gaussian fit, 2d gaussian fit or com (center of mass) Returns ------- xcen, ycen : float Source x and y centers """ pos = np.asarray(pos) ny, nx = image.shape window_size = int(window_size) nstars = pos.shape[0] star_pos = np.zeros([nstars, 2], dtype=np.float32) for i in range(nstars): x, y = pos[i][0], pos[i][1] xmin, xmax = int(x) - int(window_size / 2), int(x) + int(window_size / 2) + 1 ymin, ymax = int(y) - int(window_size / 2), int(y) + int(window_size / 2) + 1 if xmin < 0: xmin = 0 if ymin < 0: ymin = 0 if xmax > nx: xmax = nx if ymax > ny: ymax = ny if method == "1dg": xcen, ycen = centroid_1dg(image[ymin:ymax, xmin:xmax]) elif method == "2dg": xcen, ycen = centroid_2dg(image[ymin:ymax, xmin:xmax]) elif method == "com": xcen, ycen = centroid_com(image[ymin:ymax, xmin:xmax]) if (np.abs(xmin + xcen - x)) > 3.0 or (np.abs(ymin + ycen - y)) > 3.0: star_pos[i, 0] = x star_pos[i, 1] = y else: star_pos[i, 0] = xmin + xcen star_pos[i, 1] = ymin + ycen return star_pos
def photometry(image_paths, master_dark_path, master_flat_path, target_centroid, comparison_flux_threshold, aperture_radii, centroid_stamp_half_width, psf_stddev_init, aperture_annulus_radius, output_path): """ Parameters ---------- master_dark_path : str Path to master dark frame master_flat_path :str Path to master flat field target_centroid : `~numpy.ndarray` position of centroid, with shape (2, 1) comparison_flux_threshold : float Minimum fraction of the target star flux required to accept for a comparison star to be included aperture_radii : `~numpy.ndarray` Range of aperture radii to use centroid_stamp_half_width : int Centroiding is done within image stamps centered on the stars. This parameter sets the half-width of the image stamps. psf_stddev_init : float Initial guess for the width of the PSF stddev parameter, used for fitting 2D Gaussian kernels to the target star's PSF. aperture_annulus_radius : int For each aperture in ``aperture_radii``, measure the background in an annulus ``aperture_annulus_radius`` pixels bigger than the aperture radius output_path : str Path to where outputs will be saved. """ master_dark = fits.getdata(master_dark_path) master_flat = fits.getdata(master_flat_path) star_positions = init_centroids(image_paths[0], master_flat, master_dark, target_centroid, plots=True, min_flux=comparison_flux_threshold).T # Initialize some empty arrays to fill with data: times = np.zeros(len(image_paths)) fluxes = np.zeros( (len(image_paths), len(star_positions), len(aperture_radii))) errors = np.zeros( (len(image_paths), len(star_positions), len(aperture_radii))) xcentroids = np.zeros((len(image_paths), len(star_positions))) ycentroids = np.zeros((len(image_paths), len(star_positions))) airmass = np.zeros(len(image_paths)) airpress = np.zeros(len(image_paths)) humidity = np.zeros(len(image_paths)) telfocus = np.zeros(len(image_paths)) psf_stddev = np.zeros(len(image_paths)) medians = np.zeros(len(image_paths)) with ProgressBar(len(image_paths)) as bar: for i in range(len(image_paths)): bar.update() # Subtract image by the dark frame, normalize by flat field #imagedata = (rebin_image(fits.getdata(image_paths[i]), 2) - master_dark[:-1, :-1]) / master_flat[:-1, :-1] imagedata = (fits.getdata(image_paths[i]) - master_dark) / master_flat # Collect information from the header imageheader = fits.getheader(image_paths[i]) exposure_duration = imageheader['EXPTIME'] times[i] = Time(imageheader['DATE-OBS'], format='isot', scale='utc').jd medians[i] = np.median(imagedata) airmass[i] = imageheader['AIRMASS'] airpress[i] = imageheader['AIRPRESS'] humidity[i] = imageheader['HUMIDITY'] telfocus[i] = imageheader['TELFOCUS'] # Initial guess for each stellar centroid informed by previous centroid for j in range(len(star_positions)): if i == 0: init_x = star_positions[j][0] init_y = star_positions[j][1] else: init_x = ycentroids[i - 1][j] init_y = xcentroids[i - 1][j] # Cut out a stamp of the full image centered on the star image_stamp = imagedata[init_y - centroid_stamp_half_width:init_y + centroid_stamp_half_width, init_x - centroid_stamp_half_width:init_x + centroid_stamp_half_width] # Measure stellar centroid with 2D gaussian fit x_stamp_centroid, y_stamp_centroid = centroid_com(image_stamp) y_centroid = x_stamp_centroid + init_x - centroid_stamp_half_width x_centroid = y_stamp_centroid + init_y - centroid_stamp_half_width xcentroids[i, j] = x_centroid ycentroids[i, j] = y_centroid # import matplotlib.pyplot as plt # plt.figure() # plt.imshow(np.log(image_stamp), origin='lower', cmap=plt.cm.viridis) # plt.scatter(x_stamp_centroid, y_stamp_centroid, s=30) # plt.show() # # plt.figure() # s = np.std(imagedata) # m = np.median(imagedata) # plt.imshow(imagedata, origin='lower', cmap=plt.cm.viridis, # vmin=m-2*s, vmax=m+2*s) # plt.show() # For the target star, measure PSF: if j == 0: psf_model_init = models.Gaussian2D( amplitude=np.max(image_stamp), x_mean=centroid_stamp_half_width, y_mean=centroid_stamp_half_width, x_stddev=psf_stddev_init, y_stddev=psf_stddev_init) fit_p = fitting.LevMarLSQFitter() y, x = np.mgrid[:image_stamp.shape[0], :image_stamp. shape[1]] best_psf_model = fit_p( psf_model_init, x, y, image_stamp - np.median(image_stamp)) psf_stddev[i] = 0.5 * (best_psf_model.x_stddev.value + best_psf_model.y_stddev.value) positions = np.vstack([ycentroids[i, :], xcentroids[i, :]]) for k, aperture_radius in enumerate(aperture_radii): target_apertures = CircularAperture(positions, aperture_radius) background_annuli = CircularAnnulus( positions, r_in=aperture_radius + aperture_annulus_radius, r_out=aperture_radius + 2 * aperture_annulus_radius) flux_in_annuli = aperture_photometry( imagedata, background_annuli)['aperture_sum'].data background = flux_in_annuli / background_annuli.area() flux = aperture_photometry( imagedata, target_apertures)['aperture_sum'].data background_subtracted_flux = ( flux - background * target_apertures.area()) fluxes[i, :, k] = background_subtracted_flux / exposure_duration errors[i, :, k] = np.sqrt(flux) ## Save some values results = PhotometryResults(times, fluxes, errors, xcentroids, ycentroids, airmass, airpress, humidity, medians, psf_stddev, aperture_radii) results.save(output_path) return results
def photometry(star_positions, aperture_radii, centroid_stamp_half_width, psf_stddev_init, aperture_annulus_radius, output_path): """ Parameters ---------- master_dark_path : str Path to master dark frame master_flat_path :str Path to master flat field target_centroid : `~numpy.ndarray` position of centroid, with shape (2, 1) comparison_flux_threshold : float Minimum fraction of the target star flux required to accept for a comparison star to be included aperture_radii : `~numpy.ndarray` Range of aperture radii to use centroid_stamp_half_width : int Centroiding is done within image stamps centered on the stars. This parameter sets the half-width of the image stamps. psf_stddev_init : float Initial guess for the width of the PSF stddev parameter, used for fitting 2D Gaussian kernels to the target star's PSF. aperture_annulus_radius : int For each aperture in ``aperture_radii``, measure the background in an annulus ``aperture_annulus_radius`` pixels bigger than the aperture radius output_path : str Path to where outputs will be saved. """ master_dark = fits.getdata(master_dark_path) master_flat = fits.getdata(master_flat_path) master_flat[master_flat < 0.1] = 1.0 # tmp #star_positions = init_centroids(image_paths[0:3], master_flat, master_dark, # target_centroid, plots=True, # min_flux=comparison_flux_threshold).T # Initialize some empty arrays to fill with data: times = np.zeros(len(image_paths)) fluxes = np.zeros((len(image_paths), len(star_positions), len(aperture_radii))) errors = np.zeros((len(image_paths), len(star_positions), len(aperture_radii))) xcentroids = np.zeros((len(image_paths), len(star_positions))) ycentroids = np.zeros((len(image_paths), len(star_positions))) airmass = np.zeros(len(image_paths)) airpress = np.zeros(len(image_paths)) humidity = np.zeros(len(image_paths)) telfocus = np.zeros(len(image_paths)) psf_stddev = np.zeros(len(image_paths)) medians = np.zeros(len(image_paths)) with ProgressBar(len(image_paths)) as bar: for i in range(len(image_paths)): bar.update() # Subtract image by the dark frame, normalize by flat field imagedata = (fits.getdata(image_paths[i]) - master_dark) / master_flat # Collect information from the header imageheader = fits.getheader(image_paths[i]) exposure_duration = imageheader['EXPTIME'] times[i] = Time(imageheader['DATE-OBS'], format='isot', scale=imageheader['TIMESYS'].lower()).jd medians[i] = np.median(imagedata) airmass[i] = imageheader['AIRMASS'] airpress[i] = imageheader['AIRPRESS'] humidity[i] = imageheader['HUMIDITY'] telfocus[i] = imageheader['TELFOCUS'] # Initial guess for each stellar centroid informed by previous centroid for j in range(len(star_positions)): if i == 0: init_x = star_positions[j][0] init_y = star_positions[j][1] else: init_x = ycentroids[i-1][j] init_y = xcentroids[i-1][j] # Cut out a stamp of the full image centered on the star image_stamp = imagedata[int(init_y) - centroid_stamp_half_width: int(init_y) + centroid_stamp_half_width, int(init_x) - centroid_stamp_half_width: int(init_x) + centroid_stamp_half_width] # Measure stellar centroid with 2D gaussian fit x_stamp_centroid, y_stamp_centroid = centroid_com(image_stamp) y_centroid = x_stamp_centroid + init_x - centroid_stamp_half_width x_centroid = y_stamp_centroid + init_y - centroid_stamp_half_width xcentroids[i, j] = x_centroid ycentroids[i, j] = y_centroid # For the target star, measure PSF: if j == 0: psf_model_init = models.Gaussian2D(amplitude=np.max(image_stamp), x_mean=centroid_stamp_half_width, y_mean=centroid_stamp_half_width, x_stddev=psf_stddev_init, y_stddev=psf_stddev_init) fit_p = fitting.LevMarLSQFitter() y, x = np.mgrid[:image_stamp.shape[0], :image_stamp.shape[1]] best_psf_model = fit_p(psf_model_init, x, y, image_stamp - np.median(image_stamp)) psf_stddev[i] = 0.5*(best_psf_model.x_stddev.value + best_psf_model.y_stddev.value) positions = np.vstack([ycentroids[i, :], xcentroids[i, :]]) for k, aperture_radius in enumerate(aperture_radii): target_apertures = CircularAperture(positions, aperture_radius) background_annuli = CircularAnnulus(positions, r_in=aperture_radius + aperture_annulus_radius, r_out=aperture_radius + 2 * aperture_annulus_radius) flux_in_annuli = aperture_photometry(imagedata, background_annuli)['aperture_sum'].data background = flux_in_annuli/background_annuli.area() flux = aperture_photometry(imagedata, target_apertures)['aperture_sum'].data background_subtracted_flux = (flux - background * target_apertures.area()) fluxes[i, :, k] = background_subtracted_flux/exposure_duration errors[i, :, k] = np.sqrt(flux) ## Save some values results = PhotometryResults(times, fluxes, errors, xcentroids, ycentroids, airmass, airpress, humidity, medians, psf_stddev, aperture_radii) results.save(output_path) return results