def find_sources(file_, fwhm): """ Uses DAOStarFinder to extract source positions from fits file :param file_ (str): name of target .fits file :param fwhm (float): The full width half maximum of the gaussian kernel in pixels For more config see https://photutils.readthedocs.io/en/stable/api/photutils.detection.DAOStarFinder.html """ # Read in fits file as numpy array data = read_fits(file_, return_array=True) # Calculate background level mean, median, std = stats.sigma_clipped_stats(data) print(('mean', 'median', 'std')) print((mean, median, std)) # Set up DAO Finder and run on bg subtracted image, printing results # sharplo=.2, sharphi=1., roundlo=-.3, roundhi=.3, daofind = DAOStarFinder(exclude_border=True, fwhm=fwhm, threshold=std) sources = daofind.find_stars(data - median) # daofind(data-median) # print('Sources:') print(sources) # Save positions of detected sources to csv file positions = (sources['xcentroid'], sources['ycentroid']) print_positions = zip(*[ sources[x] for x in [ 'id', 'xcentroid', 'ycentroid', 'sharpness', 'roundness1', 'roundness2', 'npix', 'sky', 'peak', 'flux', 'mag' ] ]) header = 'id,xcentroid,ycentroid,sharpness,roundness1,roundness2,npix,sky,peak,flux,mag' np.savetxt(file_[:-5] + '_positions.csv', print_positions, fmt='%.5e', header=header) # Show image with detected sources circled in blue apertures = CircularAperture(positions, r=4.) norm = ImageNormalize(stretch=SqrtStretch()) plt.imshow(data, cmap='Greys', origin='lower', norm=norm) apertures.plot(color='blue', lw=1.5, alpha=0.5) plt.draw() # Scatter plot sharpness vs magnitude plt.figure(2) sharp, round_, mags = (sources['sharpness'], sources['roundness1'], sources['mag']) plt.scatter(mags, sharp) plt.title('Sharpness vs Magnitude') plt.xlabel('Mag') plt.ylabel('Sharp') # Scatter plot roundness vs magnitude plt.figure(3) plt.scatter(mags, round_) plt.title('Roundness vs Magnitude') plt.xlabel('Mag') plt.ylabel('Roundness1') plt.show()
def calc_gain(flats, crop_length=0): """ Find camera gain :param flats (str[][]): Pairs of filenames of debiased flat frames (for a range of intensities) :param crop_length (int): Use only a (centered) square of this side length cut out of the frames """ sigs = [] vars_ = [] for pair in flats: pair_0 = read_fits(pair[0], return_array=True) pair_1 = read_fits(pair[1], return_array=True) mean_0 = np.mean(crop_middle(pair_0, crop_length)) mean_1 = np.mean(crop_middle(pair_1, crop_length)) mean_ratio = mean_0 / mean_1 pair_1_corrected = pair_1 * mean_ratio flat_corrected = pair_0 - pair_1_corrected std = np.std(crop_middle(flat_corrected, crop_length)) var = (std**2) / 2. sigs.append(mean_0) vars_.append(var) gain = np.polyfit(vars_, sigs, 1)[0] return gain
def hough_transform(file_name, threshold=None, crop={}, pad=0): """ Use a hough transform on a file to find prominent straight lines Can threshold, crop and pad the image beforehand :param threshold (int): pixel value to threshold at :param crop (dict): coordinates of the crop (top left, bottom right): {"x1", "x2", "y1", "y2} :param pad (int): number of pixels of padding to add to each side """ fits_image = read_fits(file_name, crop, pad, return_array=True) if threshold is not None: fits_image = threshold_image(fits_image, threshold) h, theta, d = hough_line(fits_image) # Find peaks in hough space hspace, angles, dists = hough_line_peaks(h, theta, d) return hspace, angles, dists
def t2d(file_): """Read in a transmission fits file and output a copy converted to density""" if 'density' in file_: print(f'{file_} already converted.') return None array = read_fits(file_, return_array=True) LUT = make_LUT(array) density_array = np.copy(array) for x in np.nditer(density_array, op_flags=['readwrite']): x[...] = LUT[x] density_array = np.flipud(density_array) hdu = fits.PrimaryHDU(density_array) hdulist = fits.HDUList([hdu]) try: hdulist.writeto(file_[:-5] + '_density.fits') except IOError: print(f'{file_} already converted.')
def hough_transform_interactive(image_, crop_coords={}, convert_coords=False, pad=0): """ Like threshold_image_interactive, but will display the result of a hough transform following thresholding and give the option to repeat the proceess """ fits_image = read_fits(image_, crop_coords, convert_coords, pad) # Success counter used to allow the user to restart the process if # the hough transform returns too many lines and they wish to restart # with a new cutoff threshold success = 'n' while success.upper() != 'Y': thresh_image = threshold_image_interactive(fits_image) thresh_array = np.array(thresh_image) h, theta, d = hough_line(thresh_array) # Show the original image in greyscale fig, axes = plt.subplots(1, 3, figsize=(15, 6), subplot_kw={'adjustable': 'box'}) ax = axes.ravel() gray_cmap = cm.get_cmap("gray") ax[0].imshow(thresh_image, cmap=gray_cmap) ax[0].set_title('Input image') ax[0].set_axis_off() # Show the hough transform ax[1].imshow( np.log(1 + h), extent=[np.rad2deg(theta[-1]), np.rad2deg(theta[0]), d[-1], d[0]], cmap=gray_cmap, aspect=8) ax[1].set_title('Hough transform') ax[1].set_xlabel('Angles (degrees)') ax[1].set_ylabel('Distance (pixels)') ax[1].axis('image') # Show the original image with the detected lines overlaid in red ax[2].imshow(thresh_image, cmap=gray_cmap) [image_width, image_height] = thresh_array.shape for _, angle, dist in zip(*hough_line_peaks(h, theta, d)): y0 = (dist - 0 * np.cos(angle)) / np.sin(angle) y1 = (dist - image_height * np.cos(angle)) / np.sin(angle) ax[2].plot((0, image_height), (y0, y1), '-r') ax[2].set_xlim((0, image_height)) ax[2].set_ylim((image_width, 0)) ax[2].set_axis_off() ax[2].set_title('Detected lines') plt.tight_layout() plt.show() # Ask user if they wish to start again success = input('Happy with result? (y/N) ') # Find peaks in hough space lines_ = hough_line_peaks(h, theta, d) # Get angles associated with peaks in degree format angles = [np.rad2deg(x) for x in lines_[1]] # For each detected line, rotate the original image such that that line is horizontal, # and display it along with the rotation angle fig, rotations = plt.subplots(1, len(angles)) if len(angles) > 1: rt = rotations.ravel() for i in range(0, len(angles)): rt[i].set_title('Rotation angle: ' + '{:f}'.format(angles[i] + 90) + ' degrees.') rt[i].imshow(ndimage.rotate(fits_image, angles[i] + 90)) else: rotations.set_title('Rotation angle: ' + '{:f}'.format(angles[0] + 90) + ' degrees.') rotations.imshow(ndimage.rotate(fits_image, angles[0] + 90)) plt.show()
p0=guesses, sigma=sigs, absolute_sigma=True) pretty_output(opt2, cov2, f'After masking - {half}') plot_result(x_data=image_x_data, image=half_image_data, fit=tophat_function(image_x_data, *opt2), title=f'After masking - {half}', masked=outliers) plt.show() done = input('Press return to close.') return opt, cov, opt2, cov2 if __name__ == '__main__': # hough_transform_interactive( # "psf/5523.fits", {"x1": 1024, "x2": 2017, "y1": 1562, "y2": 1609}, convert_coords=True) # hspace, angles, dists = hough_transform("psf/5523.fits", threshold=600, # crop={"x1": 1024, "x2": 2017, "y1": 1562, "y2": 1609}) # print(hspace, angles, dists) test_data = read_fits('psf/5523.fits', crop_coords={ "x1": 1024, "x2": 2017, "y1": 1562, "y2": 1609 }, return_array=True) psf_data = read_fits('./5523_moffat25_width35.psf.fits', return_array=True) fit(test_data, psf_data, 1, bg_sigma=32, psf_scale_factor=10)