Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/changes/DM-54976.api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Removed the `obs_info` component from `Image`, `Mask`, and `MaskedImage`, in favor of defining it directly on `VisitImage`.

Fully unified the butler formatters into `lsst.images.formatters.GenericFormatter` and deleted the old ones.
7 changes: 4 additions & 3 deletions python/lsst/images/_backgrounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import pydantic

from .fields import Field, FieldSerializationModel
from .serialization import ArchiveTree, InputArchive, OutputArchive
from .serialization import ArchiveTree, InputArchive, InvalidParameterError, OutputArchive


@dataclasses.dataclass(frozen=True)
Expand Down Expand Up @@ -152,8 +152,9 @@ class BackgroundMapSerializationModel(ArchiveTree):
description="Name of the background that was subtracted, or `None` if no background was subtracted.",
)

def deserialize(self, archive: InputArchive[Any]) -> BackgroundMap:
"""Read a background map from an archive."""
def deserialize(self, archive: InputArchive[Any], **kwargs: Any) -> BackgroundMap:
if kwargs:
raise InvalidParameterError(f"Unrecognized parameters for BackgroundMap: {set(kwargs.keys())}.")
return BackgroundMap(
[
Background(
Expand Down
8 changes: 6 additions & 2 deletions python/lsst/images/_color_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from ._geom import Box
from ._image import Image, ImageSerializationModel
from ._transforms import Projection, ProjectionSerializationModel
from .serialization import ArchiveTree, InputArchive, MetadataValue, OutputArchive
from .serialization import ArchiveTree, InputArchive, InvalidParameterError, MetadataValue, OutputArchive
from .utils import is_none


Expand Down Expand Up @@ -201,7 +201,9 @@ def bbox(self) -> Box:
"""The bounding box of the image."""
return self.red.bbox

def deserialize(self, archive: InputArchive[Any], *, bbox: Box | None = None) -> ColorImage:
def deserialize(
self, archive: InputArchive[Any], *, bbox: Box | None = None, **kwargs: Any
) -> ColorImage:
"""Deserialize a image from an input archive.

Parameters
Expand All @@ -214,6 +216,8 @@ def deserialize(self, archive: InputArchive[Any], *, bbox: Box | None = None) ->
bbox
Bounding box of a subimage to read instead.
"""
if kwargs:
raise InvalidParameterError(f"Unrecognized parameters for ColoImage: {set(kwargs.keys())}.")
r = self.red.deserialize(archive, bbox=bbox)
g = self.green.deserialize(archive, bbox=bbox)
b = self.blue.deserialize(archive, bbox=bbox)
Expand Down
60 changes: 15 additions & 45 deletions python/lsst/images/_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import numpy as np
import numpy.typing as npt
import pydantic
from astro_metadata_translator import ObservationInfo

from lsst.resources import ResourcePath, ResourcePathExpression

Expand All @@ -39,6 +38,7 @@
InlineArrayModel,
InlineArrayQuantityModel,
InputArchive,
InvalidParameterError,
MetadataValue,
OutputArchive,
no_header_updates,
Expand Down Expand Up @@ -72,9 +72,6 @@ class Image(GeneralizedImage):
Units for the image's pixel values.
projection
Projection that maps the pixel grid to the sky.
obs_info
General information about the associated observation in standardized
form.
metadata
Arbitrary flexible metadata to associate with the image.

Expand Down Expand Up @@ -111,7 +108,6 @@ def __init__(
dtype: npt.DTypeLike | None = None,
unit: astropy.units.UnitBase | None = None,
projection: Projection[Any] | None = None,
obs_info: ObservationInfo | None = None,
metadata: dict[str, MetadataValue] | None = None,
):
super().__init__(metadata)
Expand Down Expand Up @@ -140,7 +136,6 @@ def __init__(
self._bbox: Box = bbox
self._unit = unit
self._projection = projection
self._obs_info = obs_info

@property
def array(self) -> np.ndarray:
Expand Down Expand Up @@ -192,26 +187,13 @@ def projection(self) -> Projection[Any] | None:
"""
return self._projection

@property
def obs_info(self) -> ObservationInfo | None:
"""General information about the associated observation in standard
form. (`~astro_metadata_translator.ObservationInfo` | `None`).
"""
return self._obs_info

def __getitem__(self, bbox: Box | EllipsisType) -> Image:
if bbox is ...:
return self
super().__getitem__(bbox)
indices = bbox.slice_within(self._bbox)
return self._transfer_metadata(
Image(
self._array[indices],
bbox=bbox,
unit=self._unit,
projection=self._projection,
obs_info=self._obs_info,
),
Image(self._array[indices], bbox=bbox, unit=self._unit, projection=self._projection),
bbox=bbox,
)

Expand All @@ -235,13 +217,7 @@ def __eq__(self, other: object) -> bool:

def copy(self) -> Image:
return self._transfer_metadata(
Image(
self._array.copy(),
bbox=self._bbox,
unit=self._unit,
projection=self._projection,
obs_info=self._obs_info,
),
Image(self._array.copy(), bbox=self._bbox, unit=self._unit, projection=self._projection),
copy=True,
)

Expand All @@ -251,7 +227,6 @@ def view(
unit: astropy.units.UnitBase | None | EllipsisType = ...,
projection: Projection | None | EllipsisType = ...,
start: Sequence[int] | EllipsisType = ...,
obs_info: ObservationInfo | None | EllipsisType = ...,
) -> Image:
"""Make a view of the image, with optional updates."""
if unit is ...:
Expand All @@ -260,19 +235,14 @@ def view(
projection = self._projection
if start is ...:
start = self._bbox.start
if obs_info is ...:
obs_info = self._obs_info
return self._transfer_metadata(
Image(self._array, start=start, unit=unit, projection=projection, obs_info=obs_info)
)
return self._transfer_metadata(Image(self._array, start=start, unit=unit, projection=projection))

def serialize[P: pydantic.BaseModel](
self,
archive: OutputArchive[P],
*,
update_header: Callable[[astropy.io.fits.Header], None] = no_header_updates,
save_projection: bool = True,
save_obs_info: bool = True,
add_offset_wcs: str | None = "A",
) -> ImageSerializationModel[P]:
"""Serialize the image to an output archive.
Expand All @@ -291,10 +261,6 @@ def serialize[P: pydantic.BaseModel](
is one. This does not affect whether a FITS WCS corresponding to
the projection is written (it always is, if available, and if
``add_offset_wcs`` is not ``" "``).
save_obs_info
If `True`, save the
`~astro_metadata_translator.ObservationInfo` attached to the
image, if there is one.
add_offset_wcs
A FITS WCS single-character suffix to use when adding a linear
WCS that maps the FITS array to the logical pixel coordinates
Expand Down Expand Up @@ -326,7 +292,6 @@ def _update_header(header: astropy.io.fits.Header) -> None:
data=data,
start=list(self.bbox.start),
projection=serialized_projection,
obs_info=self._obs_info if save_obs_info else None,
metadata=self.metadata,
)

Expand Down Expand Up @@ -532,11 +497,6 @@ class ImageSerializationModel[P: pydantic.BaseModel](ArchiveTree):
exclude_if=is_none,
description="Projection that maps the logical pixel grid onto the sky.",
)
obs_info: ObservationInfo | None = pydantic.Field(
default=None,
exclude_if=is_none,
description="Standardized description of image metadata",
)

@property
def bbox(self) -> Box:
Expand All @@ -554,6 +514,7 @@ def deserialize(
*,
bbox: Box | None = None,
strip_header: Callable[[astropy.io.fits.Header], None] = no_header_updates,
**kwargs: Any,
) -> Image:
"""Deserialize an image from an input archive.

Expand All @@ -567,7 +528,12 @@ def deserialize(
A callable that strips out any FITS header cards added by the
``update_header`` argument in the corresponding call to
`Image.serialize`.
**kwargs
Unsupported keyword arguments are accepted only to provide better
error messages (raising `serialization.InvalidParameterError`).
"""
if kwargs:
raise InvalidParameterError(f"Unrecognized parameters for Image: {set(kwargs.keys())}.")
array_model: ArrayReferenceModel | InlineArrayModel
unit: astropy.units.UnitBase | None = None
if isinstance(self.data, ArrayReferenceQuantityModel | InlineArrayQuantityModel):
Expand All @@ -590,5 +556,9 @@ def _strip_header(header: astropy.io.fits.Header) -> None:
start=self.start if bbox is None else bbox.start,
unit=unit,
projection=projection,
obs_info=self.obs_info,
)._finish_deserialize(self)

def deserialize_component(self, component: str, archive: InputArchive[Any], **kwargs: Any) -> Any:
if kwargs:
raise InvalidParameterError(f"Unsupported parameters for Image components: {set(kwargs.keys())}.")
return super().deserialize_component(component, archive)
Loading
Loading