Example #1
0
 def test_get_pixel_sed(self):
     images1 = np.arange(210, dtype=float).reshape(5, 6, 7)
     images2 = images1 / 4
     obs1 = scarlet.Observation(images1)
     obs2 = scarlet.Observation(images2)
     observations = [obs1, obs2]
     skycoord = (3, 2)
     true_sed1 = images1[:, skycoord[0], skycoord[1]]
     true_sed2 = images2[:, skycoord[0], skycoord[1]]
     true_sed = np.concatenate((true_sed1, true_sed2))
     sed = np.concatenate([
         scarlet.source.get_pixel_sed(skycoord, obs) for obs in observations
     ])
     assert_array_equal(sed, true_sed)
Example #2
0
    def test_fit_point_source(self):
        shape = (6, 31, 55)
        coords = [(20, 10), (10, 30), (17, 42)]
        amplitudes = [3, 2, 1]
        result = init_data(shape, coords, amplitudes, dtype=np.float64)
        target_psf, psfs, images, channels, seds, morphs = result
        B, Ny, Nx = shape

        frame = scarlet.Frame(images.shape,
                              psfs=target_psf[None],
                              dtype=np.float64)
        observation = scarlet.Observation(images, psfs=psfs).match(frame)
        sources = [
            scarlet.PointSource(frame, coord, observation) for coord in coords
        ]
        blend = scarlet.Blend(sources, observation)
        # Try to run for 10 iterations
        # Since the model is already near exact, it should converge
        # on the 2nd iteration (since it doesn't calculate the initial loss)
        blend.fit(10)

        assert blend.it == 2
        assert_almost_equal(blend.mse,
                            [3.875628098330452e-15, 3.875598349723412e-15],
                            decimal=10)
        assert blend.mse[0] > blend.mse[1]
Example #3
0
def scarlet1_initialize(images, peaks, psfs, variances, bands):
    """ Deblend input images with scarlet
    Args:
        images: Numpy array of multi-band image to run scarlet on
               [Number of bands, height, width].
        peaks: Array of x and y coordinates of centroids of objects in
               the image [number of sources, 2].
        bg_rms: Background RMS value of the images [Number of bands]
        iters: Maximum number of iterations if scarlet doesn't converge
               (Default: 200).
    e_rel: Relative error for convergence (Default: 0.015)
    Returns
        blend: scarlet.Blend object for the initialized sources
        rejected_sources: list of sources (if any) that scarlet was
        unable to initialize the image with.
    """
    model_psf = scarlet.PSF(partial(scarlet.psf.gaussian, sigma=0.8),
                            shape=(None, 41, 41))
    model_frame = scarlet.Frame(images.shape, psfs=model_psf, channels=bands)
    observation = scarlet.Observation(images, psfs=scarlet.PSF(psfs),
                                      weights=1./variances,
                                      channels=bands).match(model_frame)
    sources = []
    for n, peak in enumerate(peaks):
        result = scarlet.ExtendedSource(model_frame, (peak[1], peak[0]),
                                        observation, symmetric=True,
                                        monotonic=True, thresh=1,
                                        shifting=True)
        sed = result.sed
        morph = result.morph
        if np.all([s < 0 for s in sed]) or np.sum(morph) == 0:
            raise ValueError("Incorrectly initialized")
        sources.append(result)
    blend = scarlet.Blend(sources, observation)
    return blend, observation
Example #4
0
    def test_fit_extended_source(self):
        shape = (6, 31, 55)
        coords = [(20, 10), (10, 30), (17, 42)]
        amplitudes = [3, 2, 1]
        result = init_data(shape, coords, amplitudes, dtype=np.float64)
        target_psf, psfs, images, channels, seds, morphs = result
        B, Ny, Nx = shape

        frame = scarlet.Frame(images.shape,
                              psfs=target_psf[None],
                              dtype=np.float64)
        observation = scarlet.Observation(images, psfs=psfs).match(frame)
        bg_rms = np.ones((B, ))
        sources = [
            scarlet.ExtendedSource(frame, coord, observation, bg_rms)
            for coord in coords
        ]
        blend = scarlet.Blend(sources, observation)

        # Scale the input psfs by the observation and model psfs to ensure
        # the sources were initialized correctly
        psf_scale = observation.frame.psfs.max(axis=(1,
                                                     2)) / frame.psfs[0].max()
        scaled_seds = np.array([c.sed * psf_scale for c in blend.components])

        assert_almost_equal(scaled_seds, seds)

        # Fit the model
        blend.fit(100)
        assert blend.it < 20
        mse = np.array(blend.mse[:-1])
        _mse = np.array(blend.mse[1:])
        assert np.all(mse - _mse >= 0)
Example #5
0
def scarlet1_multi_initialize(images, peaks, psfs, variances, bands):
    """ Initializes scarlet MultiComponentSource at locations input as
    peaks in the (multi-band) input images.
    Args:
        images: Numpy array of multi-band image to run scarlet on
                [Number of bands, height, width].
        peaks: Array of x and y coordinates of centroids of objects in
               the image [number of sources, 2].
        bg_rms: Background RMS value of the images [Number of bands]
    Returns
        blend: scarlet.Blend object for the initialized sources
        rejected_sources: list of sources (if any) that scarlet was
                          unable to initialize the image with.
    """
    model_psf = scarlet.PSF(partial(scarlet.psf.gaussian, sigma=0.8),
                            shape=(None, 41, 41))
    model_frame = scarlet.Frame(images.shape, psfs=model_psf, channels=bands)
    observation = scarlet.Observation(images, psfs=scarlet.PSF(psfs),
                                      weights=1./variances,
                                      channels=bands).match(model_frame)
    sources = []
    for n, peak in enumerate(peaks):
        result = scarlet.MultiComponentSource(model_frame, (peak[1], peak[0]),
                                              observation, symmetric=True,
                                              monotonic=True, thresh=1,
                                              shifting=True)
        for i in range(result.n_sources):
            sed = result.components[i].sed
            morph = result.components[i].morph
            if np.all([s < 0 for s in sed]) or np.sum(morph) == 0:
                raise ValueError("Incorrectly initialized")
        sources.append(result)
    blend = scarlet.Blend(sources, observation)
    return blend, observation
Example #6
0
    def test_point_source(self):
        shape = (5, 11, 21)
        coords = [(4, 8), (8, 11), (5, 16)]

        B, Ny, Nx = shape
        seds, morphs, images = create_sources(shape, coords, [2, 3, .1])
        psfs = np.array([[[.25, .5, .25], [.5, 1, .5], [.25, .5, .25]]])
        psfs /= psfs.sum(axis=(1, 2))[:, None, None]

        frame = scarlet.Frame(images.shape)
        obs = scarlet.Observation(images).match(frame)

        src = scarlet.PointSource(frame, coords[0], obs)
        truth = np.zeros_like(src.morph)
        truth[coords[0]] = 1

        assert_array_equal(src.sed, seds[0])
        assert_array_equal(src.morph, truth)
        assert src.pixel_center == coords[0]
        assert src.symmetric is True
        assert src.monotonic is True
        assert src.center_step == 5
        assert src.delay_thresh == 10

        # frame PSF same as source
        frame = scarlet.Frame(images.shape, psfs=psfs)
        src = scarlet.PointSource(frame, coords[0], obs)

        # We need to multiply by 4 because of psf normalization
        assert_almost_equal(src.sed * 4, seds[0])
        assert_almost_equal(morphs[0], src.morph)
        assert src.pixel_center == coords[0]
Example #7
0
    def test_render_loss(self):
        # model frame with minimal PSF
        shape0 = (3, 13, 13)
        s0 = 0.9
        model_psf = scarlet.PSF(partial(scarlet.psf.gaussian, sigma=s0), shape=shape0)
        shape = (3, 43, 43)
        channels = np.arange(shape[0])
        model_frame = scarlet.Frame(shape, psfs=model_psf, channels=channels)

        # insert point source manually into center for model
        origin = (0, shape[1] // 2 - shape0[1] // 2, shape[2] // 2 - shape0[2] // 2)
        bbox = scarlet.Box(shape0, origin=origin)
        model = np.zeros(shape)
        box = np.stack([model_psf.image[0] for c in range(shape[0])], axis=0)
        bbox.insert_into(model, box)

        # generate observation with wider PSFs
        psf = scarlet.PSF(self.get_psfs(shape[1:], [2.1, 1.1, 3.5]))
        images = np.ones(shape)
        observation = scarlet.Observation(images, psfs=psf, channels=channels)
        observation.match(model_frame)
        model_ = observation.render(model)
        assert_almost_equal(model_, psf.image)

        # compute the expected loss
        weights = 1
        log_norm = (
            np.prod(images.shape) / 2 * np.log(2 * np.pi)
            + np.sum(np.log(1 / weights)) / 2
        )
        true_loss = log_norm + np.sum(weights * (model_ - images) ** 2) / 2
        # loss is negative logL
        assert_almost_equal(observation.get_log_likelihood(model), -true_loss)
Example #8
0
 def test_get_loss(self):
     shape = (3, 4, 5)
     frame = scarlet.Frame(shape)
     images = np.arange(60).reshape(shape)
     weights = np.ones_like(images) * 2
     observation = scarlet.Observation(images, weights=weights).match(frame)
     model = 4 * np.ones_like(images)
     true_loss = 0.5 * np.sum((weights * (model - images))**2)
     assert_almost_equal(true_loss, observation.get_loss(model))
Example #9
0
def setup_scarlet(data_hr,
                  wcs_hr,
                  data_lr,
                  wcs_lr,
                  psf_hr,
                  psf_lr,
                  channels,
                  coverage="union"):
    """Performs the initialisation steps for scarlet to run its resampling scheme
    Prameters
    ---------
    data_hr: galsim Image
        galsim Image object with the high resolution simulated image and its WCS
    data_lr: galsim Image
        galsim Image object with the low resolution simulated image and its WCS
    psf_hr: numpy array
        psf of the high resolution image
    psf_lr: numpy array
        psf of the low resolution image
    channels: tuple
        names of the channels
    Returns
    -------
    obs: array of observations
        array of scarlet.Observation objects initialised for resampling
    """
    # Extract data
    im_hr = data_hr[None, :, :]
    im_lr = data_lr[None, :, :]
    # define two observation objects and match to frame
    obs_hr = scarlet.Observation(im_hr,
                                 wcs=wcs_hr,
                                 psfs=scarlet.ImagePSF(psf_hr),
                                 channels=[channels[1]])
    obs_lr = scarlet.Observation(im_lr,
                                 wcs=wcs_lr,
                                 psfs=scarlet.ImagePSF(psf_lr),
                                 channels=[channels[0]])
    # Keep the order of the observations consistent with the `channels` parameter
    # This implementation is a bit of a hack and will be refined in the future
    obs = [obs_lr, obs_hr]
    scarlet.Frame.from_observations(obs, obs_id=1, coverage=coverage)
    return obs
Example #10
0
    def test_get_best_fit_seds(self):
        shape = (7, 11, 21)
        coords = [(4, 8), (8, 11), (5, 16)]
        seds, morphs, images = create_sources(shape, coords)

        frame = scarlet.Frame(images.shape)
        obs = scarlet.Observation(images).match(frame)

        _seds = scarlet.source.get_best_fit_seds(morphs, frame, obs)

        assert_array_equal(_seds, seds)
Example #11
0
    def test_psf_match(self):
        shape = (43, 43)
        target_psf = self.get_psfs(shape, [.9])[1]
        psfs, truth = self.get_psfs(shape, [2.1, 1.1, 3.5])
        psfs /= psfs.sum(axis=(1, 2))[:, None, None]

        frame = scarlet.Frame(psfs.shape, psfs=target_psf)
        observation = scarlet.Observation(psfs, psfs)
        observation.match(frame)
        result = observation.render(np.array([target_psf[0]] * len(psfs)))

        assert_almost_equal(result, truth)
Example #12
0
    def test_init(self):
        images = np.arange(1, 430, dtype=np.float32).reshape(3, 11, 13)
        weights = np.ones_like(images)
        psfs = np.arange(1, 76).reshape(3, 5, 5)
        norm_psfs = psfs / psfs.sum(axis=(1, 2))[:, None, None]
        wcs = get_airy_wcs()
        channels = np.arange(len(images))

        # Minimal init
        obs = scarlet.Observation(images)
        assert obs.frame.C == 3
        assert obs.frame.Ny == 11
        assert obs.frame.Nx == 13
        assert obs.frame.shape == images.shape
        assert obs.frame.psfs is None
        assert_array_equal(obs.frame.get_pixel((5.1, 1.3)), (5, 1))
        assert obs.weights == 1
        assert obs.frame.channels is None

        # Full init
        obs = scarlet.Observation(images,
                                  psfs=norm_psfs,
                                  weights=weights,
                                  wcs=wcs,
                                  channels=channels)
        assert obs.frame.C == 3
        assert obs.frame.Ny == 11
        assert obs.frame.Nx == 13
        assert obs.frame.shape == images.shape
        assert_almost_equal(obs.frame.psfs.image, norm_psfs)
        assert_almost_equal(obs.frame.psfs.sum(axis=(1, 2)), [1] * 3)
        assert_array_equal(obs.weights, weights)
        assert_array_equal(obs.frame.channels, channels)

        skycoord = [210.945, -73.1]
        assert_array_equal(obs.frame.get_pixel(skycoord), [-110, -202])
    def test_init(self):
        # Initialize the model
        shape = (5, 31, 55)
        B, Ny, Nx = shape

        x = np.linspace(-2, 2, 5)
        y = np.linspace(-2, 2, 5)
        x, y = np.meshgrid(x, y)
        r = np.sqrt(x**2 + y**2)

        trueSed = np.arange(B)
        trueMorph = np.zeros(shape[1:])

        center = (np.array(trueMorph.shape) - 1) // 2
        cy, cx = center
        trueMorph[cy-2:cy+3, cx-2:cx+3] = 3-r

        morph = trueMorph.copy()
        # Make a point that is not monotonic or symmetric to ensure
        # that it is supressed.
        morph[5, 3] = 10

        # Create the scarlet objects
        images = trueSed[:, None, None] * morph[None, :, :]
        frame = scarlet.Frame(shape, channels=np.arange(B))
        observation = scarlet.Observation(images, channels=np.arange(B))

        # init stack objects
        foot, peak, bbox = numpyToStack(images, center, (15, 3))
        # init source
        xmin = bbox.getMinX()
        ymin = bbox.getMinY()
        center = np.array([peak.getIy()-ymin, peak.getIx()-xmin], dtype=int)
        src = initSource(frame=frame, center=center, observation=observation, thresh=0, downgrade=False)

        # scarlet has more flexible models now,
        # so `sed` and `morph` are no longer attributes,
        # meaning we have to extract them ourselves.
        sed = src.children[0].parameters[0]._data
        morph = src.children[1].parameters[0]._data

        self.assertFloatsAlmostEqual(sed/3, trueSed)
        src_morph = np.zeros(frame.shape[1:], dtype=morph.dtype)
        src_morph[src._model_frame_slices[1:]] = (morph*3)[src._model_slices[1:]]
        self.assertFloatsAlmostEqual(src_morph, trueMorph, rtol=1e-7)
        self.assertFloatsEqual(src.center, center)
        self.assertEqual(foot.getBBox(), bbox)
Example #14
0
    def test_build_detection_coadd(self):
        truth = np.array(
            [[[0.05235454, 0.02073789, 0.04880617, 0.03637619, 0.02399899],
              [0.03744485, 0.29331713, 0.52876383, 0.28429441, 0.04679640],
              [0.02611349, 0.52057058, 1.02958156, 0.51620345, 0.02391584],
              [0.03627858, 0.28669982, 0.54027293, 0.26347546, 0.05124271],
              [0.03635369, 0.05010319, 0.04445647, 0.04545365, 0.02991638]],
             [[0.00704491, 0.00566508, 0.00848275, 0.00673316, 0.00564367],
              [0.00686349, 0.25730076, 0.50470101, 0.25151582, 0.00715177],
              [0.00951771, 0.50618275, 1.00161330, 0.50362382, 0.00521353],
              [0.00189936, 0.25494626, 0.50437369, 0.25620321, 0.00515993],
              [0.00751398, 0.00719382, 0.00812517, 0.00260853, 0.00908961]],
             [[0.66289178, 0.31370533, 0.62558879, 0.43856888, 0.72209347],
              [0.96661099, 0.57698197, 1.58224512, 0.93506400, 1.08122335],
              [0.99298264, 1.26054670, 1.58495813, 1.61148374, 0.82737327],
              [1.05820433, 0.92412937, 1.24225533, 1.33838207, 0.79615945],
              [0.82488505, 1.13293652, 0.93197919, 1.37564087, 0.96079598]]])
        true_cutoff = np.array([0.03630302, 0.00769658, 0.82658430])

        np.random.seed(0)
        shape = (5, 11, 21)
        coords = [(4, 8), (8, 11), (5, 16)]

        B, Ny, Nx = shape
        K = len(coords)
        seds, morphs, images = create_sources(shape, coords, [2, 3, .1])
        bg_rms = np.arange(1, B + 1) / 10

        # Add noise to the image
        noise = np.random.rand(*shape) * bg_rms[:, None, None]
        images += noise

        frame = scarlet.Frame(shape)
        for k in range(K):
            observation = scarlet.Observation(images).match(frame)
            coadd, cutoff = scarlet.source.build_detection_coadd(
                seds[k], bg_rms, observation)
            cy, cx = coords[k]
            window = slice(cy - 2, cy + 3), slice(cx - 2, cx + 3)
            assert_almost_equal(coadd[window], truth[k])
            assert_almost_equal(cutoff, true_cutoff[k])

        with pytest.raises(ValueError):
            scarlet.source.build_detection_coadd(seds[0],
                                                 np.zeros_like(bg_rms),
                                                 observation, frame)
Example #15
0
def define_model(images,weights,psf="startpsf.npy"):
    """ Create model psf and obsevation
    """
    start_psf = np.load(psf)
    out = np.outer(np.ones(len(images)),start_psf)
    # WARNING, using same arbitray psf for all now.
    out.shape = (len(images),start_psf.shape[0],start_psf.shape[1])
    psfs = scarlet.PSF(out)
    model_psf = scarlet.PSF(partial(scarlet.psf.gaussian, sigma=.8),
                            shape=(None, 8, 8))
    model_frame = scarlet.Frame(
                  images.shape,
                  psfs=model_psf)
    observation = scarlet.Observation(
                  images,
                  weights=weights,
                  psfs=psfs).match(model_frame)
    return model_frame, observation
    def test_to_heavy(self):
        shape = (5, 31, 55)
        B, Ny, Nx = shape
        coords = [(20, 10), (10, 30), (17, 42)]
        result = initData(shape, coords, [3, 2, 1])
        targetPsfImage, psfImages, images, channels, seds, morphs, targetPsf, psfs = result
        images = images.astype(np.float32)
        seds = seds.astype(np.float32)

        frame = scarlet.Frame(shape, psf=targetPsf, channels=np.arange(B))
        observation = scarlet.Observation(images, psf=psfImages, channels=np.arange(B)).match(frame)
        foot, peak, bbox = numpyToStack(images, coords[0], (15, 3))
        xmin = bbox.getMinX()
        ymin = bbox.getMinY()
        center = np.array([peak.getIy()-ymin, peak.getIx()-xmin], dtype=int)
        src = init_source(frame=frame, center=center, observations=[observation], thresh=0)

        # Convolve the model with the observed PSF
        model = src.get_model(frame=src.frame)
        model = observation.render(model)
Example #17
0
    def test_model_render(self):
        shape = (6, 31, 55)
        coords = [(20, 10), (10, 30), (17, 42)]
        result = init_data(shape, coords, [3, 2, 1], dtype=np.float64)
        target_psf, psfs, images, channels, seds, morphs = result

        # Test init with psfs
        frame = scarlet.Frame(images.shape,
                              psfs=target_psf[None],
                              dtype=np.float64)
        observation = scarlet.Observation(images, psfs=psfs).match(frame)

        sources = [
            scarlet.PointSource(frame, coord, observation) for coord in coords
        ]
        blend = scarlet.Blend(sources, observation)
        model = observation.render(blend.get_model())

        assert_almost_equal(images, model, decimal=5)

        for s0, s in zip(sources, blend.sources):
            assert_array_equal(s.get_model(), s0.get_model())
    def test_to_heavy(self):
        shape = (5, 31, 55)
        B, Ny, Nx = shape
        coords = [(20, 10), (10, 30), (17, 42)]
        result = initData(shape, coords, [3, 2, 1])
        targetPsfImage, psfImages, images, channels, seds, morphs, targetPsf, psfs = result
        images = images.astype(np.float32)
        seds = seds.astype(np.float32)

        frame = scarlet.Frame(shape, psfs=targetPsf, channels=np.arange(B))
        observation = scarlet.Observation(images, psfs=psfImages, channels=np.arange(B)).match(frame)
        foot, peak, bbox = numpyToStack(images, coords[0], (15, 3))
        xmin = bbox.getMinX()
        ymin = bbox.getMinY()
        center = np.array([peak.getIy()-ymin, peak.getIx()-xmin], dtype=int)
        src = initSource(frame=frame, center=center, observation=observation, thresh=0, downgrade=False)

        # Convolve the model with the observed PSF
        model = src.get_model(frame=src.frame)
        model = observation.render(model)

        # Test Model to Heavy
        filters = [f for f in "grizy"]
        src.detectedPeak = peak
        hFoot = mes.source.modelToHeavy(src, filters, bbox.getMin(), observation)
        hModel = hFoot.getImage(fill=0).image.array

        self.assertEqual(bbox, hFoot.getBBox())
        self.assertFloatsAlmostEqual(hModel, model, rtol=1e-4, atol=1e-4)

        # Test the peak in each band
        for single in hFoot:
            peaks = single.getPeaks()
            self.assertEqual(len(peaks), 1)
            hPeak = peaks[0]
            self.assertEqual(hPeak.getIx()-xmin, coords[0][1])
            self.assertEqual(hPeak.getIy()-ymin, coords[0][0])
Example #19
0
    def test_render(self):
        shape = (43, 43)
        target_psf = self.get_psfs(shape, [.9])[1][0]
        target_psf = target_psf[None]
        psfs, normalized = self.get_psfs(shape, [2.1, 1.1, 3.5])
        psfs /= psfs.sum(axis=(1, 2))[:, None, None]

        ry = rx = 21
        coords = [[33, 31], [43, 33], [54, 26], [68, 72]]
        images = np.zeros((3, 101, 101))
        for coord in coords:
            py, px = coord
            images[:, py - ry:py + ry + 1, px - rx:px + rx + 1] += normalized

        model = np.zeros_like(images)
        for coord in coords:
            py, px = coord
            model[:, py - ry:py + ry + 1, px - rx:px + rx + 1] += target_psf

        frame = scarlet.Frame(images.shape, psfs=target_psf)
        observation = scarlet.Observation(images, psfs=psfs)
        observation.match(frame)
        result = observation.render(model)
        assert_almost_equal(result, images)
Example #20
0
    def test_init_extended(self):
        shape = (5, 11, 15)
        B, Ny, Nx = shape

        x = np.linspace(-2, 2, 5)
        y = np.linspace(-2, 2, 5)
        x, y = np.meshgrid(x, y)
        r = np.sqrt(x**2 + y**2)

        true_sed = np.arange(B)
        true_morph = np.zeros(shape[1:])

        skycoord = (np.array(true_morph.shape) - 1) // 2
        cy, cx = skycoord
        true_morph[cy - 2:cy + 3, cx - 2:cx + 3] = 3 - r

        morph = true_morph.copy()
        morph[5, 3] = 10

        # Test function
        images = true_sed[:, None, None] * morph[None, :, :]
        frame = scarlet.Frame(shape)
        observation = scarlet.Observation(images).match(frame)
        bg_rms = np.ones_like(true_sed) * 1e-3
        sed, morph = scarlet.source.init_extended_source(
            skycoord, frame, observation, bg_rms)

        assert_array_equal(sed / 3, true_sed)
        assert_almost_equal(morph * 3, true_morph)

        # Test ExtendedSource.__init__
        src = scarlet.ExtendedSource(frame, skycoord, observation, bg_rms)
        assert_array_equal(src.pixel_center, skycoord)
        assert src.symmetric is True
        assert src.monotonic is True
        assert src.center_step == 5
        assert src.delay_thresh == 10

        assert_array_equal(src.sed / 3, true_sed)
        assert_almost_equal(src.morph * 3, true_morph)

        # Test monotonicity
        morph = true_morph.copy()
        morph[5, 5] = 2

        images = true_sed[:, None, None] * morph[None, :, :]
        frame = scarlet.Frame(shape)
        observation = scarlet.Observation(images).match(frame)
        bg_rms = np.ones_like(true_sed) * 1e-3
        sed, morph = scarlet.source.init_extended_source(skycoord,
                                                         frame,
                                                         observation,
                                                         bg_rms,
                                                         symmetric=False)

        _morph = true_morph.copy()
        _morph[5, 5] = 1.5816233815926433
        assert_array_equal(sed / 3, true_sed)
        assert_almost_equal(morph * 3, _morph)

        # Test symmetry
        morph = true_morph.copy()
        morph[5, 5] = 2

        images = true_sed[:, None, None] * morph[None, :, :]
        frame = scarlet.Frame(shape)
        observation = scarlet.Observation(images).match(frame)
        bg_rms = np.ones_like(true_sed) * 1e-3
        sed, morph = scarlet.source.init_extended_source(skycoord,
                                                         frame,
                                                         observation,
                                                         bg_rms,
                                                         monotonic=False)

        assert_array_equal(sed / 3, true_sed)
        assert_almost_equal(morph * 3, true_morph)