Esempio n. 1
0
    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
Esempio n. 2
0
    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()
Esempio n. 3
0
    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()
Esempio n. 4
0
    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()
Esempio n. 5
0
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)
Esempio n. 6
0
    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()
Esempio n. 7
0
    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()
Esempio n. 8
0
    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()
Esempio n. 9
0
    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()