26 from __future__
import absolute_import, division, print_function
33 "drawBBox",
"drawFootprint",
"drawCoaddInputs",
37 """!Return an afwDisplay.Display given either a display or a frame ID.
39 If the two arguments are consistent, return the desired display; if they are not,
40 raise a RuntimeError exception.
42 If the desired display is None, return None;
43 if (display, frame) == ("deferToFrame", None), return the default display"""
47 if display
in (
"deferToFrame",
None):
48 if display
is None and frame
is None:
54 if display
and not hasattr(display,
"frame"):
55 raise RuntimeError(
"display == %s doesn't support .frame" % display)
57 if frame
and display
and display.frame != frame:
58 raise RuntimeError(
"Please specify display *or* frame")
63 display = afwDisplay.getDisplay(frame, create=
True)
70 """A class to handle mosaics of one or more identically-sized images (or Masks or MaskedImages)
75 m.setMode("square") # the default; other options are "x" or "y"
77 mosaic = m.makeMosaic(im1, im2, im3) # build the mosaic
78 display = afwDisplay.getDisplay()
79 display.mtv(mosaic) # display it
80 m.drawLabels(["Label 1", "Label 2", "Label 3"], display) # label the panels
82 # alternative way to build a mosaic
83 images = [im1, im2, im3]
84 labels = ["Label 1", "Label 2", "Label 3"]
86 mosaic = m.makeMosaic(images)
88 m.drawLabels(labels, display)
90 # Yet another way to build a mosaic (no need to build the images/labels lists)
91 for i in range(len(images)):
92 m.append(images[i], labels[i])
93 # You may optionally include a colour, e.g. afwDisplay.YELLOW, as a third argument
95 mosaic = m.makeMosaic()
97 m.drawLabels(display=display)
100 mosaic = m.makeMosaic(display=display)
102 You can return the (ix, iy)th (or nth) bounding box (in pixels) with getBBox()
104 def __init__(self, gutter=3, background=0, mode="square"):
114 """Reset the list of images to be mosaiced"""
118 def append(self, image, label=None, ctype=None):
119 """Add an image to the list of images to be mosaiced
120 Set may be cleared with Mosaic.reset()
122 Returns the index of this image (may be passed to getBBox())
125 self.
xsize = image.getWidth()
126 self.
ysize = image.getHeight()
128 self.images.append(image)
129 self.labels.append((label, ctype))
133 def makeMosaic(self, images=None, display="deferToFrame", mode=None, background=None, title="", frame=None):
134 """Return a mosaic of all the images provided; if none are specified,
135 use the list accumulated with Mosaic.append().
137 Note that this mosaic is a patchwork of the input images; if you want to
138 make a mosaic of a set images of the sky, you probably want to use the coadd code
140 If display or frame (deprecated) is specified, display the mosaic
148 raise RuntimeError,
"You must provide at least one image"
152 w, h = im.getWidth(), im.getHeight()
158 if background
is None:
165 while nx*im.getWidth() < ny*im.getHeight():
177 assert(nx*ny >= self.
nImage)
182 elif isinstance(mode, int):
188 raise RuntimeError, (
"Unknown mosaicing mode: %s" % mode)
190 self.nx, self.
ny = nx, ny
192 mosaic = images[0].Factory(
197 except AttributeError:
198 raise RuntimeError(
"Attempt to mosaic images of type %s which don't support set" %
201 for i
in range(len(images)):
202 smosaic = mosaic.Factory(mosaic, self.
getBBox(i%nx, i//nx), afwImage.LOCAL)
205 if smosaic.getDimensions() != im.getDimensions():
207 (smosaic.getHeight() - im.getHeight())//2)
208 smosaic = smosaic.Factory(smosaic,
afwGeom.Box2I(llc, im.getDimensions()), afwImage.LOCAL)
214 display.mtv(mosaic, title=title)
222 """Set the number of pixels between panels in a mosaic"""
226 """Set the value in the gutters"""
230 """Set mosaicing mode. Valid options:
231 square Make mosaic as square as possible
232 x Make mosaic one image high
233 y Make mosaic one image wide
236 if mode
not in (
"square",
"x",
"y"):
237 raise RuntimeError, (
"Unknown mosaicing mode: %s" % mode)
242 """Get the BBox for the nth or (ix, iy)the panel"""
245 ix, iy = ix % self.nx, ix//self.nx
250 def drawLabels(self, labels=None, display="deferToFrame", frame=None):
251 """Draw the list labels at the corners of each panel. If labels is None, use the ones
252 specified by Mosaic.append()"""
260 if len(labels) != self.
nImage:
261 raise RuntimeError, (
"You provided %d labels for %d panels" % (len(labels), self.
nImage))
267 with display.Buffering():
268 for i
in range(len(labels)):
270 label, ctype = labels[i],
None
279 display.dot(str(label), self.
getBBox(i).getMinX(), self.
getBBox(i).getMinY(), ctype=ctype)
281 def drawBBox(bbox, borderWidth=0.0, origin=None, display="deferToFrame", ctype=None, bin=1, frame=None):
282 """Draw an afwImage::BBox on a display frame with the specified ctype. Include an extra borderWidth pixels
283 If origin is present, it's Added to the BBox
285 All BBox coordinates are divided by bin, as is right and proper for overlaying on a binned image
287 x0, y0 = bbox.getMinX(), bbox.getMinY()
288 x1, y1 = bbox.getMaxX(), bbox.getMaxY()
291 x0 += origin[0]; x1 += origin[0]
292 y0 += origin[1]; y1 += origin[1]
299 display.line([(x0 - borderWidth, y0 - borderWidth),
300 (x0 - borderWidth, y1 + borderWidth),
301 (x1 + borderWidth, y1 + borderWidth),
302 (x1 + borderWidth, y0 - borderWidth),
303 (x0 - borderWidth, y0 - borderWidth),
306 def drawFootprint(foot, borderWidth=0.5, origin=None, XY0=None, frame=None, ctype=None, bin=1,
307 peaks=
False, symb=
"+", size=0.4, ctypePeak=
None, display=
"deferToFrame"):
308 """Draw an afwDetection::Footprint on a display frame with the specified ctype. Include an extra borderWidth
309 pixels If origin is present, it's Added to the Footprint; if XY0 is present is Subtracted from the Footprint
311 If peaks is True, also show the object's Peaks using the specified symbol and size and ctypePeak
313 All Footprint coordinates are divided by bin, as is right and proper for overlaying on a binned image
318 raise RuntimeError(
"You may not specify both origin and XY0")
319 origin = (-XY0[0], -XY0[1])
322 with display.Buffering():
324 for s
in foot.getSpans():
325 y, x0, x1 = s.getY(), s.getX0(), s.getX1()
328 x0 += origin[0]; x1 += origin[0]
331 x0 /= bin; x1 /= bin; y /= bin
333 display.line([(x0 - borderWidth, y - borderWidth),
334 (x0 - borderWidth, y + borderWidth),
335 (x1 + borderWidth, y + borderWidth),
336 (x1 + borderWidth, y - borderWidth),
337 (x0 - borderWidth, y - borderWidth),
341 for p
in foot.getPeaks():
342 x, y = p.getIx(), p.getIy()
345 x += origin[0]; y += origin[1]
349 display.dot(symb, x, y, size=size, ctype=ctypePeak)
352 """Draw the bounding boxes of input exposures to a coadd on a display frame with the specified ctype,
353 assuming display.mtv() has already been called on the given exposure on this frame.
356 All coordinates are divided by bin, as is right and proper for overlaying on a binned image
358 coaddWcs = exposure.getWcs()
359 catalog = exposure.getInfo().getCoaddInputs().ccds
365 with display.Buffering():
366 for record
in catalog:
368 ccdCorners = ccdBox.getCorners()
369 coaddCorners = [coaddWcs.skyToPixel(record.getWcs().pixelToSky(point)) + offset
370 for point
in ccdCorners]
371 display.line([(coaddCorners[i].getX()/bin, coaddCorners[i].getY()/bin)
372 for i
in range(-1, 4)], ctype=ctype)
An integer coordinate rectangle.
def _getDisplayFromDisplayOrFrame
Return an afwDisplay.Display given either a display or a frame ID.
A floating-point coordinate rectangle geometry.