LSSTApplications  19.0.0+10,19.0.0+80,19.0.0-1-g20d9b18+31,19.0.0-1-g49a97f9+4,19.0.0-1-g8c57eb9+31,19.0.0-1-g9a028c0+13,19.0.0-1-ga72da6b+3,19.0.0-1-gb77924a+15,19.0.0-1-gbfe0924+66,19.0.0-1-gc3516c3,19.0.0-1-gefe1d0d+49,19.0.0-1-gf8cb8b4+3,19.0.0-14-g7511ce4+6,19.0.0-16-g3dc1a33c+6,19.0.0-17-g59f0e8a+4,19.0.0-17-g9c22e3c+9,19.0.0-18-g35bb99870+2,19.0.0-19-g2772d4a+9,19.0.0-2-g260436e+53,19.0.0-2-g31cdcee,19.0.0-2-g9675b69+3,19.0.0-2-gaa2795f,19.0.0-2-gbcc4de1,19.0.0-2-gd6f004e+6,19.0.0-2-gde8e5e3+5,19.0.0-2-gff6972b+15,19.0.0-21-ge306cd8,19.0.0-21-gf122e69+2,19.0.0-3-g2d43a51+2,19.0.0-3-gf3b1435+6,19.0.0-4-g56feb96,19.0.0-4-gac56cce+17,19.0.0-49-gce872c1+1,19.0.0-5-g66946eb+6,19.0.0-5-gd8897ba+6,19.0.0-51-gfc4a647e,19.0.0-7-g686a884+5,19.0.0-7-g886f805+5,19.0.0-8-g305ff64,w.2020.17
LSSTDataManagementBasePackage
utils.py
Go to the documentation of this file.
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 """
23 Support for displaying cameraGeom objects.
24 """
25 
26 __all__ = ['prepareWcsData', 'plotFocalPlane', 'makeImageFromAmp', 'calcRawCcdBBox', 'makeImageFromCcd',
27  'FakeImageDataSource', 'ButlerImage', 'rawCallback', 'overlayCcdBoxes',
28  'showAmp', 'showCcd', 'getCcdInCamBBoxList', 'getCameraImageBBox',
29  'makeImageFromCamera', 'showCamera', 'makeFocalPlaneWcs', 'findAmp']
30 
31 import math
32 import numpy
33 
34 import lsst.geom
35 from lsst.afw.fits import FitsError
36 import lsst.afw.geom as afwGeom
37 import lsst.afw.image as afwImage
38 import lsst.afw.math as afwMath
39 import lsst.afw.cameraGeom as afwCameraGeom
40 import lsst.daf.base as dafBase
41 import lsst.log
42 import lsst.pex.exceptions as pexExceptions
43 
44 from .rotateBBoxBy90 import rotateBBoxBy90
45 from .assembleImage import assembleAmplifierImage, assembleAmplifierRawImage
46 from .cameraGeomLib import FIELD_ANGLE, FOCAL_PLANE
47 from lsst.afw.display.utils import _getDisplayFromDisplayOrFrame
48 from lsst.afw.cameraGeom import DetectorType
49 
50 import lsst.afw.display as afwDisplay
51 import lsst.afw.display.utils as displayUtils
52 
53 
54 def prepareWcsData(wcs, amp, isTrimmed=True):
55  """Put Wcs from an Amp image into CCD coordinates
56 
57  Parameters
58  ----------
59  wcs : `lsst.afw.geom.SkyWcs`
60  The WCS object to start from.
61  amp : `lsst.afw.table.AmpInfoRecord`
62  Amp object to use
63  isTrimmed : `bool`
64  Is the image to which the WCS refers trimmed of non-imaging pixels?
65 
66  Returns
67  -------
68  ampWcs : `lsst.afw.geom.SkyWcs`
69  The modified WCS.
70  """
71  if not amp.getHasRawInfo():
72  raise RuntimeError("Cannot modify wcs without raw amp information")
73  if isTrimmed:
74  ampBox = amp.getRawDataBBox()
75  else:
76  ampBox = amp.getRawBBox()
77  ampCenter = lsst.geom.Point2D(ampBox.getDimensions()/2.0)
78  wcs = afwGeom.makeFlippedWcs(wcs, amp.getRawFlipX(), amp.getRawFlipY(), ampCenter)
79  # Shift WCS for trimming
80  if isTrimmed:
81  trim_shift = ampBox.getMin() - amp.getBBox().getMin()
82  wcs = wcs.copyAtShiftedPixelOrigin(lsst.geom.Extent2D(-trim_shift.getX(), -trim_shift.getY()))
83  # Account for shift of amp data in larger ccd matrix
84  offset = amp.getRawXYOffset()
85  return wcs.copyAtShiftedPixelOrigin(lsst.geom.Extent2D(offset))
86 
87 
88 def plotFocalPlane(camera, fieldSizeDeg_x=0, fieldSizeDeg_y=None, dx=0.1, dy=0.1, figsize=(10., 10.),
89  useIds=False, showFig=True, savePath=None):
90  """Make a plot of the focal plane along with a set points that sample
91  the field of view.
92 
93  Parameters
94  ----------
95  camera : `lsst.afw.cameraGeom.Camera`
96  A camera object
97  fieldSizeDeg_x : `float`
98  Amount of the field to sample in x in degrees
99  fieldSizeDeg_y : `float` or `None`
100  Amount of the field to sample in y in degrees
101  dx : `float`
102  Spacing of sample points in x in degrees
103  dy : `float`
104  Spacing of sample points in y in degrees
105  figsize : `tuple` containing two `float`
106  Matplotlib style tuple indicating the size of the figure in inches
107  useIds : `bool`
108  Label detectors by name, not id?
109  showFig : `bool`
110  Display the figure on the screen?
111  savePath : `str` or `None`
112  If not `None`, save a copy of the figure to this name.
113  """
114  try:
115  from matplotlib.patches import Polygon
116  from matplotlib.collections import PatchCollection
117  import matplotlib.pyplot as plt
118  except ImportError:
119  raise ImportError(
120  "Can't run plotFocalPlane: matplotlib has not been set up")
121 
122  if fieldSizeDeg_x:
123  if fieldSizeDeg_y is None:
124  fieldSizeDeg_y = fieldSizeDeg_x
125 
126  field_gridx, field_gridy = numpy.meshgrid(
127  numpy.arange(0., fieldSizeDeg_x + dx, dx) - fieldSizeDeg_x/2.,
128  numpy.arange(0., fieldSizeDeg_y + dy, dy) - fieldSizeDeg_y/2.)
129  field_gridx, field_gridy = field_gridx.flatten(), field_gridy.flatten()
130  else:
131  field_gridx, field_gridy = [], []
132 
133  xs = []
134  ys = []
135  pcolors = []
136 
137  # compute focal plane positions corresponding to field angles field_gridx, field_gridy
138  posFieldAngleList = [lsst.geom.Point2D(x*lsst.geom.radians, y*lsst.geom.radians)
139  for x, y in zip(field_gridx, field_gridy)]
140  posFocalPlaneList = camera.transform(posFieldAngleList, FIELD_ANGLE, FOCAL_PLANE)
141  for posFocalPlane in posFocalPlaneList:
142  xs.append(posFocalPlane.getX())
143  ys.append(posFocalPlane.getY())
144  dets = camera.findDetectors(posFocalPlane, FOCAL_PLANE)
145  if len(dets) > 0:
146  pcolors.append('w')
147  else:
148  pcolors.append('k')
149 
150  colorMap = {DetectorType.SCIENCE: 'b', DetectorType.FOCUS: 'y',
151  DetectorType.GUIDER: 'g', DetectorType.WAVEFRONT: 'r'}
152 
153  patches = []
154  colors = []
155  plt.figure(figsize=figsize)
156  ax = plt.gca()
157  xvals = []
158  yvals = []
159  for det in camera:
160  corners = [(c.getX(), c.getY()) for c in det.getCorners(FOCAL_PLANE)]
161  for corner in corners:
162  xvals.append(corner[0])
163  yvals.append(corner[1])
164  colors.append(colorMap[det.getType()])
165  patches.append(Polygon(corners, True))
166  center = det.getOrientation().getFpPosition()
167  ax.text(center.getX(), center.getY(), det.getId() if useIds else det.getName(),
168  horizontalalignment='center', size=6)
169 
170  patchCollection = PatchCollection(patches, alpha=0.6, facecolor=colors)
171  ax.add_collection(patchCollection)
172  ax.scatter(xs, ys, s=10, alpha=.7, linewidths=0., c=pcolors)
173  ax.set_xlim(min(xvals) - abs(0.1*min(xvals)),
174  max(xvals) + abs(0.1*max(xvals)))
175  ax.set_ylim(min(yvals) - abs(0.1*min(yvals)),
176  max(yvals) + abs(0.1*max(yvals)))
177  ax.set_xlabel('Focal Plane X (mm)')
178  ax.set_ylabel('Focal Plane Y (mm)')
179  if savePath is not None:
180  plt.savefig(savePath)
181  if showFig:
182  plt.show()
183 
184 
185 def makeImageFromAmp(amp, imValue=None, imageFactory=afwImage.ImageU, markSize=10, markValue=0,
186  scaleGain=lambda gain: (gain*1000)//10):
187  """Make an image from an amp object.
188 
189  Since images are integer images by default, the gain needs to be scaled to
190  give enough dynamic range to see variation from amp to amp.
191  The scaling algorithm is assignable.
192 
193  Parameters
194  ----------
195  amp : `lsst.afw.table.AmpInfoRecord`
196  Amp record to use for constructing the raw amp image.
197  imValue : `float` or `None`
198  Value to assign to the constructed image, or scaleGain(gain) if `None`.
199  imageFactory : callable like `lsst.afw.image.Image`
200  Type of image to construct.
201  markSize : `float`
202  Size of mark at read corner in pixels.
203  markValue : `float`
204  Value of pixels in the read corner mark.
205  scaleGain : callable
206  The function by which to scale the gain (must take a single argument).
207 
208  Returns
209  -------
210  ampImage : `lsst.afw.image`
211  An untrimmed amp image, of the type produced by ``imageFactory``.
212  """
213  if not amp.getHasRawInfo():
214  raise RuntimeError(
215  "Can't create a raw amp image without raw amp information")
216  bbox = amp.getRawBBox()
217  dbbox = amp.getRawDataBBox()
218  img = imageFactory(bbox)
219  if imValue is None:
220  img.set(int(scaleGain(amp.getGain())))
221  else:
222  img.set(imValue)
223  # Set the first pixel read to a different value
224  markbbox = lsst.geom.Box2I()
225  if amp.getReadoutCorner() == afwCameraGeom.ReadoutCorner.LL:
226  markbbox.include(dbbox.getMin())
227  markbbox.include(dbbox.getMin() + lsst.geom.Extent2I(markSize, markSize))
228  elif amp.getReadoutCorner() == afwCameraGeom.ReadoutCorner.LR:
229  cornerPoint = lsst.geom.Point2I(dbbox.getMaxX(), dbbox.getMinY())
230  markbbox.include(cornerPoint)
231  markbbox.include(cornerPoint + lsst.geom.Extent2I(-markSize, markSize))
232  elif amp.getReadoutCorner() == afwCameraGeom.ReadoutCorner.UR:
233  cornerPoint = lsst.geom.Point2I(dbbox.getMax())
234  markbbox.include(cornerPoint)
235  markbbox.include(cornerPoint + lsst.geom.Extent2I(-markSize, -markSize))
236  elif amp.getReadoutCorner() == afwCameraGeom.ReadoutCorner.UL:
237  cornerPoint = lsst.geom.Point2I(dbbox.getMinX(), dbbox.getMaxY())
238  markbbox.include(cornerPoint)
239  markbbox.include(cornerPoint + lsst.geom.Extent2I(markSize, -markSize))
240  else:
241  raise RuntimeError("Could not set readout corner")
242  mimg = imageFactory(img, markbbox)
243  mimg.set(markValue)
244  return img
245 
246 
247 def calcRawCcdBBox(ccd):
248  """Calculate the raw ccd bounding box.
249 
250  Parameters
251  ----------
252  ccd : `lsst.afw.cameraGeom.Detector`
253  Detector for which to calculate the un-trimmed bounding box.
254 
255  Returns
256  -------
257  bbox : `lsst.geom.Box2I` or `None`
258  Bounding box of the un-trimmed Detector, or `None` if there is not enough
259  information to calculate raw BBox.
260  """
261  bbox = lsst.geom.Box2I()
262  for amp in ccd:
263  if not amp.getHasRawInfo():
264  return None
265  tbbox = amp.getRawBBox()
266  tbbox.shift(amp.getRawXYOffset())
267  bbox.include(tbbox)
268  return bbox
269 
270 
271 def makeImageFromCcd(ccd, isTrimmed=True, showAmpGain=True, imageFactory=afwImage.ImageU, rcMarkSize=10,
272  binSize=1):
273  """Make an Image of a CCD.
274 
275  Parameters
276  ----------
277  ccd : `lsst.afw.cameraGeom.Detector`
278  Detector to use in making the image.
279  isTrimmed : `bool`
280  Assemble a trimmed Detector image.
281  showAmpGain : `bool`
282  Use the per-amp gain to color the pixels in the image?
283  imageFactory : callable like `lsst.afw.image.Image`
284  Image type to generate.
285  rcMarkSize : `float`
286  Size of the mark to make in the amp images at the read corner.
287  binSize : `int`
288  Bin the image by this factor in both dimensions.
289 
290  Returns
291  -------
292  image : `lsst.afw.image.Image`
293  Image of the Detector (type returned by ``imageFactory``).
294  """
295  ampImages = []
296  index = 0
297  if isTrimmed:
298  bbox = ccd.getBBox()
299  else:
300  bbox = calcRawCcdBBox(ccd)
301  for amp in ccd:
302  if amp.getHasRawInfo():
303  if showAmpGain:
304  ampImages.append(makeImageFromAmp(
305  amp, imageFactory=imageFactory, markSize=rcMarkSize))
306  else:
307  ampImages.append(makeImageFromAmp(amp, imValue=(index + 1)*1000,
308  imageFactory=imageFactory, markSize=rcMarkSize))
309  index += 1
310 
311  if len(ampImages) > 0:
312  ccdImage = imageFactory(bbox)
313  for ampImage, amp in zip(ampImages, ccd):
314  if isTrimmed:
315  assembleAmplifierImage(ccdImage, ampImage, amp)
316  else:
317  assembleAmplifierRawImage(ccdImage, ampImage, amp)
318  else:
319  if not isTrimmed:
320  raise RuntimeError(
321  "Cannot create untrimmed CCD without amps with raw information")
322  ccdImage = imageFactory(ccd.getBBox())
323  ccdImage = afwMath.binImage(ccdImage, binSize)
324  return ccdImage
325 
326 
328  """A class to retrieve synthetic images for display by the show* methods
329 
330  Parameters
331  ----------
332  isTrimmed : `bool`
333  Should amps be trimmed?
334  verbose : `bool`
335  Be chatty?
336  background : `float`
337  The value of any pixels that lie outside the CCDs.
338  showAmpGain : `bool`
339  Color the amp segments with the gain of the amp?
340  markSize : `float`
341  Size of the side of the box used to mark the read corner.
342  markValue : `float`
343  Value to assign the read corner mark.
344  ampImValue : `float` or `None`
345  Value to assign to amps; scaleGain(gain) is used if `None`.
346  scaleGain : callable
347  Function to scale the gain by.
348  """
349  def __init__(self, isTrimmed=True, verbose=False, background=numpy.nan,
350  showAmpGain=True, markSize=10, markValue=0,
351  ampImValue=None, scaleGain=lambda gain: (gain*1000)//10):
352  self.isTrimmed = isTrimmed
353  self.verbose = verbose
354  self.background = background
355  self.showAmpGain = showAmpGain
356  self.markSize = markSize
357  self.markValue = markValue
358  self.ampImValue = ampImValue
359  self.scaleGain = scaleGain
360 
361  def getCcdImage(self, det, imageFactory, binSize):
362  """Return a CCD image for the detector and the (possibly updated) Detector.
363 
364  Parameters
365  ----------
366  det : `lsst.afw.cameraGeom.Detector`
367  Detector to use for making the image.
368  imageFactory : callable like `lsst.afw.image.Image`
369  Image constructor for making the image.
370  binSize : `int`
371  Bin the image by this factor in both dimensions.
372 
373  Returns
374  -------
375  ccdImage : `lsst.afw.image.Image`
376  The constructed image.
377  """
378  ccdImage = makeImageFromCcd(det, isTrimmed=self.isTrimmed, showAmpGain=self.showAmpGain,
379  imageFactory=imageFactory, binSize=binSize)
380  return afwMath.rotateImageBy90(ccdImage, det.getOrientation().getNQuarter()), det
381 
382  def getAmpImage(self, amp, imageFactory):
383  """Return an amp segment image.
384 
385  Parameters
386  ----------
387  amp : `lsst.afw.table.AmpInfoTable`
388  AmpInfoTable for this amp.
389  imageFactory : callable like `lsst.afw.image.Image`
390  Image constructor for making the image.
391 
392  Returns
393  -------
394  ampImage : `lsst.afw.image.Image`
395  The constructed image.
396  """
397  ampImage = makeImageFromAmp(amp, imValue=self.ampImValue, imageFactory=imageFactory,
398  markSize=self.markSize, markValue=self.markValue,
399  scaleGain=self.scaleGain)
400  if self.isTrimmed:
401  ampImage = ampImage.Factory(ampImage, amp.getRawDataBBox())
402  return ampImage
403 
404 
406  """A class to return an Image of a given Ccd using the butler.
407 
408  Parameters
409  ----------
410  butler : `lsst.daf.persistence.Butler` or `None`
411  The butler to use. If `None`, an empty image is returned.
412  type : `str`
413  The type of image to read (e.g. raw, bias, flat, calexp).
414  isTrimmed : `bool`
415  If true, the showCamera command expects to be given trimmed images.
416  verbose : `bool`
417  Be chatty (in particular, log any error messages from the butler)?
418  background : `float`
419  The value of any pixels that lie outside the CCDs.
420  callback : callable
421  A function called with (image, ccd, butler) for every image, which
422  returns the image to be displayed (e.g. rawCallback). The image must
423  be of the correct size, allowing for the value of isTrimmed.
424  *args : `list`
425  Passed to the butler.
426  **kwargs : `dict`
427  Passed to the butler.
428 
429  Notes
430  -----
431  You can define a short named function as a callback::
432 
433  def callback(im, ccd, imageSource):
434  return cameraGeom.utils.rawCallback(im, ccd, imageSource, correctGain=True)
435  """
436  def __init__(self, butler=None, type="raw",
437  isTrimmed=True, verbose=False, background=numpy.nan,
438  callback=None, *args, **kwargs):
439  super(ButlerImage, self).__init__(*args)
440  self.isTrimmed = isTrimmed
441  self.type = type
442  self.butler = butler
443  self.kwargs = kwargs
444  self.isRaw = False
445  self.background = background
446  self.verbose = verbose
447  self.callback = callback
448 
449  def _prepareImage(self, ccd, im, binSize, allowRotate=True):
450  if binSize > 1:
451  im = afwMath.binImage(im, binSize)
452 
453  if allowRotate:
455  im, ccd.getOrientation().getNQuarter())
456 
457  return im
458 
459  def getCcdImage(self, ccd, imageFactory=afwImage.ImageF, binSize=1, asMaskedImage=False):
460  """Return an image of the specified ccd, and also the (possibly updated) ccd"""
461 
462  log = lsst.log.Log.getLogger("afw.cameraGeom.utils.ButlerImage")
463 
464  if self.isTrimmed:
465  bbox = ccd.getBBox()
466  else:
467  bbox = calcRawCcdBBox(ccd)
468 
469  im = None
470  if self.butler is not None:
471  err = None
472  for dataId in [dict(detector=ccd.getId()), dict(ccd=ccd.getId()), dict(ccd=ccd.getName())]:
473  try:
474  im = self.butler.get(self.type, dataId, **self.kwargs)
475  except FitsError as e: # no point trying another dataId
476  err = IOError(e.args[0].split('\n')[0]) # It's a very chatty error
477  break
478  except Exception as e: # try a different dataId
479  if err is None:
480  err = e
481  continue
482  else:
483  ccd = im.getDetector() # possibly modified by assembleCcdTask
484  break
485 
486  if im:
487  if asMaskedImage:
488  im = im.getMaskedImage()
489  else:
490  im = im.getMaskedImage().getImage()
491  else:
492  if self.verbose:
493  # Lost by jupyterlab.
494  print(f"Reading {ccd.getId()}: {err}")
495 
496  log.warn(f"Reading {ccd.getId()}: {err}")
497 
498  if im is None:
499  return self._prepareImage(ccd, imageFactory(*bbox.getDimensions()), binSize), ccd
500 
501  if self.type == "raw":
502  if hasattr(im, 'convertF'):
503  im = im.convertF()
504  if False and self.callback is None: # we need to trim the raw image
505  self.callback = rawCallback
506 
507  allowRotate = True
508  if self.callback:
509  try:
510  im = self.callback(im, ccd, imageSource=self)
511  except Exception as e:
512  if self.verbose:
513  log.error(f"callback failed: {e}")
514  im = imageFactory(*bbox.getDimensions())
515  else:
516  allowRotate = False # the callback was responsible for any rotations
517 
518  return self._prepareImage(ccd, im, binSize, allowRotate=allowRotate), ccd
519 
520 
521 def rawCallback(im, ccd=None, imageSource=None,
522  correctGain=False, subtractBias=False, convertToFloat=False, obeyNQuarter=True):
523  """A callback function that may or may not subtract bias/correct gain/trim
524  a raw image.
525 
526  Parameters
527  ----------
528  im : `lsst.afw.image.Image` or `lsst.afw.image.MaskedImage` or `lsst.afw.image.Exposure`
529  An image of a chip, ready to be binned and maybe rotated.
530  ccd : `lsst.afw.cameraGeom.Detector` or `None`
531  The Detector; if `None` assume that im is an exposure and extract its Detector.
532  imageSource : `FakeImageDataSource` or `None`
533  Source to get ccd images. Must have a `getCcdImage()` method.
534  correctGain : `bool`
535  Correct each amplifier for its gain?
536  subtractBias : `bool`
537  Subtract the bias from each amplifier?
538  convertToFloat : `bool`
539  Convert ``im`` to floating point if possible.
540  obeyNQuarter : `bool`
541  Obey nQuarter from the Detector (default: True)
542 
543  Returns
544  -------
545  image : `lsst.afw.image.Image` like
546  The constructed image (type returned by ``im.Factory``).
547 
548  Notes
549  -----
550  If imageSource is derived from ButlerImage, imageSource.butler is available.
551  """
552  if ccd is None:
553  ccd = im.getDetector()
554  if hasattr(im, "getMaskedImage"):
555  im = im.getMaskedImage()
556  if convertToFloat and hasattr(im, "convertF"):
557  im = im.convertF()
558 
559  isTrimmed = imageSource.isTrimmed
560  if isTrimmed:
561  bbox = ccd.getBBox()
562  else:
563  bbox = calcRawCcdBBox(ccd)
564 
565  ampImages = []
566  for a in ccd:
567  if isTrimmed:
568  data = im[a.getRawDataBBox()]
569  else:
570  data = im
571 
572  if subtractBias:
573  bias = im[a.getRawHorizontalOverscanBBox()]
574  data -= afwMath.makeStatistics(bias, afwMath.MEANCLIP).getValue()
575  if correctGain:
576  data *= a.getGain()
577 
578  ampImages.append(data)
579 
580  ccdImage = im.Factory(bbox)
581  for ampImage, amp in zip(ampImages, ccd):
582  if isTrimmed:
583  assembleAmplifierImage(ccdImage, ampImage, amp)
584  else:
585  assembleAmplifierRawImage(ccdImage, ampImage, amp)
586 
587  if obeyNQuarter:
588  nQuarter = ccd.getOrientation().getNQuarter()
589  ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter)
590 
591  return ccdImage
592 
593 
594 def overlayCcdBoxes(ccd, untrimmedCcdBbox=None, nQuarter=0,
595  isTrimmed=False, ccdOrigin=(0, 0), display=None, binSize=1):
596  """Overlay bounding boxes on an image display.
597 
598  Parameters
599  ----------
600  ccd : `lsst.afw.cameraGeom.Detector`
601  Detector to iterate for the amp bounding boxes.
602  untrimmedCcdBbox : `lsst.geom.Box2I` or `None`
603  Bounding box of the un-trimmed Detector.
604  nQuarter : `int`
605  number of 90 degree rotations to apply to the bounding boxes (used for rotated chips).
606  isTrimmed : `bool`
607  Is the Detector image over which the boxes are layed trimmed?
608  ccdOrigin : `tuple` of `float`
609  Detector origin relative to the parent origin if in a larger pixel grid.
610  display : `lsst.afw.display.Display`
611  Image display to display on.
612  binSize : `int`
613  Bin the image by this factor in both dimensions.
614 
615  Notes
616  -----
617  The colours are:
618  - Entire detector GREEN
619  - All data for amp GREEN
620  - HorizontalPrescan YELLOW
621  - HorizontalOverscan RED
622  - Data BLUE
623  - VerticalOverscan MAGENTA
624  - VerticalOverscan MAGENTA
625  """
626  if not display: # should be second parameter, and not defaulted!!
627  raise RuntimeError("Please specify a display")
628 
629  if untrimmedCcdBbox is None:
630  if isTrimmed:
631  untrimmedCcdBbox = ccd.getBBox()
632  else:
633  untrimmedCcdBbox = lsst.geom.Box2I()
634  for a in ccd.getAmplifiers():
635  bbox = a.getRawBBox()
636  untrimmedCcdBbox.include(bbox)
637 
638  with display.Buffering():
639  ccdDim = untrimmedCcdBbox.getDimensions()
640  ccdBbox = rotateBBoxBy90(untrimmedCcdBbox, nQuarter, ccdDim)
641  for amp in ccd:
642  if isTrimmed:
643  ampbbox = amp.getBBox()
644  else:
645  ampbbox = amp.getRawBBox()
646  if nQuarter != 0:
647  ampbbox = rotateBBoxBy90(ampbbox, nQuarter, ccdDim)
648 
649  displayUtils.drawBBox(ampbbox, origin=ccdOrigin, borderWidth=0.49,
650  display=display, bin=binSize)
651 
652  if not isTrimmed and amp.getHasRawInfo():
653  for bbox, ctype in ((amp.getRawHorizontalOverscanBBox(), afwDisplay.RED),
654  (amp.getRawDataBBox(), afwDisplay.BLUE),
655  (amp.getRawVerticalOverscanBBox(),
656  afwDisplay.MAGENTA),
657  (amp.getRawPrescanBBox(), afwDisplay.YELLOW)):
658  if nQuarter != 0:
659  bbox = rotateBBoxBy90(bbox, nQuarter, ccdDim)
660  displayUtils.drawBBox(bbox, origin=ccdOrigin, borderWidth=0.49, ctype=ctype,
661  display=display, bin=binSize)
662  # Label each Amp
663  xc, yc = ((ampbbox.getMin()[0] + ampbbox.getMax()[0])//2,
664  (ampbbox.getMin()[1] + ampbbox.getMax()[1])//2)
665  #
666  # Rotate the amp labels too
667  #
668  if nQuarter == 0:
669  c, s = 1, 0
670  elif nQuarter == 1:
671  c, s = 0, -1
672  elif nQuarter == 2:
673  c, s = -1, 0
674  elif nQuarter == 3:
675  c, s = 0, 1
676  c, s = 1, 0
677  ccdHeight = ccdBbox.getHeight()
678  ccdWidth = ccdBbox.getWidth()
679  xc -= 0.5*ccdHeight
680  yc -= 0.5*ccdWidth
681 
682  xc, yc = 0.5*ccdHeight + c*xc + s*yc, 0.5*ccdWidth + -s*xc + c*yc
683 
684  if ccdOrigin:
685  xc += ccdOrigin[0]
686  yc += ccdOrigin[1]
687  display.dot(str(amp.getName()), xc/binSize,
688  yc/binSize, textAngle=nQuarter*90)
689 
690  displayUtils.drawBBox(ccdBbox, origin=ccdOrigin,
691  borderWidth=0.49, ctype=afwDisplay.MAGENTA, display=display, bin=binSize)
692 
693 
694 def showAmp(amp, imageSource=FakeImageDataSource(isTrimmed=False), display=None, overlay=True,
695  imageFactory=afwImage.ImageU):
696  """Show an amp in an image display.
697 
698  Parameters
699  ----------
700  amp : `lsst.afw.tables.AmpInfoRecord`
701  Amp record to use in display.
702  imageSource : `FakeImageDataSource` or `None`
703  Source for getting the amp image. Must have a ``getAmpImage()`` method.
704  display : `lsst.afw.display.Display`
705  Image display to use.
706  overlay : `bool`
707  Overlay bounding boxes?
708  imageFactory : callable like `lsst.afw.image.Image`
709  Type of image to display (only used if ampImage is `None`).
710  """
711  if not display:
712  display = _getDisplayFromDisplayOrFrame(display)
713 
714  ampImage = imageSource.getAmpImage(amp, imageFactory=imageFactory)
715  ampImSize = ampImage.getDimensions()
716  title = amp.getName()
717  display.mtv(ampImage, title=title)
718  if overlay:
719  with display.Buffering():
720  if amp.getHasRawInfo() and ampImSize == amp.getRawBBox().getDimensions():
721  bboxes = [(amp.getRawBBox(), 0.49, afwDisplay.GREEN), ]
722  xy0 = bboxes[0][0].getMin()
723  bboxes.append(
724  (amp.getRawHorizontalOverscanBBox(), 0.49, afwDisplay.RED))
725  bboxes.append((amp.getRawDataBBox(), 0.49, afwDisplay.BLUE))
726  bboxes.append((amp.getRawPrescanBBox(),
727  0.49, afwDisplay.YELLOW))
728  bboxes.append((amp.getRawVerticalOverscanBBox(),
729  0.49, afwDisplay.MAGENTA))
730  else:
731  bboxes = [(amp.getBBox(), 0.49, None), ]
732  xy0 = bboxes[0][0].getMin()
733 
734  for bbox, borderWidth, ctype in bboxes:
735  if bbox.isEmpty():
736  continue
737  bbox = lsst.geom.Box2I(bbox)
738  bbox.shift(-lsst.geom.ExtentI(xy0))
739  displayUtils.drawBBox(
740  bbox, borderWidth=borderWidth, ctype=ctype, display=display)
741 
742 
743 def showCcd(ccd, imageSource=FakeImageDataSource(), display=None, overlay=True,
744  imageFactory=afwImage.ImageF, binSize=1, inCameraCoords=False):
745  """Show a CCD on display.
746 
747  Parameters
748  ----------
749  ccd : `lsst.afw.cameraGeom.Detector`
750  Detector to use in display.
751  imageSource : `FakeImageDataSource` or `None`
752  Source to get ccd images. Must have a ``getCcdImage()`` method.
753  display : `lsst.afw.display.Display`
754  image display to use.
755  overlay : `bool`
756  Show amp bounding boxes on the displayed image?
757  imageFactory : callable like `lsst.afw.image.Image`
758  The image factory to use in generating the images.
759  binSize : `int`
760  Bin the image by this factor in both dimensions.
761  inCameraCoords : `bool`
762  Show the Detector in camera coordinates?
763  """
764  display = _getDisplayFromDisplayOrFrame(display)
765 
766  ccdOrigin = lsst.geom.Point2I(0, 0)
767  nQuarter = 0
768  ccdImage, ccd = imageSource.getCcdImage(
769  ccd, imageFactory=imageFactory, binSize=binSize)
770 
771  ccdBbox = ccdImage.getBBox()
772  if ccdBbox.getDimensions() == ccd.getBBox().getDimensions():
773  isTrimmed = True
774  else:
775  isTrimmed = False
776 
777  if inCameraCoords:
778  nQuarter = ccd.getOrientation().getNQuarter()
779  ccdImage = afwMath.rotateImageBy90(ccdImage, nQuarter)
780  title = ccd.getName()
781  if isTrimmed:
782  title += "(trimmed)"
783 
784  if display:
785  display.mtv(ccdImage, title=title)
786 
787  if overlay:
788  overlayCcdBoxes(ccd, ccdBbox, nQuarter, isTrimmed,
789  ccdOrigin, display, binSize)
790 
791  return ccdImage
792 
793 
794 def getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin):
795  """Get the bounding boxes of a list of Detectors within a camera sized pixel grid
796 
797  Parameters
798  ----------
799  ccdList : `lsst.afw.cameraGeom.Detector`
800  List of Detector.
801  binSize : `int`
802  Bin the image by this factor in both dimensions.
803  pixelSize_o : `float`
804  Size of the pixel in mm.
805  origin : `int`
806  Origin of the camera pixel grid in pixels.
807 
808  Returns
809  -------
810  boxList : `list` [`lsst.geom.Box2I`]
811  A list of bounding boxes in camera pixel coordinates.
812  """
813  boxList = []
814  for ccd in ccdList:
815  if not pixelSize_o == ccd.getPixelSize():
816  raise RuntimeError(
817  "Cameras with detectors with different pixel scales are not currently supported")
818 
819  dbbox = lsst.geom.Box2D()
820  for corner in ccd.getCorners(FOCAL_PLANE):
821  dbbox.include(corner)
822  llc = dbbox.getMin()
823  nQuarter = ccd.getOrientation().getNQuarter()
824  cbbox = ccd.getBBox()
825  ex = cbbox.getDimensions().getX()//binSize
826  ey = cbbox.getDimensions().getY()//binSize
827  bbox = lsst.geom.Box2I(
828  cbbox.getMin(), lsst.geom.Extent2I(int(ex), int(ey)))
829  bbox = rotateBBoxBy90(bbox, nQuarter, bbox.getDimensions())
830  bbox.shift(lsst.geom.Extent2I(int(llc.getX()//pixelSize_o.getX()/binSize),
831  int(llc.getY()//pixelSize_o.getY()/binSize)))
832  bbox.shift(lsst.geom.Extent2I(-int(origin.getX()//binSize),
833  -int(origin.getY())//binSize))
834  boxList.append(bbox)
835  return boxList
836 
837 
838 def getCameraImageBBox(camBbox, pixelSize, bufferSize):
839  """Get the bounding box of a camera sized image in pixels
840 
841  Parameters
842  ----------
843  camBbox : `lsst.geom.Box2D`
844  Camera bounding box in focal plane coordinates (mm).
845  pixelSize : `float`
846  Size of a detector pixel in mm.
847  bufferSize : `int`
848  Buffer around edge of image in pixels.
849 
850  Returns
851  -------
852  box : `lsst.geom.Box2I`
853  The resulting bounding box.
854  """
855  pixMin = lsst.geom.Point2I(int(camBbox.getMinX()//pixelSize.getX()),
856  int(camBbox.getMinY()//pixelSize.getY()))
857  pixMax = lsst.geom.Point2I(int(camBbox.getMaxX()//pixelSize.getX()),
858  int(camBbox.getMaxY()//pixelSize.getY()))
859  retBox = lsst.geom.Box2I(pixMin, pixMax)
860  retBox.grow(bufferSize)
861  return retBox
862 
863 
864 def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10,
865  imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1):
866  """Make an Image of a Camera.
867 
868  Put each detector's image in the correct location and orientation on the
869  focal plane. The input images can be binned to an integer fraction of their
870  original bboxes.
871 
872  Parameters
873  ----------
874  camera : `lsst.afw.cameraGeom.Camera`
875  Camera object to use to make the image.
876  detectorNameList : `list` [`str`]
877  List of detector names from ``camera`` to use in building the image.
878  Use all Detectors if `None`.
879  background : `float`
880  Value to use where there is no Detector.
881  bufferSize : `int`
882  Size of border in binned pixels to make around the camera image.
883  imageSource : `FakeImageDataSource` or `None`
884  Source to get ccd images. Must have a ``getCcdImage()`` method.
885  imageFactory : callable like `lsst.afw.image.Image`
886  Type of image to build.
887  binSize : `int`
888  Bin the image by this factor in both dimensions.
889 
890  Returns
891  -------
892  image : `lsst.afw.image.Image`
893  Image of the entire camera.
894  """
895  log = lsst.log.Log.getLogger("afw.cameraGeom.utils.makeImageFromCamera")
896 
897  if detectorNameList is None:
898  ccdList = camera
899  else:
900  ccdList = [camera[name] for name in detectorNameList]
901 
902  if detectorNameList is None:
903  camBbox = camera.getFpBBox()
904  else:
905  camBbox = lsst.geom.Box2D()
906  for detName in detectorNameList:
907  for corner in camera[detName].getCorners(FOCAL_PLANE):
908  camBbox.include(corner)
909 
910  pixelSize_o = camera[next(camera.getNameIter())].getPixelSize()
911  camBbox = getCameraImageBBox(camBbox, pixelSize_o, bufferSize*binSize)
912  origin = camBbox.getMin()
913 
914  camIm = imageFactory(int(math.ceil(camBbox.getDimensions().getX()/binSize)),
915  int(math.ceil(camBbox.getDimensions().getY()/binSize)))
916  camIm[:] = imageSource.background
917 
918  assert imageSource.isTrimmed, "isTrimmed is False isn't supported by getCcdInCamBBoxList"
919 
920  boxList = getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin)
921  for det, bbox in zip(ccdList, boxList):
922  im = imageSource.getCcdImage(det, imageFactory, binSize)[0]
923  if im is None:
924  continue
925 
926  imView = camIm.Factory(camIm, bbox, afwImage.LOCAL)
927  try:
928  imView[:] = im
929  except pexExceptions.LengthError as e:
930  log.error(f"Unable to fit image for detector \"{det.getName()}\" into image of camera: {e}")
931 
932  return camIm
933 
934 
935 def showCamera(camera, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageF,
936  detectorNameList=None, binSize=10, bufferSize=10, overlay=True, title="",
937  showWcs=None, ctype=afwDisplay.GREEN, textSize=1.25, originAtCenter=True, display=None,
938  **kwargs):
939  """Show a Camera on display, with the specified display.
940 
941  The rotation of the sensors is snapped to the nearest multiple of 90 deg.
942  Also note that the pixel size is constant over the image array. The lower
943  left corner (LLC) of each sensor amp is snapped to the LLC of the pixel
944  containing the LLC of the image.
945 
946  Parameters
947  ----------
948  camera : `lsst.afw.cameraGeom.Camera`
949  Camera object to use to make the image.
950  imageSource : `FakeImageDataSource` or `None`
951  Source to get ccd images. Must have a ``getCcdImage()`` method.
952  imageFactory : `lsst.afw.image.Image`
953  Type of image to make
954  detectorNameList : `list` [`str`] or `None`
955  List of detector names from `camera` to use in building the image.
956  Use all Detectors if `None`.
957  binSize : `int`
958  Bin the image by this factor in both dimensions.
959  bufferSize : `int`
960  Size of border in binned pixels to make around the camera image.
961  overlay : `bool`
962  Overlay Detector IDs and boundaries?
963  title : `str`
964  Title to use in display.
965  showWcs : `bool`
966  Include a WCS in the display?
967  ctype : `lsst.afw.display.COLOR` or `str`
968  Color to use when drawing Detector boundaries.
969  textSize : `float`
970  Size of detector labels
971  originAtCenter : `bool`
972  Put origin of the camera WCS at the center of the image?
973  If `False`, the origin will be at the lower left.
974  display : `lsst.afw.display`
975  Image display on which to display.
976  **kwargs :
977  All remaining keyword arguments are passed to makeImageFromCamera
978 
979  Returns
980  -------
981  image : `lsst.afw.image.Image`
982  The mosaic image.
983  """
984  display = _getDisplayFromDisplayOrFrame(display)
985 
986  if binSize < 1:
987  binSize = 1
988  cameraImage = makeImageFromCamera(camera, detectorNameList=detectorNameList, bufferSize=bufferSize,
989  imageSource=imageSource, imageFactory=imageFactory, binSize=binSize,
990  **kwargs)
991 
992  if detectorNameList is None:
993  ccdList = [camera[name] for name in camera.getNameIter()]
994  else:
995  ccdList = [camera[name] for name in detectorNameList]
996 
997  if detectorNameList is None:
998  camBbox = camera.getFpBBox()
999  else:
1000  camBbox = lsst.geom.Box2D()
1001  for detName in detectorNameList:
1002  for corner in camera[detName].getCorners(FOCAL_PLANE):
1003  camBbox.include(corner)
1004  pixelSize = ccdList[0].getPixelSize()
1005 
1006  if showWcs:
1007  if originAtCenter:
1008  wcsReferencePixel = lsst.geom.Box2D(
1009  cameraImage.getBBox()).getCenter()
1010  else:
1011  wcsReferencePixel = lsst.geom.Point2I(0, 0)
1012  wcs = makeFocalPlaneWcs(pixelSize*binSize, wcsReferencePixel)
1013  else:
1014  wcs = None
1015 
1016  if display:
1017  if title == "":
1018  title = camera.getName()
1019  display.mtv(cameraImage, title=title, wcs=wcs)
1020 
1021  if overlay:
1022  with display.Buffering():
1023  camBbox = getCameraImageBBox(
1024  camBbox, pixelSize, bufferSize*binSize)
1025  bboxList = getCcdInCamBBoxList(
1026  ccdList, binSize, pixelSize, camBbox.getMin())
1027  for bbox, ccd in zip(bboxList, ccdList):
1028  nQuarter = ccd.getOrientation().getNQuarter()
1029  # borderWidth to 0.5 to align with the outside edge of the
1030  # pixel
1031  displayUtils.drawBBox(
1032  bbox, borderWidth=0.5, ctype=ctype, display=display)
1033  dims = bbox.getDimensions()
1034  display.dot(ccd.getName(), bbox.getMinX() + dims.getX()/2, bbox.getMinY() + dims.getY()/2,
1035  ctype=ctype, size=textSize, textAngle=nQuarter*90)
1036 
1037  return cameraImage
1038 
1039 
1040 def makeFocalPlaneWcs(pixelSize, referencePixel):
1041  """Make a WCS for the focal plane geometry
1042  (i.e. one that returns positions in "mm")
1043 
1044  Parameters
1045  ----------
1046  pixelSize : `float`
1047  Size of the image pixels in physical units
1048  referencePixel : `lsst.geom.Point2D`
1049  Pixel for origin of WCS
1050 
1051  Returns
1052  -------
1053  `lsst.afw.geom.Wcs`
1054  Wcs object for mapping between pixels and focal plane.
1055  """
1056  md = dafBase.PropertySet()
1057  if referencePixel is None:
1058  referencePixel = lsst.geom.PointD(0, 0)
1059  for i in range(2):
1060  md.set("CRPIX%d"%(i + 1), referencePixel[i])
1061  md.set("CRVAL%d"%(i + 1), 0.)
1062  md.set("CDELT1", pixelSize[0])
1063  md.set("CDELT2", pixelSize[1])
1064  md.set("CTYPE1", "CAMERA_X")
1065  md.set("CTYPE2", "CAMERA_Y")
1066  md.set("CUNIT1", "mm")
1067  md.set("CUNIT2", "mm")
1068 
1069  return afwGeom.makeSkyWcs(md)
1070 
1071 
1072 def findAmp(ccd, pixelPosition):
1073  """Find the Amp with the specified pixel position within the composite
1074 
1075  Parameters
1076  ----------
1077  ccd : `lsst.afw.cameraGeom.Detector`
1078  Detector to look in.
1079  pixelPosition : `lsst.geom.Point2I`
1080  The pixel position to find the amp for.
1081 
1082  Returns
1083  -------
1084  `lsst.afw.table.AmpInfoCatalog`
1085  Amp record in which ``pixelPosition`` falls or `None` if no Amp found.
1086  """
1087  for amp in ccd:
1088  if amp.getBBox().contains(pixelPosition):
1089  return amp
1090 
1091  return None
def makeImageFromAmp(amp, imValue=None, imageFactory=afwImage.ImageU, markSize=10, markValue=0, scaleGain=lambda gain:(gain *1000)//10)
Definition: utils.py:186
Angle abs(Angle const &a)
Definition: Angle.h:106
def makeFocalPlaneWcs(pixelSize, referencePixel)
Definition: utils.py:1040
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
def plotFocalPlane(camera, fieldSizeDeg_x=0, fieldSizeDeg_y=None, dx=0.1, dy=0.1, figsize=(10., 10.), useIds=False, showFig=True, savePath=None)
Definition: utils.py:89
Reports attempts to exceed implementation-defined length limits for some classes. ...
Definition: Runtime.h:76
def getCcdInCamBBoxList(ccdList, binSize, pixelSize_o, origin)
Definition: utils.py:794
def getCcdImage(self, det, imageFactory, binSize)
Definition: utils.py:361
int min
def findAmp(ccd, pixelPosition)
Definition: utils.py:1072
def getCameraImageBBox(camBbox, pixelSize, bufferSize)
Definition: utils.py:838
Definition: Log.h:706
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
The makeStatistics() overload to handle lsst::afw::math::MaskedVector<>
Definition: Statistics.h:520
def getAmpImage(self, amp, imageFactory)
Definition: utils.py:382
def __init__(self, isTrimmed=True, verbose=False, background=numpy.nan, showAmpGain=True, markSize=10, markValue=0, ampImValue=None, scaleGain=lambda gain:(gain *1000)//10)
Definition: utils.py:351
def _prepareImage(self, ccd, im, binSize, allowRotate=True)
Definition: utils.py:449
def makeImageFromCamera(camera, detectorNameList=None, background=numpy.nan, bufferSize=10, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageU, binSize=1)
Definition: utils.py:865
std::shared_ptr< SkyWcs > makeFlippedWcs(SkyWcs const &wcs, bool flipLR, bool flipTB, lsst::geom::Point2D const &center)
Return a copy of a FITS-WCS with pixel positions flipped around a specified center.
Definition: SkyWcs.cc:472
def __init__(self, butler=None, type="raw", isTrimmed=True, verbose=False, background=numpy.nan, callback=None, args, kwargs)
Definition: utils.py:438
def makeImageFromCcd(ccd, isTrimmed=True, showAmpGain=True, imageFactory=afwImage.ImageU, rcMarkSize=10, binSize=1)
Definition: utils.py:272
def rawCallback(im, ccd=None, imageSource=None, correctGain=False, subtractBias=False, convertToFloat=False, obeyNQuarter=True)
Definition: utils.py:522
def showCamera(camera, imageSource=FakeImageDataSource(), imageFactory=afwImage.ImageF, detectorNameList=None, binSize=10, bufferSize=10, overlay=True, title="", showWcs=None, ctype=afwDisplay.GREEN, textSize=1.25, originAtCenter=True, display=None, kwargs)
Definition: utils.py:938
int max
std::shared_ptr< ImageT > rotateImageBy90(ImageT const &image, int nQuarter)
Rotate an image by an integral number of quarter turns.
Definition: rotateImage.cc:39
def assembleAmplifierImage(destImage, rawImage, amplifier)
def showAmp(amp, imageSource=FakeImageDataSource(isTrimmed=False), display=None, overlay=True, imageFactory=afwImage.ImageU)
Definition: utils.py:695
static Log getLogger(Log const &logger)
Definition: Log.h:760
def showCcd(ccd, imageSource=FakeImageDataSource(), display=None, overlay=True, imageFactory=afwImage.ImageF, binSize=1, inCameraCoords=False)
Definition: utils.py:744
def prepareWcsData(wcs, amp, isTrimmed=True)
Definition: utils.py:54
std::shared_ptr< SkyWcs > makeSkyWcs(TransformPoint2ToPoint2 const &pixelsToFieldAngle, lsst::geom::Angle const &orientation, bool flipX, lsst::geom::SpherePoint const &boresight, std::string const &projection="TAN")
Construct a FITS SkyWcs from camera geometry.
Definition: SkyWcs.cc:536
Class for storing generic metadata.
Definition: PropertySet.h:67
std::shared_ptr< ImageT > binImage(ImageT const &inImage, int const binsize, lsst::afw::math::Property const flags=lsst::afw::math::MEAN)
Definition: binImage.cc:38
def assembleAmplifierRawImage(destImage, rawImage, amplifier)
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
def overlayCcdBoxes(ccd, untrimmedCcdBbox=None, nQuarter=0, isTrimmed=False, ccdOrigin=(0, 0), display=None, binSize=1)
Definition: utils.py:595
An integer coordinate rectangle.
Definition: Box.h:55
def rotateBBoxBy90(bbox, n90, dimensions)
def getCcdImage(self, ccd, imageFactory=afwImage.ImageF, binSize=1, asMaskedImage=False)
Definition: utils.py:459