Hide keyboard shortcuts

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/>. 

21 

22__all__ = ['assembleAmplifierImage', 'assembleAmplifierRawImage', 

23 'makeUpdatedDetector'] 

24 

25import lsst.geom 

26 

27# dict of doFlip: slice 

28_SliceDict = { 

29 False: slice(None, None, 1), 

30 True: slice(None, None, -1), 

31} 

32 

33 

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. 

38 

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()] 

48 

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] 

52 

53 

54def assembleAmplifierImage(destImage, rawImage, amplifier): 

55 """Assemble the amplifier region of an image from a raw image. 

56 

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. 

66 

67 Raises 

68 ------ 

69 RuntimeError 

70 Raised if image types do not match or amplifier has no raw amplifier info. 

71 """ 

72 if type(destImage.Factory) != type(rawImage.Factory): # noqa: E721 

73 raise RuntimeError(f"destImage type = {type(destImage.Factory).__name__} != " 

74 f"{type(rawImage.Factory).__name__} = rawImage type") 

75 inView = rawImage.Factory(rawImage, amplifier.getRawDataBBox()) 

76 outView = destImage.Factory(destImage, amplifier.getBBox()) 

77 

78 _insertPixelChunk(outView, inView, amplifier, 

79 hasattr(rawImage, "getArrays")) 

80 

81 

82def assembleAmplifierRawImage(destImage, rawImage, amplifier): 

83 """Assemble the amplifier region of a raw CCD image. 

84 

85 For most cameras this is a no-op: the raw image already is an assembled 

86 CCD image. 

87 However, it is useful for camera such as LSST for which each amplifier 

88 image is a separate image. 

89 

90 Parameters 

91 ---------- 

92 destImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 

93 CCD Image; the region amplifier.getRawAmplifier().getBBox() 

94 is overwritten with the raw amplifier image. 

95 rawImage : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` 

96 Raw image (same type as destImage). 

97 amplifier : `lsst.afw.cameraGeom.Amplifier` 

98 Amplifier geometry with raw amplifier info 

99 

100 Raises 

101 ------ 

102 RuntimeError 

103 Raised if image types do not match or amplifier has no raw amplifier info. 

104 """ 

105 if type(destImage.Factory) != type(rawImage.Factory): # noqa: E721 

106 raise RuntimeError(f"destImage type = {type(destImage.Factory).__name__} != " 

107 f"{type(rawImage.Factory).__name__} = rawImage type") 

108 inBBox = amplifier.getRawBBox() 

109 inView = rawImage.Factory(rawImage, inBBox) 

110 outBBox = amplifier.getRawBBox() 

111 outBBox.shift(amplifier.getRawXYOffset()) 

112 outView = destImage.Factory(destImage, outBBox) 

113 

114 _insertPixelChunk(outView, inView, amplifier, 

115 hasattr(rawImage, "getArrays")) 

116 

117 

118def makeUpdatedDetector(ccd): 

119 """Return a Detector that has had the definitions of amplifier geometry 

120 updated post assembly. 

121 

122 Parameters 

123 ---------- 

124 ccd : `lsst.afw.image.Detector` 

125 The detector to copy and update. 

126 """ 

127 builder = ccd.rebuild() 

128 for amp in builder.getAmplifiers(): 

129 bbox = amp.getRawBBox() 

130 awidth, aheight = bbox.getDimensions() 

131 # 

132 # Figure out how far flipping the amp LR and/or TB offsets the bboxes 

133 # 

134 boxMin0 = bbox.getMin() # initial position of rawBBox's LLC corner 

135 if amp.getRawFlipX(): 

136 bbox.flipLR(awidth) 

137 if amp.getRawFlipY(): 

138 bbox.flipTB(aheight) 

139 shift = boxMin0 - bbox.getMin() 

140 

141 for bboxName in ("", 

142 "HorizontalOverscan", 

143 "Data", 

144 "VerticalOverscan", 

145 "Prescan"): 

146 bbox = getattr(amp, f"getRaw{bboxName}BBox")() 

147 if amp.getRawFlipX(): 

148 bbox.flipLR(awidth) 

149 if amp.getRawFlipY(): 

150 bbox.flipTB(aheight) 

151 bbox.shift(amp.getRawXYOffset() + shift) 

152 

153 getattr(amp, f"setRaw{bboxName}BBox")(bbox) 

154 # 

155 # All of these have now been transferred to the per-amp geometry 

156 # 

157 amp.setRawXYOffset(lsst.geom.ExtentI(0, 0)) 

158 amp.setRawFlipX(False) 

159 amp.setRawFlipY(False) 

160 

161 return builder.finish()