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