22 __all__ = [
'assembleAmplifierImage',
'assembleAmplifierRawImage',
23 'makeUpdatedDetector',
'AmplifierIsolator']
27 False: slice(
None,
None, 1),
28 True: slice(
None,
None, -1),
32 def _insertPixelChunk(outView, inView, amplifier, hasArrays):
37 xSlice = _SliceDict[amplifier.getRawFlipX()]
38 ySlice = _SliceDict[amplifier.getRawFlipY()]
41 inArrList = inView.getArrays()
42 outArrList = outView.getArrays()
44 inArrList = [inView.getArray()]
45 outArrList = [outView.getArray()]
47 for inArr, outArr
in zip(inArrList, outArrList):
49 outArr[:] = inArr[ySlice, xSlice]
53 """Assemble the amplifier region of an image from a raw image.
57 destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
58 Assembled image; the region amplifier.getBBox() is overwritten with
59 the assembled amplifier image.
60 rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
61 Raw image (same type as destImage).
62 amplifier : `lsst.afw.cameraGeom.Amplifier`
63 Amplifier geometry, with raw amplifier info.
68 Raised if image types do not match or amplifier has no raw amplifier info.
70 if type(destImage.Factory) !=
type(rawImage.Factory):
71 raise RuntimeError(f
"destImage type = {type(destImage.Factory).__name__} != "
72 f
"{type(rawImage.Factory).__name__} = rawImage type")
73 inView = rawImage.Factory(rawImage, amplifier.getRawDataBBox())
74 outView = destImage.Factory(destImage, amplifier.getBBox())
76 _insertPixelChunk(outView, inView, amplifier,
77 hasattr(rawImage,
"getArrays"))
81 """Assemble the amplifier region of a raw CCD image.
83 For most cameras this is a no-op: the raw image already is an assembled
85 However, it is useful for camera such as LSST for which each amplifier
86 image is a separate image.
90 destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
91 CCD Image; the region amplifier.getRawAmplifier().getBBox()
92 is overwritten with the raw amplifier image.
93 rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage`
94 Raw image (same type as destImage).
95 amplifier : `lsst.afw.cameraGeom.Amplifier`
96 Amplifier geometry with raw amplifier info
101 Raised if image types do not match or amplifier has no raw amplifier info.
103 if type(destImage.Factory) !=
type(rawImage.Factory):
104 raise RuntimeError(f
"destImage type = {type(destImage.Factory).__name__} != "
105 f
"{type(rawImage.Factory).__name__} = rawImage type")
106 inBBox = amplifier.getRawBBox()
107 inView = rawImage.Factory(rawImage, inBBox)
108 outBBox = amplifier.getRawBBox()
109 outBBox.shift(amplifier.getRawXYOffset())
110 outView = destImage.Factory(destImage, outBBox)
112 _insertPixelChunk(outView, inView, amplifier,
113 hasattr(rawImage,
"getArrays"))
117 """Return a Detector that has had the definitions of amplifier geometry
118 updated post assembly.
122 ccd : `lsst.afw.image.Detector`
123 The detector to copy and update.
125 builder = ccd.rebuild()
126 for amp
in builder.getAmplifiers():
128 return builder.finish()
132 """A class that can extracts single-amplifier subimages from trimmed or
133 untrimmed assembled images and transforms them to a particular orientation
136 Callers who have a in-memory assembled `lsst.afw.image.Exposure` should
137 generally just use the `apply` class method. Other methods can be used to
138 implement subimage loads of on on-disk images (e.g. formatter classes in
139 ``obs_base``) or obtain subsets from other image classes.
143 amplifier : `Amplifier`
144 Amplifier object that identifies the amplifier to load and sets the
145 orientation and offset of the returned subimage.
146 parent_bbox : `lsst.geom.Box2I`
147 Bounding box of the assembled parent image. This must be equal to
148 either ``parent_detector.getBBox()`` or
149 ``parent_detector.getRawBBox()``; which one is used to determine
150 whether the parent image (and hence the amplifier subimages) is
152 parent_detector : `Detector`
153 Detector object that describes the parent image.
156 def __init__(self, amplifier, parent_bbox, parent_detector):
167 f
"The given amplifier's trimmed bounding box ({self._amplifier.getBBox()}) is not the "
168 "same as the trimmed bounding box of the same amplifier in the parent image "
169 f
"({self._parent_amplifier.getBBox()})."
176 "The given amplifier's subregions are fundamentally incompatible with those of the "
177 "parent image's amplifier."
182 """The bounding box of the target amplifier in the parent image
191 """Transform an already-extracted subimage to match the orientation
192 and offset of the target amplifier.
196 subimage : image-like
197 The subimage to transform; may be any of `lsst.afw.image.Image`,
198 `lsst.afw.image.Mask`, `lsst.afw.image.MaskedImage`, and
199 `lsst.afw.image.Exposure`.
203 transformed : image-like
204 Transformed image of the same type as ``subimage``.
207 if hasattr(subimage,
"getMaskedImage"):
211 result = subimage.clone()
212 result.setMaskedImage(
214 subimage.getMaskedImage(),
226 result.setXY0(self.
_amplifier_amplifier.getBBox().getMin())
228 result.setXY0(self.
_amplifier_amplifier.getRawBBox().getMin() + self.
_amplifier_amplifier.getRawXYOffset())
232 """Create a single-amplifier detector that describes the transformed
237 detector : `Detector`
238 Detector object with a single amplifier, a trimmed bounding box
239 equal to the amplifier's trimmed bounding box, and no crosstalk.
243 detector.append(self.
_amplifier_amplifier.rebuild())
244 detector.setBBox(self.
_amplifier_amplifier.getBBox())
245 detector.unsetCrosstalk()
246 return detector.finish()
249 def apply(cls, parent_exposure, amplifier):
250 """Obtain a single-amplifier `lsst.afw.image.Exposure` subimage that
251 masquerades as full-detector image for a single-amp detector.
255 parent_exposure : `lsst.afw.image.Exposure`
256 Parent image to obtain a subset from.
257 `~lsst.afw.image.Exposure.getDetector` must not return `None`.
258 amplifier : `Amplifier`
259 Target amplifier for the subimage. May differ from the amplifier
260 obtained by ``parent_exposure.getDetector()[amplifier.getName()]``
261 only by flips and differences in `~Amplifier.getRawXYOffset`.
265 subimage : `lsst.afw.image.Exposure`
266 Exposure subimage for the target amplifier, with the
267 orientation and XY0 described by that amplifier, and a single-amp
268 detector holding a copy of that amplifier.
272 Because we use the target amplifier's bounding box as the bounding box
273 of the detector attached to the returned exposure, other exposure
274 components that are passed through unmodified (e.g. the WCS) should
275 still be valid for the single-amp exposure after it is trimmed and
276 "assembled". Unlike most trimmed+assembled images, however, it will
277 have a nonzero XY0, and code that (incorrectly!) does not pay attention
280 instance = cls(amplifier, parent_bbox=parent_exposure.getBBox(),
281 parent_detector=parent_exposure.getDetector())
282 result = instance.transform_subimage(parent_exposure[instance.subimage_bbox])
283 result.setDetector(instance.make_detector())
def transform_subimage(self, subimage)
def __init__(self, amplifier, parent_bbox, parent_detector)
def apply(cls, parent_exposure, amplifier)
def assembleAmplifierRawImage(destImage, rawImage, amplifier)
def makeUpdatedDetector(ccd)
def assembleAmplifierImage(destImage, rawImage, amplifier)
std::string const & getName() const noexcept
Return a filter's name.
std::shared_ptr< ImageT > flipImage(ImageT const &inImage, bool flipLR, bool flipTB)
Flip an image left–right and/or top–bottom.