def aperture_photometry_scan(data, x_pos, y_pos, ap_width, ap_length, theta=0.0, show=False, plt_title=None): """Aperture photometry on source located on x_pos, y_pos with rectangular aperture of dimensions specified by ap_length, ap_width is used. Aperture sums are NOT sky subtracted. Parameters ---------- data : `np.array` 2D array of floats x_pos : float X position of source. y_pos : float Y position of source ap_width : int Width (along x axis) of photometric aperture. ap_length : int Length (along y axis) of photometric aperture. theta : float Angle of orientation (from x-axis) for aperture, in radians. Increases counter-clockwise. show : bool, optional If true, plot showing aperture(s) on source will pop up. Defaults to F. plt_title : str or None, optional Only used if `show` is True. Title for plot. Defaults to None. Returns ------- phot_tab : `astropy.table` Table containing """ copy_data = copy.copy(data) rect_ap = RectangularAperture((x_pos, y_pos), w=ap_width, h=ap_length, theta=theta) phot_table = aperture_photometry(copy_data, rect_ap, method='exact') if show: mask = rect_ap.to_mask(method='center') data_cutout = mask.cutout(data) plt.title(plt_title) z1, z2 = (-12.10630989074707, 32.53888328838081) plt.imshow(data, origin='lower', vmin=z1, vmax=z2) rect_ap.plot(color='white', lw=2) plt.show() plt.close() return phot_table
def asymmetric_elongated_aperture_photom(scidata, starts, inverted, jpeg='', plot=False, sat_adu = 16383, spectral_band='G'): ''' Compute photometry using rectangular apertures. This is a good method to use for "April 2014" de Bruijn encoding ''' logger = logging.getLogger() logger.debug(f'science image is dimensions: {np.shape(scidata)}') match, factor = table_matches_image(starts, scidata) if not match: logger.warning(f'table data does not match image data. Dividing table coordinates by a factor of {factor:.2f} to table data (spectral band is {spectral_band})') starts['x_image'] /= factor starts['y_image'] /= factor positions, radii, thetas = aperture_centers_weighted_start_differential(starts) # get median pixel value inside the fireball bounding box median_bckgnd = np.median(get_bounding_box(scidata, starts)) if plot: plt.close() fig = plt.gcf() ax = fig.gca() plt.imshow(jpeg, cmap=plt.cm.gray) starts['aperture_sum'] = np.nan starts['bckgng_sub_measurements'] = np.nan starts['SNR'] = np.nan starts['signal'] = np.nan starts['exp_time'] = np.nan starts['aperture_sum_err'] = np.nan starts['aperture_sum_err_plus'] = np.nan starts['aperture_sum_err_minus'] = np.nan starts['aperture_saturated'] = False for i in range(len(starts)-1): starts[i]['exp_time'] = LC_open_time(starts, i, i+1, inverted) for el, pos, radius, theta in zip(starts[:-1], positions, radii, thetas): #zero_order_light = scidata[int(pos[1])][int(pos[0])] aperture = RectangularAperture(pos, w=radius*2, h=7.*2, theta=theta) # 7 # determine if any of the pixels in the aperture have reached saturation level, # flag accordingly aperture_mask = aperture.to_mask('center') aperture_values = aperture_mask.multiply(scidata) if np.any(aperture_values == sat_adu): el['aperture_saturated'] = True # do photometry aperture_result = aperture_photometry(scidata, aperture, method='subpixel', subpixels=16) el['aperture_sum'] = aperture_result['aperture_sum'].data #el['aperture_sum_err'] = aperture_result['aperture_sum_err'].data TODO FIXME el['bckgng_sub_measurements'] = el['aperture_sum'] - aperture.area*median_bckgnd el['SNR'] = el['aperture_sum'] / np.sqrt(el['aperture_sum'] + aperture.area*median_bckgnd) el['aperture_sum_err_plus'] = 1/el['SNR'] el['aperture_sum_err_minus'] = 1/el['SNR'] if plot: aperture.plot(color='white') if plot: #min_x, min_y, max_x, max_y = get_bounds([p['x_image'] for p in points], pos2) ax.set_xlim([np.min(starts['x_image']), np.max(starts['x_image'])]) ax.set_ylim([np.min(starts['y_image']), np.max(starts['y_image'])]) full_path = starts.meta['self_file_name'] dirname = os.path.dirname(full_path) basename = os.path.basename(full_path).split('.')[0] fname = os.path.join(dirname, basename + "_aperture_photometry_"+spectral_band+".jpg") plt.savefig(fname, dpi=150) return starts
def do_Rect_phot(pos, FWHM, trail, ap_min=3., ap_factor=1.5, \ win=None, wout=None, hout=None,\ sky_nsigma=3., sky_iter=10 ): if win == None: win = 4 * FWHM + trail if wout == None: wout = 8 * FWHM + trail if hout == None: hout = 8 * FWHM N = len(pos) if pos.ndim == 1: N = 1 theta = give_theta(number_of_stars=5) an = RectAn(pos, w_in=win, w_out=wout, h_out=hout, theta=theta) ap_size = np.max([ap_min, ap_factor*FWHM]) aperture = RectAp(pos, w=(trail+ap_size), h=ap_size, theta=theta) flux = aperture.do_photometry(image_reduc, method='exact')[0] # do phot and get sum from aperture. [0] is sum and [1] is error. #For test: #FWHM = FWHM_moffat.copy() #trail=trail_len.copy() #win = 4 * FWHM + trail #wout = 8 * FWHM + trail #hout = 8 * FWHM #N=len(pos_star_fit) #an = RectAn(pos_star_fit, w_in=win, w_out=wout, h_out=hout, theta=(theta+np.pi/2)) #ap_size = 1.5*FWHM_moffat #aperture = RectAp(pos_star_fit, w=(trail+ap_size), h=ap_size, theta=(theta+np.pi/2)) #flux = aperture.do_photometry(image_reduc, method='exact')[0] #plt.figure(figsize=(12,12)) #plt.imshow(image_reduc, origin='lower', vmin=-10, vmax=1000) #an.plot(color='white') #aperture.plot(color='red') flux_ss = np.zeros(N) error = np.zeros(N) for i in range(0, N): mask_an = (an.to_mask(method='center'))[i] # cf: test = mask_an.cutout(image_reduc) <-- will make cutout image. sky_an = mask_an.apply(image_reduc) all_sky = sky_an[np.nonzero(sky_an)] # only annulus region will be saved as np.ndarray msky, stdev, nsky, nrej = sky_fit(all_sky, method='Mode', mode_option='sex') area = aperture.area() flux_ss[i] = flux[i] - msky*area # sky subtracted flux error[i] = np.sqrt( flux_ss[i]/gain \ + area * stdev**2 \ + area**2 * stdev**2 / nsky ) if inputs.star_img_save: from matplotlib import pyplot as plt mask_ap = (aperture.to_mask(method='exact'))[i] star_ap_ss = mask_ap.apply(image_reduc-msky) sky_an_ss = mask_an.apply(image_reduc-msky) plt.suptitle('{0}, Star ID={1} ({nsky:3d} {nrej:3d} {msky:7.2f} {stdev:7.2f})'.format( inputs.filename, i, nsky=nsky, nrej=nrej, msky=msky, stdev=stdev )) ax1 = plt.subplot(1,2,1) im1 = ax1.imshow(sky_an_ss, origin='lower') plt.colorbar(im1, orientation='horizontal') ax2 = plt.subplot(1,2,2) im2 = ax2.imshow(star_ap_ss, origin='lower') plt.colorbar(im2, orientation='horizontal') plt.savefig('{0}.star{1}.png'.format(inputs.filename, i)) plt.clf() if pos.ndim > 1: print('\t[{x:7.2f}, {y:7.2f}], {nsky:3d} {nrej:3d} {msky:7.2f} {stdev:7.2f} {flux:7.1f} {ferr:3.1f}'.format(\ x=pos[i][0], y=pos[i][1], \ nsky=nsky, nrej=nrej, msky=msky, stdev=stdev,\ flux=flux_ss[i], ferr=error[i])) return flux_ss, error
def measure_flux(fitsimage, detections=None, pixel_coords=None, skycoords=None, method='single-aperture', a=None, b=None, theta=None, n_boostrap=100, minimal_aperture_size=1, aperture_size=None, aperture_scale=6.0, gaussian_segment_scale=4.0, plot=False, ax=None, color='white', debug=False): """Accurate flux measure Args: fitsimage: the FitsImage class detections: astropy.table, including all source position and shapes pixel_coords: the pixel coordinates of the detections skycoords: the sky coordinates of the detections. aperture_size: the fixed size of the aperture, in arcsec a,b,theta: the size of the source, in arcsec and deg minimal_aperture_size: if the aperture_size is None, this can control the minial aperture_size for the fain source, where the adaptive aperture could not be securely measured aperture_scale: the source shape determined aperture, lower priority than aperture_size Note: When several coordinates parameters are provided, detections has the higher priority """ pixel2arcsec = fitsimage.pixel2deg_ra * 3600 arcsec2pixel = 1 / pixel2arcsec if detections is not None: if len(detections) < 1: print('No source founded...') return None, None dets_colnames = detections.colnames # if ('x' in dets_colnames) and ('y' in dets_colnames): # pixel_coords = np.array(list(zip(detections['x'], detections['y']))) if ('ra' in dets_colnames) and ('dec' in dets_colnames): ra = np.array([detections['ra']]) dec = np.array([detections['dec']]) skycoords = SkyCoord(ra.flatten(), dec.flatten(), unit='deg') pixel_coords = np.array( list(zip(*skycoord_to_pixel(skycoords, fitsimage.wcs)))) if aperture_scale is not None: if a is None: # in arcsec if 'a' in detections.colnames: a = detections['a'] else: a = fitsimage.bmaj * 0.5 * 3600 if b is None: if 'b' in detections.colnames: b = detections['b'] else: b = fitsimage.bmin * 0.5 * 3600 if theta is None: # in deg if 'theta' in detections.colnames: theta = detections['theta'] else: theta = fitsimage.bpa elif skycoords is not None: pixel_coords = np.array( list(zip(*skycoord_to_pixel(skycoords, fitsimage.wcs)))) if a is None: a = fitsimage.bmaj * 0.5 * 3600 if b is None: b = fitsimage.bmin * 0.5 * 3600 if theta is None: theta = fitsimage.bpa # in deg elif pixel_coords is not None: if a is None: a = fitsimage.bmaj * 0.5 * 3600 if b is None: b = fitsimage.bmin * 0.5 * 3600 if theta is None: theta = fitsimage.bpa # in deg else: print("Nothing to do...") return None, None n_sources = len(pixel_coords) # define aperture for all the detections if aperture_scale is not None: if isinstance(a, (tuple, list, np.ndarray)): a_aper = aperture_scale * a * arcsec2pixel # a_aper = aperture_scale*a*u.arcsec else: a_aper = np.full(n_sources, aperture_scale * a * arcsec2pixel) if isinstance(b, (tuple, list, np.ndarray)): b_aper = aperture_scale * b * arcsec2pixel # b_aper = aperture_scale*b*u.arcsec else: b_aper = np.full(n_sources, aperture_scale * b * arcsec2pixel) if minimal_aperture_size is not None: minimal_aperture_size_in_pixel = minimal_aperture_size * arcsec2pixel a_aper[ a_aper < minimal_aperture_size_in_pixel] = minimal_aperture_size_in_pixel b_aper[ b_aper < minimal_aperture_size_in_pixel] = minimal_aperture_size_in_pixel if not isinstance(theta, (tuple, list, np.ndarray)): theta = np.full(n_sources, theta) if aperture_size is not None: aperture_size_pixel = aperture_size * arcsec2pixel a_aper = np.full(n_sources, aperture_size_pixel) b_aper = np.full(n_sources, aperture_size_pixel) theta = np.full(n_sources, 0) apertures = [] for i, coord in enumerate(pixel_coords): apertures.append( EllipticalAperture(coord, a_aper[i], b_aper[i], theta[i])) # apertures.append(SkyEllipticalAperture(skycoords, a_aper[i], b_aper[i], theta[i])) detections_mask = np.zeros(fitsimage.imagesize, dtype=bool) for mask in apertures: image_aper_mask = mask.to_mask().to_image(shape=fitsimage.imagesize) if image_aper_mask is not None: detections_mask = detections_mask + image_aper_mask else: continue detections_mask = (detections_mask > 0) | fitsimage.imagemask detections_apers = [] flux = np.zeros(n_sources) fluxerr = np.zeros(n_sources) if method == 'single-aperture': # measuring flux density for i, aper in enumerate(apertures): x, y = pixel_coords[i] pixel_fluxscale = 1. / (fitsimage.beamsize) detections_apers.append( EllipticalAperture([x, y], a_aper[i], b_aper[i], theta[i])) if fitsimage.has_pbcor: phot_table = aperture_photometry(fitsimage.image_pbcor, aper, mask=fitsimage.imagemask) else: phot_table = aperture_photometry(fitsimage.image, aper, mask=fitsimage.imagemask) flux[i] = phot_table['aperture_sum'].value * pixel_fluxscale # measuring the error of flux density # run the boostrap for random aperture with the image pixel_x = np.random.random(n_boostrap) * fitsimage.imagesize[ 1] # 1 for x axis pixel_y = np.random.random(n_boostrap) * fitsimage.imagesize[ 0] # 0 for y axis # points_select = (pixel_x**2 + pixel_y**2) < (np.min(fitsimage.imagesize)-np.max([a,b]))**2 # points_select = (pixel_x-**2 + pixel_y**2) > (np.max([a,b]))**2 # pixel_coords_boostrap = np.vstack([pixel_x[points_select], pixel_y[points_select]]).T pixel_coords_boostrap = np.vstack([pixel_x, pixel_y]).T apertures_boostrap = EllipticalAperture(pixel_coords_boostrap, a_aper[i], b_aper[i], theta[i]) noise_boostrap = aperture_photometry(fitsimage.image, apertures_boostrap, mask=detections_mask) fluxerr[i] = np.std( np.ma.masked_invalid( noise_boostrap['aperture_sum'])) * pixel_fluxscale # fluxerr[i] = np.std(noise_boostrap['aperture_sum']) * pixel_fluxscale if fitsimage.has_pbcor: pixel_pbcor = 1. / fitsimage.image_pb[int(np.round(x)), int(np.round(y))] fluxerr[i] = fluxerr[i] * pixel_pbcor if method == 'gaussian': seg_size = gaussian_segment_scale * np.int(fitsimage.bmaj_pixel) segments = RectangularAperture(pixel_coords, seg_size, seg_size, theta=0) segments_mask = segments.to_mask(method='center') for i, s in enumerate(segments_mask): x, y = pixel_coords[i] pixel_fluxscale = 1 / (fitsimage.beamsize) image_cutout = s.cutout(fitsimage.image) gaussian_fitting = gaussian_2Dfitting(image_cutout, debug=debug) flux[i] = gaussian_fitting['flux'] * pixel_fluxscale # boostrap for noise measurement a_fitted_aper = 1.0 * 2.355 * gaussian_fitting[ 'x_stddev'] # 2xFWHM of gaussian b_fitted_aper = 1.0 * 2.355 * gaussian_fitting['y_stddev'] theta_fitted = gaussian_fitting['theta'] detections_apers.append( EllipticalAperture([x, y], a_fitted_aper, b_fitted_aper, theta_fitted)) pixel_x = np.random.random(n_boostrap) * fitsimage.imagesize[ 1] # 1 for x axis pixel_y = np.random.random(n_boostrap) * fitsimage.imagesize[ 0] # 0 for y axis pixel_coords_boostrap = np.vstack([pixel_x, pixel_y]).T apertures_boostrap = EllipticalAperture(pixel_coords_boostrap, a_fitted_aper, b_fitted_aper, theta_fitted) noise_boostrap = aperture_photometry(fitsimage.image, apertures_boostrap, mask=detections_mask) fluxerr[i] = np.std( np.ma.masked_invalid( noise_boostrap['aperture_sum'])) * pixel_fluxscale if fitsimage.has_pbcor: pixel_pbcor = 1. / fitsimage.image_pb[int(np.round(x)), int(np.round(y))] flux[i] = flux[i] * pixel_pbcor fluxerr[i] = fluxerr[i] * pixel_pbcor if plot: if ax is None: fig, ax = plt.subplots(figsize=(8, 6)) im = ax.imshow(fitsimage.image, interpolation='nearest', vmin=-0.2 * fitsimage.std, vmax=10.0 * fitsimage.std, origin='lower') plt.colorbar(im, fraction=0.046, pad=0.04) for i in range(n_sources): obj = pixel_coords[i] im = detections_apers[i].plot(color=color, lw=1, alpha=0.8) ax.text( obj[0], (1.0 - 2.0 * detections_apers[i].a / fitsimage.imagesize[0]) * obj[1], "{:.2f}mJy".format(flux[i] * 1e3), color=color, horizontalalignment='center', verticalalignment='top', ) # # only for test # for ap in apertures_boostrap: # im = ap.plot(color='gray', lw=2, alpha=0.2) return flux, fluxerr