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

79 

80 _insertPixelChunk(outView, inView, amplifier, 

81 hasattr(rawImage, "getArrays")) 

82 

83 

84def assembleAmplifierRawImage(destImage, rawImage, amplifier): 

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

86 

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. 

91 

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 

101 

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) 

117 

118 _insertPixelChunk(outView, inView, amplifier, 

119 hasattr(rawImage, "getArrays")) 

120 

121 

122def makeUpdatedDetector(ccd): 

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

124 updated post assembly. 

125 

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

134 

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

146 

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) 

158 

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) 

166 

167 return builder.finish()