22from lsst.geom import Point2I, Box2I, Extent2I
23from ._imageLib
import LOCAL, PARENT, ImageOrigin
25__all__ = [
"supportSlicing"]
29 """Separate the actual slice from origin arguments to __getitem__ or
30 __setitem__, using PARENT for the origin
if it
is not provided.
34 sliceArgs : `tuple`, `Box2I`,
or `Point2I`
35 The first argument passed to an image-like object
's
36 ``__getitem__`` or ``__setitem__``.
40 sliceArgs : `tuple`, `Box2I`,
or `Point2I`
41 The original sliceArgs passed
in,
with any ImageOrigin argument
43 origin : `ImageOrigin`
44 Enum value that sets whether
or not to consider xy0
in positions.
46 See interpretSliceArgs
for more information.
48 Intended primarily
for internal use by `supportSlicing()`.
50 defaultOrigin = PARENT
52 if isinstance(sliceArgs[-1], ImageOrigin):
54 if len(sliceArgs) == 2:
55 return sliceArgs[0], sliceArgs[-1]
57 return sliceArgs[:-1], sliceArgs[-1]
60 return sliceArgs, defaultOrigin
62 return sliceArgs, defaultOrigin
66 """Handle negative indices passed to image accessors.
68 When negative indices are used in LOCAL coordinates, we interpret them
as
69 relative to the upper bounds of the array,
as in regular negative indexing
72 Using negative indices
in PARENT coordinates
is not allowed unless passed
73 via a `Point2I`
or `Box2I`; the potential
for confusion between actual
74 negative indices (when ``xy0 < 0``)
and offsets relative to the upper
75 bounds of the array
is too great.
79 index : `int`
or `
None`
80 1-d pixel index to interpret,
as given by a caller to an image-like
81 object
's ``__getitem__`` or ``__setitem__``.
83 Size of the image in the dimension corresponding to ``index``.
84 origin : `ImageOrigin`
85 Enum value that sets whether
or not to consider xy0
in positions.
87 Index to
return if `index`
is None.
92 If ``origin==PARENT``, either the given ``index``
or ``default``.
93 If ``origin==LOCAL``, an equivalent index guaranteed to be nonnegative.
95 Intended primarily
for internal use by `supportSlicing()`.
98 assert default
is not None
104 raise IndexError(
"Negative indices are not permitted with the PARENT origin. "
105 "Use LOCAL to use negative to index relative to the end, "
106 "and Point2I or Box2I indexing to access negative pixels "
107 "in PARENT coordinates.")
112 """Transform a tuple of slice objects into a Box2I, correctly handling negative indices.
114 see `interpretSliceArgs` for a description of parameters
118 box : `Box2I`
or `
None`
119 A box to use to create a subimage,
or None if the slice refers to a
121 index: `tuple`
or `
None`
122 An ``(x, y)`` tuple of integers,
or None if the slice refers to a
124 origin : `ImageOrigin`
125 Enum indicating whether to account
for xy0.
128 if isinstance(slices, Point2I):
129 return None, slices, origin
130 elif isinstance(slices, Box2I):
131 return slices,
None, origin
135 if isinstance(x, slice):
136 assert isinstance(y, slice)
137 if x.step
is not None or y.step
is not None:
138 raise ValueError(
"Slices with steps are not supported in image indexing.")
139 begin = Point2I(x.start, y.start)
140 end = Point2I(x.stop, y.stop)
141 return Box2I(begin, end - begin),
None, origin
143 assert not isinstance(y, slice)
144 return None, Point2I(x, y), origin
148 """Transform arguments to __getitem__ or __setitem__ to a standard form.
152 sliceArgs : `tuple`, `Box2I`, or `Point2I`
153 Slice arguments passed directly to `__getitem__`
or `__setitem__`.
154 bboxGetter : callable
155 Callable that accepts an ImageOrigin enum value
and returns the
156 appropriate image bounding box. Usually the bound getBBox method
157 of an Image, Mask,
or MaskedImage object.
162 Index
or slice
in the x dimension
164 Index
or slice
in the y dimension
165 origin : `ImageOrigin`
166 Either `PARENT` (coordinates respect XY0)
or LOCAL
167 (coordinates do
not respect XY0)
170 if isinstance(slices, Point2I):
171 return slices.getX(), slices.getY(), origin
172 elif isinstance(slices, Box2I):
173 x0 = slices.getMinX()
174 y0 = slices.getMinY()
175 return slice(x0, x0 + slices.getWidth()), slice(y0, y0 + slices.getHeight()), origin
176 elif isinstance(slices, slice):
177 if slices.start
is not None or slices.stop
is not None or slices.step
is not None:
178 raise TypeError(
"Single-dimension slices must not have bounds.")
185 bbox = bboxGetter(origin)
186 if isinstance(x, slice):
187 if isinstance(y, slice):
188 xSlice = slice(
handleNegativeIndex(x.start, bbox.getWidth(), origin, default=bbox.getBeginX()),
190 ySlice = slice(
handleNegativeIndex(y.start, bbox.getHeight(), origin, default=bbox.getBeginY()),
192 return xSlice, ySlice, origin
193 raise TypeError(
"Mixed indices of the form (slice, int) are not supported for images.")
195 if isinstance(y, slice):
196 raise TypeError(
"Mixed indices of the form (int, slice) are not supported for images.")
202def imageIndicesToNumpy(sliceArgs, bboxGetter):
203 """Convert slicing format to numpy
205 LSST `afw` image-like objects use an `[x,y]` coordinate
206 convention, accept `Point2I` and `Box2I`
207 objects
for slicing,
and slice relative to the
208 bounding box `XY0` location;
209 while python
and numpy use the convention `[y,x]`
210 with no `XY0`, so this method converts the `afw`
211 indices
or slices into numpy indices
or slices
215 sliceArgs: `sequence`, `Point2I`
or `Box2I`
216 An `(xIndex, yIndex)` pair,
or a single `(xIndex,)` tuple,
217 where `xIndex`
and `yIndex` can be a `slice`
or `int`,
218 or list of `int` objects,
and if only a single `xIndex`
is
219 given, a `Point2I`
or `Box2I`.
220 bboxGetter : callable
221 Callable that accepts an ImageOrigin enum value
and returns the
222 appropriate image bounding box. Usually the bound getBBox method
223 of an Image, Mask,
or MaskedImage object.
228 Index
or `slice`
in the y dimension
230 Index
or `slice`
in the x dimension
232 Bounding box of the image.
233 If `bbox`
is `
None` then the result
is a point
and
234 not a subset of an image.
238 x0 = bboxGetter().getMinX()
239 y0 = bboxGetter().getMinY()
242 if isinstance(x, slice):
243 assert isinstance(y, slice)
244 bbox =
Box2I(Point2I(x.start, y.start), Extent2I(x.stop-x.start, y.stop-y.start))
245 x = slice(x.start - x0, x.stop - x0)
246 y = slice(y.start - y0, y.stop - y0)
252 elif origin != LOCAL:
253 raise ValueError(
"Unrecognized value for origin")
256 if isinstance(x, slice):
257 assert isinstance(y, slice)
258 bbox =
Box2I(Point2I(x.start + x0, y.start + y0),
259 Extent2I(x.stop-x.start, y.stop-y.start))
265def supportSlicing(cls):
266 """Support image slicing
269 def Factory(self, *args, **kwargs):
270 """Return an object of this type
272 return cls(*args, **kwargs)
273 cls.Factory = Factory
276 """Return a deep copy of self"""
277 return cls(self,
True)
280 def __getitem__(self, imageSlice):
283 return self.subset(box, origin=origin)
284 return self._get(index, origin=origin)
285 cls.__getitem__ = __getitem__
287 def __setitem__(self, imageSlice, rhs):
290 if self.assign(rhs, box, origin)
is NotImplemented:
291 lhs = self.subset(box, origin=origin)
294 self._set(index, origin=origin, value=rhs)
295 cls.__setitem__ = __setitem__
An integer coordinate rectangle.
splitSliceArgs(sliceArgs)
translateSliceArgs(sliceArgs, bboxGetter)
interpretSliceArgs(sliceArgs, bboxGetter)
handleNegativeIndex(index, size, origin, default)