31 "drawBBox",
"drawFootprint",
"drawCoaddInputs",
35 def _getDisplayFromDisplayOrFrame(display, frame=None):
36 """Return an `lsst.afw.display.Display` given either a display or a frame ID.
40 If the two arguments are consistent, return the desired display; if they are not,
41 raise a `RuntimeError` exception.
43 If the desired display is `None`, return `None`;
44 if ``(display, frame) == ("deferToFrame", None)``, return the default display
50 if display
in (
"deferToFrame",
None):
51 if display
is None and frame
is None:
57 if display
and not hasattr(display,
"frame"):
58 raise RuntimeError(f
"display == {display} doesn't support .frame")
60 if frame
and display
and display.frame != frame:
61 raise RuntimeError(
"Please specify display *or* frame")
66 display = afwDisplay.getDisplay(frame, create=
True)
72 """A class to handle mosaics of one or more identically-sized images
73 (or `~lsst.afw.image.Mask` or `~lsst.afw.image.MaskedImage`)
77 Note that this mosaic is a patchwork of the input images; if you want to
78 make a mosaic of a set images of the sky, you probably want to use the coadd code
88 m.setMode("square") # the default; other options are "x" or "y"
90 mosaic = m.makeMosaic(im1, im2, im3) # build the mosaic
91 display = afwDisplay.getDisplay()
92 display.mtv(mosaic) # display it
93 m.drawLabels(["Label 1", "Label 2", "Label 3"], display) # label the panels
95 # alternative way to build a mosaic
96 images = [im1, im2, im3]
97 labels = ["Label 1", "Label 2", "Label 3"]
99 mosaic = m.makeMosaic(images)
101 m.drawLabels(labels, display)
103 # Yet another way to build a mosaic (no need to build the images/labels lists)
104 for i in range(len(images)):
105 m.append(images[i], labels[i])
106 # You may optionally include a colour, e.g. afwDisplay.YELLOW, as a third argument
108 mosaic = m.makeMosaic()
110 m.drawLabels(display=display)
116 mosaic = m.makeMosaic(display=display)
118 You can return the (ix, iy)th (or nth) bounding box (in pixels) with `getBBox()`
121 def __init__(self, gutter=3, background=0, mode="square"):
131 """Reset the list of images to be mosaiced"""
135 def append(self, image, label=None, ctype=None):
136 """Add an image to the list of images to be mosaiced
141 the index of this image (may be passed to `getBBox()`)
145 Set may be cleared with ``Mosaic.reset()``
148 self.
xsize = image.getWidth()
149 self.
ysize = image.getHeight()
156 def makeMosaic(self, images=None, display="deferToFrame", mode=None,
157 background=None, title=""):
158 """Return a mosaic of all the images provided.
160 If none are specified, use the list accumulated with `Mosaic.append()`.
162 If display is specified, display the mosaic
168 f
"You have already appended {len(self.images)} images to this Mosaic")
180 raise RuntimeError(
"You must provide at least one image")
184 w, h = im.getWidth(), im.getHeight()
190 if background
is None:
197 while nx*im.getWidth() < ny*im.getHeight():
209 assert(nx*ny >= self.
nImage)
214 elif isinstance(mode, int):
220 raise RuntimeError(f
"Unknown mosaicing mode: {mode}")
222 self.nx, self.
ny = nx, ny
230 except AttributeError:
231 raise RuntimeError(f
"Attempt to mosaic images of type {type(mosaic)} which don't support set")
233 for i
in range(len(images)):
234 smosaic = mosaic.Factory(
235 mosaic, self.
getBBox(i%nx, i//nx), afwImage.LOCAL)
238 if smosaic.getDimensions() != im.getDimensions():
240 (smosaic.getHeight() - im.getHeight())//2)
242 llc, im.getDimensions()), afwImage.LOCAL)
246 display = _getDisplayFromDisplayOrFrame(display)
248 display.mtv(mosaic, title=title)
256 """Set the number of pixels between panels in a mosaic
261 """Set the value in the gutters
266 """Set mosaicing mode.
270 mode : {"square", "x", "y"}
274 Make mosaic as square as possible
276 Make mosaic one image high
278 Make mosaic one image wide
281 if mode
not in (
"square",
"x",
"y"):
282 raise RuntimeError(f
"Unknown mosaicing mode: {mode}")
287 """Get the BBox for a panel
292 If ``iy`` is not `None`, this is the x coordinate of the panel.
293 If ``iy`` is `None`, this is the number of the panel.
295 The y coordinate of the panel.
299 ix, iy = ix % self.nx, ix//self.nx
304 def drawLabels(self, labels=None, display="deferToFrame", frame=None):
305 """Draw the list labels at the corners of each panel.
309 If labels is None, use the ones specified by ``Mosaic.append()``
318 if len(labels) != self.
nImage:
319 raise RuntimeError(f
"You provided {len(labels)} labels for {self.nImage} panels")
321 display = _getDisplayFromDisplayOrFrame(display, frame)
325 with display.Buffering():
326 for i
in range(len(labels)):
328 label, ctype = labels[i],
None
337 display.dot(str(label), self.
getBBox(i).getMinX(),
338 self.
getBBox(i).getMinY(), ctype=ctype)
347 def drawBBox(bbox, borderWidth=0.0, origin=None, display="deferToFrame", ctype=None, bin=1, frame=None):
348 """Draw a bounding box on a display frame with the specified ctype.
352 bbox : `lsst.geom.Box2I` or `lsst.geom.Box2D`
354 borderWidth : `float`
355 Include this many pixels
357 If specified, the box is shifted by ``origin``
360 The desired color, either e.g. `lsst.afw.display.RED` or a color name known to X11
362 All BBox coordinates are divided by bin, as is right and proper for overlaying on a binned image
365 x0, y0 = bbox.getMinX(), bbox.getMinY()
366 x1, y1 = bbox.getMaxX(), bbox.getMaxY()
380 display = _getDisplayFromDisplayOrFrame(display, frame)
381 display.line([(x0 - borderWidth, y0 - borderWidth),
382 (x0 - borderWidth, y1 + borderWidth),
383 (x1 + borderWidth, y1 + borderWidth),
384 (x1 + borderWidth, y0 - borderWidth),
385 (x0 - borderWidth, y0 - borderWidth),
389 def drawFootprint(foot, borderWidth=0.5, origin=None, XY0=None, frame=None, ctype=None, bin=1,
390 peaks=False, symb="+", size=0.4, ctypePeak=None, display="deferToFrame"):
391 """Draw an `lsst.afw.detection.Footprint` on a display frame with the specified ctype.
395 foot : `lsst.afw.detection.Footprint`
396 borderWidth : `float`
397 Include an extra borderWidth pixels
399 If ``origin`` is present, it's arithmetically added to the Footprint
401 if ``XY0`` is present is subtracted from the Footprint
404 The desired color, either e.g. `lsst.afw.display.RED` or a color name known to X11
406 All Footprint coordinates are divided by bin, as is right and proper
407 for overlaying on a binned image
409 If peaks is `True`, also show the object's Peaks using the specified
410 ``symb`` and ``size`` and ``ctypePeak``
414 The desired color for peaks, either e.g. `lsst.afw.display.RED` or a color name known to X11
420 raise RuntimeError(
"You may not specify both origin and XY0")
421 origin = (-XY0[0], -XY0[1])
423 display = _getDisplayFromDisplayOrFrame(display, frame)
424 with display.Buffering():
426 for s
in foot.getSpans():
427 y, x0, x1 = s.getY(), s.getX0(), s.getX1()
438 display.line([(x0 - borderWidth, y - borderWidth),
439 (x0 - borderWidth, y + borderWidth),
440 (x1 + borderWidth, y + borderWidth),
441 (x1 + borderWidth, y - borderWidth),
442 (x0 - borderWidth, y - borderWidth),
446 for p
in foot.getPeaks():
447 x, y = p.getIx(), p.getIy()
456 display.dot(symb, x, y, size=size, ctype=ctypePeak)
460 """Draw the bounding boxes of input exposures to a coadd on a display
461 frame with the specified ctype, assuming ``display.mtv()`` has already been
462 called on the given exposure on this frame.
464 All coordinates are divided by ``bin``, as is right and proper for overlaying on a binned image
466 coaddWcs = exposure.getWcs()
467 catalog = exposure.getInfo().getCoaddInputs().ccds
471 display = _getDisplayFromDisplayOrFrame(display, frame)
473 with display.Buffering():
474 for record
in catalog:
476 ccdCorners = ccdBox.getCorners()
477 coaddCorners = [coaddWcs.skyToPixel(record.getWcs().pixelToSky(point)) + offset
478 for point
in ccdCorners]
479 display.line([(coaddCorners[i].getX()/bin, coaddCorners[i].getY()/bin)
480 for i
in range(-1, 4)], ctype=ctype)