LSST Applications g0603fd7c41+501e3db9f9,g0aad566f14+23d8574c86,g0dd44d6229+a1a4c8b791,g2079a07aa2+86d27d4dc4,g2305ad1205+a62672bbc1,g2bbee38e9b+047b288a59,g337abbeb29+047b288a59,g33d1c0ed96+047b288a59,g3a166c0a6a+047b288a59,g3d1719c13e+23d8574c86,g487adcacf7+cb7fd919b2,g4be5004598+23d8574c86,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+4a9e435310,g63cd9335cc+585e252eca,g858d7b2824+23d8574c86,g88963caddf+0cb8e002cc,g99cad8db69+43388bcaec,g9ddcbc5298+9a081db1e4,ga1e77700b3+a912195c07,gae0086650b+585e252eca,gb0e22166c9+60f28cb32d,gb2522980b2+793639e996,gb3a676b8dc+b4feba26a1,gb4b16eec92+63f8520565,gba4ed39666+c2a2e4ac27,gbb8dafda3b+a5d255a82e,gc120e1dc64+d820f8acdb,gc28159a63d+047b288a59,gc3e9b769f7+f4f1cc6b50,gcf0d15dbbd+a1a4c8b791,gdaeeff99f8+f9a426f77a,gdb0af172c8+b6d5496702,ge79ae78c31+047b288a59,w.2024.19
LSST Data Management Base Package
Loading...
Searching...
No Matches
Classes | Functions
lsst.scarlet.lite.operators Namespace Reference

Classes

class  Monotonicity
 

Functions

np.ndarray prox_connected (np.ndarray morph, Sequence[Sequence[int]] centers)
 
tuple[int, int] get_peak (np.ndarray image, tuple[int, int] center, int radius=1)
 
tuple[np.ndarray, np.ndarray, tuple[int, int, int, int]] prox_monotonic_mask (np.ndarray x, tuple[int, int] center, int center_radius=1, float variance=0.0, int max_iter=3)
 
np.ndarray uncentered_operator (np.ndarray x, Callable func, tuple[int, int]|None center=None, float|None fill=None, **kwargs)
 
 prox_sdss_symmetry (np.ndarray x)
 
np.ndarray prox_uncentered_symmetry (np.ndarray x, tuple[int, int]|None center=None, float|None fill=None)
 

Function Documentation

◆ get_peak()

tuple[int, int] lsst.scarlet.lite.operators.get_peak ( np.ndarray image,
tuple[int, int] center,
int radius = 1 )
Search around a location for the maximum flux

For monotonicity it is important to start at the brightest pixel
in the center of the source. This may be off by a pixel or two,
so we search for the correct center before applying
monotonic_tree.

Parameters
----------
image:
    The image of the source.
center:
    The suggested center of the source.
radius:
    The number of pixels around the `center` to search
    for a higher flux value.

Returns
-------
new_center:
    The true center of the source.

Definition at line 255 of file operators.py.

255def get_peak(image: np.ndarray, center: tuple[int, int], radius: int = 1) -> tuple[int, int]:
256 """Search around a location for the maximum flux
257
258 For monotonicity it is important to start at the brightest pixel
259 in the center of the source. This may be off by a pixel or two,
260 so we search for the correct center before applying
261 monotonic_tree.
262
263 Parameters
264 ----------
265 image:
266 The image of the source.
267 center:
268 The suggested center of the source.
269 radius:
270 The number of pixels around the `center` to search
271 for a higher flux value.
272
273 Returns
274 -------
275 new_center:
276 The true center of the source.
277 """
278 cy, cx = int(center[0]), int(center[1])
279 y0 = np.max([cy - radius, 0])
280 x0 = np.max([cx - radius, 0])
281 y_slice = slice(y0, cy + radius + 1)
282 x_slice = slice(x0, cx + radius + 1)
283 subset = image[y_slice, x_slice]
284 center = cast(tuple[int, int], np.unravel_index(np.argmax(subset), subset.shape))
285 return center[0] + y0, center[1] + x0
286
287

◆ prox_connected()

np.ndarray lsst.scarlet.lite.operators.prox_connected ( np.ndarray morph,
Sequence[Sequence[int]] centers )
Remove all pixels not connected to the center of a source.

Parameters
----------
morph:
    The morphology that is being constrained.
centers:
    The `(cy, cx)` center of any sources that all pixels must be
    connected to.

Returns
-------
result:
    The morphology with all pixels that are not connected to a center
    postion set to zero.

Definition at line 11 of file operators.py.

11def prox_connected(morph: np.ndarray, centers: Sequence[Sequence[int]]) -> np.ndarray:
12 """Remove all pixels not connected to the center of a source.
13
14 Parameters
15 ----------
16 morph:
17 The morphology that is being constrained.
18 centers:
19 The `(cy, cx)` center of any sources that all pixels must be
20 connected to.
21
22 Returns
23 -------
24 result:
25 The morphology with all pixels that are not connected to a center
26 postion set to zero.
27 """
28 result = np.zeros(morph.shape, dtype=bool)
29
30 for center in centers:
31 unchecked = np.ones(morph.shape, dtype=bool)
32 cy, cx = center
33 cy = int(cy)
34 cx = int(cx)
35 bounds = np.array([cy, cy, cx, cx]).astype(np.int32)
36 # Update the result in place with the pixels connected to this center
37 get_connected_pixels(cy, cx, morph, unchecked, result, bounds, 0)
38
39 return result * morph
40
41

◆ prox_monotonic_mask()

tuple[np.ndarray, np.ndarray, tuple[int, int, int, int]] lsst.scarlet.lite.operators.prox_monotonic_mask ( np.ndarray x,
tuple[int, int] center,
int center_radius = 1,
float variance = 0.0,
int max_iter = 3 )
Apply monotonicity from any path from the center

Parameters
----------
x:
    The input image that the mask is created for.
center:
    The location of the center of the mask.
center_radius:
    Radius from the center pixel to search for a better center
    (ie. a pixel in `X` with higher flux than the pixel given by
     `center`).
    If `center_radius == 0` then the `center` pixel is assumed
    to be correct.
variance:
    The average variance in the image.
    This is used to allow pixels to be non-monotonic up to `variance`,
    so setting `variance=0` will force strict monotonicity in the mask.
max_iter:
    Maximum number of iterations to interpolate non-monotonic pixels.

Returns
-------
valid:
    Boolean array of pixels that are monotonic.
model:
    The model with invalid pixels masked out.
bounds:
    The bounds of the valid monotonic pixels.

Definition at line 288 of file operators.py.

294) -> tuple[np.ndarray, np.ndarray, tuple[int, int, int, int]]:
295 """Apply monotonicity from any path from the center
296
297 Parameters
298 ----------
299 x:
300 The input image that the mask is created for.
301 center:
302 The location of the center of the mask.
303 center_radius:
304 Radius from the center pixel to search for a better center
305 (ie. a pixel in `X` with higher flux than the pixel given by
306 `center`).
307 If `center_radius == 0` then the `center` pixel is assumed
308 to be correct.
309 variance:
310 The average variance in the image.
311 This is used to allow pixels to be non-monotonic up to `variance`,
312 so setting `variance=0` will force strict monotonicity in the mask.
313 max_iter:
314 Maximum number of iterations to interpolate non-monotonic pixels.
315
316 Returns
317 -------
318 valid:
319 Boolean array of pixels that are monotonic.
320 model:
321 The model with invalid pixels masked out.
322 bounds:
323 The bounds of the valid monotonic pixels.
324 """
325 from lsst.scarlet.lite.operators_pybind11 import (
326 get_valid_monotonic_pixels,
327 linear_interpolate_invalid_pixels,
328 )
329
330 if center_radius > 0:
331 i, j = get_peak(x, center, center_radius)
332 else:
333 i, j = int(np.round(center[0])), int(np.round(center[1]))
334 unchecked = np.ones(x.shape, dtype=bool)
335 unchecked[i, j] = False
336 orphans = np.zeros(x.shape, dtype=bool)
337 # This is the bounding box of the result
338 bounds = np.array([i, i, j, j], dtype=np.int32)
339 # Get all of the monotonic pixels
340 get_valid_monotonic_pixels(i, j, x, unchecked, orphans, variance, bounds, 0)
341 # Set the initial model to the exact input in the valid pixels
342 model = x.copy()
343
344 it = 0
345
346 while np.sum(orphans & unchecked) > 0 and it < max_iter:
347 it += 1
348 all_i, all_j = np.where(orphans)
349 linear_interpolate_invalid_pixels(all_i, all_j, unchecked, model, orphans, variance, True, bounds)
350 valid = ~unchecked & ~orphans
351 # Clear all of the invalid pixels from the input image
352 model = model * valid
353 return valid, model, tuple(bounds) # type: ignore
354
355
void get_valid_monotonic_pixels(const int i, const int j, Eigen::Ref< M, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > image, Eigen::Ref< MatrixB, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > unchecked, Eigen::Ref< MatrixB, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > orphans, const double variance, Eigen::Ref< Bounds, 0, Eigen::Stride< 4, 1 > > bounds, const double thresh=0)
void linear_interpolate_invalid_pixels(Eigen::Ref< const IndexVector > row_indices, Eigen::Ref< const IndexVector > column_indices, Eigen::Ref< MatrixB, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > unchecked, Eigen::Ref< M, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > model, Eigen::Ref< MatrixB, 0, Eigen::Stride< Eigen::Dynamic, Eigen::Dynamic > > orphans, const double variance, bool recursive, Eigen::Ref< Bounds, 0, Eigen::Stride< 4, 1 > > bounds)

◆ prox_sdss_symmetry()

lsst.scarlet.lite.operators.prox_sdss_symmetry ( np.ndarray x)
SDSS/HSC symmetry operator

This function uses the *minimum* of the two
symmetric pixels in the update.

Parameters
----------
x:
    The array to make symmetric.

Returns
-------
result:
    The updated `x`.

Definition at line 423 of file operators.py.

423def prox_sdss_symmetry(x: np.ndarray):
424 """SDSS/HSC symmetry operator
425
426 This function uses the *minimum* of the two
427 symmetric pixels in the update.
428
429 Parameters
430 ----------
431 x:
432 The array to make symmetric.
433
434 Returns
435 -------
436 result:
437 The updated `x`.
438 """
439 symmetric = np.fliplr(np.flipud(x))
440 x[:] = np.min([x, symmetric], axis=0)
441 return x
442
443

◆ prox_uncentered_symmetry()

np.ndarray lsst.scarlet.lite.operators.prox_uncentered_symmetry ( np.ndarray x,
tuple[int, int] | None center = None,
float | None fill = None )
Symmetry with off-center peak

Symmetrize X for all pixels with a symmetric partner.

Parameters
----------
x:
    The parameter to update.
center:
    The center pixel coordinates to apply the symmetry operator.
fill:
    The value to fill the region that cannot be made symmetric.
    When `fill` is `None` then the region of `X` that is not symmetric
    is not constrained.

Returns
-------
result:
    The update function based on the specified parameters.

Definition at line 444 of file operators.py.

448) -> np.ndarray:
449 """Symmetry with off-center peak
450
451 Symmetrize X for all pixels with a symmetric partner.
452
453 Parameters
454 ----------
455 x:
456 The parameter to update.
457 center:
458 The center pixel coordinates to apply the symmetry operator.
459 fill:
460 The value to fill the region that cannot be made symmetric.
461 When `fill` is `None` then the region of `X` that is not symmetric
462 is not constrained.
463
464 Returns
465 -------
466 result:
467 The update function based on the specified parameters.
468 """
469 return uncentered_operator(x, prox_sdss_symmetry, center, fill=fill)

◆ uncentered_operator()

np.ndarray lsst.scarlet.lite.operators.uncentered_operator ( np.ndarray x,
Callable func,
tuple[int, int] | None center = None,
float | None fill = None,
** kwargs )
Only apply the operator on a centered patch

In some cases, for example symmetry, an operator might not make
sense outside of a centered box. This operator only updates
the portion of `X` inside the centered region.

Parameters
----------
x:
    The parameter to update.
func:
    The function (or operator) to apply to `x`.
center:
    The location of the center of the sub-region to
    apply `func` to `x`.
fill:
    The value to fill the region outside of centered
    `sub-region`, for example `0`. If `fill` is `None`
    then only the subregion is updated and the rest of
    `x` remains unchanged.

Returns
-------
result:
    `x`, with an operator applied based on the shifted center.

Definition at line 356 of file operators.py.

362) -> np.ndarray:
363 """Only apply the operator on a centered patch
364
365 In some cases, for example symmetry, an operator might not make
366 sense outside of a centered box. This operator only updates
367 the portion of `X` inside the centered region.
368
369 Parameters
370 ----------
371 x:
372 The parameter to update.
373 func:
374 The function (or operator) to apply to `x`.
375 center:
376 The location of the center of the sub-region to
377 apply `func` to `x`.
378 fill:
379 The value to fill the region outside of centered
380 `sub-region`, for example `0`. If `fill` is `None`
381 then only the subregion is updated and the rest of
382 `x` remains unchanged.
383
384 Returns
385 -------
386 result:
387 `x`, with an operator applied based on the shifted center.
388 """
389 if center is None:
390 py, px = cast(tuple[int, int], np.unravel_index(np.argmax(x), x.shape))
391 else:
392 py, px = center
393 cy, cx = np.array(x.shape) // 2
394
395 if py == cy and px == cx:
396 return func(x, **kwargs)
397
398 dy = int(2 * (py - cy))
399 dx = int(2 * (px - cx))
400 if not x.shape[0] % 2:
401 dy += 1
402 if not x.shape[1] % 2:
403 dx += 1
404 if dx < 0:
405 xslice = slice(None, dx)
406 else:
407 xslice = slice(dx, None)
408 if dy < 0:
409 yslice = slice(None, dy)
410 else:
411 yslice = slice(dy, None)
412
413 if fill is not None:
414 _x = np.ones(x.shape, x.dtype) * fill
415 _x[yslice, xslice] = func(x[yslice, xslice], **kwargs)
416 x[:] = _x
417 else:
418 x[yslice, xslice] = func(x[yslice, xslice], **kwargs)
419
420 return x
421
422