lsst.pipe.tasks g11492f7fc6+8335dcbd4d
Loading...
Searching...
No Matches
visualizeVisit.py
Go to the documentation of this file.
1# This file is part of pipe_tasks.
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 <http://www.gnu.org/licenses/>.
21import numpy as np
22
23import lsst.pex.config as pexConfig
24import lsst.pipe.base as pipeBase
25import lsst.pipe.base.connectionTypes as cT
26import lsst.afw.math as afwMath
27import lsst.afw.image as afwImage
28import lsst.afw.cameraGeom.utils as afwUtils
29
30
31__all__ = ['VisualizeBinExpConfig', 'VisualizeBinExpTask',
32 'VisualizeMosaicExpConfig', 'VisualizeMosaicExpTask']
33
34
35class VisualizeBinExpConnections(pipeBase.PipelineTaskConnections,
36 dimensions=("instrument", "detector")):
37 inputExp = cT.Input(
38 name="calexp",
39 doc="Input exposure data to mosaic.",
40 storageClass="ExposureF",
41 dimensions=("instrument", "detector"),
42 )
43 camera = cT.PrerequisiteInput(
44 name="camera",
45 doc="Input camera to use for mosaic geometry.",
46 storageClass="Camera",
47 dimensions=("instrument",),
48 isCalibration=True,
49 )
50
51 outputExp = cT.Output(
52 name="calexpBin",
53 doc="Output binned image.",
54 storageClass="ExposureF",
55 dimensions=("instrument", "detector"),
56 )
57
58
59class VisualizeBinExpConfig(pipeBase.PipelineTaskConfig,
60 pipelineConnections=VisualizeBinExpConnections):
61 """Configuration for focal plane visualization.
62 """
63 binning = pexConfig.Field(
64 dtype=int,
65 default=8,
66 doc="Binning factor to apply to each input exposure's image data.",
67 )
68 detectorKeyword = pexConfig.Field(
69 dtype=str,
70 default='DET-ID',
71 doc="Metadata keyword to use to find detector if not available from input.",
72 )
73
74
75class VisualizeBinExpTask(pipeBase.PipelineTask,
76 pipeBase.CmdLineTask):
77 """Bin the detectors of an exposure.
78
79 The outputs of this task should be passed to
80 VisualizeMosaicExpTask to be mosaicked into a full focal plane
81 visualization image.
82 """
83 ConfigClass = VisualizeBinExpConfig
84 _DefaultName = 'VisualizeBinExp'
85
86 def run(self, inputExp, camera):
87 """Bin input image, attach associated detector.
88
89 Parameters
90 ----------
91 inputExp : `lsst.afw.image.Exposure`
92 Input exposure data to bin.
94 Input camera to use for mosaic geometry.
95
96 Returns
97 -------
98 output : `lsst.pipe.base.Struct`
99 Results struct with attribute:
100
101 ``outputExp``
102 Binned version of input image (`lsst.afw.image.Exposure`).
103 """
104 if inputExp.getDetector() is None:
105 detectorId = inputExp.getMetadata().get(self.config.detectorKeyword)
106 if detectorId is not None:
107 inputExp.setDetector(camera[detectorId])
108
109 binned = inputExp.getMaskedImage()
110 binned = afwMath.binImage(binned, self.config.binning)
111 outputExp = afwImage.makeExposure(binned)
112
113 outputExp.setInfo(inputExp.getInfo())
114
115 return pipeBase.Struct(
116 outputExp=outputExp,
117 )
118
119
120class VisualizeMosaicExpConnections(pipeBase.PipelineTaskConnections,
121 dimensions=("instrument", )):
122 inputExps = cT.Input(
123 name="calexpBin",
124 doc="Input binned images mosaic.",
125 storageClass="ExposureF",
126 dimensions=("instrument", "detector"),
127 multiple=True,
128 )
129 camera = cT.PrerequisiteInput(
130 name="camera",
131 doc="Input camera to use for mosaic geometry.",
132 storageClass="Camera",
133 dimensions=("instrument",),
134 isCalibration=True,
135 )
136
137 outputData = cT.Output(
138 name="calexpFocalPlane",
139 doc="Output binned mosaicked frame.",
140 storageClass="ImageF",
141 dimensions=("instrument", ),
142 )
143
144
145class VisualizeMosaicExpConfig(pipeBase.PipelineTaskConfig,
146 pipelineConnections=VisualizeMosaicExpConnections):
147 """Configuration for focal plane visualization.
148 """
149 binning = pexConfig.Field(
150 dtype=int,
151 default=8,
152 doc="Binning factor previously applied to input exposures.",
153 )
154
155
156class VisualizeMosaicExpTask(pipeBase.PipelineTask,
157 pipeBase.CmdLineTask):
158 """Task to mosaic binned products.
159
160 The config.binning parameter must match that used in the
161 VisualizeBinExpTask. Otherwise there will be a mismatch between
162 the input image size and the expected size of that image in the
163 full focal plane frame.
164 """
165 ConfigClass = VisualizeMosaicExpConfig
166 _DefaultName = 'VisualizeMosaicExp'
167
168 def makeCameraImage(self, inputExps, camera, binning):
169 """Make an image of an entire focal plane.
170
171 Parameters
172 ----------
173 exposures: `dict` [`int`, `lsst.afw.image.Exposure`]
174 CCD exposures, binned by `binning`. The keys are the
175 detectorIDs, with the values the binned image exposure.
176
177 Returns
178 -------
179 image : `lsst.afw.image.Image`
180 Image mosaicked from the individual binned images for each
181 detector.
182 """
183 image = afwUtils.makeImageFromCamera(
184 camera,
185 imageSource=ImageSource(inputExps),
186 imageFactory=afwImage.ImageF,
187 binSize=binning
188 )
189 return image
190
191 def run(self, inputExps, camera):
192 """Mosaic inputs together to create focal plane image.
193
194 Parameters
195 ----------
196 inputExp : `list` [`lsst.afw.image.Exposure`]
197 Input exposure data to bin.
199 Input camera to use for mosaic geometry.
200
201 Returns
202 -------
203 output : `lsst.pipe.base.Struct`
204 Results struct with attribute:
205
206 ``outputExp``
207 Binned version of input image (`lsst.afw.image.Exposure`).
208 """
209 expDict = {exp.getDetector().getId(): exp for exp in inputExps}
210 image = self.makeCameraImage(expDict, camera, self.config.binning)
211
212 return pipeBase.Struct(
213 outputData=image,
214 )
215
216
218 """Source of images for makeImageFromCamera"""
219 def __init__(self, exposures):
220 self.exposures = exposures
221 self.isTrimmed = True
222 self.background = np.nan
223
224 def getCcdImage(self, detector, imageFactory, binSize):
225 """Provide image of CCD to makeImageFromCamera
226
227 Parameters
228 ----------
229 detector : `int`
230 Detector ID to get image data for.
231 imageFactory : `lsst.afw.image.Image`
232 Type of image to construct.
233 binSize : `int`
234 Binsize to use to recompute dimensions.
235
236 Returns
237 -------
238 image : `lsst.afw.image.Image`
239 Appropriately rotated, binned, and transformed
240 image to be mosaicked.
242 Camera detector that the returned image data
243 belongs to.
244 """
245 detId = detector.getId()
246
247 if detId not in self.exposures:
248 dims = detector.getBBox().getDimensions()/binSize
249 image = imageFactory(*[int(xx) for xx in dims])
250 image.set(self.background)
251 else:
252 image = self.exposures[detector.getId()]
253 if hasattr(image, "getMaskedImage"):
254 image = image.getMaskedImage()
255 if hasattr(image, "getMask"):
256 mask = image.getMask()
257 isBad = mask.getArray() & mask.getPlaneBitMask("NO_DATA") > 0
258 image = image.clone()
259 image.getImage().getArray()[isBad] = self.background
260 if hasattr(image, "getImage"):
261 image = image.getImage()
262
263 # afwMath.rotateImageBy90 checks NQuarter values,
264 # so we don't need to here.
265 image = afwMath.rotateImageBy90(image, detector.getOrientation().getNQuarter())
266 return image, detector
def getCcdImage(self, detector, imageFactory, binSize)
def makeCameraImage(self, inputExps, camera, binning)