Beispiel #1
0
    def from_scarlet(self, scarlet_model_dir, pixel_scale=HSC_pixel_scale):
        from galsim import Image, InterpolatedImage
        from galsim.interpolant import Lanczos

        with open(scarlet_model_dir, 'rb') as f:
            blend, info, mask = dill.load(f)
            f.close()
        assert ''.join(blend.observations[0].channels) == self.channels

        # Crop the mask
        new_weights = blend.observations[0].weights
        x1, y1 = blend.sources[0].bbox.origin[1:]
        x2 = x1 + blend.sources[0].bbox.shape[1:][0]
        y2 = y1 + blend.sources[0].bbox.shape[1:][1]
        mask = mask.astype(bool)[x1:x2, y1:y2]
        mask += np.sum((new_weights[:, x1:x2, y1:y2] == 0),
                       axis=0).astype(bool)

        mockgal_img = blend.sources[0].get_model() * np.repeat(
            ~mask[np.newaxis, :, :], len(self.channels), axis=0)
        gal_image = np.empty_like(self.bkg.images)
        for i in range(len(mockgal_img)):
            mockgal = InterpolatedImage(Image(mockgal_img[i], dtype=float),
                                        scale=pixel_scale,
                                        x_interpolant=Lanczos(3))
            gal_image[i] = mockgal.drawImage(scale=pixel_scale,
                                             nx=self.bkg.images.shape[2],
                                             ny=self.bkg.images.shape[1]).array

        # Generate variance map
        ra, dec = self.bkg.wcs.wcs_pix2world(self.bkg.images.shape[2] / 2,
                                             self.bkg.images.shape[1] / 2, 0)
        info = {
            'ra': ra,
            'dec': dec,
            'scarlet_model': scarlet_model_dir,
            'model_type': 'scarlet_lsbg_wvlt_0.5'
        }
        mock_model = Data(images=gal_image,
                          variances=None,
                          masks=None,
                          channels=self.channels,
                          wcs=None,
                          weights=None,
                          psfs=self.bkg.psfs,
                          info=info)

        # Finished!!!
        self.model = mock_model  # model only has `images`, `channels`, `psfs`, and `info`!
        self.set_mock()  # mock has other things, including modified variances.
Beispiel #2
0
    def resize_mask(self, f, method='iraf', order=5, cval=0.0):
        '''Zoom/Resize the mask of Celestial object. 
            f > 1 means the mask will be resampled (finer)! f < 1 means the mask will be degraded.

        Parameters:
            f (float): the positive factor of zoom. If 0 < f < 1, the mask will be resized to smaller one.
            method (str): interpolation method. Use 'lanczos' or 'spline' or 'iraf'.
            order (int): the order Lanczos interpolation (>0).
            cval (scalar): value to fill the edges. Default is NaN.

        Returns:
            shift_image: ndarray.
        '''
        if method == 'lanczos':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )

            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                       scale=self.pixel_scale,
                                       x_interpolant=Lanczos(order))
            ny, nx = self.mask.shape
            result = galimg.drawImage(
                scale=self.pixel_scale / f, nx=round(nx * f),
                ny=round(ny * f))  #, wcs=AstropyWCS(self.wcs))
            self.wcs = self._resize_wcs(self.image, self.wcs, f)
            self._image = result.array
            self.shape = self.mask.shape
            self._wcs_header_merge()
            self.pixel_scale /= f
            return result.array
        elif method == 'iraf':
            self.save_to_fits('./_temp.fits', 'mask')
            if f > 1:
                magnify('./_temp.fits', './_resize_temp.fits', f, f)
            else:
                blkavg('./_temp.fits',
                       './_resize_temp.fits',
                       1 / f,
                       1 / f,
                       option='sum')
            hdu = fits.open('./_resize_temp.fits')
            self.mask = hdu[0].data
            self.shape = hdu[0].data.shape
            self.header = hdu[0].header
            self.wcs = wcs.WCS(self.header)
            self.pixel_scale /= f
            hdu.close()
            imdelete('./*temp.fits')
        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos' or 'iraf'."
            )
Beispiel #3
0
    def shift_mask(self, dx, dy, method='iraf', order=5, cval=0.0):
        '''Shift the mask of Celestial object.

        Parameters:
            dx, dy (float): shift distance (in pixel) along x (horizontal) and y (vertical). 
                Note that elements in one row has the same y but different x. 
                Example: dx = 2 is to shift the image "RIGHT", dy = 3 is to shift the image "UP".
            method (str): interpolation method. Use 'lanczos' or 'spline' or 'iraf'
            order (int): the order of spline interpolation (within 0-5) or Lanczos interpolation (>0).
            cval (scalar): value to fill the edges. Default is NaN.

        Returns:
            shift_mask: ndarray.
        '''
        ny, nx = self.mask.shape
        if abs(dx) > nx or abs(ny) > ny:
            raise ValueError('# Shift distance is beyond the image size.')
        if method == 'lanczos':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )
            # Begin shift
            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                       scale=self.pixel_scale,
                                       x_interpolant=Lanczos(order))
            galimg = galimg.shift(dx=dx * self.pixel_scale,
                                  dy=dy * self.pixel_scale)
            result = galimg.drawImage(scale=self.pixel_scale, nx=nx,
                                      ny=ny)  #, wcs=AstropyWCS(self.wcs))
            self._mask = result.array
            # Change the WCS of image
            hdr = copy.deepcopy(self.header)
            hdr['CRPIX1'] += dx
            hdr['CRPIX2'] += dy
            self.header = hdr
            self.wcs = wcs.WCS(hdr)
            self._wcs_header_merge()
            return result.array
        elif method == 'iraf':
            self.save_to_fits('./_temp.fits', 'mask')
            imshift('./_temp.fits',
                    './_shift_temp.fits',
                    dx,
                    dy,
                    interp_type='poly3',
                    boundary_type='constant')
            hdu = fits.open('./_shift_temp.fits')
            self.mask = hdu[0].data
            self.shape = hdu[0].data.shape
            self.header = hdu[0].header
            self.wcs = wcs.WCS(self.header)
            hdu.close()
            imdelete('./*temp.fits')
        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos' or 'iraf'."
            )
Beispiel #4
0
    def outlier_rejection(star_list,
                          pos_list,
                          mask_list,
                          ccd_list,
                          SNR_list=None,
                          RA_list=None,
                          DEC_list=None,
                          shape_std_max=5.,
                          print_fun=None):
        r"""Outlier star rejection method.

        Notes
        -----
        It is based on the measurements from Galsim's HSM adaptive moments.
        The method calculates the 2nd order moments from the stars
        in the exposure. If there are stars that have an aberrant value in one
        of the stats, e1, e2 or R2 we discard the star.
        An aberrant value is defined as a value that is more
        than ``shape_std_max`` sigmas away from the mean.

        It inputs all the lists that will be used as a method and returns
        the same lists without the stars that where considered as outliers.

        ``print_fun`` is a function that prints details about the stars
        being removed.

        """
        # Define the printing function. Could be printing on a log file.
        if print_fun is None:

            def print_fun(msg):
                print(msg)

        # Reject outliers
        all_stars = np.concatenate(star_list, axis=2)
        all_stars = utils.reg_format(np.copy(all_stars))
        all_masks = np.concatenate(mask_list, axis=2)
        all_masks = utils.reg_format(np.copy(all_masks))
        # hsm thinks 0 means good
        badpix_masks = np.rint(np.abs(all_masks - 1))

        star_moms = [
            hsm.FindAdaptiveMom(Image(star), badpix=Image(bp), strict=False)
            for star, bp in zip(all_stars, badpix_masks)
        ]
        star_shapes = np.array([[
            moms.observed_shape.g1, moms.observed_shape.g2,
            2. * moms.moments_sigma**2,
            int(bool(moms.error_message))
        ] for moms in star_moms])

        # Outlier rejection based on e1, e2 and R2
        R2_thresh = shape_std_max * np.std(star_shapes[:, 2]) + \
            np.mean(star_shapes[:, 2])
        R2_bad_stars = (abs(star_shapes[:, 2]) > R2_thresh)

        e2_thresh = shape_std_max * np.std(star_shapes[:, 1]) + \
            np.mean(star_shapes[:, 1])
        e2_bad_stars = (abs(star_shapes[:, 1]) > e2_thresh)

        e1_thresh = shape_std_max * np.std(star_shapes[:, 0]) + \
            np.mean(star_shapes[:, 0])
        e1_bad_stars = (abs(star_shapes[:, 0]) > e1_thresh)

        bad_stars = np.logical_or(e1_bad_stars, e2_bad_stars)
        bad_stars = np.logical_or(bad_stars, R2_bad_stars)

        bad_stars_idx = np.nonzero(bad_stars)[0]
        print_fun(bad_stars_idx)
        print_fun(bad_stars_idx.shape)

        # Create masks
        erase_masks = [
            np.zeros(star_list[i].shape[2], dtype=bool)
            for i in range(len(star_list))
        ]

        if bad_stars_idx.size > 0:
            # We have to erase the outliers
            # Create the reference ids (to match the global
            # array to the list of arrays)
            idx_ref = np.zeros((len(all_stars), 3), dtype=int)
            glob_id, star_id, ccd_id = 0, 0, 0
            for stars in star_list:
                star_id = 0
                for _star in utils.reg_format(stars):
                    idx_ref[glob_id, 0] = glob_id
                    idx_ref[glob_id, 1] = star_id
                    idx_ref[glob_id, 2] = ccd_id
                    glob_id += 1
                    star_id += 1
                ccd_id += 1

            # select outlier stars
            for bad_id in bad_stars_idx:
                print_fun('Outlier: Glob_id=%d , star_id=%d , ccd_id=%d' %
                          (idx_ref[bad_id, 0], idx_ref[bad_id,
                                                       1], idx_ref[bad_id, 2]))
                erase_masks[idx_ref[bad_id, 2]][idx_ref[bad_id, 1]] = True

            for it_star in range(len(star_list)):
                mask = ~erase_masks[it_star]
                # erase elements and overwrite
                star_list[it_star] = star_list[it_star][:, :, mask]
                mask_list[it_star] = mask_list[it_star][:, :, mask]
                pos_list[it_star] = pos_list[it_star][mask, :]
                if SNR_list is not None:
                    SNR_list[it_star] = SNR_list[it_star][mask]
                if RA_list is not None:
                    RA_list[it_star] = RA_list[it_star][mask]
                    DEC_list[it_star] = DEC_list[it_star][mask]

        return star_list, pos_list, mask_list, ccd_list, SNR_list, RA_list,\
            DEC_list, erase_masks
Beispiel #5
0
    def resize_mask(self, f, method='lanczos', order=5, cval=0.0):
        '''Zoom/Resize the mask of Stack object.
        Cautious: don't use ['bicubic', 'nearest', 'cubic', 'bilinear'] methods! They don't conserve the total flux!

        Parameters:
            f (float): the positive factor of zoom. If 0 < f < 1, the image will be resized to smaller one.
            method (str): interpolation method. Use 'lanczos' or 'spline'.
            order (int): the order of spline interpolation (within 0-5) or Lanczos interpolation (>0).
            cval (scalar): value to fill the edges. Default is NaN.

        Returns:
            shift_image: ndarray.
        '''
        if method == 'lanczos':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )

            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                       scale=0.168,
                                       x_interpolant=Lanczos(order))
            #galimg = galimg.magnify(f)
            ny, nx = self.mask.shape
            result = galimg.drawImage(
                scale=0.168 / f, nx=round(nx * f),
                ny=round(ny * f))  #, wcs=AstropyWCS(self.wcs))
            self.wcs = self._resize_wcs(self.mask, self.wcs, f)
            self._mask = result.array
            self.shape = self.mask.shape
            return result.array
        elif method == 'spline':
            from scipy.ndimage import zoom
            assert 0 < order <= 5 and isinstance(
                order, int), 'order of ' + method + ' must be within 0-5.'
            result = zoom(self.mask,
                          float(f),
                          order=order,
                          mode='constant',
                          cval=cval)
            self._mask = result
            self.wcs = self._resize_wcs(self.mask, self.wcs, f)
            self.shape = self.mask.shape
            return result
        elif method in ['bicubic', 'nearest', 'cubic', 'bilinear']:
            raise Warning(
                "Cautious! Don't use ['bicubic', 'nearest', 'cubic', 'bilinear'] methods! They don't conserve the total flux!"
            )
            try:
                from scipy.misc import imresize
            except:
                raise ImportError(
                    '# Import `scipy.misc.imresize` failed! This function may no longer be included in scipy!'
                )
            result = imresize(self.mask, float(f), interp=method)
            self._mask = result.astype(float)
            self.wcs = self._resize_wcs(self.mask, self.wcs, f)
            self.shape = self.mask.shape
            return result.astype(float)
        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos' or 'spline'."
            )
Beispiel #6
0
    def shift_mask(self, dx, dy, method='lanczos', order=5, cval=0.0):
        '''Shift the mask of Stack object.

        Parameters:
            dx, dy (float): shift distance (in pixel) along x (horizontal) and y (vertical). 
                Note that elements in one row has the same y but different x. 
                Example: dx = 2 is to shift the image "RIGHT", dy = 3 is to shift the image "UP".
            method (str): interpolation method. Use 'lanczos' or 'spline'.
            order (int): the order of spline interpolation (within 0-5) or Lanczos interpolation (>0).
            cval (scalar): value to fill the edges. Default is NaN.

        Returns:
            shift_mask: ndarray.
        '''
        if not hasattr(self, 'mask'):
            raise AttributeError("This `Stack` object doesn't have `mask`!")
        ny, nx = self.image.shape
        if abs(dx) > nx or abs(ny) > ny:
            raise ValueError('# Shift distance is beyond the image size.')

        if method == 'lanczos':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )
            # Begin shift
            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                       scale=0.168,
                                       x_interpolant=Lanczos(order))
            galimg = galimg.shift(dx=dx * 0.168, dy=dy * 0.168)
            result = galimg.drawImage(scale=0.168, nx=nx,
                                      ny=ny)  #, wcs=AstropyWCS(self.wcs))
            self._mask = (result.array > 0.5).astype(float)
            # Change the WCS of image
            hdr = copy.deepcopy(self.header)
            hdr['CRPIX1'] += dx
            hdr['CRPIX2'] += dy
            self.header = hdr
            self.wcs = wcs.WCS(hdr)
            return result.array
        elif method == 'spline':
            from scipy.ndimage.interpolation import shift
            assert 0 < order <= 5 and isinstance(
                order, int), 'order of ' + method + ' must be within 0-5.'
            result = shift(self.mask, [dy, dx],
                           order=order,
                           mode='constant',
                           cval=cval)
            self._mask = (result > 0.5).astype(float)
            # Change the WCS of image
            hdr = copy.deepcopy(self.header)
            hdr['CRPIX1'] += dx
            hdr['CRPIX2'] += dy
            self.header = hdr
            self.wcs = wcs.WCS(hdr)
            return result
        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos' or 'spline'."
            )
Beispiel #7
0
    def rotate_mask(self,
                    angle,
                    method='lanczos',
                    order=5,
                    reshape=False,
                    cval=0.0):
        '''Rotate the mask of Stack object.

        Parameters:
            angle (float): rotation angle in degress, counterclockwise.
            method (str): interpolation method. Use 'lanczos', 'spline', 'cubic', 
                'bicubic', 'nearest' or 'bilinear'.
            order (int): the order of spline interpolation (within 0-5) or Lanczos interpolation (>0).
            reshape (bool): if True, the output shape is adapted so that the rorated image 
                is contained completely in the output array.
            cval (scalar): value to fill the edges. Default is NaN.
        
        Returns:
            rotate_image: ndarray.
        '''
        angle = angle % 360

        if not hasattr(self, 'mask'):
            raise AttributeError("This `Stack` object doesn't have `mask`!")
        else:
            if method == 'lanczos':
                try:
                    from galsim import degrees, Angle
                    from galsim.interpolant import Lanczos
                    from galsim import Image, InterpolatedImage
                    from galsim.fitswcs import AstropyWCS
                except:
                    raise ImportError(
                        '# Import `galsim` failed! Please check if `galsim` is installed!'
                    )
                # Begin rotation
                assert (order > 0) and isinstance(
                    order,
                    int), 'order of ' + method + ' must be positive interger.'
                galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                           scale=0.168,
                                           x_interpolant=Lanczos(order))
                galimg = galimg.rotate(Angle(angle, unit=degrees))
                ny, nx = self.image.shape
                result = galimg.drawImage(scale=0.168, nx=nx,
                                          ny=ny)  #, wcs=AstropyWCS(self.wcs))
                self._mask = (result.array > 0.5).astype(float)
                self.wcs = self._rotate_wcs(self.mask, self.wcs, angle)
                return result.array

            elif method == 'spline':
                from scipy.ndimage.interpolation import rotate as rt
                assert 0 < order <= 5 and isinstance(
                    order, int), 'order of ' + method + ' must be within 0-5.'
                result = rt(self.mask,
                            -angle,
                            order=order,
                            mode='constant',
                            cval=cval,
                            reshape=reshape)
                self._mask = (result > 0.5).astype(float)
                self.wcs = self._rotate_wcs(self.mask, self.wcs, angle)
                return result
            elif method in ['bicubic', 'nearest', 'cubic', 'bilinear']:
                raise Warning(
                    "Cautious! Don't use ['bicubic', 'nearest', 'cubic', 'bilinear'] methods! They don't conserve the total flux!"
                )
                try:
                    from scipy.misc import imrotate
                except:
                    raise ImportError(
                        '# Import `scipy.misc.imrotate` failed! This function may no longer be included in scipy!'
                    )
                result = imrotate(self.mask, -angle, interp=method)
                self._mask = (result > 0.5).astype(float)
                self.wcs = self._rotate_wcs(self.mask, self.wcs, angle)
                return result
            else:
                raise ValueError(
                    "# Not supported interpolation method. Use 'lanczos', 'spline', 'cubic', \
                                'bicubic', 'nearest', 'bilinear'.")
Beispiel #8
0
    def resize_mask(self, f, method='cubic', order=5, cval=0.0):
        '''
        Zoom/Resize the mask of Celestial object. 
        f > 1 means the mask will be resampled (finer)! f < 1 means the mask will be degraded.

        Parameters:
            f (float): the positive factor of zoom. If 0 < f < 1, the mask will be resized to smaller one.
            method (str): interpolation method. Use 'lanczos', 'cubic', 'quintic' or 'iraf'. 
                First three methods require ``GalSim`` installed. 
                Other methods are now consistent with "iraf" results.
            order (int): the order Lanczos interpolation (>0).
            cval (float): value to fill the edges. Default is 0.

        Returns:
            resize_mask (ndarray): resized image. The "mask" attribute of ``Celestial`` class will also be changed accordingly.
        '''

        if not hasattr(self, 'mask'):
            raise ValueError("This object doesn't have mask yet!")

        if method == 'lanczos' or method == 'cubic' or method == 'quintic':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )

            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            if method == 'lanczos':
                galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=Lanczos(order))
            else:
                galimg = InterpolatedImage(Image(self.mask, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=method)
            ny, nx = self.mask.shape
            if f > 1:
                result = galimg.drawImage(scale=self.pixel_scale / f,
                                          nx=int((nx - 1) * f + 1),
                                          ny=int((ny - 1) * f + 1))
                self.header = self._resize_header_wcs(self.mask, f)
                self.header['CRPIX1'] += (1 - f * 1)
                self.header['CRPIX2'] += (1 - f * 1)
                self._mask = result.array
                self.shape = self.mask.shape
                self.header['NAXIS1'] = result.array.shape[1]
                self.header['NAXIS2'] = result.array.shape[0]
                self.pixel_scale /= f
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The following block could be wrong! ####
                ## Probably you'll need extra shift of image
                dshift = 2 * (1 - f * 1) % 0.5
                self.shift_mask(dshift, dshift, method='spline')
                # We don't want to shift wcs.
                self.header['CRPIX1'] -= dshift
                self.header['CRPIX2'] -= dshift
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The above block could be wrong! ####
            else:
                from math import ceil
                b = round(1 / f)
                nxout = ceil(nx / b)
                nyout = ceil(ny / b)
                result = galimg.drawImage(scale=self.pixel_scale * b,
                                          nx=nxout,
                                          ny=nyout)
                self.header = self._resize_header_wcs(self.mask, f)
                self.header['CRPIX1'] += 0.5 - 1 / b / 2
                self.header['CRPIX2'] += 0.5 - 1 / b / 2
                self._mask = result.array
                self.shape = self.image.shape
                self.header['NAXIS1'] = result.array.shape[1]
                self.header['NAXIS2'] = result.array.shape[0]
                self.pixel_scale *= b
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The following block could be wrong! ####
                ## Probably you'll need extra shift of image
                dshift = 0.5 - 1 / b / 2
                self.shift_image(-dshift, -dshift, method='spline')
                # We don't want to shift wcs.
                self.header['CRPIX1'] -= dshift
                self.header['CRPIX2'] -= dshift
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The above block could be wrong! ####

            return self.mask

        elif method == 'iraf':
            self.save_to_fits('./_temp.fits', 'mask')
            if f > 1:
                magnify('./_temp.fits', './_resize_temp.fits', f, f)
            else:
                blkavg('./_temp.fits',
                       './_resize_temp.fits',
                       round(1 / f),
                       round(1 / f),
                       option='sum')
            hdu = fits.open('./_resize_temp.fits')
            self.mask = hdu[0].data
            self.shape = hdu[0].data.shape
            self.header = hdu[0].header
            self.wcs = wcs.WCS(self.header)
            self.pixel_scale /= f
            hdu.close()
            imdelete('./*temp.fits')
            return self.mask

        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos', 'spline' or 'iraf'."
            )
Beispiel #9
0
    def shift_mask(self, dx, dy, method='spline', order=5, cval=0.0):
        '''Shift the mask of Celestial object.

        Parameters:
            dx (float): shift distance (in pixel) along x (horizontal). 
                Note that elements in one row has the same y but different x. 
                Example: dx = 2 is to shift the mask "RIGHT" (as seen in DS9), dy = 3 is to shift the image "UP".
            dy (float): shift distance (in pixel) along y (vertical). 
                Note that elements in one row has the same y but different x. 
                Example: dx = 2 is to shift the mask "RIGHT" (as seen in DS9), dy = 3 is to shift the image "UP".
            method (str): interpolation method. Use 'spline', lanczos' or 'iraf'. 
                If using 'iraf', default interpolation is 'poly3. 'Lanczos' requires ``GalSim`` installed.
            order (int): the order of Spline or Lanczos interpolation (>0).
            cval (float): value to fill the edges. Default is 0.

        Returns:
            shift_mask (ndarray): shifted mask. The "mask" attribute of ``Celestial`` class will also be changed accordingly.
        '''

        ny, nx = self.mask.shape
        if abs(dx) > nx or abs(ny) > ny:
            raise ValueError('# Shift distance is beyond the image size.')
        if method == 'lanczos' or method == 'cubic' or method == 'quintic':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import ``galsim`` failed! Please check if ``galsim`` is installed!'
                )
            # Begin shift
            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            if method == 'lanczos':
                galimg = InterpolatedImage(Image(self.image, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=Lanczos(order))
            else:
                galimg = InterpolatedImage(Image(self.image, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=method)
            galimg = galimg.shift(dx=dx * self.pixel_scale,
                                  dy=dy * self.pixel_scale)
            result = galimg.drawImage(scale=self.pixel_scale, nx=nx,
                                      ny=ny)  #, wcs=AstropyWCS(self.wcs))
            self._mask = result.array
            # Change the WCS of image
            hdr = copy.deepcopy(self.header)
            hdr['CRPIX1'] += dx
            hdr['CRPIX2'] += dy
            self.header = hdr
            self.wcs = wcs.WCS(self.header)
            return result.array

        elif method == 'iraf':
            self.save_to_fits('./_temp.fits', 'mask')
            imshift('./_temp.fits',
                    './_shift_temp.fits',
                    dx,
                    dy,
                    interp_type='poly3',
                    boundary_type='constant')
            hdu = fits.open('./_shift_temp.fits')
            self.mask = hdu[0].data
            self.shape = hdu[0].data.shape
            self.header = hdu[0].header
            self.wcs = wcs.WCS(self.header)
            hdu.close()
            imdelete('./*temp.fits')
            return self.mask

        elif method == 'spline':
            from scipy.ndimage.interpolation import shift
            assert 0 < order <= 5 and isinstance(
                order, int), 'order of ' + method + ' must be within 0-5.'
            result = shift(self.mask, [dy, dx],
                           order=order,
                           mode='constant',
                           cval=cval)
            self._mask = result
            # Change the WCS of image
            hdr = copy.deepcopy(self.header)
            hdr['CRPIX1'] += dx
            hdr['CRPIX2'] += dy
            self.header = hdr
            self.wcs = wcs.WCS(self.header)
            return result

        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos' or 'iraf'."
            )
Beispiel #10
0
    def resize_image(self, f, method='cubic', order=3, cval=0.0):
        '''
        Zoom/Resize the image of Celestial object. 
        f > 1 means the image will be resampled (finer)! f < 1 means the image will be degraded.

        Parameters:
            f (float): the positive factor of zoom. If 0 < f < 1, the image will be resized to smaller one.
            method (str): interpolation method. Use 'spline', 'iraf', or 'lanczos', 'cubic', 'quintic'. 
                We recommend using 'spline' or 'iraf. The last three methods require ``GalSim`` installed. 
                Other methods are now consistent with "iraf" results.
            order (int): the order Lanczos interpolation (>0).
            cval (float): value to fill the edges. Default is 0.

        Returns:
            resize_image (ndarray): resized image. The "image" attribute of ``Celestial`` class will also be changed accordingly.
        '''

        if method == 'lanczos' or method == 'cubic' or method == 'quintic':
            try:  # try to import galsim
                from galsim import degrees, Angle
                from galsim.interpolant import Lanczos
                from galsim import Image, InterpolatedImage
                from galsim.fitswcs import AstropyWCS
            except:
                raise ImportError(
                    '# Import `galsim` failed! Please check if `galsim` is installed!'
                )

            assert (order > 0) and isinstance(
                order,
                int), 'order of ' + method + ' must be positive interger.'
            if method == 'lanczos':
                galimg = InterpolatedImage(Image(self.image, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=Lanczos(order))
            else:
                galimg = InterpolatedImage(Image(self.image, dtype=float),
                                           scale=self.pixel_scale,
                                           x_interpolant=method)

            ny, nx = self.image.shape
            if f > 1:
                result = galimg.drawImage(scale=self.pixel_scale / f,
                                          nx=int((nx - 1) * f + 1),
                                          ny=int((ny - 1) * f + 1))
                self.header = self._resize_header_wcs(f)
                self.header['CRPIX1'] += (1 - f * 1)
                self.header['CRPIX2'] += (1 - f * 1)
                self._image = result.array
                self.shape = self.image.shape
                self.header['NAXIS1'] = result.array.shape[1]
                self.header['NAXIS2'] = result.array.shape[0]
                self.pixel_scale /= f
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The following block could be wrong! ####
                ## Probably you'll need extra shift of image
                dshift = 2 * (1 - f * 1) % 0.5
                self.shift_image(dshift, dshift, method='spline')
                # We don't want to shift wcs.
                self.header['CRPIX1'] -= dshift
                self.header['CRPIX2'] -= dshift
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The above block could be wrong! ####

            else:
                from math import ceil
                b = round(1 / f)
                nxout = ceil(nx / b)
                nyout = ceil(ny / b)
                result = galimg.drawImage(scale=self.pixel_scale * b,
                                          nx=nxout,
                                          ny=nyout)
                self.header = self._resize_header_wcs(f)
                self.header['CRPIX1'] += 0.5 - 1 / b / 2
                self.header['CRPIX2'] += 0.5 - 1 / b / 2
                self._image = result.array
                self.shape = self.image.shape
                self.header['NAXIS1'] = result.array.shape[1]
                self.header['NAXIS2'] = result.array.shape[0]
                self.pixel_scale *= b
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The following block could be wrong! ####
                ## Probably you'll need extra shift of image
                dshift = 0.5 - 1 / b / 2
                self.shift_image(-dshift, -dshift, method='spline')
                # We don't want to shift wcs.
                self.header['CRPIX1'] -= dshift
                self.header['CRPIX2'] -= dshift
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The above block could be wrong! ####
            return self.image

        elif method == 'iraf':
            self.save_to_fits('./_temp.fits', 'image')
            if f > 1:
                magnify('./_temp.fits', './_resize_temp.fits', f, f)
            else:
                blkavg('./_temp.fits',
                       './_resize_temp.fits',
                       round(1 / f),
                       round(1 / f),
                       option='sum')
            try:
                hdu = fits.open('./_resize_temp.fits')
            except Exception as e:
                raise ValueError(
                    'Interpolation using IRAF filed with error "{}". \n Please try another interpolation method!'
                    .format(e))
            self.image = hdu[0].data
            self.shape = hdu[0].data.shape
            self.header = hdu[0].header
            #### Remove redundant PC keywords ###
            for i in self.header['PC*'].keys():
                del self.header[i]
            #####################################
            self.wcs = wcs.WCS(self.header)
            self.pixel_scale /= f
            hdu.close()
            imdelete('./*temp.fits')
            return self.image

        elif method == 'spline':
            ny, nx = self.image.shape
            if f > 1:
                from scipy import ndimage
                assert 0 < order <= 5 and isinstance(
                    order, int), 'order of ' + method + ' must be within 0-5.'
                nx_zoomed = (nx - 1) * f + 1
                f_eff = nx_zoomed / nx
                result = ndimage.zoom(self.image, f_eff, order=order)
                result *= 1 / (f_eff**2
                               )  # Multiplying by this factor to conserve flux
                self.header = self._resize_header_wcs(f)
                #self.header['CRPIX1'] += (1 - f * 1)
                #self.header['CRPIX2'] += (1 - f * 1)
                self._image = result
                self.shape = self.image.shape
                self.header['NAXIS1'] = result.shape[1]
                self.header['NAXIS2'] = result.shape[0]
                self.pixel_scale /= f
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The following block could be wrong! ####
                ## Probably you'll need extra shift of image
                dshift = 2 * (1 - f * 1) % 0.5
                self.shift_image(dshift, dshift, method='spline')
                # We don't want to shift wcs.
                self.header['CRPIX1'] -= dshift
                self.header['CRPIX2'] -= dshift
                self.wcs = wcs.WCS(self.header)
                #### Cautious! The above block could be wrong! ####
            else:
                b = round(1 / f)
                ny_bin = int(ny / b)
                nx_bin = int(nx / b)
                shape = (ny_bin, b, nx_bin, b)
                x_crop = int(nx_bin * b)
                y_crop = int(ny_bin * b)
                result = self.image[0:y_crop,
                                    0:x_crop].reshape(shape).sum(3).sum(1)
                self.header = self._resize_header_wcs(f)
                self.header['CRPIX1'] += 0.5 - 1 / b / 2
                self.header['CRPIX2'] += 0.5 - 1 / b / 2
                self._image = result
                self.shape = self.image.shape
                self.header['NAXIS1'] = result.shape[1]
                self.header['NAXIS2'] = result.shape[0]
                self.pixel_scale *= b
                self.wcs = wcs.WCS(self.header)

        else:
            raise ValueError(
                "# Not supported interpolation method. Use 'lanczos', 'spline' or 'iraf'."
            )
Beispiel #11
0
    def gen_mock_lsbg(self,
                      galaxy,
                      zp=HSC_zeropoint,
                      pixel_scale=HSC_pixel_scale,
                      verbose=True):
        '''
        Generate mock low surface brightness galaxies. 
        '''
        import galsim
        from galsim import Angle, Image, InterpolatedImage, degrees
        from galsim.fitswcs import AstropyWCS
        from galsim.interpolant import Lanczos
        big_fft_params = galsim.GSParams(maximum_fft_size=20000)

        if not isinstance(galaxy['comp'], list):
            galaxy['comp'] = list(galaxy['comp'])

        if len(galaxy['comp']) == 1:
            galaxy['flux_fraction'] = [1.0]

        # print some information
        if verbose:
            print('# Generating mock galaxy.')
            print('    - Total components: ', len(galaxy['comp']))
            print('    - Types: ',
                  [c['model'].__name__ for c in galaxy['comp']])
            print('    - Flux fraction: ', galaxy['flux_fraction'])

        # Empty canvas
        field = np.empty_like(self.bkg.images[0])
        model_images = np.empty_like(self.bkg.images)

        # Calculate RA, DEC of the mock galaxy
        y_cen = self.bkg.images.shape[2] / 2
        x_cen = self.bkg.images.shape[1] / 2
        galaxy['ra'], galaxy['dec'] = self.bkg.wcs.wcs_pix2world(
            x_cen, y_cen, 0)

        # Calculate flux based on i-band mag and SED
        i_band_loc = np.argwhere(np.array(list(self.channels)) == 'i')[0][
            0]  # location of i-band in `channels`
        seds = np.array([c['sed'] for c in galaxy['comp']])
        # Normalize SED w.r.t i-band
        seds /= seds[:, i_band_loc][:, np.newaxis]
        tot_sed = np.sum(seds *
                         np.array(galaxy['flux_fraction'])[:, np.newaxis],
                         axis=0)
        for i, band in enumerate(self.channels):
            galaxy[f'{band}mag'] = -2.5 * np.log10(tot_sed[i]) + galaxy['imag']

        if verbose:
            print(f'    - Magnitude in {self.channels}: ',
                  [round(galaxy[f'{band}mag'], 1) for band in self.channels])

        #### Star generating mock galaxy in each band ####
        for i, band in enumerate(self.channels):  # griz
            # Random number seed
            # This random number seed should be fixed across bands!!!
            rng = galsim.BaseDeviate(23333)

            # Sky background level
            sky_SB = 29  # mag/arcsec^2
            sky_level = 10**((zp - sky_SB) / 2.5)  # counts / arcsec^2

            # Define the PSF
            interp_psf = InterpolatedImage(Image(self.bkg.psfs[i] /
                                                 self.bkg.psfs[i].sum(),
                                                 dtype=float),
                                           scale=pixel_scale,
                                           x_interpolant=Lanczos(3))

            # Total flux for all components
            tot_flux = 10**((zp - galaxy[f'{band}mag']) / 2.5)

            gal_list = []
            for k, comp in enumerate(galaxy['comp']):
                # Define the galaxy
                gal = comp['model'](**comp['model_params'],
                                    gsparams=big_fft_params)

                gal_shape = galsim.Shear(
                    **comp['shear_params'])  # Shear the galaxy
                gal = gal.shear(gal_shape)

                if 'shift' in comp.keys():  # Shift the center
                    gal = gal.shift(comp['shift'])

                # Add star forming knots
                if 'n_knots' in comp.keys() and comp['n_knots'] > 0:
                    if not 'knots_frac' in comp.keys():
                        raise KeyError(
                            '`knots_frac` must be provided to generate star forming knots!'
                        )
                    else:
                        if 'knots_sed' in comp.keys():
                            knot_frac = comp['knots_frac'] * \
                                (comp['knots_sed'] /
                                 np.sum(comp['knots_sed']))[i]
                        else:
                            knot_frac = comp['knots_frac'] * 0.25  # flat SED
                        knots = galsim.RandomKnots(
                            comp['n_knots'],
                            half_light_radius=comp['model_params']
                            ['half_light_radius'],
                            flux=knot_frac,
                            rng=rng)
                    gal = galsim.Add([gal, knots])

                gal = gal.withFlux(tot_flux *
                                   galaxy['flux_fraction'][k])  # Get Flux
                gal_list.append(gal)

            # Adding all components together
            gal = galsim.Add(gal_list)

            # Convolve galaxy with PSF
            final = galsim.Convolve([gal, interp_psf])

            # Draw the image with a particular pixel scale.
            gal_image = final.drawImage(scale=pixel_scale,
                                        nx=field.shape[1],
                                        ny=field.shape[0])

            # Add noise
            sky_sigma = hsc_sky[f'{band}'] / 3.631 * \
                10**((zp - 22.5) / 2.5) * pixel_scale**2
            noise = galsim.GaussianNoise(rng, sigma=sky_sigma)
            # gal_image.addNoise(noise)

            # Generate mock image
            model_img = gal_image.array
            model_images[i] = model_img

        # Generate variance map
        mock_model = Data(images=model_images,
                          variances=None,
                          masks=None,
                          channels=self.channels,
                          wcs=None,
                          weights=None,
                          psfs=self.bkg.psfs,
                          info=galaxy)

        # Finished!!!
        self.model = mock_model  # model only has `images`, `channels`, `psfs`, and `info`!
        self.set_mock()  # mock has other things, including modified variances.