Esempio n. 1
0
def align_image(image_in: np.ndarray,
                im_index: int,
                interpolation: str,
                accuracy: float,
                resize: Optional[float],
                num_references: int,
                subframe: Optional[float],
                ref_images_reshape: np.ndarray,
                ref_images_shape: Tuple[int, int, int]) -> np.ndarray:

    offset = np.array([0., 0.])

    # Reshape the reference images back to their original 3D shape
    # The original shape can not be used directly because of util.module.update_arguments
    ref_images = ref_images_reshape.reshape(ref_images_shape)

    for i in range(num_references):
        if subframe is None:
            tmp_offset, _, _ = phase_cross_correlation(ref_images[i, :, :],
                                                       image_in,
                                                       upsample_factor=accuracy)

        else:
            sub_in = crop_image(image_in, None, subframe)
            sub_ref = crop_image(ref_images[i, :, :], None, subframe)

            tmp_offset, _, _ = phase_cross_correlation(sub_ref,
                                                       sub_in,
                                                       upsample_factor=accuracy)
        offset += tmp_offset

    offset /= float(num_references)

    if resize is not None:
        offset *= resize

        sum_before = np.sum(image_in)

        tmp_image = rescale(image_in,
                            (resize, resize),
                            order=5,
                            mode='reflect',
                            multichannel=False,
                            anti_aliasing=True)

        sum_after = np.sum(tmp_image)

        # Conserve flux because the rescale function normalizes all values to [0:1].
        tmp_image = tmp_image*(sum_before/sum_after)

    else:
        tmp_image = image_in

    return shift_image(tmp_image, offset, interpolation)
Esempio n. 2
0
def locate_star(image, center, width, fwhm):
    """
    Function to locate the star by finding the brightest pixel.

    :param image: Input image.
    :type image: ndarray
    :param center: Pixel center (y, x) of the subframe. The full image is used if set to None.
    :type center: (int, int)
    :param width: The width (pixel) of the subframe. The full image is used if set to None.
    :type width: int
    :param fwhm: Full width at half maximum of the Gaussian kernel.
    :type fwhm: int

    :return: Position (y, x) of the brightest pixel.
    :rtype: (int, int)
    """

    if width is not None:
        if center is None:
            center = image_center_pixel(image)

        image = crop_image(image, center, width)

    sigma = fwhm / math.sqrt(8. * math.log(2.))
    kernel = (fwhm * 2 + 1, fwhm * 2 + 1)
    smooth = cv2.GaussianBlur(image, kernel, sigma)

    # argmax[0] is the y position and argmax[1] is the y position
    argmax = np.asarray(np.unravel_index(smooth.argmax(), smooth.shape))

    if center is not None and width is not None:
        argmax[0] += center[0] - (image.shape[0] - 1) // 2  # y
        argmax[1] += center[1] - (image.shape[1] - 1) // 2  # x

    return argmax
Esempio n. 3
0
        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, tuple(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
Esempio n. 4
0
        def _crop_rotating_star(image, position, im_size, filter_size):

            starpos = locate_star(image=image,
                                  center=position,
                                  width=self.m_search_size,
                                  fwhm=filter_size)

            return crop_image(image=image, center=starpos, size=im_size)
Esempio n. 5
0
        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
Esempio n. 6
0
        def _crop_around_star(image: np.ndarray,
                              position: Optional[Union[Tuple[int, int, float],
                                                       Tuple[None, None, float]]],
                              im_size: int,
                              fwhm: int) -> np.ndarray:

            if position is None:
                center = None
                width = None

            else:
                if position[0] is None and position[1] is None:
                    center = None
                else:
                    center = (position[1], position[0])  # (y, x)

                width = int(math.ceil(position[2]/pixscale))

            starpos = locate_star(image, center, width, fwhm)

            try:
                im_crop = crop_image(image, tuple(starpos), im_size)

            except ValueError:
                if cpu == 1:
                    warnings.warn(f'Chosen image size is too large to crop the image around the '
                                  f'brightest pixel (image index = {self.m_count}, pixel [x, y] '
                                  f'= [{starpos[0]}, {starpos[1]}]). Using the center of the '
                                  f'image instead.')

                    index.append(self.m_count)

                else:
                    warnings.warn('Chosen image size is too large to crop the image around the '
                                  'brightest pixel. Using the center of the image instead.')

                starpos = center_pixel(image)
                im_crop = crop_image(image, tuple(starpos), im_size)

            if cpu == 1:
                star.append((starpos[1], starpos[0]))
                self.m_count += 1

            return im_crop
Esempio n. 7
0
    def aperture_phot(
        image: np.ndarray, position: np.ndarray,
        aperture: Union[Tuple[str, float, float], Tuple[str, None, float]]
    ) -> np.float64:
        """
        Parameters
        ----------
        image : np.ndarray
            Input image (2D).
        position : np.ndarray
            Center position (y, x) of the aperture.
        aperture : tuple(str, float, float)
            Tuple with the aperture properties for measuring the
            photometry around the location of the brightest pixel. The
            first element contains the aperture type ('circular',
            'annulus', or 'ratio'). For a circular aperture, the second
            element is empty and the third element contains the aperture
            radius (pix). For the other two types, the second and third
            element are the inner and outer radii (pix) of the aperture.

        Returns
        -------
        np.float64
            Photometry value.
        """

        check_pos_in = any(np.floor(position[:] - aperture[2]) < 0.)
        check_pos_out = any(
            np.ceil(position[:] + aperture[2]) > image.shape[0])

        if check_pos_in or check_pos_out:
            phot = np.nan

        else:
            im_crop = crop_image(image, tuple(position),
                                 2 * int(math.ceil(aperture[2])))

            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**2 + yy_grid**2)

            if aperture[0] == 'circular':
                phot = np.sum(im_crop[rr_grid < aperture[2]])

            elif aperture[0] == 'annulus':
                phot = np.sum(im_crop[(rr_grid > aperture[1])
                                      & (rr_grid < aperture[2])])

            elif aperture[0] == 'ratio':
                phot = np.sum(im_crop[rr_grid < aperture[1]]) / \
                       np.sum(im_crop[(rr_grid > aperture[1]) & (rr_grid < aperture[2])])

        return phot
Esempio n. 8
0
        def _align_image(image_in):
            offset = np.array([0., 0.])

            for i in range(self.m_num_references):
                if self.m_subframe is None:
                    tmp_offset, _, _ = register_translation(
                        ref_images[i, :, :],
                        image_in,
                        upsample_factor=self.m_accuracy)

                else:
                    sub_in = crop_image(image_in, None, self.m_subframe)
                    sub_ref = crop_image(ref_images[i, :, :], None,
                                         self.m_subframe)

                    tmp_offset, _, _ = register_translation(
                        sub_ref, sub_in, upsample_factor=self.m_accuracy)
                offset += tmp_offset

            offset /= float(self.m_num_references)

            if self.m_resize is not None:
                offset *= self.m_resize

                sum_before = np.sum(image_in)

                tmp_image = rescale(image=np.asarray(image_in,
                                                     dtype=np.float64),
                                    scale=(self.m_resize, self.m_resize),
                                    order=5,
                                    mode='reflect',
                                    anti_aliasing=True,
                                    multichannel=False)

                sum_after = np.sum(tmp_image)

                # Conserve flux because the rescale function normalizes all values to [0:1].
                tmp_image = tmp_image * (sum_before / sum_after)

            else:
                tmp_image = image_in

            return shift_image(tmp_image, offset, self.m_interpolation)
Esempio n. 9
0
def crop_around_star(image: np.ndarray,
                     im_index: int,
                     position: Optional[Union[Tuple[int, int, float],
                                              Tuple[None, None, float]]],
                     im_size: int,
                     fwhm: int,
                     pixscale: float,
                     index_out_port: Optional[OutputPort],
                     image_out_port: OutputPort) -> np.ndarray:

    if position is None:
        center = None
        width = None

    else:
        if position[0] is None and position[1] is None:
            center = None
        else:
            center = (position[1], position[0])  # (y, x)

        width = int(math.ceil(position[2]/pixscale))

    starpos = locate_star(image, center, width, fwhm)

    try:
        im_crop = crop_image(image, tuple(starpos), im_size)

    except ValueError:
        warnings.warn(f'Chosen image size is too large to crop the image around the '
                      f'brightest pixel (image index = {im_index}, pixel [x, y] '
                      f'= [{starpos[0]}, {starpos[1]}]). Using the center of the '
                      f'image instead.')

        if index_out_port is not None:
            index_out_port.append([im_index], data_dim=1)

        starpos = center_pixel(image)
        im_crop = crop_image(image, tuple(starpos), im_size)

    return im_crop
Esempio n. 10
0
        def _crop_rotating_star(image: np.ndarray,
                                position: Union[Tuple[float, float], np.ndarray],
                                im_size: int,
                                filter_size: Optional[int]) -> np.ndarray:

            starpos = locate_star(image=image,
                                  center=tuple(position),
                                  width=self.m_search_size,
                                  fwhm=filter_size)

            return crop_image(image=image,
                              center=tuple(starpos),
                              size=im_size)
Esempio n. 11
0
    def run(self) -> None:
        """
        Run method of the module. Decreases the image size by cropping around an given position.
        The module always returns odd-sized images.

        Returns
        -------
        NoneType
            None
        """

        self.m_image_out_port.del_all_attributes()
        self.m_image_out_port.del_all_data()

        # Get memory and number of images to split the frames into chunks
        memory = self._m_config_port.get_attribute('MEMORY')
        nimages = self.m_image_in_port.get_shape()[0]
        frames = memory_frames(memory, nimages)

        # Convert size parameter from arcseconds to pixels
        pixscale = self.m_image_in_port.get_attribute('PIXSCALE')
        self.m_size = int(math.ceil(self.m_size / pixscale))

        # Crop images chunk by chunk
        start_time = time.time()
        for i in range(len(frames[:-1])):

            # Update progress bar
            progress(i, len(frames[:-1]), 'Running CropImagesModule...',
                     start_time)

            # Select and crop images in the current chunk
            images = self.m_image_in_port[frames[i]:frames[i + 1], ]
            images = crop_image(images, self.m_center, self.m_size, copy=False)

            # Write cropped images to output port
            self.m_image_out_port.append(images, data_dim=3)

        # Update progress bar (cropping of images is finished)
        sys.stdout.write('Running CropImagesModule... [DONE]\n')
        sys.stdout.flush()

        # Save history and copy attributes
        history = f'image size [pix] = {self.m_size}'
        self.m_image_out_port.add_history('CropImagesModule', history)
        self.m_image_out_port.copy_attributes(self.m_image_in_port)
        self.m_image_out_port.close_port()
Esempio n. 12
0
def locate_star(image: np.ndarray,
                center: Union[tuple, None],
                width: Union[int, None],
                fwhm: Union[int, None]) -> np.ndarray:
    """
    Function to locate the star by finding the brightest pixel.

    Parameters
    ----------
    image : numpy.ndarray
        Input image (2D).
    center : tuple(int, int), None
        Pixel center (y, x) of the subframe. The full image is used if set to None.
    width : int, None
        The width (pix) of the subframe. The full image is used if set to None.
    fwhm : int, None
        Full width at half maximum (pix) of the Gaussian kernel. Not used if set to None.

    Returns
    -------
    numpy.ndarray
        Position (y, x) of the brightest pixel.
    """

    if width is not None:
        if center is None:
            center = center_pixel(image)

        image = crop_image(image, center, width)

    if fwhm is None:
        smooth = np.copy(image)

    else:
        sigma = fwhm / math.sqrt(8. * math.log(2.))
        kernel = (fwhm * 2 + 1, fwhm * 2 + 1)
        smooth = cv2.GaussianBlur(image, kernel, sigma)

    # argmax[0] is the y position and argmax[1] is the y position
    argmax = np.asarray(np.unravel_index(smooth.argmax(), smooth.shape))

    if center is not None and width is not None:
        argmax[0] += center[0] - (image.shape[0] - 1) // 2  # y
        argmax[1] += center[1] - (image.shape[1] - 1) // 2  # x

    return argmax
Esempio n. 13
0
    def run(self) -> None:
        """
        Run the module. The FITS files are collected from the input directory and uncompressed if
        needed. The images are then sorted by the two chop positions (chop A and chop B). The
        required FITS header keywords (which should be set in the configuration file) are also
        imported and stored as attributes to the two output datasets in the HDF5 database.

        Returns
        -------
        NoneType
            None
        """

        # clear the output ports
        self.m_chopa_out_port.del_all_data()
        self.m_chopa_out_port.del_all_attributes()
        self.m_chopb_out_port.del_all_data()
        self.m_chopb_out_port.del_all_attributes()

        # uncompress the FITS files if needed
        self.uncompress()

        # find and sort the FITS files
        files = []

        for filename in os.listdir(self.m_input_location):
            if filename.endswith('.fits'):
                files.append(os.path.join(self.m_input_location, filename))

        files.sort()

        # check if there are FITS files present in the input location
        assert (files), f'No FITS files found in {self.m_input_location}.'

        # if cropping chop A, get pixscale and convert crop_size to pixels and swap x/y
        if self.m_crop is not None:
            pixscale = self._m_config_port.get_attribute('PIXSCALE')
            self.m_crop = (self.m_crop[1], self.m_crop[0],
                           int(math.ceil(self.m_crop[2] / pixscale)))

        start_time = time.time()
        for i, filename in enumerate(files):
            progress(i, len(files), 'Preprocessing NEAR data...', start_time)

            # get the primary header data and the image shape
            header, im_shape = self.read_header(filename)

            # get the images of chop A and chop B
            chopa, chopb = self.read_images(filename, im_shape)

            if self.m_subtract:
                chopa = chopa - chopb
                chopb = -1. * np.copy(chopa)

            if self.m_crop is not None:
                chopa = crop_image(chopa,
                                   center=self.m_crop[0:2],
                                   size=self.m_crop[2],
                                   copy=False)

                chopb = crop_image(chopb,
                                   center=self.m_crop[0:2],
                                   size=self.m_crop[2],
                                   copy=False)

            if self.m_combine is not None:

                if self.m_combine == 'mean':
                    chopa = np.mean(chopa, axis=0)
                    chopb = np.mean(chopb, axis=0)

                elif self.m_combine == 'median':
                    chopa = np.median(chopa, axis=0)
                    chopb = np.median(chopb, axis=0)

                header[self._m_config_port.get_attribute('NFRAMES')] = 1

            # append the images of chop A and B
            self.m_chopa_out_port.append(chopa, data_dim=3)
            self.m_chopb_out_port.append(chopb, data_dim=3)

            # starting value for the INDEX attribute
            first_index = 0

            for port in (self.m_chopa_out_port, self.m_chopb_out_port):

                # set the static attributes
                set_static_attr(fits_file=filename,
                                header=header,
                                config_port=self._m_config_port,
                                image_out_port=port,
                                check=True)

                # set the non-static attributes
                set_nonstatic_attr(header=header,
                                   config_port=self._m_config_port,
                                   image_out_port=port,
                                   check=True)

                # set the remaining attributes
                set_extra_attr(fits_file=filename,
                               nimages=im_shape[0] // 2,
                               config_port=self._m_config_port,
                               image_out_port=port,
                               first_index=first_index)

                # increase the first value of the INDEX attribute
                first_index += im_shape[0] // 2

                # flush the output port
                port.flush()

        # add history information
        self.m_chopa_out_port.add_history('NearReadingModule', 'Chop A')
        self.m_chopb_out_port.add_history('NearReadingModule', 'Chop B')

        # close all connections to the database
        self.m_chopa_out_port.close_port()
Esempio n. 14
0
    def run(self) -> None:
        """
        Run method of the module. Computes the similarity between frames based on the Mean Squared
        Error (MSE), the Pearson Correlation Coefficient (PCC), or the Structural Similarity (SSIM).
        The correlation values are stored as non-static attribute (``MSE``, ``PCC``, or ``SSIM``)
        to the input data. After running this module, the
        :class:`~pynpoint.processing.frameselection.SelectByAttributeModule` can be used to select
        the images with the highest correlation.

        Returns
        -------
        NoneType
            None
        """

        cpu = self._m_config_port.get_attribute('CPU')
        pixscale = self.m_image_in_port.get_attribute('PIXSCALE')

        # get number of images
        nimages = self.m_image_in_port.get_shape()[0]

        # convert arcsecs to pixels
        self.m_mask_radii = (math.floor(self.m_mask_radii[0] / pixscale),
                             math.floor(self.m_mask_radii[1] / pixscale))
        self.m_window_size = int(self.m_window_size / pixscale)

        # overlay the same mask over all images
        images = self.m_image_in_port.get_all()

        # close the port during the calculations
        self.m_image_out_port.close_port()

        images = crop_image(images, None, int(self.m_mask_radii[1]))

        if self.m_temporal_median == 'constant':
            temporal_median = np.median(images, axis=0)
        else:
            temporal_median = False

        # compare images and store similarity
        similarities = np.zeros(nimages)

        pool = mp.Pool(cpu)
        async_results = []

        for i in range(nimages):
            async_results.append(
                pool.apply_async(FrameSimilarityModule._similarity,
                                 args=(images, i, self.m_method,
                                       self.m_window_size, temporal_median)))

        pool.close()

        start_time = time.time()

        # wait for all processes to finish
        while mp.active_children():
            # number of finished processes
            nfinished = sum([i.ready() for i in async_results])

            progress(nfinished, nimages, 'Calculating image similarity...',
                     start_time)

            # check if new processes have finished every 5 seconds
            time.sleep(5)

        if nfinished != nimages:
            print('\r                                                      ')
            print('\rCalculating image similarity... [DONE]')

        # get the results for every async_result object
        for async_result in async_results:
            reference, similarity = async_result.get()
            similarities[reference] = similarity

        pool.terminate()

        # reopen the port after the calculation
        self.m_image_out_port.open_port()
        self.m_image_out_port.add_attribute(f'{self.m_method}',
                                            similarities,
                                            static=False)
        self.m_image_out_port.close_port()
Esempio n. 15
0
    def run(self) -> None:
        """
        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.

        Returns
        -------
        NoneType
            None
        """
        @typechecked
        def _get_center(
            image_number: int, center: Optional[Tuple[int, int]]
        ) -> Tuple[np.ndarray, Tuple[int, int]]:

            if center_shape[-3] > 1:
                warnings.warn(
                    'Multiple center images found. Using the first image of the stack.'
                )

            if ndim == 3:
                center_frame = self.m_center_in_port[0, ]
            elif ndim == 4:
                center_frame = self.m_center_in_port[image_number, 0, ]

            if center is None:
                center = center_pixel(center_frame)
            else:
                center = (int(np.floor(center[0])), int(np.floor(center[1])))

            return center_frame, center

        center_shape = self.m_center_in_port.get_shape()
        im_shape = self.m_image_in_port.get_shape()
        ndim = self.m_image_in_port.get_ndim()

        center_frame, self.m_center = _get_center(0, self.m_center)

        # Read in wavelength information or set it to default values
        if ndim == 4:
            wavelength = self.m_image_in_port.get_attribute('WAVELENGTH')

            if wavelength is None:
                raise ValueError(
                    'The wavelength information is required to centre IFS data. '
                    'Please add it via the WavelengthReadingModule before using '
                    'the WaffleCenteringModule.')

            if im_shape[0] != center_shape[0]:
                raise ValueError(
                    f'Number of science wavelength channels: {im_shape[0]}. '
                    f'Number of center wavelength channels: {center_shape[0]}. '
                    'Exactly one center image per wavelength is required.')

            wavelength_min = np.min(wavelength)

        elif ndim == 3:
            # for none ifs data, use default value
            wavelength = [1.]
            wavelength_min = 1.

        # check if science and center images have the same shape
        if im_shape[-2:] != center_shape[-2:]:
            raise ValueError(
                'Science and center images should have the same shape.')

        # Setting angle via pattern (used for backwards compability)
        if self.m_pattern is not None:

            if self.m_pattern == 'x':
                self.m_angle = 45.

            elif self.m_pattern == '+':
                self.m_angle = 0.

            else:
                raise ValueError(
                    f'The pattern {self.m_pattern} is not valid. Please select '
                    f'either \'x\' or \'+\'.')

            warnings.warn(
                f'The \'pattern\' parameter will be deprecated in a future release. '
                f'Please Use the \'angle\' parameter instead and set it to '
                f'{self.m_angle} degrees.', DeprecationWarning)

        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)

        # 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)

        # Arrays for the center position for each wavelength
        x_center = np.zeros((len(wavelength)))
        y_center = np.zeros((len(wavelength)))

        # Loop for 4 waffle spots
        for w, wave_nr in enumerate(wavelength):

            # Prapre centering frame
            center_frame, _ = _get_center(w, self.m_center)

            center_frame_unsharp = center_frame - gaussian_filter(
                input=center_frame, sigma=self.m_sigma)

            for i in range(4):
                # Approximate positions of waffle spots
                radius = self.m_radius * wave_nr / wavelength_min

                x_0 = np.floor(self.m_center[0] + radius *
                               np.cos(self.m_angle * np.pi / 180 + np.pi / 4. *
                                      (2 * i)))

                y_0 = np.floor(self.m_center[1] + radius *
                               np.sin(self.m_angle * np.pi / 180 + 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
                coords = np.unravel_index(indices=np.argmax(tmp_center_frame),
                                          shape=tmp_center_frame.shape)

                y_max, x_max = coords[0], coords[1]

                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:
                    coords = np.unravel_index(
                        indices=np.argmax(tmp_center_frame),
                        shape=tmp_center_frame.shape)

                    y_max_new, x_max_new = coords[0], coords[1]

                    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[w] = ((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[w] = x_center[w]*(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])))

        # Adjust science images
        nimages = self.m_image_in_port.get_shape()[-3]
        npix = self.m_image_in_port.get_shape()[-2]
        nwavelengths = len(wavelength)

        start_time = time.time()

        for i in range(nimages):
            im_storage = []
            for j in range(nwavelengths):
                im_index = i * nwavelengths + j

                progress(im_index, nimages * nwavelengths,
                         'Centering the images...', start_time)

                if ndim == 3:
                    image = self.m_image_in_port[i, ]
                elif ndim == 4:
                    image = self.m_image_in_port[j, i, ]

                shift_yx = np.array([
                    (float(im_shape[-2]) - 1.) / 2. - y_center[j],
                    (float(im_shape[-1]) - 1.) / 2. - x_center[j]
                ])

                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)
                    im_storage.append(im_crop)
                else:
                    im_storage.append(im_shift)

            if ndim == 3:
                self.m_image_out_port.append(im_storage[0], data_dim=3)
            elif ndim == 4:
                self.m_image_out_port.append(np.asarray(im_storage),
                                             data_dim=4)

        print(f'Center [x, y] = [{x_center}, {y_center}]')

        history = f'[x, y] = [{round(x_center[j], 2)}, {round(y_center[j], 2)}]'
        self.m_image_out_port.copy_attributes(self.m_image_in_port)
        self.m_image_out_port.add_history('WaffleCenteringModule', history)
        self.m_image_out_port.close_port()
Esempio n. 16
0
    def run(self) -> None:
        """
        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.

        Returns
        -------
        NoneType
            None
        """
        def _get_center(center):
            center_frame = self.m_center_in_port[0, ]

            if center_shape[0] > 1:
                warnings.warn(
                    'Multiple center images found. Using the first image of the stack.'
                )

            if center is None:
                center = 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_shape = self.m_center_in_port.get_shape()
        im_shape = self.m_image_in_port.get_shape()

        center_frame, self.m_center = _get_center(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
            coords = np.unravel_index(indices=np.argmax(tmp_center_frame),
                                      shape=tmp_center_frame.shape)

            y_max, x_max = coords[0], coords[1]

            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:
                coords = np.unravel_index(indices=np.argmax(tmp_center_frame),
                                          shape=tmp_center_frame.shape)

                y_max_new, x_max_new = coords[0], coords[1]

                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 = self.m_image_in_port.get_shape()[0]
        npix = self.m_image_in_port.get_shape()[1]

        start_time = time.time()
        for i in range(nimages):
            progress(i, nimages, 'Centering the images...', start_time)

            image = self.m_image_in_port[i, ]

            shift_yx = np.array([(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)

        print(f'Center [x, y] = [{x_center}, {y_center}]')

        history = f'[x, y] = [{round(x_center, 2)}, {round(y_center, 2)}]'
        self.m_image_out_port.copy_attributes(self.m_image_in_port)
        self.m_image_out_port.add_history('WaffleCenteringModule', history)
        self.m_image_out_port.close_port()
Esempio n. 17
0
        def _crop(image_in, size, center):

            return crop_image(image_in, center, size)
Esempio n. 18
0
    def run(self) -> None:
        """
        Run method of the module. Computes the similarity between frames based on the Mean Squared
        Error (MSE), the Pearson Correlation Coefficient (PCC), or the Structural Similarity (SSIM).

        Returns
        -------
        NoneType
            None
        """

        # get image number and image shapes
        nimages = self.m_image_in_port.get_shape()[0]
        im_shape = self.m_image_in_port.get_shape()[1:]

        cpu = self._m_config_port.get_attribute('CPU')
        pixscale = self.m_image_in_port.get_attribute('PIXSCALE')

        # convert arcsecs to pixels
        self.m_mask_radii = (math.floor(self.m_mask_radii[0] / pixscale),
                             math.floor(self.m_mask_radii[1] / pixscale))
        self.m_window_size = int(self.m_window_size / pixscale)

        # overlay the same mask over all images
        mask = create_mask(im_shape, self.m_mask_radii)
        images = self.m_image_in_port.get_all()

        # close the port during the calculations
        self.m_image_out_port.close_port()

        if self.m_temporal_median == 'constant':
            temporal_median = np.median(images, axis=0)
        else:
            temporal_median = False

        if self.m_method == 'SSIM':
            images = crop_image(images, None, int(self.m_mask_radii[1]))
            temporal_median = crop_image(temporal_median, None, int(self.m_mask_radii[1]))
        else:
            images *= mask

        # compare images and store similarity
        similarities = np.zeros(nimages)

        pool = mp.Pool(cpu)
        async_results = []

        for i in range(nimages):
            async_results.append(pool.apply_async(FrameSimilarityModule._similarity,
                                                  args=(images,
                                                        i,
                                                        self.m_method,
                                                        self.m_window_size,
                                                        temporal_median)))

        pool.close()

        start_time = time.time()

        # wait for all processes to finish
        while mp.active_children():
            # number of finished processes
            nfinished = sum([i.ready() for i in async_results])

            progress(nfinished, nimages, 'Running FrameSimilarityModule', start_time)

            # check if new processes have finished every 5 seconds
            time.sleep(5)

        # get the results for every async_result object
        for async_result in async_results:
            reference, similarity = async_result.get()
            similarities[reference] = similarity

        pool.terminate()

        # reopen the port after the calculation
        self.m_image_out_port.open_port()
        self.m_image_out_port.add_attribute(f'{self.m_method}', similarities, static=False)
        self.m_image_out_port.close_port()
Esempio n. 19
0
        def _image_cutting(image_in,
                           size,
                           center):

            return crop_image(image_in, center, size)
Esempio n. 20
0
    def run(self) -> None:
        """
        Run method of the module. Decreases the image size by cropping around an given position.
        The module always returns odd-sized images.

        Returns
        -------
        NoneType
            None
        """

        # Get memory and number of images to split the frames into chunks
        memory = self._m_config_port.get_attribute('MEMORY')
        nimages = self.m_image_in_port.get_shape()[0]

        # Get the numnber of dimensions and shape
        ndim = self.m_image_in_port.get_ndim()
        im_shape = self.m_image_in_port.get_shape()

        if ndim == 3:
            # Number of images
            nimages = im_shape[-3]

            # Split into batches to comply with memory constraints
            frames = memory_frames(memory, nimages)

        elif ndim == 4:
            # Process all wavelengths per exposure at once
            frames = np.linspace(0, im_shape[-3], im_shape[-3] + 1)

        # Convert size parameter from arcseconds to pixels
        pixscale = self.m_image_in_port.get_attribute('PIXSCALE')
        print(f'New image size (arcsec) = {self.m_size}')
        self.m_size = int(math.ceil(self.m_size / pixscale))
        print(f'New image size (pixels) = {self.m_size}')

        if self.m_center is not None:
            print(f'New image center (x, y) = {self.m_center}')

        # Crop images chunk by chunk
        start_time = time.time()
        for i in range(len(frames[:-1])):

            # Update progress bar
            progress(i, len(frames[:-1]), 'Cropping images...', start_time)

            # Select images in the current chunk
            if ndim == 3:
                images = self.m_image_in_port[frames[i]:frames[i + 1], ]

            elif ndim == 4:
                # Process all wavelengths per exposure at once
                images = self.m_image_in_port[:, i, ]

            # crop images according to input parameters
            images = crop_image(images, self.m_center, self.m_size, copy=False)

            # Write processed images to output port
            if ndim == 3:
                self.m_image_out_port.append(images, data_dim=3)
            elif ndim == 4:
                self.m_image_out_port.append(images, data_dim=4)

        # Save history and copy attributes
        history = f'image size (pix) = {self.m_size}'
        self.m_image_out_port.add_history('CropImagesModule', history)
        self.m_image_out_port.copy_attributes(self.m_image_in_port)
        self.m_image_out_port.close_port()