LSST Applications g0603fd7c41+022847dfd1,g0aad566f14+f45185db35,g180d380827+40e913b07a,g2079a07aa2+86d27d4dc4,g2305ad1205+696e5f3872,g2bbee38e9b+047b288a59,g337abbeb29+047b288a59,g33d1c0ed96+047b288a59,g3a166c0a6a+047b288a59,g3d1719c13e+f45185db35,g3de15ee5c7+5201731f0d,g487adcacf7+19f9b77d7d,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+248b16177b,g63cd9335cc+585e252eca,g858d7b2824+f45185db35,g88963caddf+0cb8e002cc,g991b906543+f45185db35,g99cad8db69+1747e75aa3,g9b9dfce982+78139cbddb,g9ddcbc5298+9a081db1e4,ga1e77700b3+a912195c07,gae0086650b+585e252eca,gb0e22166c9+60f28cb32d,gb3a676b8dc+b4feba26a1,gb4b16eec92+f82f04eb54,gba4ed39666+c2a2e4ac27,gbb8dafda3b+215b19b0ab,gc120e1dc64+b0284b5341,gc28159a63d+047b288a59,gc3e9b769f7+dcad4ace9a,gcf0d15dbbd+78139cbddb,gdaeeff99f8+f9a426f77a,ge79ae78c31+047b288a59,w.2024.19
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | List of all members
lsst.scarlet.lite.operators.Monotonicity Class Reference

Public Member Functions

 __init__ (self, tuple[int, int] shape, npt.DTypeLike dtype=float, bool auto_update=True, int fit_radius=1)
 
tuple[int, int] shape (self)
 
tuple[int, int] center (self)
 
 update (self, tuple[int, int] shape)
 
 check_size (self, tuple[int, int] shape, tuple[int, int] center, bool update=True)
 
np.ndarray __call__ (self, np.ndarray image, tuple[int, int] center)
 

Public Attributes

 dtype
 
 auto_update
 
 fit_radius
 
 weights
 
 distance
 
 sizes
 

Detailed Description

Class to implement Monotonicity

Callable class that applies monotonicity as a pseudo proximal
operator (actually a projection operator) to *a* radially
monotonic solution.

Notes
-----
This differs from monotonicity in the main scarlet branch because
this stores a single monotonicity operator to set the weights for all
of the pixels up to the size of the largest shape expected,
and only needs to be created once _per blend_, as opposed to
once _per source_..
This class is then called with the source morphology
to make monotonic and the location of the "center" of the image,
and the full weight matrix is sliced accordingly.

Parameters
----------
shape:
    The shape of the full operator.
    This must be larger than the largest possible object size
    in the blend.
dtype:
    The numpy ``dtype`` of the output image.
auto_update:
    If ``True`` the operator will update its shape if a image is
    too big to fit in the current operator.
fit_radius:
    Pixels within `fit_radius` of the center of the array to make
    monotonic are checked to see if they have more flux than the center
    pixel. If they do, the pixel with larger flux is used as the center.

Definition at line 42 of file operators.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.scarlet.lite.operators.Monotonicity.__init__ ( self,
tuple[int, int] shape,
npt.DTypeLike dtype = float,
bool auto_update = True,
int fit_radius = 1 )

Definition at line 77 of file operators.py.

83 ):
84 # Initialize defined variables
85 self.weights: np.ndarray | None = None
86 self.distance: np.ndarray | None = None
87 self.sizes: tuple[int, int, int, int] | None = None
88 self.dtype = dtype
89 self.auto_update = auto_update
90 self.fit_radius = fit_radius
91 self.update(shape)
92

Member Function Documentation

◆ __call__()

np.ndarray lsst.scarlet.lite.operators.Monotonicity.__call__ ( self,
np.ndarray image,
tuple[int, int] center )
Make an input image monotonic about a center pixel

Parameters
----------
image:
    The image to make monotonic.
center:
    The ``(y, x)`` location _in image coordinates_ to make the
    center of the monotonic region.

Returns
-------
result:
    The input image is updated in place, but also returned from this
    method.

Definition at line 214 of file operators.py.

214 def __call__(self, image: np.ndarray, center: tuple[int, int]) -> np.ndarray:
215 """Make an input image monotonic about a center pixel
216
217 Parameters
218 ----------
219 image:
220 The image to make monotonic.
221 center:
222 The ``(y, x)`` location _in image coordinates_ to make the
223 center of the monotonic region.
224
225 Returns
226 -------
227 result:
228 The input image is updated in place, but also returned from this
229 method.
230 """
231 # Check for a better center
232 center = get_peak(image, center, self.fit_radius)
233
234 # Check that the operator can fit the image
235 self.check_size(cast(tuple[int, int], image.shape), center, self.auto_update)
236
237 # Create the bounding box to slice the weights and distance as needed
238 cy, cx = self.center
239 py, px = center
240 bbox = Box((9,) + image.shape, origin=(0, cy - py, cx - px))
241 weights = cast(np.ndarray, self.weights)[bbox.slices]
242 indices = np.argsort(cast(np.ndarray, self.distance)[bbox.slices[1:]].flatten())
243 coords = np.unravel_index(indices, image.shape)
244
245 # Pad the image by 1 so that we don't have to worry about
246 # weights on the edges.
247 result_shape = (image.shape[0] + 2, image.shape[1] + 2)
248 result = np.zeros(result_shape, dtype=image.dtype)
249 result[1:-1, 1:-1] = image
250 new_monotonicity(coords[0], coords[1], [w for w in weights], result)
251 image[:] = result[1:-1, 1:-1]
252 return image
253
254

◆ center()

tuple[int, int] lsst.scarlet.lite.operators.Monotonicity.center ( self)
The center of the full operator

Returns
-------
result:
    The center of the full operator.

Definition at line 105 of file operators.py.

105 def center(self) -> tuple[int, int]:
106 """The center of the full operator
107
108 Returns
109 -------
110 result:
111 The center of the full operator.
112 """
113 shape = self.shape
114 cx = (shape[1] - 1) // 2
115 cy = (shape[0] - 1) // 2
116 return cy, cx
117

◆ check_size()

lsst.scarlet.lite.operators.Monotonicity.check_size ( self,
tuple[int, int] shape,
tuple[int, int] center,
bool update = True )
Check to see if the operator can be applied

Parameters
----------
shape:
    The shape of the image to apply monotonicity.
center:
    The location (in `shape`) of the point where the monotonicity will
    be taken from.
update:
    When ``True`` the operator will update itself so that an image
    with shape `shape` can be made monotonic about the `center`.

Raises
------
ValueError:
    Raised when an array with shape `shape` does not fit in the
    current operator and `update` is `False`.

Definition at line 186 of file operators.py.

186 def check_size(self, shape: tuple[int, int], center: tuple[int, int], update: bool = True):
187 """Check to see if the operator can be applied
188
189 Parameters
190 ----------
191 shape:
192 The shape of the image to apply monotonicity.
193 center:
194 The location (in `shape`) of the point where the monotonicity will
195 be taken from.
196 update:
197 When ``True`` the operator will update itself so that an image
198 with shape `shape` can be made monotonic about the `center`.
199
200 Raises
201 ------
202 ValueError:
203 Raised when an array with shape `shape` does not fit in the
204 current operator and `update` is `False`.
205 """
206 sizes = np.array(tuple(center) + (shape[0] - center[0], shape[1] - center[1]))
207 if np.any(sizes > self.sizes):
208 if update:
209 size = 2 * np.max(sizes) + 1
210 self.update((size, size))
211 else:
212 raise ValueError(f"Cannot apply monotonicity to image with shape {shape} at {center}")
213

◆ shape()

tuple[int, int] lsst.scarlet.lite.operators.Monotonicity.shape ( self)
The 2D shape of the largest component that can be made monotonic

Returns
-------
result:
    The shape of the oeprator.

Definition at line 94 of file operators.py.

94 def shape(self) -> tuple[int, int]:
95 """The 2D shape of the largest component that can be made monotonic
96
97 Returns
98 -------
99 result:
100 The shape of the oeprator.
101 """
102 return cast(tuple[int, int], cast(np.ndarray, self.weights).shape[1:])
103

◆ update()

lsst.scarlet.lite.operators.Monotonicity.update ( self,
tuple[int, int] shape )
Update the operator with a new shape

Parameters
----------
shape:
    The new shape

Definition at line 118 of file operators.py.

118 def update(self, shape: tuple[int, int]):
119 """Update the operator with a new shape
120
121 Parameters
122 ----------
123 shape:
124 The new shape
125 """
126 if len(shape) != 2:
127 msg = f"Monotonicity is a 2D operator but received shape with {len(shape)} dimensions"
128 raise ValueError(msg)
129 if shape[0] % 2 == 0 or shape[1] % 2 == 0:
130 raise ValueError(f"The shape must be odd, got {shape}")
131 # Use the center of the operator as the center
132 # and calculate the distance to each pixel from the center
133 cx = (shape[1] - 1) // 2
134 cy = (shape[0] - 1) // 2
135 x = np.arange(shape[1], dtype=self.dtype) - cx
136 y = np.arange(shape[0], dtype=self.dtype) - cy
137 x, y = np.meshgrid(x, y)
138 distance = np.sqrt(x**2 + y**2)
139
140 # Calculate the distance from each pixel to its 8 nearest neighbors
141 neighbor_dist = np.zeros((9,) + distance.shape, dtype=self.dtype)
142 neighbor_dist[0, 1:, 1:] = distance[1:, 1:] - distance[:-1, :-1]
143 neighbor_dist[1, 1:, :] = distance[1:, :] - distance[:-1, :]
144 neighbor_dist[2, 1:, :-1] = distance[1:, :-1] - distance[:-1, 1:]
145 neighbor_dist[3, :, 1:] = distance[:, 1:] - distance[:, :-1]
146
147 # For the center pixel, set the distance to 1 just so that it is
148 # non-zero
149 neighbor_dist[4, cy, cx] = 1
150 neighbor_dist[5, :, :-1] = distance[:, :-1] - distance[:, 1:]
151 neighbor_dist[6, :-1, 1:] = distance[:-1, 1:] - distance[1:, :-1]
152 neighbor_dist[7, :-1, :] = distance[:-1, :] - distance[1:, :]
153 neighbor_dist[8, :-1, :-1] = distance[:-1, :-1] - distance[1:, 1:]
154
155 # Calculate the difference in angle to the center
156 # from each pixel to its 8 nearest neighbors
157 angles = np.arctan2(y, x)
158 angle_diff = np.zeros((9,) + angles.shape, dtype=self.dtype)
159 angle_diff[0, 1:, 1:] = angles[1:, 1:] - angles[:-1, :-1]
160 angle_diff[1, 1:, :] = angles[1:, :] - angles[:-1, :]
161 angle_diff[2, 1:, :-1] = angles[1:, :-1] - angles[:-1, 1:]
162 angle_diff[3, :, 1:] = angles[:, 1:] - angles[:, :-1]
163 # For the center pixel, on the center will have a non-zero cosine,
164 # which is used as the weight.
165 angle_diff[4] = 1
166 angle_diff[4, cy, cx] = 0
167 angle_diff[5, :, :-1] = angles[:, :-1] - angles[:, 1:]
168 angle_diff[6, :-1, 1:] = angles[:-1, 1:] - angles[1:, :-1]
169 angle_diff[7, :-1, :] = angles[:-1, :] - angles[1:, :]
170 angle_diff[8, :-1, :-1] = angles[:-1, :-1] - angles[1:, 1:]
171
172 # Use cos(theta) to set the weights, then normalize
173 # This gives more weight to neighboring pixels that are more closely
174 # aligned with the vector pointing toward the center.
175 weights = np.cos(angle_diff)
176 weights[neighbor_dist <= 0] = 0
177 # Adjust for the discontinuity at theta = 2pi
178 weights[weights < 0] = -weights[weights < 0]
179 weights = weights / np.sum(weights, axis=0)[None, :, :]
180
181 # Store the parameters needed later
182 self.weights = weights
183 self.distance = distance
184 self.sizes = (cy, cx, shape[0] - cy, shape[1] - cx)
185

Member Data Documentation

◆ auto_update

lsst.scarlet.lite.operators.Monotonicity.auto_update

Definition at line 89 of file operators.py.

◆ distance

lsst.scarlet.lite.operators.Monotonicity.distance

Definition at line 183 of file operators.py.

◆ dtype

lsst.scarlet.lite.operators.Monotonicity.dtype

Definition at line 88 of file operators.py.

◆ fit_radius

lsst.scarlet.lite.operators.Monotonicity.fit_radius

Definition at line 90 of file operators.py.

◆ sizes

lsst.scarlet.lite.operators.Monotonicity.sizes

Definition at line 184 of file operators.py.

◆ weights

lsst.scarlet.lite.operators.Monotonicity.weights

Definition at line 102 of file operators.py.


The documentation for this class was generated from the following file: