22from __future__
import annotations
25 "ExtendedPsfImageInfo",
26 "ExtendedPsfImageSerializationModel",
31from types
import EllipsisType
35from astropy.units
import UnitBase
36from pydantic
import BaseModel, Field
38from lsst.images
import Box, GeneralizedImage, Image, ImageSerializationModel
39from lsst.images.serialization
import ArchiveTree, InputArchive, MetadataValue, OutputArchive
41from .extended_psf_fit
import ExtendedPsfFit, ExtendedPsfMoffatFit
45 """Additional information about an `ExtendedPsfImage`.
49 n_stars : `int`, optional
50 Number of stars used to construct the extended PSF image.
53 n_stars: int |
None =
None
56 attrs =
", ".join(f
"{k}={v!r}" for k, v
in self.__dict__.items())
57 return f
"ExtendedPsfImageInfo({attrs})"
63 """A Pydantic model used to represent a serialized `ExtendedPsfImage`."""
65 image: ImageSerializationModel[P] = Field(
66 description=
"The main data image.",
68 variance: ImageSerializationModel[P] = Field(
69 description=
"Per-pixel variance estimates for the main image."
71 info: ExtendedPsfImageInfo = Field(
72 description=
"Additional information about the extended PSF image.",
74 fit: ExtendedPsfMoffatFit | ExtendedPsfFit = Field(
75 description=
"The results of an extended PSF fit to the image.",
80 """The bounding box of the image."""
81 return self.image.bbox
83 def deserialize(self, archive: InputArchive[Any], *, bbox: Box |
None =
None) -> ExtendedPsfImage:
84 """Deserialize an image from an input archive.
91 Bounding box of a subimage to read instead.
94 variance = self.variance.
deserialize(archive, bbox=bbox)
100 )._finish_deserialize(self)
104 """A multi-plane image with data (image) and variance planes, and the
105 results of a profile fit to the image.
109 image : `~lsst.images.Image`
110 The main image plane.
111 variance : `~lsst.images.Image`, optional
112 The per-pixel uncertainty of the main image as an image of variance
113 values. Must have the same bounding box as ``image`` if provided, and
114 its units must be the square of ``image.unit`` or `None`.
115 Values default to ``1.0``. Any attached projection is replaced
116 (possibly by `None`).
117 info : `ExtendedPsfImageInfo`, optional
118 Additional information about how the extended PSF image was
120 fit : `ExtendedPsfFit`, optional
121 The results of a profile fit to the image.
122 metadata : `dict` [`str`, `MetadataValue`], optional
123 Arbitrary flexible metadata to associate with the image.
127 image : `~lsst.images.Image`
128 The main image plane.
129 variance : `~lsst.images.Image`
130 The per-pixel uncertainty of the main image as an image of variance
132 bbox : `~lsst.images.Box`
133 The bounding box shared by both image planes.
134 unit : `astropy.units.Unit` or `None`
135 The units of the image plane, or `None` if the image is dimensionless.
137 The projection that maps the pixel grid to the sky. Always `None` for
139 info : `ExtendedPsfImageInfo`
140 Additional information about how the extended PSF image was
142 fit : `ExtendedPsfFit`
143 The results of a profile fit to the image.
150 variance: Image |
None =
None,
151 info: ExtendedPsfImageInfo |
None =
None,
152 fit: ExtendedPsfFit |
None =
None,
153 metadata: dict[str, MetadataValue] |
None =
None,
161 unit=
None if image.unit
is None else image.unit**2,
164 if image.bbox != variance.bbox:
165 raise ValueError(f
"Image ({image.bbox}) and variance ({variance.bbox}) bboxes do not agree.")
166 if image.unit
is None:
167 if variance.unit
is not None:
168 raise ValueError(f
"Image has no units but variance does ({variance.unit}).")
169 elif variance.unit
is None:
170 variance = variance.view(unit=image.unit**2)
171 elif variance.unit != image.unit**2:
173 f
"Variance unit ({variance.unit}) should be the square of the image unit ({image.unit})."
186 """The main image plane (`Image`)."""
191 """The variance plane (`Image`)."""
196 """The bounding box shared by both image planes (`Box`)."""
200 def unit(self) -> UnitBase | None:
201 """The units of the image plane (`astropy.units.Unit` | `None`)."""
206 """The projection that maps the pixel grid to the sky.
208 ExtendedPsfImage does not support attached projections,
209 so this always returns `None`.
214 def info(self) -> ExtendedPsfImageInfo:
215 """Additional information about the image (`ExtendedPsfImageInfo`)."""
219 def fit(self) -> ExtendedPsfFit:
220 """The results of a profile fit to the image."""
223 def __getitem__(self, bbox: Box | EllipsisType) -> ExtendedPsfImage:
227 return self._transfer_metadata(
237 def __setitem__(self, bbox: Box | EllipsisType, value: ExtendedPsfImage) ->
None:
238 self.
_image[bbox] = value.image
242 return f
"ExtendedPsfImage({self.image!s}, info={self.info!r}, fit={self.fit!r})"
246 def copy(self) -> ExtendedPsfImage:
247 """Deep-copy the profile image and metadata."""
248 return self._transfer_metadata(
252 info=self.
_info.model_copy(),
253 fit=self.
_fit.model_copy(),
258 def serialize(self, archive: OutputArchive[Any]) -> ExtendedPsfImageSerializationModel:
259 """Serialize the Extended PSF image to an output archive.
266 serialized_image = archive.serialize_direct(
267 "image", functools.partial(self.
image.serialize, save_projection=
False)
269 serialized_variance = archive.serialize_direct(
270 "variance", functools.partial(self.
variance.serialize, save_projection=
False)
272 serialized_info = self.
info
273 serialized_fit = self.
fit
275 image=serialized_image,
276 variance=serialized_variance,
277 info=serialized_info,
279 metadata=self.metadata,
284 model: ExtendedPsfImageSerializationModel[Any], archive: InputArchive[Any], *, bbox: Box |
None =
None
285 ) -> ExtendedPsfImage:
286 """Deserialize an image from an input archive.
291 A Pydantic model representation of the image, holding references
292 to data stored in the archive.
294 Archive to read from.
296 Bounding box of a subimage to read instead.
298 return model.deserialize(archive, bbox=bbox)
301 def _get_archive_tree_type[P: BaseModel](
302 pointer_type: type[P],
303 ) -> type[ExtendedPsfImageSerializationModel[P]]:
304 """Return the serialization model type for this object for an archive
305 type that uses the given pointer type.
307 return ExtendedPsfImageSerializationModel[pointer_type]
None __setitem__(self, Box|EllipsisType bbox, ExtendedPsfImage value)
ExtendedPsfImageInfo info(self)
ExtendedPsfImage __getitem__(self, Box|EllipsisType bbox)
ExtendedPsfImage copy(self)
ExtendedPsfImage deserialize(ExtendedPsfImageSerializationModel[Any] model, InputArchive[Any] archive, *, Box|None bbox=None)
ExtendedPsfImageSerializationModel serialize(self, OutputArchive[Any] archive)
__init__(self, Image image, *, Image|None variance=None, ExtendedPsfImageInfo|None info=None, ExtendedPsfFit|None fit=None, dict[str, MetadataValue]|None metadata=None)
ExtendedPsfImageInfo _info
ExtendedPsfImage deserialize(self, InputArchive[Any] archive, *, Box|None bbox=None)
ImageSerializationModel variance
ExtendedPsfImageInfo info
ImageSerializationModel image