Coverage for python/lsst/cell_coadds/_image_planes.py: 69%
72 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-12 02:00 -0700
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-12 02:00 -0700
1# This file is part of cell_coadds.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
22from __future__ import annotations
24__all__ = (
25 "ImagePlanes",
26 "OwnedImagePlanes",
27 "ViewImagePlanes",
28)
30from abc import ABC, abstractmethod
31from collections.abc import Callable, Sequence
32from typing import TYPE_CHECKING, Self
34from lsst.afw.image import MaskedImageF
36if TYPE_CHECKING: 36 ↛ 37line 36 didn't jump to line 37, because the condition on line 36 was never true
37 from lsst.afw.image import Mask, MaskedImage
38 from lsst.geom import Box2I
40 from .typing_helpers import ImageLike
43class ImagePlanes(ABC):
44 """Struct interface for the image-like planes we coadd.
46 Notes
47 -----
48 The extends the set of planes in `lsst.afw.image.MaskedImage` by adding
49 noise realizations and "mask fraction" images.
50 """
52 @property
53 @abstractmethod
54 def bbox(self) -> Box2I:
55 """The bounding box common to all image planes."""
56 raise NotImplementedError()
58 @property
59 @abstractmethod
60 def image(self) -> ImageLike:
61 """The data image itself."""
62 raise NotImplementedError()
64 @property
65 @abstractmethod
66 def mask(self) -> Mask:
67 """An integer bitmask."""
68 raise NotImplementedError()
70 @property
71 @abstractmethod
72 def variance(self) -> ImageLike:
73 """Per-pixel variances for the image."""
74 raise NotImplementedError()
76 @property
77 @abstractmethod
78 def mask_fractions(self) -> ImageLike | None:
79 """The (weighted) fraction of masked pixels that contribute to each
80 pixel.
81 """
82 raise NotImplementedError()
84 @property
85 @abstractmethod
86 def noise_realizations(self) -> Sequence[ImageLike]:
87 """A sequence of noise realizations that were coadded with the same
88 operations that were appled to the data image.
89 """
90 raise NotImplementedError()
92 def asMaskedImage(self) -> MaskedImageF:
93 """Return an `lsst.afw.image.MaskedImage` view of the image, mask, and
94 variance planes.
95 """
96 return MaskedImageF(self.image, self.mask, self.variance)
99class OwnedImagePlanes(ImagePlanes):
100 """An implementation of the `ImagePlanes` interface backed by actual
101 afw objects.
102 """
104 def __init__(
105 self,
106 *,
107 image: ImageLike,
108 mask: Mask,
109 variance: ImageLike,
110 mask_fractions: ImageLike | None = None,
111 noise_realizations: Sequence[ImageLike] = (),
112 ):
113 self._image = image
114 self._mask = mask
115 self._variance = variance
116 self._mask_fractions = mask_fractions
117 self._noise_realizations = tuple(noise_realizations)
119 @classmethod
120 def from_masked_image(
121 cls,
122 masked_image: MaskedImage,
123 mask_fractions: ImageLike | None = None,
124 noise_realizations: Sequence[ImageLike] = (),
125 ) -> Self:
126 """Construct from an `lsst.afw.image.MaskedImage`.
128 Parameters
129 ----------
130 masked_image : `~lsst.afw.image.MaskedImage`
131 The image to construct from. The image, mask and variance planes
132 of ``masked_image`` will be used as the image, mask and variance
133 planes of the constructed object.
134 mask_fractions : `ImageLike`, optional
135 The mask fractions image.
136 noise_realizations : `Sequence` [`ImageLike`], optional
137 The noise realizations.
139 Returns
140 -------
141 self : `OwnedImagePlanes`
142 An instance of OwnedImagePlanes.
143 """
144 return cls(
145 image=masked_image.image,
146 mask=masked_image.mask,
147 variance=masked_image.variance,
148 mask_fractions=mask_fractions,
149 noise_realizations=noise_realizations,
150 )
152 @property
153 def bbox(self) -> Box2I:
154 # Docstring inherited.
155 return self._image.getBBox()
157 @property
158 def image(self) -> ImageLike:
159 # Docstring inherited.
160 return self._image
162 @property
163 def mask(self) -> Mask:
164 # Docstring inherited.
165 return self._mask
167 @property
168 def variance(self) -> ImageLike:
169 # Docstring inherited.
170 return self._variance
172 @property
173 def mask_fractions(self) -> ImageLike | None:
174 # Docstring inherited.
175 return self._mask_fractions
177 @property
178 def noise_realizations(self) -> Sequence[ImageLike]:
179 # Docstring inherited.
180 return self._noise_realizations
183class ViewImagePlanes(ImagePlanes):
184 """An implementation of the `ImagePlanes` interface that extracts views
185 from another target `ImagePlanes` instance.
187 Parameters
188 ----------
189 target : `ImagePlanes`
190 Planes to construct views of.
191 make_view : `Callable`
192 Callable that takes an original image plane and returns a view into it.
193 bbox : `Box2I`, optional
194 Bounding box of the new image plane. Defaults to ``target.bbox``.
195 """
197 def __init__(
198 self, target: ImagePlanes, make_view: Callable[[ImageLike], ImageLike], bbox: Box2I | None = None
199 ):
200 self._target = target
201 self._bbox = bbox if bbox is not None else self._target.bbox
202 self._make_view = make_view
204 @property
205 def bbox(self) -> Box2I:
206 # Docstring inherited.
207 return self._bbox
209 @property
210 def image(self) -> ImageLike:
211 # Docstring inherited.
212 return self._make_view(self._target.image)
214 @property
215 def mask(self) -> Mask:
216 # Docstring inherited.
217 return self._make_view(self._target.mask)
219 @property
220 def variance(self) -> ImageLike:
221 # Docstring inherited.
222 return self._make_view(self._target.variance)
224 @property
225 def mask_fractions(self) -> ImageLike | None:
226 # Docstring inherited.
227 if self._target.mask_fractions is not None:
228 return self._make_view(self._target.mask_fractions)
230 return None
232 @property
233 def noise_realizations(self) -> Sequence[ImageLike]:
234 # Docstring inherited.
235 # We could make this even lazier with a custom Sequence class, but it
236 # doesn't seem worthwhile.
237 return tuple(self._make_view(r) for r in self._target.noise_realizations)