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