lsst.afw
g3a5ebb7d8a+28b83bf6a5
Toggle main menu visibility
Loading...
Searching...
No Matches
python
lsst
afw
multiband.py
Go to the documentation of this file.
1
# This file is part of afw.
2
#
3
# Developed for the LSST Data Management System.
4
# This product includes software developed by the LSST Project
5
# (http://www.lsst.org).
6
# See the COPYRIGHT file at the top-level directory of this distribution
7
# for details of code ownership.
8
#
9
# This program is free software: you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation, either version 3 of the License, or
12
# (at your option) any later version.
13
#
14
# This program is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
18
#
19
# You should have received a copy of the GNU General Public License
20
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
22
__all__ = [
"MultibandBase"
]
23
24
from
abc
import
ABC, abstractmethod
25
26
from
deprecated.sphinx
import
deprecated
27
28
from
lsst.geom
import
Box2I
29
30
31
class
MultibandBase
(ABC):
32
"""Base class for multiband objects
33
34
The LSST stack has a number of image-like classes that have
35
data in multiple bands that are stored as separate objects.
36
Analyzing the data can be easier using a Multiband object that
37
wraps the underlying data as a single data cube that can be sliced and
38
updated as a single object.
39
40
`MultibandBase` is designed to contain the most important universal
41
methods for initializing, slicing, and extracting common parameters
42
(such as the bounding box or XY0 position) to all of the single band classes,
43
as long as derived classes either call the base class `__init__`
44
or set the `_bands`, `_singles`, and `_bbox`.
45
46
Parameters
47
----------
48
bands: `list`
49
List of band names.
50
singles: `list`
51
List of single band objects
52
bbox: `Box2I`
53
By default `MultibandBase` uses `singles[0].getBBox()` to set
54
the bounding box of the multiband
55
"""
56
def
__init__
(self, bands, singles, bbox=None):
57
self.
_bands
= tuple([f
for
f
in
bands])
58
self.
_singles
= tuple(singles)
59
60
if
bbox
is
None
:
61
self.
_bbox
= self.
_singles
[0].
getBBox
()
62
if
not
all([s.getBBox() == self.
getBBox
()
for
s
in
self.
singles
]):
63
bboxes = [s.getBBox() == self.
getBBox
()
for
s
in
self.
singles
]
64
err =
"`singles` are required to have the same bounding box, received {0}"
65
raise
ValueError(err.format(bboxes))
66
else
:
67
self.
_bbox
= bbox
68
69
@abstractmethod
70
def
clone
(self, deep=True):
71
"""Copy the current object
72
73
This must be overloaded in a subclass of `MultibandBase`
74
75
Parameters
76
----------
77
deep: `bool`
78
Whether or not to make a deep copy
79
80
Returns
81
-------
82
result: `MultibandBase`
83
copy of the instance that inherits from `MultibandBase`
84
"""
85
pass
86
87
@property
88
@deprecated
(reason=
"This has been replaced with `bands`. Will be removed after v29."
,
89
version=
"v29.0"
, category=FutureWarning)
90
def
filters
(self):
91
"""List of filter names for the single band objects (deprecated)
92
93
Use `bands` instead.
94
"""
95
return
self.
_bands
96
97
@property
98
def
bands
(self):
99
"""List of band names for the single band objects
100
"""
101
return
self.
_bands
102
103
@property
104
def
singles
(self):
105
"""List of single band objects
106
"""
107
return
self.
_singles
108
109
def
getBBox
(self):
110
"""Bounding box
111
"""
112
return
self.
_bbox
113
114
def
getXY0
(self):
115
"""Minimum coordinate in the bounding box
116
"""
117
return
self.
getBBox
().getMin()
118
119
@property
120
def
x0
(self):
121
"""X0
122
123
X component of XY0 `Point2I.getX()`
124
"""
125
return
self.
getBBox
().getMinX()
126
127
@property
128
def
y0
(self):
129
"""Y0
130
131
Y component of XY0 `Point2I.getY()`
132
"""
133
return
self.
getBBox
().getMinY()
134
135
@property
136
def
origin
(self):
137
"""Minimum (y,x) position
138
139
This is the position of `self.getBBox().getMin()`,
140
but available as a tuple for numpy array indexing.
141
"""
142
return
(self.
y0
, self.
x0
)
143
144
@property
145
def
width
(self):
146
"""Width of the images
147
"""
148
return
self.
getBBox
().getWidth()
149
150
@property
151
def
height
(self):
152
"""Height of the images
153
"""
154
return
self.
getBBox
().getHeight()
155
156
def
__len__
(self):
157
return
len(self.
bands
)
158
159
def
__getitem__
(self, args):
160
"""Get a slice of the underlying array
161
162
If only a single band is specified,
163
return the single band object sliced
164
appropriately.
165
"""
166
if
not
isinstance(args, tuple):
167
indices = (args,)
168
else
:
169
indices = args
170
171
# Return the single band object if the first
172
# index is not a list or slice.
173
bands, bandIndex = self.
_bandNamesToIndex
(indices[0])
174
if
not
isinstance(bandIndex, slice)
and
len(bandIndex) == 1:
175
if
len(indices) > 2:
176
return
self.
singles
[bandIndex[0]][indices[1:]]
177
elif
len(indices) == 2:
178
return
self.
singles
[bandIndex[0]][indices[1]]
179
else
:
180
return
self.
singles
[bandIndex[0]]
181
182
return
self.
_slice
(bands=bands, bandIndex=bandIndex, indices=indices[1:])
183
184
def
__iter__
(self):
185
self.
_bandIndex
= 0
186
return
self
187
188
def
__next__
(self):
189
if
self.
_bandIndex
< len(self.
bands
):
190
result = self.
singles
[self.
_bandIndex
]
191
self.
_bandIndex
+= 1
192
else
:
193
raise
StopIteration
194
return
result
195
196
def
_bandNamesToIndex
(self, bandIndex):
197
"""Convert a list of band names to an index or a slice
198
199
Parameters
200
----------
201
bandIndex: iterable or `object`
202
Index to specify a band or list of bands,
203
usually a string or enum.
204
For example `bandIndex` can be
205
`"R"` or `["R", "G", "B"]` or `[Band.R, Band.G, Band.B]`,
206
if `Band` is an enum.
207
208
Returns
209
-------
210
bandNames: `list`
211
Names of the bands in the slice
212
bandIndex: `slice` or `list` of `int`
213
Index of each band in `bandNames` in
214
`self.bands`.
215
"""
216
if
isinstance(bandIndex, slice):
217
if
bandIndex.start
is
not
None
:
218
start = self.
bands
.index(bandIndex.start)
219
else
:
220
start =
None
221
if
bandIndex.stop
is
not
None
:
222
stop = self.
bands
.index(bandIndex.stop)
223
else
:
224
stop =
None
225
bandIndices = slice(start, stop, bandIndex.step)
226
bandNames = self.
bands
[bandIndices]
227
else
:
228
if
isinstance(bandIndex, str):
229
bandNames = [bandIndex]
230
bandIndices = [self.
bands
.index(bandIndex)]
231
else
:
232
try
:
233
# Check to see if the bandIndex is an iterable
234
bandNames = [f
for
f
in
bandIndex]
235
except
TypeError:
236
bandNames = [bandIndex]
237
bandIndices = [self.
bands
.index(f)
for
f
in
bandNames]
238
return
tuple(bandNames), bandIndices
239
240
def
setXY0
(self, xy0):
241
"""Shift the bounding box but keep the same Extent
242
243
Parameters
244
----------
245
xy0: `Point2I`
246
New minimum bounds of the bounding box
247
"""
248
self.
_bbox
=
Box2I
(xy0, self.
_bbox
.getDimensions())
249
for
singleObj
in
self.
singles
:
250
singleObj.setXY0(xy0)
251
252
def
shiftedTo
(self, xy0):
253
"""Shift the bounding box but keep the same Extent
254
255
This method is broken until DM-10781 is completed.
256
257
Parameters
258
----------
259
xy0: `Point2I`
260
New minimum bounds of the bounding box
261
262
Returns
263
-------
264
result: `MultibandBase`
265
A copy of the object, shifted to `xy0`.
266
"""
267
raise
NotImplementedError(
"shiftedBy not implemented until DM-10781"
)
268
result = self.
clone
(
False
)
269
result._bbox =
Box2I
(xy0, result._bbox.getDimensions())
270
for
singleObj
in
result.singles:
271
singleObj.setXY0(xy0)
272
return
result
273
274
def
shiftedBy
(self, offset):
275
"""Shift a bounding box by an offset, but keep the same Extent
276
277
This method is broken until DM-10781 is completed.
278
279
Parameters
280
----------
281
offset: `Extent2I`
282
Amount to shift the bounding box in x and y.
283
284
Returns
285
-------
286
result: `MultibandBase`
287
A copy of the object, shifted by `offset`
288
"""
289
raise
NotImplementedError(
"shiftedBy not implemented until DM-10781"
)
290
xy0 = self.
_bbox
.getMin() + offset
291
return
self.
shiftedTo
(xy0)
292
293
@abstractmethod
294
def
_slice
(self, bands, bandIndex, indices):
295
"""Slice the current object and return the result
296
297
Different inherited classes will handling slicing differently,
298
so this method must be overloaded in inherited classes.
299
300
Parameters
301
----------
302
bands: `list` of `str`
303
List of band names for the slice. This is a subset of the
304
bands in the parent multiband object
305
bandIndex: `list` of `int` or `slice`
306
Index along the band dimension
307
indices: `tuple` of remaining indices
308
`MultibandBase.__getitem__` separates the first (band)
309
index from the remaining indices, so `indices` is a tuple
310
of all of the indices that come after `band` in the
311
`args` passed to `MultibandBase.__getitem__`.
312
313
Returns
314
-------
315
result: `object`
316
Sliced version of the current object, which could be the
317
same class or a different class depending on the
318
slice being made.
319
"""
320
pass
321
322
def
__repr__
(self):
323
result =
"<{0}, bands={1}, bbox={2}>"
.format(
324
self.__class__.__name__, self.bands, self.getBBox().
__repr__
())
325
return
result
326
327
def
__str__
(self):
328
if
hasattr(self,
"array"
):
329
return
str(self.
array
)
330
return
self.
__repr__
()
lsst::afw.multiband.MultibandBase
Definition
multiband.py:31
lsst::afw.multiband.MultibandBase.bands
bands
Definition
multiband.py:157
lsst::afw.multiband.MultibandBase._singles
_singles
Definition
multiband.py:58
lsst::afw.multiband.MultibandBase.setXY0
setXY0(self, xy0)
Definition
multiband.py:240
lsst::afw.multiband.MultibandBase._slice
_slice(self, bands, bandIndex, indices)
Definition
multiband.py:294
lsst::afw.multiband.MultibandBase.__iter__
__iter__(self)
Definition
multiband.py:184
lsst::afw.multiband.MultibandBase.__next__
__next__(self)
Definition
multiband.py:188
lsst::afw.multiband.MultibandBase.getXY0
getXY0(self)
Definition
multiband.py:114
lsst::afw.multiband.MultibandBase._bands
_bands
Definition
multiband.py:57
lsst::afw.multiband.MultibandBase._bandNamesToIndex
_bandNamesToIndex(self, bandIndex)
Definition
multiband.py:196
lsst::afw.multiband.MultibandBase.width
width(self)
Definition
multiband.py:145
lsst::afw.multiband.MultibandBase.origin
origin(self)
Definition
multiband.py:136
lsst::afw.multiband.MultibandBase.getBBox
getBBox(self)
Definition
multiband.py:109
lsst::afw.multiband.MultibandBase.__str__
__str__(self)
Definition
multiband.py:327
lsst::afw.multiband.MultibandBase.__repr__
__repr__(self)
Definition
multiband.py:322
lsst::afw.multiband.MultibandBase.x0
x0
Definition
multiband.py:142
lsst::afw.multiband.MultibandBase.__getitem__
__getitem__(self, args)
Definition
multiband.py:159
lsst::afw.multiband.MultibandBase.__init__
__init__(self, bands, singles, bbox=None)
Definition
multiband.py:56
lsst::afw.multiband.MultibandBase.clone
clone(self, deep=True)
Definition
multiband.py:70
lsst::afw.multiband.MultibandBase._bbox
_bbox
Definition
multiband.py:61
lsst::afw.multiband.MultibandBase.shiftedBy
shiftedBy(self, offset)
Definition
multiband.py:274
lsst::afw.multiband.MultibandBase.filters
filters(self)
Definition
multiband.py:90
lsst::afw.multiband.MultibandBase.__len__
__len__(self)
Definition
multiband.py:156
lsst::afw.multiband.MultibandBase.singles
singles
Definition
multiband.py:249
lsst::afw.multiband.MultibandBase.height
height(self)
Definition
multiband.py:151
lsst::afw.multiband.MultibandBase.y0
y0
Definition
multiband.py:142
lsst::afw.multiband.MultibandBase._bandIndex
int _bandIndex
Definition
multiband.py:185
lsst::afw.multiband.MultibandBase.shiftedTo
shiftedTo(self, xy0)
Definition
multiband.py:252
lsst::afw.multiband.MultibandBase.array
array
Definition
multiband.py:329
lsst::geom::Box2I
lsst::geom
Generated on
for lsst.afw by
1.17.0