Coverage for python/lsst/afw/cameraGeom/assembleImage.py : 9%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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/>.
22__all__ = ['assembleAmplifierImage', 'assembleAmplifierRawImage',
23 'makeUpdatedDetector']
25import lsst.geom
27# dict of doFlip: slice
28_SliceDict = {
29 False: slice(None, None, 1),
30 True: slice(None, None, -1),
31}
34def _insertPixelChunk(outView, inView, amplifier, hasArrays):
35 # For the sake of simplicity and robustness, this code does not short-circuit the case flipX=flipY=False.
36 # However, it would save a bit of time, including the cost of making numpy array views.
37 # If short circuiting is wanted, do it here.
39 xSlice = _SliceDict[amplifier.getRawFlipX()]
40 ySlice = _SliceDict[amplifier.getRawFlipY()]
41 if hasArrays:
42 # MaskedImage
43 inArrList = inView.getArrays()
44 outArrList = outView.getArrays()
45 else:
46 inArrList = [inView.getArray()]
47 outArrList = [outView.getArray()]
49 for inArr, outArr in zip(inArrList, outArrList):
50 # y,x because numpy arrays are transposed w.r.t. afw Images
51 outArr[:] = inArr[ySlice, xSlice]
54def assembleAmplifierImage(destImage, rawImage, amplifier):
55 """Assemble the amplifier region of an image from a raw image.
57 Parameters
58 ----------
59 destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
60 Assembled image; the region amplifier.getBBox() is overwritten with
61 the assembled amplifier image.
62 rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
63 Raw image (same type as destImage).
64 amplifier : `lsst.afw.cameraGeom.Amplifier`
65 Amplifier geometry, with raw amplifier info.
67 Raises
68 ------
69 RuntimeError
70 Raised if image types do not match or amplifier has no raw amplifier info.
71 """
72 if not amplifier.getHasRawInfo():
73 raise RuntimeError("amplifier must contain raw amplifier info")
74 if type(destImage.Factory) != type(rawImage.Factory): # noqa: E721
75 raise RuntimeError(f"destImage type = {type(destImage.Factory).__name__} != "
76 f"{type(rawImage.Factory).__name__} = rawImage type")
77 inView = rawImage.Factory(rawImage, amplifier.getRawDataBBox())
78 outView = destImage.Factory(destImage, amplifier.getBBox())
80 _insertPixelChunk(outView, inView, amplifier,
81 hasattr(rawImage, "getArrays"))
84def assembleAmplifierRawImage(destImage, rawImage, amplifier):
85 """Assemble the amplifier region of a raw CCD image.
87 For most cameras this is a no-op: the raw image already is an assembled
88 CCD image.
89 However, it is useful for camera such as LSST for which each amplifier
90 image is a separate image.
92 Parameters
93 ----------
94 destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
95 CCD Image; the region amplifier.getRawAmplifier().getBBox()
96 is overwritten with the raw amplifier image.
97 rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
98 Raw image (same type as destImage).
99 amplifier : `lsst.afw.cameraGeom.Amplifier`
100 Amplifier geometry with raw amplifier info
102 Raises
103 ------
104 RuntimeError
105 Raised if image types do not match or amplifier has no raw amplifier info.
106 """
107 if not amplifier.getHasRawInfo():
108 raise RuntimeError("amplifier must contain raw amplifier info")
109 if type(destImage.Factory) != type(rawImage.Factory): # noqa: E721
110 raise RuntimeError(f"destImage type = {type(destImage.Factory).__name__} != "
111 f"{type(rawImage.Factory).__name__} = rawImage type")
112 inBBox = amplifier.getRawBBox()
113 inView = rawImage.Factory(rawImage, inBBox)
114 outBBox = amplifier.getRawBBox()
115 outBBox.shift(amplifier.getRawXYOffset())
116 outView = destImage.Factory(destImage, outBBox)
118 _insertPixelChunk(outView, inView, amplifier,
119 hasattr(rawImage, "getArrays"))
122def makeUpdatedDetector(ccd):
123 """Return a Detector that has had the definitions of amplifier geometry
124 updated post assembly.
126 Parameters
127 ----------
128 ccd : `lsst.afw.image.Detector`
129 The detector to copy and update.
130 """
131 builder = ccd.rebuild()
132 for amp in builder.getAmplifiers():
133 assert amp.getHasRawInfo()
135 bbox = amp.getRawBBox()
136 awidth, aheight = bbox.getDimensions()
137 #
138 # Figure out how far flipping the amp LR and/or TB offsets the bboxes
139 #
140 boxMin0 = bbox.getMin() # initial position of rawBBox's LLC corner
141 if amp.getRawFlipX():
142 bbox.flipLR(awidth)
143 if amp.getRawFlipY():
144 bbox.flipTB(aheight)
145 shift = boxMin0 - bbox.getMin()
147 for bboxName in ("",
148 "HorizontalOverscan",
149 "Data",
150 "VerticalOverscan",
151 "Prescan"):
152 bbox = getattr(amp, f"getRaw{bboxName}BBox")()
153 if amp.getRawFlipX():
154 bbox.flipLR(awidth)
155 if amp.getRawFlipY():
156 bbox.flipTB(aheight)
157 bbox.shift(amp.getRawXYOffset() + shift)
159 getattr(amp, f"setRaw{bboxName}BBox")(bbox)
160 #
161 # All of these have now been transferred to the per-amp geometry
162 #
163 amp.setRawXYOffset(lsst.geom.ExtentI(0, 0))
164 amp.setRawFlipX(False)
165 amp.setRawFlipY(False)
167 return builder.finish()