def photometry_on_directory(directory_with_images, object_of_interest, star_locs, aperture_rad, inner_annulus, outer_annulus, max_adu, star_ids, camera, bjd_coords=None, observatory_location=None, fwhm_by_fit=True): """ Perform aperture photometry on a directory of images. Parameters ---------- directory_with_images : str Folder containing the images on which to do photometry. Photometry will only be done on images that contain the ``object_of_interest``. object_of_interest : str Name of the object of interest. The only files on which photometry will be done are those whose header contains the keyword ``OBJECT`` whose value is ``object_of_interest``. star_locs : tuple of numpy array The first entry in the tuple should be the right ascension of the sources, in degrees. The second should be the declination of the sources, in degrees. aperture_rad : int Radius of the aperture to use when performing photometry. inner_annulus : int Inner radius of annulus to use in for performing local sky subtraction. outer_annulus : int Outer radius of annulus to use in for performing local sky subtraction. max_adu : int Maximum allowed pixel value before a source is considered saturated. star_ids : array-like Unique identifier for each source in ``star_locs``. camera : `stellarphot.Camera` object Camera object which has gain, read noise and dark current set. gain : float Gain, in electrons/ADU, of the camera that took the image. The gain is used in calculating the instrumental magnitude. read_noise : float Read noise of the camera in electrons. Used in the CCD equation to calculate error. dark_current : float Dark current, in electron/sec. Used in the CCD equation to calculate error. """ ifc = ImageFileCollection(directory_with_images) phots = [] missing_stars = [] for a_ccd, fname in ifc.ccds(object=object_of_interest, return_fname=True): print('on image ', fname) try: # Convert RA/Dec to pixel coordinates for this image pix_coords = a_ccd.wcs.all_world2pix(star_locs[0], star_locs[1], 0) except AttributeError: print(' ....SKIPPING THIS IMAGE, NO WCS') continue xs, ys = pix_coords # Remove anything that is too close to the edges/out of frame padding = 3 * aperture_rad out_of_bounds = ((xs < padding) | (xs > (a_ccd.shape[1] - padding)) | (ys < padding) | (ys > (a_ccd.shape[0] - padding))) in_bounds = ~out_of_bounds # Find centroids of each region around star that is in_bounds xs_in = xs[in_bounds] ys_in = ys[in_bounds] print(' ...finding centroids') try: xcen, ycen = centroid_sources(a_ccd.data, xs_in, ys_in, box_size=2 * aperture_rad + 1) except NoOverlapError: print(' ....SKIPPING THIS IMAGE, CENTROID FAILED') continue # Calculate offset between centroid in this image and the positions # based on input RA/Dec. Later we will set the magnitude of those with # large differences to an invalid value (maybe). center_diff = np.sqrt((xs_in - xcen)**2 + (ys_in - ycen)**2) # FWHM is typically 5-6 pixels. The center really shouldn't move # by more than that. too_much_shift = center_diff > 6 xcen[too_much_shift] = xs_in[too_much_shift] ycen[too_much_shift] = ys_in[too_much_shift] # Set up apertures and annuli based on the centroids in this image. ap_locs = np.array([xcen, ycen]).T aps = CircularAperture(ap_locs, r=aperture_rad) anuls = CircularAnnulus(ap_locs, inner_annulus, outer_annulus) # Set any clearly bad values to NaN a_ccd.data[a_ccd.data > max_adu] = np.nan print(' ...doing photometry') # Do the photometry... pho = aperture_photometry(a_ccd.data, (aps, anuls), mask=a_ccd.mask, method='center') # We may have some stars we did not do photometry for because # those stars were out of bounds. # Add the ones we missed to the list of missing missed = star_ids[out_of_bounds] missing_stars.append(missed) # Add all the extra goodies to the table print(' ...adding extra columns') add_to_photometry_table(pho, a_ccd, anuls, aps, fname=fname, star_ids=star_ids[in_bounds], camera=camera, bjd_coords=bjd_coords, observatory_location=observatory_location, fwhm_by_fit=fwhm_by_fit) # And add the final table to the list of tables phots.append(pho) # ### Combine all of the individual photometry tables into one all_phot = vstack(phots) # ### Eliminate any stars that are missing from one or more images # # This makes life a little easier later... uniques = set() for miss in missing_stars: uniques.update(set(miss)) actually_bad = sorted([u for u in uniques if u in all_phot['star_id']]) len(uniques), len(actually_bad) all_phot.add_index('star_id') if actually_bad: bad_rows = all_phot.loc_indices[actually_bad] try: bad_rows = list(bad_rows) except TypeError: bad_rows = [bad_rows] all_phot.remove_indices('star_id') all_phot.remove_rows(sorted(bad_rows)) all_phot.remove_indices('star_id') gain = camera.gain noise = calculate_noise(gain=camera.gain, read_noise=camera.read_noise, dark_current_per_sec=camera.dark_current, flux=all_phot['aperture_net_flux'], sky_per_pix=all_phot['sky_per_pix_avg'].value, aperture_area=all_phot['aperture_area'], annulus_area=all_phot['annulus_area'], exposure=all_phot['exposure'].value, include_digitization=False) snr = gain * all_phot['aperture_net_flux'] / noise all_phot['mag_error'] = 1.085736205 / snr all_phot['noise'] = noise # AstroImageJ includes a factor of gain in the noise. IMHO it is part of the # flux but, for convenience, here it is all_phot['noise-aij'] = noise / gain all_phot['snr'] = snr return all_phot
def create_reg(ra, dec, radius, dir, show_regions): os.system('ls -d 0* >> datadirs.txt') dirs = [line.rstrip('\n').rstrip('/') for line in open('datadirs.txt')] os.system('rm datadirs.txt') image = None for i in range(len(dirs)): try_file = '%s/%s/uvot/image/sw%sum2_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break try_file = '%s/%s/uvot/image/sw%suw2_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break try_file = '%s/%s/uvot/image/sw%suw1_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break try_file = '%s/%s/uvot/image/sw%suuu_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break try_file = '%s/%s/uvot/image/sw%suvv_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break try_file = '%s/%s/uvot/image/sw%subb_sk.img.gz' % ( str(dir), str(dirs[i]), str(dirs[i])) if os.path.isfile(try_file): image = fits.open(try_file) break else: pass w = WCS(image[1].header) img = image[1].data y, x = np.indices(np.shape(img)) # Creating source region x_source, y_source = w.world_to_pixel( SkyCoord(ra=float(ra), dec=float(dec), unit="deg", frame=FK5)) new_x_source, new_y_source = centroid_sources(img, x_source, y_source, box_size=21, centroid_func=centroid_com) with open(dir + '/' + 'source.reg', "w") as text_file: text_file.write('fk5;circle(%.6f, %.6f, %.1f") # color=green' % (float(ra), float(dec), np.round(radius[0], 1))) # Creating background region rho = random.randrange(0, 300, 1) phi = random.randrange(0, 360, 1) x_0 = int(rho * np.cos(phi / 180 * np.pi)) + img.shape[1] / 2 y_0 = int(rho * np.sin(phi / 180 * np.pi)) + img.shape[0] / 2 r_map = np.sqrt((x - x_0)**2 + (y - y_0)**2) bkg_reg = r_map < radius[1] max_bkg = np.max(img[bkg_reg]) std_bkg = np.std(img[bkg_reg][img[bkg_reg] != 0]) median_bkg = np.median(img[bkg_reg][img[bkg_reg] != 0]) while (max_bkg > 5 * (median_bkg + std_bkg)) or (((x_0 - x_source)**2 + (y_0 - y_source)**2) < radius[1]**2): rho = random.randrange(0, 300, 1) phi = random.randrange(0, 360, 1) x_0 = int(rho * np.cos(phi / 180 * np.pi)) + img.shape[1] / 2 y_0 = int(rho * np.sin(phi / 180 * np.pi)) + img.shape[0] / 2 r_map = np.sqrt((x - x_0)**2 + (y - y_0)**2) bkg_reg = r_map < radius[1] max_bkg = np.max(img[bkg_reg]) std_bkg = np.std(img[bkg_reg][img[bkg_reg] != 0]) median_bkg = np.median(img[bkg_reg][img[bkg_reg] != 0]) bkg_coords = w.pixel_to_world(x_0, y_0) image.close() with open(dir + '/' + 'bkg.reg', "w") as text_file: text_file.write( 'fk5;circle(%.6f, %.6f, %.1f") # color=green' % (bkg_coords.ra.deg, bkg_coords.dec.deg, np.round(radius[1], 1))) fig, ax = plt.figure(), plt.subplot(projection=w) plot = ax.imshow(img, vmin=0, vmax=8 * (median_bkg + std_bkg), origin='lower') plt.colorbar(plot, ax=ax) c_b = plt.Circle((x_0, y_0), radius[1], color='red', fill=False) c_s = plt.Circle((new_x_source, new_y_source), radius[0], color='red', fill=False) ax.add_patch(c_s) ax.add_patch(c_b) plt.savefig(dir + '/regions.png', bbox_inches='tight') if show_regions: plt.show() plt.close('all')
def ap_an_phot(image, sources, source_ap, sky_ap, delta_ann=3.0, coords='xy', centroid=False, show_plot=False, **kargs): """Performs circular aperture fotometry on a image, given a table with the coordinates (x,y) or (ra,dec) of the sources. Background is estimated from a annular aperture and substracted Input: image: (str) name of the .fits file with the image sources: table with the Positions of the sources in the image. source_ap: Radius of the circular aperture in pixels sky_ap: inner radius of the annulus to calculate the sky. delta_ann: Width of the annulus to calculate the sky centroid: (Boolean) if True the source position centroid are recalculated. sky_coord (str) type of coordinates to use, either xy or radec. If xy sources table must have 'x' and 'y' cols. If ra dec sources table must to have 'ra' and 'dec' cols. show_plot: (Boolean) If True a plot of the aperture is displayed. Output: phot_table: Table with the resulting photometry """ data = fits.getdata(image) x, y = sources.colnames if coords == 'radec': sources = SkyCoord(sources[x], sources[y], **kargs) # convert to pixel coordinates header = fits.getheader(image) wcs = WCS(header) sources = Table(sources.to_pixel(wcs), names=[x, y]) elif coords == 'xy': warnings.warn('Image pixels start at 1 while python index stats at 0', AstropyUserWarning) # Check if the following correction is necessary # sources[x] -= 1 # sources[y] -= 1 if centroid: sources = centroid_sources(data, sources[x], sources[y], box_size=30) sources = Table(sources, names=[x, y]) # create apertures sources = [(a, b) for a, b in zip(sources[x], sources[y])] source_aperture = CircularAperture(sources, r=source_ap) sky_aperture = CircularAnnulus(sources, r_in=sky_ap, r_out=sky_ap + delta_ann) if show_plot: index = [str(i+1) for i in range(len(sources))] norm = simple_norm(data, 'sqrt', percent=99) plt.figure() plt.imshow(data, norm=norm) source_aperture.plot(color='white', lw=2) sky_aperture.plot(color='red', lw=2) for a, b in sources: plt.text(a, b, index, color="purple", fontsize=12) plt.show() # get background using sigma clipped median annulus_masks = sky_aperture.to_mask(method='center') bkg_median = [] for mask in annulus_masks: annulus_data = mask.multiply(data) annulus_data_1d = annulus_data[mask.data > 0] _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d) bkg_median.append(median_sigclip) bkg_median = np.array(bkg_median) phot_table = aperture_photometry(data, source_aperture) phot_table['annulus_median'] = bkg_median phot_table['aper_bkg'] = bkg_median * source_aperture.area() phot_table['aper_sum_bkgsub'] = phot_table['aperture_sum'] - \ phot_table['aper_bkg'] return phot_table
def ap_phot(image, sources, radius, aperture='circular', coords='xy', theta=0, centroid=False, show_plot=False, **kargs): """Performs circular aperture fotometry on a background substracted image, given a table with the coordinates (x,y) or (ra,dec) of the sources. Input: image: (str) name of the .fits file with the image sources: table with the Positions of the sources in the image. radius: Radius of the circular aperture in pixels. If aperture = 'elliptical' the semi axes of the ellipese (a,b) should be given. aperture: (str) Shape of the aperture to use. 'circular' or 'elliptical' theta: Rotation angle for elliptical aperture in radians, optional centroid: (Boolean) if True the source position centroid are recalculated. sky_coord (str) type of coordinates to use, either xy or radec. If xy sources table must have 'x' and 'y' cols. If ra dec sources table must to have 'ra' and 'dec' cols. show_plot: (Boolean) If True a plot of the aperture is displayed. Output: phot_table: Table with the resulting photometry """ data = fits.getdata(image) x, y = sources.colnames if coords == 'radec': sources = SkyCoord(sources[x], sources[y], **kargs) # convert to pixel coordinates header = fits.getheader(image) wcs = WCS(header) sources = Table(sources.to_pixel(wcs), names=[x, y]) elif coords == 'xy': warnings.warn('Image pixels start at 1 while python index stats at 0', AstropyUserWarning) # Check if the following correction is necessary # sources[x] -= 1 # sources[y] -= 1 if centroid: sources = centroid_sources(data, sources[x], sources[y], box_size=30) sources = Table(sources, names=[x, y]) # create apertures sources = [(a, b) for a, b in zip(sources[x], sources[y])] if aperture == 'circular': source_aperture = CircularAperture(sources, r=radius) elif aperture == 'elliptical': source_aperture = EllipticalAperture(sources, a=radius[0], b=radius[1], theta=theta) if show_plot: index = [str(i+1) for i in range(len(sources))] norm = simple_norm(data, 'sqrt', percent=99) plt.figure() plt.imshow(data, norm=norm) source_aperture.plot(color='white', lw=2) for a, b in sources: plt.text(a, b, index, color="purple", fontsize=12) plt.show() phot_table = aperture_photometry(data, source_aperture) return phot_table
def removeStarsPSF(img, starPixX, starPixY, starR, mags, gX, gY, gR, p1, p2, radius, showProgress, inverted = False): remove = [] for i in range(0,len(starPixX)): if i%100 == 0: print(i) for j in range(i+1,len(starPixX)): if np.abs(starPixX[i]-starPixX[j])<2.5*radius and np.abs(starPixY[i]-starPixY[j])<2.5*radius: remove.append(i) remove.append(j) mask = np.ones(len(starPixX), dtype = bool) mask[np.array(remove)] = 0 starPixX = starPixX[mask] starPixY = starPixY[mask] starR = starR[mask] mags = mags[mask] print(radius) mask = np.ones(starPixX.shape[0],dtype=bool) for i in range(gX.shape[0]): mask = np.logical_and(mask, np.sqrt((starPixX-gX[i])**2+(starPixY-gY[i])**2)>gR[i]+2*radius) starPixX = starPixX[mask] starPixY = starPixY[mask] starR = starR[mask] mags = mags[mask] mask = (2*radius<starPixX) & (starPixX<img.shape[1]-2*radius) & (2*radius<starPixY) & (starPixY<img.shape[0]-2*radius) starPixX = starPixX[mask] starPixY = starPixY[mask] starR = starR[mask] mags = mags[mask] if p1[0]==p2[0]: psfMask = np.abs(starPixX-p1[0])>2.5*radius trailMask = np.abs(starPixX-p1[0])<10 psfX = starPixX[psfMask] psfY = starPixY[psfMask] psfR = starR[psfMask] psfMags = mags[psfMask] trailX = starPixX[trailMask] trailY = starPixY[trailMask] trailMags = mags[trailMask] else: m,b = TF.getLineParams(p1,p2) par,perp = GT.findDistances(starPixX,starPixY,m,b) psfMask = np.abs(perp)>2.5*radius trailMask = np.abs(perp)<10 psfX = starPixX[psfMask] psfY = starPixY[psfMask] psfR = starR[psfMask] psfMags = mags[psfMask] trailX = starPixX[trailMask] trailY = starPixY[trailMask] trailMags = mags[trailMask] mask = psfR>10 psfX = psfX[mask] psfY = psfY[mask] psfMags = psfMags[mask] print(psfX.shape[0]) showImageWithDetectedHotPixels(img, "Image with Star Picks", psfX, psfY, "b", inverted) psfX,psfY = centroid_sources(img, psfX, psfY, box_size=21, centroid_func=centroid_com) showImageWithDetectedHotPixels(img, "Image with Star Picks Centroid", psfX, psfY, "b", inverted) stars = Table() stars["x"] = psfX stars["y"] = psfY #stars2 = Table() #stars2["x_0"] = psfX #stars2["y_0"] = psfY stars = extract_stars(NDData(data=img), stars, size = 2*int(2*radius)+1) nrows = 5 ncols = 5 fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True) ax = ax.ravel() for i in range(nrows*ncols): norm = simple_norm(stars[i], 'log', percent=99.) ax[i].imshow(stars[i], norm=norm, origin='lower', cmap='viridis') plt.show() #sigma_psf = 2.0 #daogroup = DAOGroup(2.0) #mmm_bkg = MMMBackground() #fitter = LevMarLSQFitter() #psf_model = PRF(sigma=sigma_psf) #photometry = BasicPSFPhotometry(group_maker=daogroup,bkg_estimator=mmm_bkg,psf_model=psf_model,fitter=LevMarLSQFitter(),fitshape=(11,11)) #result_tab = photometry(image=img, init_guesses=stars2) #residual_image = photometry.get_residual_image() epsfBuilder = EPSFBuilder(oversampling=2, maxiters=20, smoothing_kernel = "quadratic") epsf, starFits = epsfBuilder(stars) #showImage(residual_image,"Image No Stars",True) norm = simple_norm(epsf.data, 'log', percent=99.) plt.imshow(epsf.data, norm=norm, origin='lower', cmap='viridis') plt.colorbar() plt.show() nrows = 5 ncols = 5 fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True) ax = ax.ravel() for i in range(nrows*ncols): norm = simple_norm(starFits[i], 'log', percent=99.) ax[i].imshow(starFits[i], norm=norm, origin='lower', cmap='viridis') plt.show() nrows = 5 ncols = 5 fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(20, 20), squeeze=True) ax = ax.ravel() for i in range(nrows*ncols): norm = simple_norm(stars[i].data-starFits[i].data, 'log', percent=99.) ax[i].imshow(stars[i].data-starFits[i].data, norm=norm, origin='lower', cmap='viridis') plt.show() showImage(finalImg, "Image With No Stars", inverted)