def test_register_nddata(self): from astropy.nddata import NDData from skimage.transform import SimilarityTransform transf = SimilarityTransform(rotation=np.pi / 2.0, translation=(1, 0)) nd = NDData([[0.0, 1.0], [2.0, 3.0]], mask=[[True, False], [False, False]]) registered_img, footp = aa.apply_transform(transf, nd, nd, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, True], [False, False]]) self.assertTrue(all(err_mask.flatten())) # Test now if there is no assigned mask during creation nd = NDData([[0.0, 1.0], [2.0, 3.0]]) registered_img, footp = aa.apply_transform(transf, nd, nd, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, False], [False, False]]) self.assertTrue(all(err_mask.flatten()))
def sources(sourcelist, imagelist=None, reference=None): """ Takes a NxM list of sources, where N is the number of images and M is the number of sources in each image Operates in-place. Arguments: catalogs -- list of sources Keyword Arguments: imagelist -- An optional list of images which map 1:1 to sources if provided, the calculated transformations will be applied to images reference -- A set of points to use as a reference; default 0th index """ # FIXME this is really slow, move to Cython or do some numpy magic with # Sources class aligned = [] if reference is None: reference = sourcelist[0] if imagelist is None: imagelist = [None] * len(sourceslist) npref = [[r.x, r.y] for r in reference] for cat, im in zip(sourcelist, imagelist): npc = [[c.x, c.y] for c in cat] T, _ = astroalign.find_transform(npc, npref) if im is not None: astroalign.apply_transform(T, im, im) for source in cat: source.transform(T)
def test_register_ccddata(self): from ccdproc import CCDData from skimage.transform import SimilarityTransform transf = SimilarityTransform(rotation=np.pi / 2.0, translation=(1, 0)) cd = CCDData( [[0.0, 1.0], [2.0, 3.0]], mask=[[True, False], [False, False]], unit="adu", ) registered_img, footp = aa.apply_transform(transf, cd, cd, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, True], [False, False]]) self.assertTrue(all(err_mask.flatten())) cd = CCDData([[0.0, 1.0], [2.0, 3.0]], unit="adu") registered_img, footp = aa.apply_transform(transf, cd, cd, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, False], [False, False]]) self.assertTrue(all(err_mask.flatten()))
def test_register_npma(self): from skimage.transform import SimilarityTransform transf = SimilarityTransform(rotation=np.pi / 2.0, translation=(1, 0)) nparr = np.array([[0.0, 1.0], [2.0, 3.0]]) mask = [[True, False], [False, False]] ma = np.ma.array(nparr, mask=mask) registered_img, footp = aa.apply_transform(transf, ma, ma, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, True], [False, False]]) self.assertTrue(all(err_mask.flatten())) ma = np.ma.array(nparr) registered_img, footp = aa.apply_transform(transf, ma, ma, propagate_mask=True) err = np.linalg.norm(registered_img - np.array([[2.0, 0.0], [3.0, 1.0]])) self.assertLess(err, 1e-6) err_mask = footp == np.array([[False, False], [False, False]]) self.assertTrue(all(err_mask.flatten()))
def hdu_shift_images(hdu_list, method='fft', register_method='asterism', footprint=False, logger=logger): """Calculate and apply shifts in a set of ccddata images. The function process the list inplace. Original data altered. methods: - "asterism" : align images using asterism matching (astroalign) - "chi2" : align images using chi2 minimization (image_registration) - "fft" : align images using fourier transform correlation (skimage) """ if method == "asterism": logger.info("Registering images with astroalign.") if astroalign is None: raise RuntimeError("astroaling module not available.") im0 = hdu_list[0].data for i in hdu_list[1:]: transf, _ = astroalign.find_transform(i.data, im0) i.data = astroalign.apply_transform(transf, i.data, im0) if footprint: i.footprint = astroalign.apply_transform( transf, np.ones(i.data.shape, dtype=bool), im0) # s_method = 'similarity_transform' else: if method == 'chi2': shifts = create_chi2_shift_list([ccd.data for ccd in hdu_list]) else: shifts = create_fft_shift_list([ccd.data for ccd in hdu_list]) logger.info(f"Aligning CCDData with shifts: {shifts}") for ccd, shift in zip(hdu_list, shifts): # if method == 'fft': # s_method = method # else: # s_method = 'simple' # ccd.data = apply_shift(ccd.data, shift, method=s_method, # logger=logger) # s_method = 'simple' ccd.data, ccd.masks = apply_shift(ccd.data, shift, logger=logger) sh_string = [str(i) for i in shift] ccd.header['hierarch astropop register_shift'] = ",".join( sh_string) # if footprint: # ccd.footprint = apply_shift(np.ones_like(ccd.data, dtype=bool), # shift, method='simple', # logger=logger) if footprint: [], [], ccd.footprint = apply_shift(np.ones_like(ccd.data, dtype=bool), shift, logger=logger) for i in hdu_list: i.header['hierarch astropop registered'] = True # i.header['hierarch astropop register_method'] = method # i.header['hierarch astropop transform_method'] = s_method return hdu_list
def _align(self, img: Image) -> Image: reference = self.db.get_stacked_image(str(img.key)) if reference is None: logging.info(f"no reference found for {img.key}") return img assert img.data.dtype == np.float32 and img.data.min() >= 0.0 and img.data.max() <= 1.0, f"{img.data.dtype} {img.data.max()} {img.data.min()}" assert reference.data.dtype == np.float32 and reference.data.min() >= 0.0 and reference.data.max() <= 1.0, f"{reference.data.dtype} {reference.data.max()} {reference.data.min()}" assert reference.data.ndim == img.data.ndim, f"{reference.data.ndim} {img.data.ndim}" assert reference.data.shape == img.data.shape, f"{reference.data.shape} {img.data.shape}" with Timer(f"aligning image for {img.key}"): if img.data.ndim == 2: registered, footprint = aa.register(img.data, reference.data, fill_value=0.0) img.data = registered elif img.data.ndim == 3: transform, _ = aa.find_transform(img.data[0], reference.data[0]) for i in range(3): transformed, _ = aa.apply_transform(transform, img.data[i], reference.data[i], fill_value=0.0) img.data[i] = transformed else: raise Exception(f"invalid image dimensions {img.data.ndim}") assert img.data.dtype == np.float32 and img.data.min() >= 0.0 and img.data.max() <= 1.0, f"{img.data.dtype} {img.data.max()} {img.data.min()}" return img
def stack(files, refimage): y, x = refimage.shape[-2], refimage.shape[-1] #creating empty arrays to hold each of RGB channels stacks stacksR = np.zeros((y, x, len(files))) stacksG = np.zeros((y, x, len(files))) stacksB = np.zeros((y, x, len(files))) rawHDU = fits.open(files[0]) rawHEADER = rawHDU[0].header for i in range(len(files)): rawDATA = get_img(files[i]) #Image part of the file try: p = align(rawDATA[0], refimage) #getting transformation rawDATAred = aa.apply_transform(p, rawDATA[0], refimage) rawDATAgrn = aa.apply_transform(p, rawDATA[1], refimage) rawDATAblu = aa.apply_transform(p, rawDATA[2], refimage) stacksR[:, :, i] = rawDATAred stacksG[:, :, i] = rawDATAgrn stacksB[:, :, i] = rawDATAblu except: print('oops file %s didnt meet alignment criteria' % files[i]) files.remove(files[i]) continue reds = np.median(stacksR, axis=2) grns = np.median(stacksG, axis=2) blue = np.median(stacksB, axis=2) procDATA = np.array([reds, grns, blue]) procHDU = fits.PrimaryHDU(procDATA) #new file, processed procHDU.header = rawHEADER #replacing header #specify your filename procHDU.writeto('stacked.fits', overwrite=True)
def align_image(image_name_1, image_name_2, new_file_name): File_List = [image_name_1, image_name_2] with fits.open(f'RAW_DATA/{File_List[0]}') as image_hdu_1: Data_1 = image_hdu_1[0].data image_hdu_1.close() with fits.open(f'RAW_DATA/{File_List[1]}') as image_hdu_2: Data_2 = image_hdu_2[0].data # Creating a numpy array of the exposure image_hdu_2.close() Image_Data = [Data_1, Data_2] transf, (source_list, target_list) = aa.find_transform(Image_Data[0], Image_Data[1]) Aligned_Image_Data, footprint = aa.apply_transform(transf, Image_Data[0], Image_Data[1]) # Aligning plt.style.use(astropy_mpl_style) Norm = ImageNormalize(stretch = SqrtStretch()) plt.figure(1) plt.imshow(Image_Data[0], cmap = 'gray', interpolation = 'bicubic', norm = Norm, vmin = 700, vmax = 800) plt.colorbar() plt.figure(2) plt.imshow(Image_Data[1], cmap = 'gray', interpolation = 'bicubic', norm = Norm) plt.colorbar() plt.figure(3) plt.imshow(Aligned_Image_Data, cmap = 'gray', interpolation = 'bicubic', norm = Norm) plt.colorbar() with fits.open(f'RAW_DATA/{File_List[0]}', mode = 'update') as image_hdu_3: image_hdu_3[0].data = Aligned_Image_Data image_hdu_3.flush() image_hdu_3.writeto(f'AlIGNED/{new_file_name}', overwrite = True) # Writing to a new fits file return
def check_if_register_ok(self, numstars): """Helper function to test register with common test code for 3, 4, 5, and 6 stars""" from skimage.transform import estimate_transform if numstars > 6: raise NotImplementedError # x and y of stars in the ref frame (int's) self.star_refx = np.array([100, 120, 400, 400, 200, 200])[:numstars] self.star_refy = np.array([150, 200, 200, 320, 210, 350])[:numstars] self.num_stars = numstars # Fluxes of stars self.star_f = np.array(numstars * [700.0]) ( self.image, self.image_ref, self.star_ref_pos, self.star_new_pos, ) = simulate_image_pair( shape=(self.h, self.w), translation=(self.x_offset, self.y_offset), rot_angle_deg=50.0, noise_level=50, num_stars=self.num_stars, star_refx=self.star_refx, star_refy=self.star_refy, star_flux=self.star_f, ) aligned, footprint = aa.register(self.image_ref, self.image) source = self.star_ref_pos dest = self.star_new_pos.copy() t_true = estimate_transform("similarity", source, dest) aligned_true, fp = aa.apply_transform(t_true, self.image_ref, self.image) err = np.linalg.norm((aligned_true - aligned)[fp], 1) / np.linalg.norm( (aligned_true)[fp], 1) self.assertLess(err, 1e-1)
def _apply_single_channel_transformation(image, reference, transformation, results_dict, channel=None): """ apply a transformation on a specific channel (RGB) of a color image, or whole data of a b&w image. :param image: the image to apply transformation to :type image: Image :param reference: the align reference image :type reference: Image :param transformation: the transformation to apply :type transformation: skimage.transform._geometric.SimilarityTransform :param results_dict: the dict into which transformation result is to be stored. dict key is the channel number for a color image, or 0 for a b&w image :type results_dict: dict :param channel: the 0 indexed number of the color channel to process (0=red, 1=green, 2=blue) :type channel: int """ if channel is not None: target_index = channel source_data = image.data[channel] reference_data = reference.data[channel] else: target_index = 0 source_data = image.data reference_data = reference.data results_dict[target_index] = np.float32( al.apply_transform(transformation, source_data, reference_data))
def main(ref_path, new_path, objname): # alineo las imagenes refdata = fits.getdata(os.path.join(STACK_PATH, ref_path))[250:-250, 250:-250] newdata = fits.getdata(os.path.join(STACK_PATH, new_path))[250:-250, 250:-250] try: trf, _ = aa.find_transform(newdata.astype('<f8'), refdata.astype('<f8')) new_aligned = aa.apply_transform(t, newdata.astype('<f8'), refdata.astype('<f8')) from skimage.transform import warp init_mask = np.zeros_like(newdata) outside_px_mask = warp(init_mask, inverse_map=trf.inverse, output_shape=refdata.shape, order=3, mode='constant', cval=1., clip=False, preserve_range=False) useful = np.where(outside_px_mask == 0) max_x = np.max(useful[0]) min_x = np.min(useful[0]) max_y = np.max(useful[1]) min_y = np.min(useful[1]) new_cropped = new_aligned[min_x:max_x, min_y:max_y] new_mask = outside_px_mask[min_x:max_x, min_y:max_y] ref_cropped = refdata[min_x:max_x, min_y:max_y] except: try: aa.MIN_MATCHES_FRACTION = 0.01 ref = si.SingleImage(refdata.astype('<f8')) new = si.SingleImage(newdata.astype('<f8')) ref.best_sources.sort(order='flux') new.best_sources.sort(order='flux') #~ import ipdb; ipdb.set_trace() rs = np.empty((len(ref.best_sources), 2)) j = 0 for x, y in ref.best_sources[['x', 'y']]: rs[j] = x, y j += 1 ns = np.empty((len(new.best_sources), 2)) j = 0 for x, y in new.best_sources[['x', 'y']]: ns[j] = x, y j += 1 if abs(len(ns) - len(rs)) > 50: max_l = np.max([len(ns), len(rs)]) ns = ns[:max_l] rs = rs[:max_l] trf, _ = aa.find_transform(ns, rs) new_aligned = aa.apply_transform(trf, newdata.astype('<f8'), refdata.astype('<f8')) from skimage.transform import warp init_mask = np.zeros_like(newdata) outside_px_mask = warp(init_mask, inverse_map=trf.inverse, output_shape=refdata.shape, order=3, mode='constant', cval=1., clip=False, preserve_range=False) useful = np.where(outside_px_mask == 0) max_x = np.max(useful[0]) min_x = np.min(useful[0]) max_y = np.max(useful[1]) min_y = np.min(useful[1]) new_cropped = new_aligned[min_x:max_x, min_y:max_y] new_mask = outside_px_mask[min_x:max_x, min_y:max_y] ref_cropped = refdata[min_x:max_x, min_y:max_y] except: #~ import ipdb; ipdb.set_trace() raise # las copio al lugar designado en la pipeline ref_h = fits.getheader(os.path.join(STACK_PATH, ref_path)) fits.writeto(data=ref_cropped.astype('<f4'), header=ref_h, filename=REFERENCE_IMAGE, overwrite=True) new_h = fits.getheader(os.path.join(STACK_PATH, new_path)) fits.writeto(data=new_cropped.astype('<f4'), header=new_h, filename=NEW_IMAGE, overwrite=True) # creo un file con los detalles meta = {} meta['object'] = objname meta['orig_ref_path'] = ref_path meta['orig_new_path'] = new_path with open(DETAILS_FILE, 'w') as fp: json.dump(meta, fp) return 0
dst = np.array([xc0, yc0]).T tform = aa.estimate_transform('affine', src, dst) print("# ----- Parameters of the transformation ----- #") print(f"Rotation: {tform.rotation*180.0/np.pi:.2f} degrees") print("Scale factor: ({:.2f}, {:.2f})".format(*tform.scale)) print("Translation: (x, y) = ({:.2f}, {:.2f})".format( *tform.translation)) print(f"Tranformation matrix:\n{tform.params}") print("\n") if ((n_mch < ip.min_npoi) | (np.sqrt(np.sum(tform.translation**2.0)) > trans_tol)): print("Warning: please check this image visually: al" + wimg[i]) os.system('cp -rpv ' + wimg[i] + ' al' + wimg[i]) else: aligned_image, footprint = aa.apply_transform( tform, s1.dat, s0.dat) fits.writeto('al' + wimg[i], aligned_image, s1.hdr, overwrite=True) else: os.system('cp -rpv ' + wimg[i] + ' al' + wimg[i]) ysize, xsize = fits.getdata(wimg[i], ext=0).shape filt.append(wname.split('w')[1].split('_')[0]) filt = np.array(filt) # Output: alw[FILTER]_[NUMBER].fits # ----- Combining images ----- # ufilt, nfilt = np.unique(filt, return_counts=True) for i in np.arange(len(ufilt)): print("Combining " + ufilt[i] + " band...") cdat = np.zeros((ysize, xsize)) cexp = 0.
image = fits.open("light_00001.fit") rgb_ref = image[0].data image.close() plt.ion() fig = plt.figure() ax = fig.add_subplot(111) new_rvb = np.rollaxis((np.array(rgb_ref) / 65535.)**(1 / 3.), 0, 3) test = ax.imshow(new_rvb) plt.draw() plt.pause(1) for i in tqdm(nb_im_str): image = fits.open("light_" + str(i) + ".fit") rgb_new = image[0].data image.close() p, (pos_img, pos_img_rot) = al.find_transform(rgb_new[1], rgb_ref[1]) rgb_align = [] for j in tqdm(range(3)): rgb_align.append( al.apply_transform(p, rgb_new[j], rgb_ref[j]) + rgb_ref[j]) rgb_align[j] = np.where(rgb_align[j] < 65535, rgb_align[j], 65535) rgb_ref = rgb_align new_rvb = np.rollaxis((np.array(rgb_ref) / 65535.)**(1 / 3.), 0, 3) test = ax.imshow(new_rvb) plt.draw() plt.pause(0.1) plt.show()
def stack_live(work_path, im_path, counter, ref=[], first_ref=[], save_im=False, align=True, stack_methode="Sum"): """ function for process image, align and stack :param work_path: string, path of work folder :param im_path: string, path of process image :param ref: np.array, stack image (no for first image) :param first_ref: np.array, first image process, ref for alignement (no for first image) :param counter: int, number of image stacked :param save_im: bool, option for save image in fit :param align: bool, option for align image or not :param stack_methode: string, stack methode ("sum" or "mean") :return: image: np.array 3xMxN or MxN im_limit: int, bit limit (255 or 65535) im_mode: string, mode : "rgb" or "gray" TODO: Add dark possibility """ # test image format ".fit" or ".fits" or other if im_path.rfind(".fit") != -1: if im_path[im_path.rfind(".fit"):] == ".fit": extension = ".fit" elif im_path[im_path.rfind(".fit"):] == ".fits": extension = ".fits" raw_im = False else: # Other format = raw camera format (cr2, ...) extension = im_path[im_path.rfind("."):] raw_im = True # remove extension of path name = im_path.replace(extension, '') # remove path, juste save image name name = name[name.rfind("/") + 1:] if not raw_im: # open new image new_fit = fits.open(im_path) new = new_fit[0].data # save header new_header = new_fit[0].header new_fit.close() # test data type im_limit, im_type = test_utype(new) # test rgb or gray new, im_mode = test_and_debayer_to_rgb(new_header, new) else: print("convert DSLR image ...") new = rawpy.imread(im_path).postprocess(gamma=(1, 1), no_auto_bright=True, output_bps=16) im_mode = "rgb" extension = ".fits" im_limit = 2. ** 16 - 1 im_type = "uint16" new = np.rollaxis(new, 2, 0) # ____________________________________ # specific part for no first image # choix rgb ou gray scale print("alignement and stacking...") # choix du mode (rgb or B&W) if im_mode == "rgb": if align: # alignement with green : p, __ = al.find_transform(new[1], first_ref[1]) # stacking stack_image = [] for j in tqdm(range(3)): if align: # align all color : align_image = al.apply_transform(p, new[j], ref[j]) else: align_image = new[j] # chose stack methode # need convert to float32 for excess value if stack_methode == "Sum": stack = np.float32(align_image) + np.float32(ref[j]) elif stack_methode == "Mean": stack = ((counter - 1) * np.float32(ref[j]) + np.float32(align_image)) / counter else: raise ValueError("Stack method is not support") # filter excess value > limit if im_type == 'uint8': stack_image.append(np.uint8(np.where(stack < 2 ** 8 - 1, stack, 2 ** 8 - 1))) elif im_type == 'uint16': stack_image.append(np.uint16(np.where(stack < 2 ** 16 - 1, stack, 2 ** 16 - 1))) del stack del new elif im_mode == "gray": if align: # alignement p, __ = al.find_transform(new, first_ref) align_image = al.apply_transform(p, new, ref) del p else: align_image = new del new # chose stack methode # need convert to float32 for excess value if stack_methode == "Sum": stack = np.float32(align_image) + np.float32(ref) elif stack_methode == "Mean": stack = ((counter - 1) * np.float32(ref) + np.float32(align_image)) / counter else: raise ValueError("Stack method is not support") # filter excess value > limit if im_type == 'uint8': stack_image = np.uint8(np.where(stack < 2 ** 8 - 1, stack, 2 ** 8 - 1)) elif im_type == 'uint16': stack_image = np.uint16(np.where(stack < 2 ** 16 - 1, stack, 2 ** 16 - 1)) del stack else: raise ValueError("Mode not support") image = np.array(stack_image) # _____________________________ if save_im: # save stack image in fit red = fits.PrimaryHDU(data=image) red.writeto(work_path + "/" + "stack_image_" + name + extension) # delete image in memory del red return image, im_limit, im_mode
image_7 = hdu_list_7[0].data hdu_list_7.close() #%% Find the image transformation # The transformation is returned in the `p` object. The two objects `img_6_srcs` # and `img_7_srcs` give the coordinates of the sources found by the #`astroalign.find_transform()` fucntion. p, (img_6_srcs, img_7_srcs) = aa.find_transform(image_6, image_7) #%% Transform the `source` image # Unfortunatly, in version 2.4 of `astroalign` we have to convert the image data # type for our images to unsigned 16 bit integers (`uint16`) to make the # transform function work properly. We do this using the image method # `astype('uint16')`. image_6_aligned, footprint = aa.apply_transform(p, image_6.astype('uint16'), image_7.astype('uint16'), fill_value=1000) #%% Write the shifted image to a new FITS file # Creating a new header for the file and add new keyword to the file that # specifies how the image was aligned. header_6_aligned = header_6 header_6_aligned['ALINGED'] = 'Aligned to stars07_p.fits' header_6_aligned fits.writeto('../images/stars06_aligned_example.fits', image_6_aligned, header_6_aligned, overwrite=True)
def stack_live(work_path, new_image, ref_name, counter, save_im=False, align=True, stack_methode="Sum"): # test image format ".fit" or ".fits" if new_image.find(".fits") == -1: extension = ".fit" else: extension = ".fits" # remove extension name = new_image.replace(extension, '') # remove path name = name[name.rfind("/") + 1:] # open new image new_fit = fits.open(new_image) new = new_fit[0].data # save header new_header = new_fit[0].header new_fit.close() # test data type new_limit, new_type = test_utype(new) # test rgb or gray new, new_mode = test_and_debayer_to_rgb(new_header, new) # open ref image ref_fit = fits.open(work_path + "/" + ref_name) ref = ref_fit[0].data ref_fit.close() # test data type ref_limit, ref_type = test_utype(ref) if align: # open first ref image (for align) first_ref_fit = fits.open(work_path + "/" + "first_" + ref_name) first_ref = first_ref_fit[0].data first_ref_fit.close() # test rgb or gray if len(ref.shape) == 2: ref_mode = "gray" elif len(ref.shape) == 3: ref_mode = "rgb" else: raise ValueError("fit format not support") # format verification if ref_limit != new_limit: raise ValueError("ref image and new image is not same format") else: im_type = ref_type if ref_mode == new_mode: mode = ref_mode else: raise ValueError("ref image and new image is not same format") # choix rgb ou gray scale print("alignement and stacking...") if mode == "rgb": if align: # alignement p, __ = al.find_transform(new[1], first_ref[1]) # stacking stack_image = [] for j in tqdm(range(3)): if align: align_image = al.apply_transform(p, new[j], ref[j]) else: align_image = new[j] if stack_methode == "Sum": stack = np.float32(align_image) + np.float32(ref[j]) elif stack_methode == "Mean": stack = ((counter - 1) * np.float32(ref[j]) + np.float32(align_image)) / counter if im_type == 'uint8': stack_image.append( np.uint8(np.where(stack < 2**8 - 1, stack, 2**8 - 1))) elif im_type == 'uint16': stack_image.append( np.uint16(np.where(stack < 2**16 - 1, stack, 2**16 - 1))) else: raise ValueError("Stack methode is not support") elif mode == "gray": if align: # alignement p, __ = al.find_transform(new, first_ref) align_image = al.apply_transform(p, new, ref) else: align_image = new # stacking if stack_methode == "Sum": stack = np.float32(align_image) + np.float32(ref) elif stack_methode == "Mean": stack = ((counter - 1) * np.float32(ref) + np.float32(align_image)) / counter else: raise ValueError("Stack methode is not support") if im_type == 'uint8': stack_image = np.uint8(stack) elif im_type == 'uint16': stack_image = np.uint16(stack) else: raise ValueError("Mode not support") # save new stack ref image in fit os.remove(work_path + "/" + ref_name) red = fits.PrimaryHDU(data=stack_image) red.writeto(work_path + "/" + ref_name) if save_im: # save stack image in fit red = fits.PrimaryHDU(data=stack_image) red.writeto(work_path + "/stack_image_" + name + extension) # save stack image in tiff (print image) os.remove(work_path + "/stack_image.tiff") save_tiff(work_path, np.array(stack_image), mode=mode) return 1
def benchmark(size=SIZE, stars=STARS, noise=NOISE, repeats=REPEATS, seed=None): # get image image = get_image(size, stars, noise, seed) imagedata = np.ascontiguousarray(image[0]) # detect sources (we know where they are, actually) bkg = sep.Background(imagedata) thresh = 3. * bkg.globalrms sources = sep.extract(imagedata - bkg.back(), thresh) sources.sort(order='flux') # perform photometry flux, fluxerr, flag = sep.sum_circle( imagedata-bkg.back(), sources['x'], sources['y'], 3.0, err=bkg.globalrms, gain=1.0) dframes = [] # transform it for i_trsf in range(repeats): dx, dy = np.random.randint( low=-1 * size / 32., high=size / 32., size=2) theta = (np.random.random()-0.5)*0.125*np.pi s = 0.85+np.random.random()*0.3 trf = SimilarityTransform( translation=(dx, dy), rotation=theta, scale=s) target = np.zeros(shape=np.array(imagedata.shape) * 2) newimage = aa.apply_transform(trf, imagedata - bkg.back(), target) # perform photometry on new places src_coords = np.array([sources['x'], sources['y']]).T new_coords = trf(src_coords).T nflux, nfluxerr, nflag = sep.sum_circle( newimage[0], new_coords[0], new_coords[1], 3.0 * s, err=bkg.globalrms, gain=1.0) # compare fluxes good_flux = nflag == 0 new_to_orig = nflux[good_flux]/flux[good_flux] # put everything in a pd dataframe df = pd.DataFrame() df["idx"] = np.array([i_trsf] * sum(good_flux)) df["seed"] = np.array([seed] * sum(good_flux)) df["repeats"] = np.array([repeats] * sum(good_flux)) df['orig_x'] = sources['x'][good_flux] df['orig_y'] = sources['y'][good_flux] df['orig_flux'] = flux[good_flux] df['orig_fluxerr'] = fluxerr[good_flux] df['orig_flag'] = flag[good_flux] df['new_x'] = new_coords[0][good_flux] df['new_y'] = new_coords[1][good_flux] df['new_flux'] = nflux[good_flux] df['new_fluxerr'] = nfluxerr[good_flux] df['new_flag'] = nflag[good_flux] df['flux_ratio'] = new_to_orig df['trf_theta'] = theta df['trf_dx'] = dx df['trf_dy'] = dy df['trf_scale'] = s slp, intpt, r_val, p_val, std_err = stats.linregress( flux[good_flux], nflux[good_flux]) df['stats_slope'] = slp df['stats_intpt'] = intpt df['flux_per_area_ratio'] = df['flux_ratio'] / (df['trf_scale'] ** 2) dframes.append(df) final_df = pd.concat(dframes) return final_df
def register(*args): """Take several images of type numpy.ndarray and align (register) them relative to the first image. """ # Multiple color layers? Use just the green layer for alignment. def singlelayer(img): if len(img.shape) == 3: return img[:, :, 1] return img img1 = singlelayer(args[0]) img2 = singlelayer(args[1]) # Register the two images img_aligned, footprint = astroalign.register(img1, img2) # Plot the results # plot_three(img1, img2, img_aligned) transf, (pos_img, pos_img_rot) = astroalign.find_transform(img1, img2) def print_stats(): print("Rotation: %2d degrees" % (transf.rotation * 180.0 / np.pi)) print("\nScale factor: %.2f" % transf.scale) print("\nTranslation: (x, y) = (%.2f, %.2f)" % tuple(transf.translation)) print("\nTranformation matrix:\n", transf.params) print("\nPoint correspondence:") for (x1, y1), (x2, y2) in zip(pos_img, pos_img_rot): print("(%.2f, %.2f) in source --> (%.2f, %.2f) in target" % (x1, y1, x2, y2)) # print_stats() # Plot correspondences plot_three(img1, img2, img_aligned, pos_img=pos_img, pos_img_rot=pos_img_rot, transf=transf) # Align again using the transform. # Will use this to align the other channels after using one # channel to register the two images. # The documentation doesn't mention a footprint being part of the return, # but it is. realigned, footprint = astroalign.apply_transform(transf, img1, img2) # plot_three(img1, img2, realigned) newshape = args[1].shape if len(newshape) == 2: newshape = args[1].shape + (3, ) # trying https://stackoverflow.com/a/10445502 rgbArray = np.zeros(newshape, 'uint8') for i in range(newshape[-1]): rgbArray[..., i] = realigned img = Image.fromarray(rgbArray) outfile = '/tmp/out.jpg' img.save(outfile) print("Saved to", outfile)
#) #target_image_luma = cv.adaptiveThreshold(src=target_image_luma, # maxValue=255, # adaptiveMethod=cv.ADAPTIVE_THRESH_GAUSSIAN_C, # thresholdType=cv.THRESH_BINARY, # blockSize=11, # C=2) cv.imwrite("{:03d}_target.tiff".format(counter), target_image_luma) try: transf, (source_list, target_list) = aa.find_transform( source=source_image_luma, target=target_image_luma, max_control_points=MAX_CONTROL_POINTS, detection_sigma=DETECTION_SIGMA, min_area=MIN_AREA) projection_0, footprint = aa.apply_transform( transf, source_image[:, :, 0], target_image[:, :, 0]) projection_1, footprint = aa.apply_transform( transf, source_image[:, :, 1], target_image[:, :, 1]) projection_2, footprint = aa.apply_transform( transf, source_image[:, :, 2], target_image[:, :, 2]) projection_image = np.stack( [projection_0, projection_1, projection_2], axis=2) cv.imwrite("{:03d}.tiff".format(counter), projection_image.astype(np.uint8)) accumulated_image += projection_image source_image = target_image counter += 1 output_image = accumulated_image / counter print("Normalizing", end=' ', flush=True) output_image, max, min = normalize(output_image) print(max, min)
# load reference image and image to be aligned from pt5m src_img = fits.getdata(filepath + 'r0500344_am.fits') targ_img = fits.getdata(filepath + 'r0500345_am.fits') # get fits header for target image hdr = fits.getheader(filepath + 'r0500345_am.fits') # increase source image size #src_img = zoom(src_img, 1.5, order=2) #fits.writeto('zoom349.fits', src_img) # known star-to-star correspondence on image targ_str = np.array([(484.0, 267.0), (878.0, 566.0), (257.0, 443.0), (239.0, 460.0), (899.0, 474.0), (781.0, 374.0)]) src_str = np.array([(334.0, 290.0), (727.0, 589.0), (105.0, 466.0), (88.0, 483.0), (748.0, 498.0), (631.0, 398.0)]) # estimate transform tform = aa.estimate_transform('affine', targ_str, src_str) #tform = aa.find_transform(src_img, targ_img) # apply transformation to image to align aligned_img = aa.apply_transform(tform, src_img, targ_img) # update header hdr['HISTORY'] = 'Aligned' #aligned_img = aa.register(src_img, targ_img) os.remove(filename) fits.writeto(filename, aligned_img, hdr)