22from __future__
import annotations
25 "ExtendedPsfImageInfo",
26 "ExtendedPsfImageSerializationModel",
31from types
import EllipsisType
32from typing
import Any, ClassVar
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 SCHEMA_NAME: ClassVar[str] =
"extended_psf_image"
66 SCHEMA_VERSION: ClassVar[str] =
"1.0.0"
67 MIN_READ_VERSION: ClassVar[int] = 1
69 image: ImageSerializationModel[P] = Field(
70 description=
"The main data image.",
72 variance: ImageSerializationModel[P] = Field(
73 description=
"Per-pixel variance estimates for the main image."
75 info: ExtendedPsfImageInfo = Field(
76 description=
"Additional information about the extended PSF image.",
78 fit: ExtendedPsfMoffatFit | ExtendedPsfFit = Field(
79 description=
"The results of an extended PSF fit to the image.",
84 """The bounding box of the image."""
85 return self.image.bbox
87 def deserialize(self, archive: InputArchive[Any], *, bbox: Box |
None =
None) -> ExtendedPsfImage:
88 """Deserialize an image from an input archive.
95 Bounding box of a subimage to read instead.
98 variance = self.variance.
deserialize(archive, bbox=bbox)
104 )._finish_deserialize(self)
108 """A multi-plane image with data (image) and variance planes, and the
109 results of a profile fit to the image.
113 image : `~lsst.images.Image`
114 The main image plane.
115 variance : `~lsst.images.Image`, optional
116 The per-pixel uncertainty of the main image as an image of variance
117 values. Must have the same bounding box as ``image`` if provided, and
118 its units must be the square of ``image.unit`` or `None`.
119 Values default to ``1.0``. Any attached projection is replaced
120 (possibly by `None`).
121 info : `ExtendedPsfImageInfo`, optional
122 Additional information about how the extended PSF image was
124 fit : `ExtendedPsfFit`, optional
125 The results of a profile fit to the image.
126 metadata : `dict` [`str`, `MetadataValue`], optional
127 Arbitrary flexible metadata to associate with the image.
131 image : `~lsst.images.Image`
132 The main image plane.
133 variance : `~lsst.images.Image`
134 The per-pixel uncertainty of the main image as an image of variance
136 bbox : `~lsst.images.Box`
137 The bounding box shared by both image planes.
138 unit : `astropy.units.Unit` or `None`
139 The units of the image plane, or `None` if the image is dimensionless.
141 The projection that maps the pixel grid to the sky. Always `None` for
143 info : `ExtendedPsfImageInfo`
144 Additional information about how the extended PSF image was
146 fit : `ExtendedPsfFit`
147 The results of a profile fit to the image.
154 variance: Image |
None =
None,
155 info: ExtendedPsfImageInfo |
None =
None,
156 fit: ExtendedPsfFit |
None =
None,
157 metadata: dict[str, MetadataValue] |
None =
None,
165 unit=
None if image.unit
is None else image.unit**2,
168 if image.bbox != variance.bbox:
169 raise ValueError(f
"Image ({image.bbox}) and variance ({variance.bbox}) bboxes do not agree.")
170 if image.unit
is None:
171 if variance.unit
is not None:
172 raise ValueError(f
"Image has no units but variance does ({variance.unit}).")
173 elif variance.unit
is None:
174 variance = variance.view(unit=image.unit**2)
175 elif variance.unit != image.unit**2:
177 f
"Variance unit ({variance.unit}) should be the square of the image unit ({image.unit})."
190 """The main image plane (`Image`)."""
195 """The variance plane (`Image`)."""
200 """The bounding box shared by both image planes (`Box`)."""
204 def unit(self) -> UnitBase | None:
205 """The units of the image plane (`astropy.units.Unit` | `None`)."""
210 """The projection that maps the pixel grid to the sky.
212 ExtendedPsfImage does not support attached projections,
213 so this always returns `None`.
218 def info(self) -> ExtendedPsfImageInfo:
219 """Additional information about the image (`ExtendedPsfImageInfo`)."""
223 def fit(self) -> ExtendedPsfFit:
224 """The results of a profile fit to the image."""
227 def __getitem__(self, bbox: Box | EllipsisType) -> ExtendedPsfImage:
231 return self._transfer_metadata(
241 def __setitem__(self, bbox: Box | EllipsisType, value: ExtendedPsfImage) ->
None:
242 self.
_image[bbox] = value.image
246 return f
"ExtendedPsfImage({self.image!s}, info={self.info!r}, fit={self.fit!r})"
250 def copy(self) -> ExtendedPsfImage:
251 """Deep-copy the profile image and metadata."""
252 return self._transfer_metadata(
256 info=self.
_info.model_copy(),
257 fit=self.
_fit.model_copy(),
262 def serialize(self, archive: OutputArchive[Any]) -> ExtendedPsfImageSerializationModel:
263 """Serialize the Extended PSF image to an output archive.
270 serialized_image = archive.serialize_direct(
271 "image", functools.partial(self.
image.serialize, save_projection=
False)
273 serialized_variance = archive.serialize_direct(
274 "variance", functools.partial(self.
variance.serialize, save_projection=
False)
276 serialized_info = self.
info
277 serialized_fit = self.
fit
279 image=serialized_image,
280 variance=serialized_variance,
281 info=serialized_info,
283 metadata=self.metadata,
288 model: ExtendedPsfImageSerializationModel[Any], archive: InputArchive[Any], *, bbox: Box |
None =
None
289 ) -> ExtendedPsfImage:
290 """Deserialize an image from an input archive.
295 A Pydantic model representation of the image, holding references
296 to data stored in the archive.
298 Archive to read from.
300 Bounding box of a subimage to read instead.
302 return model.deserialize(archive, bbox=bbox)
305 def _get_archive_tree_type[P: BaseModel](
306 pointer_type: type[P],
307 ) -> type[ExtendedPsfImageSerializationModel[P]]:
308 """Return the serialization model type for this object for an archive
309 type that uses the given pointer type.
311 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