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 multi-plane image with data (image) and variance planes, and the
64 results of a profile fit to the image.
68 image : `~lsst.images.Image`
70 variance : `~lsst.images.Image`, optional
71 The per-pixel uncertainty of the main image as an image of variance
72 values. Must have the same bounding box as ``image`` if provided, and
73 its units must be the square of ``image.unit`` or `None`.
74 Values default to ``1.0``. Any attached ``sky_projection`` is replaced
76 info : `ExtendedPsfImageInfo`, optional
77 Additional information about how the extended PSF image was
79 fit : `ExtendedPsfFit`, optional
80 The results of a profile fit to the image.
81 metadata : `dict` [`str`, `MetadataValue`], optional
82 Arbitrary flexible metadata to associate with the image.
86 image : `~lsst.images.Image`
88 variance : `~lsst.images.Image`
89 The per-pixel uncertainty of the main image as an image of variance
91 info : `ExtendedPsfImageInfo`
92 Additional information about how the extended PSF image was
94 fit : `ExtendedPsfFit`
95 The results of a profile fit to the image.
102 variance: Image |
None =
None,
103 info: ExtendedPsfImageInfo |
None =
None,
104 fit: ExtendedPsfFit |
None =
None,
105 metadata: dict[str, MetadataValue] |
None =
None,
113 unit=
None if image.unit
is None else image.unit**2,
116 if image.bbox != variance.bbox:
117 raise ValueError(f
"Image ({image.bbox}) and variance ({variance.bbox}) bboxes do not agree.")
118 if image.unit
is None:
119 if variance.unit
is not None:
120 raise ValueError(f
"Image has no units but variance does ({variance.unit}).")
121 elif variance.unit
is None:
122 variance = variance.view(unit=image.unit**2)
123 elif variance.unit != image.unit**2:
125 f
"Variance unit ({variance.unit}) should be the square of the image unit ({image.unit})."
138 """The main image plane (`Image`)."""
143 """The variance plane (`Image`)."""
148 """The bounding box shared by both image planes (`Box`)."""
152 def unit(self) -> UnitBase | None:
153 """The units of the image plane (`astropy.units.Unit` | `None`)."""
158 """The projection that maps the pixel grid to the sky.
160 ExtendedPsfImage does not support attached projections,
161 so this always returns `None`.
166 def info(self) -> ExtendedPsfImageInfo:
167 """Additional information about the image (`ExtendedPsfImageInfo`)."""
171 def fit(self) -> ExtendedPsfFit:
172 """The results of a profile fit to the image."""
175 def __getitem__(self, bbox: Box | EllipsisType) -> ExtendedPsfImage:
176 bbox, _ = self._handle_getitem_args(bbox)
177 return self._transfer_metadata(
187 def __setitem__(self, bbox: Box | EllipsisType, value: ExtendedPsfImage) ->
None:
188 self.
_image[bbox] = value.image
192 return f
"ExtendedPsfImage({self.image!s}, info={self.info!r}, fit={self.fit!r})"
196 def copy(self) -> ExtendedPsfImage:
197 """Deep-copy the profile image and metadata."""
198 return self._transfer_metadata(
202 info=self.
_info.model_copy(),
203 fit=self.
_fit.model_copy(),
208 def serialize(self, archive: OutputArchive[Any]) -> ExtendedPsfImageSerializationModel:
209 """Serialize the Extended PSF image to an output archive.
216 serialized_image = archive.serialize_direct(
217 "image", functools.partial(self.
image.serialize, save_projection=
False)
219 serialized_variance = archive.serialize_direct(
220 "variance", functools.partial(self.
variance.serialize, save_projection=
False)
222 serialized_info = self.
info
223 serialized_fit = self.
fit
225 image=serialized_image,
226 variance=serialized_variance,
227 info=serialized_info,
229 metadata=self.metadata,
234 model: ExtendedPsfImageSerializationModel[Any], archive: InputArchive[Any], *, bbox: Box |
None =
None
235 ) -> ExtendedPsfImage:
236 """Deserialize an image from an input archive.
241 A Pydantic model representation of the image, holding references
242 to data stored in the archive.
244 Archive to read from.
246 Bounding box of a subimage to read instead.
248 return model.deserialize(archive, bbox=bbox)
251 def _get_archive_tree_type[P: BaseModel](
252 pointer_type: type[P],
253 ) -> type[ExtendedPsfImageSerializationModel[P]]:
254 """Return the serialization model type for this object for an archive
255 type that uses the given pointer type.
257 return ExtendedPsfImageSerializationModel[pointer_type]
261 """A Pydantic model used to represent a serialized `ExtendedPsfImage`."""
263 SCHEMA_NAME: ClassVar[str] =
"extended_psf_image"
264 SCHEMA_VERSION: ClassVar[str] =
"1.0.0"
265 MIN_READ_VERSION: ClassVar[int] = 1
266 PUBLIC_TYPE: ClassVar[type] = ExtendedPsfImage
268 image: ImageSerializationModel[P] = Field(
269 description=
"The main data image.",
271 variance: ImageSerializationModel[P] = Field(
272 description=
"Per-pixel variance estimates for the main image."
274 info: ExtendedPsfImageInfo = Field(
275 description=
"Additional information about the extended PSF image.",
277 fit: ExtendedPsfMoffatFit | ExtendedPsfFit = Field(
278 description=
"The results of an extended PSF fit to the image.",
283 """The bounding box of the image."""
284 return self.image.bbox
286 def deserialize(self, archive: InputArchive[Any], *, bbox: Box |
None =
None) -> ExtendedPsfImage:
287 """Deserialize an image from an input archive.
292 Archive to read from.
294 Bounding box of a subimage to read instead.
297 variance = self.variance.
deserialize(archive, bbox=bbox)
303 )._finish_deserialize(self)
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)
None sky_projection(self)
ExtendedPsfImageInfo _info
ExtendedPsfImage deserialize(self, InputArchive[Any] archive, *, Box|None bbox=None)
ImageSerializationModel variance
ExtendedPsfImageInfo info
ImageSerializationModel image