def _init(self): memory = self._m_config_port.get_attribute("MEMORY") ndim_image = self.m_image_in_port.get_ndim() ndim_psf = self.m_psf_in_port.get_ndim() if ndim_image != 3: raise ValueError( "The image_in_tag should contain a cube of images.") nimages = number_images_port(self.m_image_in_port) im_size = image_size_port(self.m_image_in_port) frames = memory_frames(memory, nimages) npsf = number_images_port(self.m_psf_in_port) psf_size = image_size_port(self.m_psf_in_port) if psf_size != im_size: raise ValueError("The images in '" + self.m_image_in_port.tag + "' should have the same " "dimensions as the images images in '" + self.m_psf_in_port.tag + "'.") if ndim_psf == 3 and npsf == 1: psf = np.squeeze(self.m_psf_in_port.get_all(), axis=0) ndim_psf = psf.ndim elif ndim_psf == 2: psf = self.m_psf_in_port.get_all() elif ndim_psf == 3 and nimages != npsf: psf = np.zeros((self.m_psf_in_port.get_shape()[1], self.m_psf_in_port.get_shape()[2])) frames_psf = memory_frames(memory, npsf) for i, _ in enumerate(frames_psf[:-1]): psf += np.sum(self.m_psf_in_port[frames_psf[i]:frames_psf[i + 1]], axis=0) psf /= float(npsf) ndim_psf = psf.ndim elif ndim_psf == 3 and nimages == npsf: psf = None return psf, ndim_psf, ndim_image, frames
def run(self): """ Run method of the module. Removes the frames and corresponding attributes, updates the NFRAMES attribute, and saves the data and attributes. :return: None """ self._initialize() memory = self._m_config_port.get_attribute("MEMORY") nimages = number_images_port(self.m_image_in_port) frames = memory_frames(memory, nimages) if memory == 0 or memory >= nimages: memory = nimages for i, _ in enumerate(frames[:-1]): progress(i, len(frames[:-1]), "Running RemoveFramesModule...") images = self.m_image_in_port[frames[i]:frames[i + 1], ] index_del = np.where(np.logical_and(self.m_frames >= frames[i], \ self.m_frames < frames[i+1])) write_selected_data(images, self.m_frames[index_del] % memory, self.m_selected_out_port, self.m_removed_out_port) sys.stdout.write("Running RemoveFramesModule... [DONE]\n") sys.stdout.flush() history = "frames removed = " + str(np.size(self.m_frames)) if self.m_selected_out_port is not None: # Copy attributes before write_selected_attributes is used self.m_selected_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_selected_out_port.add_history_information( "RemoveFramesModule", history) if self.m_removed_out_port is not None: # Copy attributes before write_selected_attributes is used self.m_removed_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_removed_out_port.add_history_information( "RemoveFramesModule", history) write_selected_attributes(self.m_frames, self.m_image_in_port, self.m_selected_out_port, self.m_removed_out_port) self.m_image_in_port.close_port()
def run(self): """ Run method of the module. Rotates all images by a constant angle. :return: None """ self.m_image_out_port.del_all_attributes() self.m_image_out_port.del_all_data() if self.m_image_in_port.tag == self.m_image_out_port.tag: raise ValueError( "Input and output port should have a different tag.") memory = self._m_config_port.get_attribute("MEMORY") ndim = self.m_image_in_port.get_ndim() nimages = number_images_port(self.m_image_in_port) frames = memory_frames(memory, nimages) for i, _ in enumerate(frames[:-1]): progress(i, len(frames[:-1]), "Running RotateImagesModule...") if nimages == 1: images = self.m_image_in_port.get_all() else: images = self.m_image_in_port[frames[i]:frames[i + 1], ] for j in range(frames[i + 1] - frames[i]): if nimages == 1: im_tmp = images else: im_tmp = images[j, ] # ndimage.rotate rotates in clockwise direction for positive angles im_tmp = rotate(im_tmp, self.m_angle, reshape=False) self.m_image_out_port.append(im_tmp, data_dim=ndim) sys.stdout.write("Running RotateImagesModule... [DONE]\n") sys.stdout.flush() self.m_image_out_port.add_history_information("Images rotated", self.m_angle) self.m_image_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_image_out_port.close_port()
def run(self): """ Run method of the module. Smooths the images with a Gaussian kernel, locates the brightest pixel in each image, measures the integrated flux around the brightest pixel, calculates the median and standard deviation of the photometry, and applies sigma clipping to remove low quality images. :return: None """ def _get_aperture(aperture): if aperture[0] == "circular": aperture = (0., aperture[1] / pixscale) elif aperture[0] == "annulus" or aperture[0] == "ratio": aperture = (aperture[1] / pixscale, aperture[2] / pixscale) return aperture def _get_starpos(fwhm, position): starpos = np.zeros((nimages, 2), dtype=np.int64) if fwhm is None: starpos[:, 0] = position[0] starpos[:, 1] = position[1] else: if position is None: center = None width = None else: if position[0] is None and position[1] is None: center = None else: center = position[0:2] width = int(math.ceil(position[2] / pixscale)) for i, _ in enumerate(starpos): starpos[i, :] = locate_star( image=self.m_image_in_port[i, ], center=center, width=width, fwhm=int(math.ceil(fwhm / pixscale))) return starpos def _photometry(images, starpos, aperture): check_pos_in = any(np.floor(starpos[:] - aperture[1]) < 0.) check_pos_out = any( np.ceil(starpos[:] + aperture[1]) > images.shape[0]) if check_pos_in or check_pos_out: phot = np.nan else: im_crop = crop_image(images, starpos, 2 * int(math.ceil(aperture[1]))) npix = im_crop.shape[0] x_grid = y_grid = np.linspace(-(npix - 1) / 2, (npix - 1) / 2, npix) xx_grid, yy_grid = np.meshgrid(x_grid, y_grid) rr_grid = np.sqrt(xx_grid * xx_grid + yy_grid * yy_grid) if self.m_aperture[0] == "circular": phot = np.sum(im_crop[rr_grid < aperture[1]]) elif self.m_aperture[0] == "annulus": phot = np.sum(im_crop[(rr_grid > aperture[0]) & (rr_grid < aperture[1])]) elif self.m_aperture[0] == "ratio": phot = np.sum(im_crop[rr_grid < aperture[0]]) / \ np.sum(im_crop[(rr_grid > aperture[0]) & (rr_grid < aperture[1])]) return phot self._initialize() pixscale = self.m_image_in_port.get_attribute("PIXSCALE") nimages = number_images_port(self.m_image_in_port) aperture = _get_aperture(self.m_aperture) starpos = _get_starpos(self.m_fwhm, self.m_position) phot = np.zeros(nimages) for i in range(nimages): progress(i, nimages, "Running FrameSelectionModule...") images = self.m_image_in_port[i] phot[i] = _photometry(images, starpos[i, :], aperture) if self.m_method == "median": phot_ref = np.nanmedian(phot) elif self.m_method == "max": phot_ref = np.nanmax(phot) phot_std = np.nanstd(phot) index_rm = np.logical_or( (phot > phot_ref + self.m_threshold * phot_std), (phot < phot_ref - self.m_threshold * phot_std)) index_rm[np.isnan(phot)] = True indices = np.where(index_rm)[0] indices = np.asarray(indices, dtype=np.int) if np.size(indices) > 0: memory = self._m_config_port.get_attribute("MEMORY") frames = memory_frames(memory, nimages) if memory == 0 or memory >= nimages: memory = nimages for i, _ in enumerate(frames[:-1]): images = self.m_image_in_port[frames[i]:frames[i + 1], ] index_del = np.where(np.logical_and(indices >= frames[i], \ indices < frames[i+1])) write_selected_data(images, indices[index_del] % memory, self.m_selected_out_port, self.m_removed_out_port) else: warnings.warn("No frames were removed.") history = "frames removed = " + str(np.size(indices)) if self.m_index_out_port is not None: self.m_index_out_port.set_all(np.transpose(indices)) self.m_index_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_index_out_port.add_attribute("STAR_POSITION", starpos, static=False) self.m_index_out_port.add_history_information( "FrameSelectionModule", history) if self.m_selected_out_port is not None: # Copy attributes before write_selected_attributes is used self.m_selected_out_port.copy_attributes_from_input_port( self.m_image_in_port) if self.m_removed_out_port is not None: # Copy attributes before write_selected_attributes is used self.m_removed_out_port.copy_attributes_from_input_port( self.m_image_in_port) write_selected_attributes(indices, self.m_image_in_port, self.m_selected_out_port, self.m_removed_out_port) if self.m_selected_out_port is not None: indices_select = np.ones(nimages, dtype=bool) indices_select[indices] = False indices_select = np.where(indices_select) self.m_selected_out_port.add_attribute("STAR_POSITION", starpos[indices_select], static=False) self.m_selected_out_port.add_history_information( "FrameSelectionModule", history) if self.m_removed_out_port is not None: self.m_removed_out_port.add_attribute("STAR_POSITION", starpos[indices], static=False) self.m_removed_out_port.add_history_information( "FrameSelectionModule", history) sys.stdout.write("Running FrameSelectionModule... [DONE]\n") sys.stdout.flush() self.m_image_in_port.close_port()
def write_selected_attributes(indices, port_input, port_selected, port_removed): """ Function to write the attributes of a selected number of images. :param indices: Indices that are removed. :type indices: ndarray :param port_input: Port to the input data. :type port_input: InputPort :param port_selected: Port to store the attributes of the selected images. :type port_selected: OutputPort :param port_removed: Port to store the attributes of the removed images. Not written if set to None. :type port_removed: OutputPort :return: None """ nimages = number_images_port(port_input) non_static = port_input.get_all_non_static_attributes() for i, item in enumerate(non_static): values = port_input.get_attribute(item) if values.shape[0] == nimages: if port_selected is not None: if np.size(indices) > 0: if values.ndim == 1: selected = np.delete(values, indices) elif values.ndim == 2: selected = np.delete(values, indices, axis=0) else: selected = values port_selected.add_attribute(item, selected, static=False) if port_removed is not None and np.size(indices) > 0: removed = values[indices] port_removed.add_attribute(item, removed, static=False) if "NFRAMES" in non_static: nframes = port_input.get_attribute("NFRAMES") nframes_sel = np.zeros(nframes.shape, dtype=np.int) nframes_del = np.zeros(nframes.shape, dtype=np.int) for i, frames in enumerate(nframes): total = np.sum(nframes[0:i]) if np.size(indices) > 0: index_del = np.where(np.logical_and(indices >= total, \ indices < total+frames))[0] nframes_sel[i] = frames - np.size(index_del) nframes_del[i] = np.size(index_del) else: nframes_sel[i] = frames nframes_del[i] = 0 if port_selected is not None: port_selected.add_attribute("NFRAMES", nframes_sel, static=False) if port_removed is not None: port_removed.add_attribute("NFRAMES", nframes_del, static=False)
def run(self): """ Run method of the module. Locates the position of the star (only pixel precision) by selecting the highest pixel value. A Gaussian kernel with a FWHM similar to the PSF is used to lower the contribution of bad pixels which may have higher values than the peak of the PSF. Images are cropped and written to an output port. The position of the star is attached to the input images as the non-static attribute STAR_POSITION (y, x). :return: None """ pixscale = self.m_image_in_port.get_attribute("PIXSCALE") if self.m_position is not None: self.m_position = np.asarray(self.m_position) nimages = number_images_port(self.m_image_in_port) if self.m_position.ndim == 2 and self.m_position.shape[ 0] != nimages: raise ValueError( "Either a single 'position' should be specified or an array " "equal in size to the number of images in 'image_in_tag'.") self.m_image_size = int(math.ceil(self.m_image_size / pixscale)) self.m_fwhm_star = int(math.ceil(self.m_fwhm_star / pixscale)) star = [] index = [] def _crop_around_star(image, position, im_size, fwhm): if position is None: center = None width = None else: if position.ndim == 1: if position[0] is None and position[1] is None: center = None else: center = (int(position[1]), int(position[0])) width = int(math.ceil(position[2] / pixscale)) elif position.ndim == 2: center = (int(position[self.m_count, 1]), int(position[self.m_count, 0])) width = int(math.ceil(position[self.m_count, 2] / pixscale)) starpos = locate_star(image, center, width, fwhm) try: im_crop = crop_image(image, starpos, im_size) except ValueError: warnings.warn( "PSF size is too large to crop the image around the brightest " "pixel (image index = " + str(self.m_count) + ", pixel [x, y] = " + str([starpos[0]] + [starpos[1]]) + "). Using the center of the " "image instead.") index.append(self.m_count) starpos = image_center_pixel(image) im_crop = crop_image(image, starpos, im_size) star.append((starpos[1], starpos[0])) self.m_count += 1 return im_crop self.apply_function_to_images(_crop_around_star, self.m_image_in_port, self.m_image_out_port, "Running StarExtractionModule...", func_args=(self.m_position, self.m_image_size, self.m_fwhm_star)) if self.m_index_out_port is not None: self.m_index_out_port.set_all(np.transpose(np.asarray(index))) self.m_index_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_index_out_port.add_history_information( "Extract star", "brightest pixel") self.m_image_out_port.add_attribute("STAR_POSITION", np.asarray(star), static=False) self.m_image_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_image_out_port.add_history_information("Extract star", "brightest pixel") self.m_image_out_port.close_port()
def run(self): """ Run method of the module. Locates the position of the calibration spots in the center frame. From the four spots, the position of the star behind the coronagraph is fitted, and the images are shifted and cropped. :return: None """ def _get_center(ndim, center): if ndim == 2: center_frame = self.m_center_in_port.get_all() elif ndim == 3: center_frame = self.m_center_in_port.get_all()[0, ] if center_shape[0] > 1: warnings.warn( "Multiple center images found. Using the first image of " "the stack.") if center is None: center = image_center_pixel(center_frame) else: center = (np.floor(center[0]), np.floor(center[1])) return center_frame, center self.m_image_out_port.del_all_data() self.m_image_out_port.del_all_attributes() center_ndim = self.m_center_in_port.get_ndim() center_shape = self.m_center_in_port.get_shape() im_shape = self.m_image_in_port.get_shape() center_frame, self.m_center = _get_center(center_ndim, self.m_center) if im_shape[-2:] != center_shape[-2:]: raise ValueError( "Science and center images should have the same shape.") pixscale = self.m_image_in_port.get_attribute("PIXSCALE") self.m_sigma /= pixscale if self.m_size is not None: self.m_size = int(math.ceil(self.m_size / pixscale)) if self.m_dither: dither_x = self.m_image_in_port.get_attribute("DITHER_X") dither_y = self.m_image_in_port.get_attribute("DITHER_Y") nframes = self.m_image_in_port.get_attribute("NFRAMES") nframes = np.cumsum(nframes) nframes = np.insert(nframes, 0, 0) center_frame_unsharp = center_frame - gaussian_filter( input=center_frame, sigma=self.m_sigma) # size of center image, only works with odd value ref_image_size = 21 # Arrays for the positions x_pos = np.zeros(4) y_pos = np.zeros(4) # Loop for 4 waffle spots for i in range(4): # Approximate positions of waffle spots if self.m_pattern == "x": x_0 = np.floor(self.m_center[0] + self.m_radius * np.cos(np.pi / 4. * (2 * i + 1))) y_0 = np.floor(self.m_center[1] + self.m_radius * np.sin(np.pi / 4. * (2 * i + 1))) elif self.m_pattern == "+": x_0 = np.floor(self.m_center[0] + self.m_radius * np.cos(np.pi / 4. * (2 * i))) y_0 = np.floor(self.m_center[1] + self.m_radius * np.sin(np.pi / 4. * (2 * i))) tmp_center_frame = crop_image(image=center_frame_unsharp, center=(int(y_0), int(x_0)), size=ref_image_size) # find maximum in tmp image y_max, x_max = np.unravel_index(np.argmax(tmp_center_frame), dims=tmp_center_frame.shape) pixmax = tmp_center_frame[y_max, x_max] max_pos = np.array([x_max, y_max]).reshape(1, 2) # Check whether it is the correct maximum: second brightest pixel should be nearby tmp_center_frame[y_max, x_max] = 0. # introduce distance parameter dist = np.inf while dist > 2: y_max_new, x_max_new = np.unravel_index( np.argmax(tmp_center_frame), dims=tmp_center_frame.shape) pixmax_new = tmp_center_frame[y_max_new, x_max_new] # Caculate minimal distance to previous points tmp_center_frame[y_max_new, x_max_new] = 0. dist = np.amin( np.linalg.norm(np.vstack((max_pos[:, 0] - x_max_new, max_pos[:, 1] - y_max_new)), axis=0)) if dist <= 2 and pixmax_new < pixmax: break max_pos = np.vstack((max_pos, [x_max_new, y_max_new])) x_max = x_max_new y_max = y_max_new pixmax = pixmax_new x_0 = x_0 - (ref_image_size - 1) / 2 + x_max y_0 = y_0 - (ref_image_size - 1) / 2 + y_max # create reference image around determined maximum ref_center_frame = crop_image(image=center_frame_unsharp, center=(int(y_0), int(x_0)), size=ref_image_size) # Fit the data using astropy.modeling gauss_init = models.Gaussian2D(amplitude=np.amax(ref_center_frame), x_mean=x_0, y_mean=y_0, x_stddev=1., y_stddev=1., theta=0.) fit_gauss = fitting.LevMarLSQFitter() y_grid, x_grid = np.mgrid[y_0 - (ref_image_size - 1) / 2:y_0 + (ref_image_size - 1) / 2 + 1, x_0 - (ref_image_size - 1) / 2:x_0 + (ref_image_size - 1) / 2 + 1] gauss = fit_gauss(gauss_init, x_grid, y_grid, ref_center_frame) x_pos[i] = gauss.x_mean.value y_pos[i] = gauss.y_mean.value # Find star position as intersection of two lines x_center = ((y_pos[0]-x_pos[0]*(y_pos[2]-y_pos[0])/(x_pos[2]-float(x_pos[0]))) - \ (y_pos[1]-x_pos[1]*(y_pos[1]-y_pos[3])/(x_pos[1]-float(x_pos[3])))) / \ ((y_pos[1]-y_pos[3])/(x_pos[1]-float(x_pos[3])) - \ (y_pos[2]-y_pos[0])/(x_pos[2]-float(x_pos[0]))) y_center = x_center*(y_pos[1]-y_pos[3])/(x_pos[1]-float(x_pos[3])) + \ (y_pos[1]-x_pos[1]*(y_pos[1]-y_pos[3])/(x_pos[1]-float(x_pos[3]))) nimages = number_images_port(self.m_image_in_port) npix = image_size_port(self.m_image_in_port)[0] for i in range(nimages): progress(i, nimages, "Running WaffleCenteringModule...") image = self.m_image_in_port[i, ] shift_yx = [(float(im_shape[-2]) - 1.) / 2. - y_center, (float(im_shape[-1]) - 1.) / 2. - x_center] if self.m_dither: index = np.digitize(i, nframes, right=False) - 1 shift_yx[0] -= dither_y[index] shift_yx[1] -= dither_x[index] if npix % 2 == 0 and self.m_size is not None: im_tmp = np.zeros((image.shape[0] + 1, image.shape[1] + 1)) im_tmp[:-1, :-1] = image image = im_tmp shift_yx[0] += 0.5 shift_yx[1] += 0.5 im_shift = shift_image(image, shift_yx, "spline") if self.m_size is not None: im_crop = crop_image(im_shift, None, self.m_size) self.m_image_out_port.append(im_crop, data_dim=3) else: self.m_image_out_port.append(im_shift, data_dim=3) sys.stdout.write("Running WaffleCenteringModule... [DONE]\n") sys.stdout.write("Center [x, y] = [" + str(x_center) + ", " + str(y_center) + "]\n") sys.stdout.flush() self.m_image_out_port.copy_attributes_from_input_port( self.m_image_in_port) history = "position [x, y] = " + str( [round(x_center, 4), round(y_center, 4)]) self.m_image_out_port.add_history_information("Waffle centering", history) self.m_image_out_port.close_port()
def run(self): """ Run method of the module. Uses a non-linear least squares (Levenberg-Marquardt) to fit the the individual images or the mean of the stack with a 2D Gaussian profile, shifts the images with subpixel precision, and writes the centered images and the fitting results. The fitting results contain zeros in case the algorithm could not converge. :return: None """ self.m_fit_out_port.del_all_data() self.m_fit_out_port.del_all_attributes() if self.m_image_out_port: self.m_image_out_port.del_all_data() self.m_image_out_port.del_all_attributes() if self.m_mask_out_port: self.m_mask_out_port.del_all_data() self.m_mask_out_port.del_all_attributes() npix = self.m_image_in_port.get_shape()[-1] memory = self._m_config_port.get_attribute("MEMORY") pixscale = self.m_image_in_port.get_attribute("PIXSCALE") if self.m_radius: self.m_radius /= pixscale if npix % 2 == 0: x_grid = y_grid = np.linspace(-npix / 2 + 0.5, npix / 2 - 0.5, npix) x_ap = np.linspace(-npix / 2 + 0.5 - self.m_guess[0], npix / 2 - 0.5 - self.m_guess[0], npix) y_ap = np.linspace(-npix / 2 + 0.5 - self.m_guess[1], npix / 2 - 0.5 - self.m_guess[1], npix) elif npix % 2 == 1: x_grid = y_grid = np.linspace(-(npix - 1) / 2, (npix - 1) / 2, npix) x_ap = np.linspace(-(npix - 1) / 2 - self.m_guess[0], (npix - 1) / 2 - self.m_guess[0], npix) y_ap = np.linspace(-(npix - 1) / 2 - self.m_guess[1], (npix - 1) / 2 - self.m_guess[1], npix) xx_grid, yy_grid = np.meshgrid(x_grid, y_grid) xx_ap, yy_ap = np.meshgrid(x_ap, y_ap) rr_ap = np.sqrt(xx_ap**2 + yy_ap**2) def _2d_gaussian(grid, x_center, y_center, fwhm_x, fwhm_y, amp, theta): (xx_grid, yy_grid) = grid x_diff = xx_grid - x_center y_diff = yy_grid - y_center sigma_x = fwhm_x / math.sqrt(8. * math.log(2.)) sigma_y = fwhm_y / math.sqrt(8. * math.log(2.)) a_gauss = 0.5 * ((np.cos(theta) / sigma_x)**2 + (np.sin(theta) / sigma_y)**2) b_gauss = 0.5 * ((np.sin(2. * theta) / sigma_x**2) - (np.sin(2. * theta) / sigma_y**2)) c_gauss = 0.5 * ((np.sin(theta) / sigma_x)**2 + (np.cos(theta) / sigma_y)**2) gaussian = amp * np.exp(-(a_gauss * x_diff**2 + b_gauss * x_diff * y_diff + c_gauss * y_diff**2)) if self.m_radius: gaussian = gaussian[rr_ap < self.m_radius] else: gaussian = np.ravel(gaussian) return gaussian def _least_squares(image): if self.m_mask_out_port: mask = np.copy(image) if self.m_radius: mask[rr_ap > self.m_radius] = 0. if self.m_method == "mean": self.m_mask_out_port.set_all(mask) elif self.m_method == "full": self.m_mask_out_port.append(mask, data_dim=3) if self.m_sign == "negative": image = -image + np.abs(np.min(-image)) if self.m_radius: image = image[rr_ap < self.m_radius] else: image = np.ravel(image) try: popt, pcov = curve_fit(_2d_gaussian, (xx_grid, yy_grid), image, p0=self.m_guess, sigma=None, method='lm') perr = np.sqrt(np.diag(pcov)) except RuntimeError: popt = np.zeros(6) perr = np.zeros(6) self.m_count += 1 res = np.asarray( (popt[0] * pixscale, perr[0] * pixscale, popt[1] * pixscale, perr[1] * pixscale, popt[2] * pixscale, perr[2] * pixscale, popt[3] * pixscale, perr[3] * pixscale, popt[4], perr[4], math.degrees(popt[5]) % 360., math.degrees(perr[5]))) self.m_fit_out_port.append(res, data_dim=2) return popt def _centering(image, popt): if self.m_method == "full": popt = _least_squares(np.copy(image)) return shift_image(image, (-popt[1], -popt[0]), self.m_interpolation) ndim = self.m_image_in_port.get_ndim() npix = self.m_image_in_port.get_shape()[-1] nimages = number_images_port(self.m_image_in_port) frames = memory_frames(memory, nimages) if self.m_method == "full": popt = None elif self.m_method == "mean": if ndim == 2: im_mean = self.m_image_in_port[:, :] elif ndim == 3: im_mean = np.zeros((npix, npix)) for i, _ in enumerate(frames[:-1]): im_mean += np.sum( self.m_image_in_port[frames[i]:frames[i + 1], ], axis=0) im_mean /= float(nimages) popt = _least_squares(im_mean) self.apply_function_to_images(_centering, self.m_image_in_port, self.m_image_out_port, "Running StarCenteringModule...", func_args=(popt, )) if self.m_count > 0: print( "2D Gaussian fit could not converge on %s image(s). [WARNING]" % self.m_count) history = "method = " + self.m_method if self.m_image_out_port: self.m_image_out_port.add_history_information( "StarCenteringModule", history) self.m_image_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_fit_out_port.add_history_information("StarCenteringModule", history) self.m_fit_out_port.copy_attributes_from_input_port( self.m_image_in_port) if self.m_mask_out_port: self.m_mask_out_port.add_history_information( "StarCenteringModule", history) self.m_mask_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_fit_out_port.close_port()
def run(self): """ Run method of the module. Calculates the SNR and FPF for a specified position in a post- processed image with the Student's t-test (Mawet et al. 2014). This approach accounts for small sample statistics. :return: None """ self.m_snr_out_port.del_all_data() self.m_snr_out_port.del_all_attributes() pixscale = self.m_image_in_port.get_attribute("PIXSCALE") self.m_aperture /= pixscale nimages = number_images_port(self.m_image_in_port) center = self.m_image_in_port.get_shape()[-1] / 2. sep = math.sqrt((center - self.m_position[0])**2. + (center - self.m_position[1])**2.) ang = (math.atan2(self.m_position[1] - center, self.m_position[0] - center) * 180. / math.pi - 90.) % 360. num_ap = int(math.pi * sep / self.m_aperture) ap_theta = np.linspace(0, 2. * math.pi, num_ap, endpoint=False) if self.m_ignore: num_ap -= 2 ap_theta = np.delete(ap_theta, [1, np.size(ap_theta) - 1]) for j in range(nimages): progress(j, nimages, "Running FalsePositiveModule...") if nimages == 1: image = self.m_image_in_port.get_all() if image.ndim == 3: image = np.squeeze(image, axis=0) else: image = self.m_image_in_port[j, ] ap_phot = np.zeros(num_ap) for i, theta in enumerate(ap_theta): x_tmp = center + (self.m_position[0]-center)*math.cos(theta) - \ (self.m_position[1]-center)*math.sin(theta) y_tmp = center + (self.m_position[0]-center)*math.sin(theta) + \ (self.m_position[1]-center)*math.cos(theta) aperture = CircularAperture((x_tmp, y_tmp), self.m_aperture) phot_table = aperture_photometry(image, aperture, method='exact') ap_phot[i] = phot_table['aperture_sum'] snr = (ap_phot[0] - np.mean(ap_phot[1:])) / \ (np.std(ap_phot[1:]) * math.sqrt(1.+1./float(num_ap-1))) fpf = 1. - t.cdf(snr, num_ap - 2) result = np.column_stack((self.m_position[0], self.m_position[1], sep * pixscale, ang, snr, fpf)) if nimages == 1: self.m_snr_out_port.set_all(result) else: self.m_snr_out_port.append(result, data_dim=2) sys.stdout.write("Running FalsePositiveModule... [DONE]\n") sys.stdout.flush() history = "aperture [arcsec] = " + str("{:.2f}".format( self.m_aperture * pixscale)) self.m_snr_out_port.add_history_information("FalsePositiveModule", history) self.m_snr_out_port.copy_attributes_from_input_port( self.m_image_in_port) self.m_snr_out_port.close_port()