Exemplo n.º 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.
Exemplo n.º 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'."
            )
Exemplo n.º 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'."
            )
Exemplo n.º 4
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'."
            )
Exemplo n.º 5
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'."
            )
Exemplo n.º 6
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'.")
Exemplo n.º 7
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'."
            )
Exemplo n.º 8
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'."
            )
Exemplo n.º 9
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'."
            )
Exemplo n.º 10
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.