lsst.afw
g3a5ebb7d8a+28b83bf6a5
Toggle main menu visibility
Loading...
Searching...
No Matches
python
lsst
afw
cameraGeom
_assembleImage.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
# (https://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 <https://www.gnu.org/licenses/>.
21
22
__all__ = [
'assembleAmplifierImage'
,
'assembleAmplifierRawImage'
,
23
'makeUpdatedDetector'
,
'AmplifierIsolator'
]
24
25
# dict of doFlip: slice
26
_SliceDict = {
27
False
: slice(
None
,
None
, 1),
28
True
: slice(
None
,
None
, -1),
29
}
30
31
32
def
_insertPixelChunk
(outView, inView, amplifier):
33
# For the sake of simplicity and robustness, this code does not short-circuit the case flipX=flipY=False.
34
# However, it would save a bit of time, including the cost of making numpy array views.
35
# If short circuiting is wanted, do it here.
36
37
xSlice = _SliceDict[amplifier.getRawFlipX()]
38
ySlice = _SliceDict[amplifier.getRawFlipY()]
39
if
hasattr(inView,
"image"
):
40
inArrList = (inView.image.array, inView.mask.array, inView.variance.array)
41
outArrList = (outView.image.array, outView.mask.array, outView.variance.array)
42
else
:
43
inArrList = [inView.array]
44
outArrList = [outView.array]
45
46
for
inArr, outArr
in
zip(inArrList, outArrList):
47
# y,x because numpy arrays are transposed w.r.t. afw Images
48
outArr[:] = inArr[ySlice, xSlice]
49
50
51
def
assembleAmplifierImage
(destImage, rawImage, amplifier):
52
"""Assemble the amplifier region of an image from a raw image.
53
54
Parameters
55
----------
56
destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
57
Assembled image; the region amplifier.getBBox() is overwritten with
58
the assembled amplifier image.
59
rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
60
Raw image (same type as destImage).
61
amplifier : `lsst.afw.cameraGeom.Amplifier`
62
Amplifier geometry, with raw amplifier info.
63
64
Raises
65
------
66
RuntimeError
67
Raised if image types do not match or amplifier has no raw amplifier info.
68
"""
69
if
type(destImage.Factory) != type(rawImage.Factory):
# noqa: E721
70
raise
RuntimeError(f
"destImage type = {type(destImage.Factory).__name__} != "
71
f
"{type(rawImage.Factory).__name__} = rawImage type"
)
72
inView = rawImage.Factory(rawImage, amplifier.getRawDataBBox())
73
outView = destImage.Factory(destImage, amplifier.getBBox())
74
75
_insertPixelChunk
(outView, inView, amplifier)
76
77
78
def
assembleAmplifierRawImage
(destImage, rawImage, amplifier):
79
"""Assemble the amplifier region of a raw CCD image.
80
81
For most cameras this is a no-op: the raw image already is an assembled
82
CCD image.
83
However, it is useful for camera such as LSST for which each amplifier
84
image is a separate image.
85
86
Parameters
87
----------
88
destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
89
CCD Image; the region amplifier.getRawAmplifier().getBBox()
90
is overwritten with the raw amplifier image.
91
rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
92
Raw image (same type as destImage).
93
amplifier : `lsst.afw.cameraGeom.Amplifier`
94
Amplifier geometry with raw amplifier info
95
96
Raises
97
------
98
RuntimeError
99
Raised if image types do not match or amplifier has no raw amplifier info.
100
"""
101
if
type(destImage.Factory) != type(rawImage.Factory):
# noqa: E721
102
raise
RuntimeError(f
"destImage type = {type(destImage.Factory).__name__} != "
103
f
"{type(rawImage.Factory).__name__} = rawImage type"
)
104
inBBox = amplifier.getRawBBox()
105
inView = rawImage.Factory(rawImage, inBBox)
106
outBBox = amplifier.getRawBBox()
107
outBBox.shift(amplifier.getRawXYOffset())
108
outView = destImage.Factory(destImage, outBBox)
109
110
_insertPixelChunk
(outView, inView, amplifier)
111
112
113
def
makeUpdatedDetector
(ccd):
114
"""Return a Detector that has had the definitions of amplifier geometry
115
updated post assembly.
116
117
Parameters
118
----------
119
ccd : `lsst.afw.image.Detector`
120
The detector to copy and update.
121
"""
122
builder = ccd.rebuild()
123
for
amp
in
builder.getAmplifiers():
124
amp.transform()
125
return
builder.finish()
126
127
128
class
AmplifierIsolator
:
129
"""A class that can extracts single-amplifier subimages from trimmed or
130
untrimmed assembled images and transforms them to a particular orientation
131
and offset.
132
133
Callers who have a in-memory assembled `lsst.afw.image.Exposure` should
134
generally just use the `apply` class method. Other methods can be used to
135
implement subimage loads of on on-disk images (e.g. formatter classes in
136
``obs_base``) or obtain subsets from other image classes.
137
138
Parameters
139
----------
140
amplifier : `Amplifier`
141
Amplifier object that identifies the amplifier to load and sets the
142
orientation and offset of the returned subimage.
143
parent_bbox : `lsst.geom.Box2I`
144
Bounding box of the assembled parent image. This must be equal to
145
either ``parent_detector.getBBox()`` or
146
``parent_detector.getRawBBox()``; which one is used to determine
147
whether the parent image (and hence the amplifier subimages) is
148
trimmed.
149
parent_detector : `Detector`
150
Detector object that describes the parent image.
151
"""
152
153
def
__init__
(self, amplifier, parent_bbox, parent_detector):
154
self.
_amplifier
= amplifier
155
self.
_parent_detector
= parent_detector
156
self.
_parent_amplifier
= self.
_parent_detector
[self.
_amplifier
.getName()]
157
self.
_is_parent_trimmed
= (parent_bbox == self.
_parent_detector
.getBBox())
158
self.
_amplifier_comparison
= self.
_amplifier
.compareGeometry(self.
_parent_amplifier
)
159
if
self.
_is_parent_trimmed
:
160
# We only care about the final bounding box; don't check e.g.
161
# overscan regions for consistency.
162
if
self.
_parent_amplifier
.getBBox() != self.
_amplifier
.getBBox():
163
raise
ValueError(
164
f
"The given amplifier's trimmed bounding box ({self._amplifier.getBBox()}) is not the "
165
"same as the trimmed bounding box of the same amplifier in the parent image "
166
f
"({self._parent_amplifier.getBBox()})."
167
)
168
else
:
169
# Parent is untrimmed, so we need all regions to be consistent
170
# between the amplifiers modulo flips and offsets.
171
if
self.
_amplifier_comparison
& self.
_amplifier_comparison
.REGIONS_DIFFER:
172
raise
ValueError(
173
"The given amplifier's subregions are fundamentally incompatible with those of the "
174
"parent image's amplifier."
175
)
176
177
@property
178
def
subimage_bbox
(self):
179
"""The bounding box of the target amplifier in the parent image
180
(`lsst.geom.Box2I`).
181
"""
182
if
self.
_is_parent_trimmed
:
183
return
self.
_parent_amplifier
.getBBox()
184
else
:
185
return
self.
_parent_amplifier
.getRawBBox()
186
187
def
transform_subimage
(self, subimage):
188
"""Transform an already-extracted subimage to match the orientation
189
and offset of the target amplifier.
190
191
Parameters
192
----------
193
subimage : image-like
194
The subimage to transform; may be any of `lsst.afw.image.Image`,
195
`lsst.afw.image.Mask`, `lsst.afw.image.MaskedImage`, and
196
`lsst.afw.image.Exposure`.
197
198
Returns
199
-------
200
transformed : image-like
201
Transformed image of the same type as ``subimage``.
202
"""
203
from
lsst.afw.math
import
flipImage
204
if
hasattr(subimage,
"getMaskedImage"
):
205
# flipImage doesn't support Exposure natively.
206
# And sadly, there's no way to write to an existing MaskedImage,
207
# so we need to make yet another copy.
208
result = subimage.clone()
209
result.setMaskedImage(
210
flipImage(
211
subimage.getMaskedImage(),
212
self.
_amplifier_comparison
& self.
_amplifier_comparison
.FLIPPED_X,
213
self.
_amplifier_comparison
& self.
_amplifier_comparison
.FLIPPED_Y,
214
)
215
)
216
else
:
217
result = flipImage(
218
subimage,
219
self.
_amplifier_comparison
& self.
_amplifier_comparison
.FLIPPED_X,
220
self.
_amplifier_comparison
& self.
_amplifier_comparison
.FLIPPED_Y,
221
)
222
if
self.
_is_parent_trimmed
:
223
result.setXY0(self.
_amplifier
.getBBox().getMin())
224
else
:
225
result.setXY0(self.
_amplifier
.getRawBBox().getMin() + self.
_amplifier
.getRawXYOffset())
226
return
result
227
228
def
make_detector
(self):
229
"""Create a single-amplifier detector that describes the transformed
230
subimage.
231
232
Returns
233
-------
234
detector : `Detector`
235
Detector object with a single amplifier, a trimmed bounding box
236
equal to the amplifier's trimmed bounding box, and no crosstalk.
237
"""
238
detector = self.
_parent_detector
.rebuild()
239
detector.clear()
240
detector.append(self.
_amplifier
.rebuild())
241
detector.setBBox(self.
_amplifier
.getBBox())
242
detector.unsetCrosstalk()
243
return
detector.finish()
244
245
@classmethod
246
def
apply
(cls, parent_exposure, amplifier):
247
"""Obtain a single-amplifier `lsst.afw.image.Exposure` subimage that
248
masquerades as full-detector image for a single-amp detector.
249
250
Parameters
251
----------
252
parent_exposure : `lsst.afw.image.Exposure`
253
Parent image to obtain a subset from.
254
`~lsst.afw.image.Exposure.getDetector` must not return `None`.
255
amplifier : `Amplifier`
256
Target amplifier for the subimage. May differ from the amplifier
257
obtained by ``parent_exposure.getDetector()[amplifier.getName()]``
258
only by flips and differences in `~Amplifier.getRawXYOffset`.
259
260
Returns
261
-------
262
subimage : `lsst.afw.image.Exposure`
263
Exposure subimage for the target amplifier, with the
264
orientation and XY0 described by that amplifier, and a single-amp
265
detector holding a copy of that amplifier.
266
267
Notes
268
-----
269
Because we use the target amplifier's bounding box as the bounding box
270
of the detector attached to the returned exposure, other exposure
271
components that are passed through unmodified (e.g. the WCS) should
272
still be valid for the single-amp exposure after it is trimmed and
273
"assembled". Unlike most trimmed+assembled images, however, it will
274
have a nonzero XY0, and code that (incorrectly!) does not pay attention
275
to XY0 may break.
276
"""
277
instance = cls(amplifier, parent_bbox=parent_exposure.getBBox(),
278
parent_detector=parent_exposure.getDetector())
279
result = instance.transform_subimage(parent_exposure[instance.subimage_bbox])
280
result.setDetector(instance.make_detector())
281
return
result
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator
Definition
_assembleImage.py:128
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator._parent_detector
_parent_detector
Definition
_assembleImage.py:155
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator.__init__
__init__(self, amplifier, parent_bbox, parent_detector)
Definition
_assembleImage.py:153
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator._amplifier
_amplifier
Definition
_assembleImage.py:154
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator._parent_amplifier
_parent_amplifier
Definition
_assembleImage.py:156
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator.apply
apply(cls, parent_exposure, amplifier)
Definition
_assembleImage.py:246
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator.subimage_bbox
subimage_bbox(self)
Definition
_assembleImage.py:178
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator.make_detector
make_detector(self)
Definition
_assembleImage.py:228
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator._amplifier_comparison
_amplifier_comparison
Definition
_assembleImage.py:158
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator._is_parent_trimmed
tuple _is_parent_trimmed
Definition
_assembleImage.py:157
lsst::afw::cameraGeom._assembleImage.AmplifierIsolator.transform_subimage
transform_subimage(self, subimage)
Definition
_assembleImage.py:187
lsst::afw::cameraGeom._assembleImage.assembleAmplifierRawImage
assembleAmplifierRawImage(destImage, rawImage, amplifier)
Definition
_assembleImage.py:78
lsst::afw::cameraGeom._assembleImage._insertPixelChunk
_insertPixelChunk(outView, inView, amplifier)
Definition
_assembleImage.py:32
lsst::afw::cameraGeom._assembleImage.assembleAmplifierImage
assembleAmplifierImage(destImage, rawImage, amplifier)
Definition
_assembleImage.py:51
lsst::afw::cameraGeom._assembleImage.makeUpdatedDetector
makeUpdatedDetector(ccd)
Definition
_assembleImage.py:113
lsst::afw::math
Definition
statistics.dox:6
Generated on
for lsst.afw by
1.17.0