def stitchTestDeepCoadd(): w13Db = dbOpen("~/.mysqlAuthLSST.lsst10", W13DeepCoaddDb) fullImg, metaFull = w13Db.getImageFullWithMetadata(19.36995, -0.3146, 'r') if fullImg == None: print("No image found") exit() # cut the image into quarters imgW = fullImg.getWidth() imgH = fullImg.getHeight() # ulImg - Upper Left image ulImg = _getSubImg(fullImg, [0, 0, imgW / 2, imgH / 2]) urImg = _getSubImg(fullImg, [(imgW / 2) + 1, 0, imgW, imgH / 2]) llImg = _getSubImg(fullImg, [0, (imgH / 2) + 1, imgW / 2, imgH]) lrImg = _getSubImg(fullImg, [(imgW / 2) + 1, (imgH / 2) + 1, imgW, imgH]) expoList = [ulImg, urImg, llImg, lrImg] fullImg.writeFits("full.fits") ulImg.writeFits("ul.fits") urImg.writeFits("ur.fits") llImg.writeFits("ll.fits") lrImg.writeFits("lr.fits") #fullWcs = lsst.afw.image.makeWcs(metaFull, False) fullWcs = fullImg.getWcs() fullImg.setWcs(fullWcs) srcExpo = ulImg srcWcs = fullWcs srcBBox = afwGeom.Box2I( afwGeom.Point2I(srcExpo.getX0(), srcExpo.getY0()), afwGeom.Extent2I(srcExpo.getWidth(), srcExpo.getHeight())) destBBox = afwGeom.Box2I(afwGeom.Point2I(fullImg.getX0(), fullImg.getY0()), afwGeom.Extent2I(imgW, imgH)) destWcs = fullWcs #destExpo = afwImage.ExposureF(destBBox, destWcs) config = CoaddConfig() warperConfig = afwMath.WarperConfig() warper = afwMath.Warper.fromConfig(warperConfig) stitchedExpo = stitchExposures(destWcs, destBBox, expoList, config.coadd, warper) stitchedExpo.writeFits("stitched.fits") return
def get(self, center_coord, width, height, filt, units): """Merge multiple patches from a SkyMap into a single image. This function takes advantage of the fact that all tracts in a SkyMap share the same WCS and should have identical pixels where they overlap. @center_coord: base coordinate of the box RA and Dec (minimum values, lower left corner) @width: in arcsec or pixel @height: in arcsec or pixel @filt: valid filter for the data set such as 'i', 'r', 'g' @units: 'pixel' or 'arcsecond' (defaults to 'pixel') """ dest_tract_info = self._skymap.findTract(center_coord) dest_wcs = dest_tract_info.getWcs() # Determine target area. if units != "arcsec" and units != "arcsecond" and units != "pixel": units = "pixel" dest_bbox = self._bbox_for_coords(dest_wcs, center_coord, width, height, units) dest_corner_coords = [ dest_wcs.pixelToSky(pixPos) for pixPos in afw_geom.Box2D(dest_bbox).getCorners() ] # Collect patches of the SkyMap that are in the target region. # Create source exposures from the patches within each tract # as all patches from a tract share a WCS. exposure_list = [] tract_patch_list = self._skymap.findTractPatchList(dest_corner_coords) for j, tract_patch in enumerate(tract_patch_list): tract_info = tract_patch[0] patch_list = tract_patch[1] self._log.info("tract_info[{}]={}".format(j, tract_info)) self._log.info("patch_list[{}]={}".format(j, patch_list)) src_wcs = tract_info.getWcs() src_bbox = afw_geom.Box2I() for patch_info in patch_list: src_bbox.include(patch_info.getOuterBBox()) src_exposure = afw_image.ExposureF(src_bbox, src_wcs) # blank, # so far exposure_list.append(src_exposure) # load srcExposures with patches tract_id = tract_info.getId() for patch_info in patch_list: patch_index = patch_info.getIndex() patch_index_str = ','.join(str(i) for i in patch_index) self._log.info("butler.get dataId=filter:{}, tract:{}, " "patch:{}".format(filt, tract_id, patch_index_str)) patch_exposure = self._butler.get("deepCoadd", dataId={ "filter": filt, "tract": tract_id, "patch": patch_index_str }) src_view = afw_image.ExposureF(src_exposure, patch_exposure.getBBox()) src_view_img = src_view.getMaskedImage() patch_img = patch_exposure.getMaskedImage() src_view_img[:] = patch_img # Copy the pixels from the source exposures to the destination # exposures. dest_exposure_list = [] for j, src_exposure in enumerate(exposure_list): src_image = src_exposure.getMaskedImage() src_wcs = src_exposure.getWcs() if j == 0: expo_bbox = dest_bbox # dest_bbox only correct for first image else: # Determine the correct BBox (in pixels) for the current src_wcs ll_corner = afw_geom.Point2I( src_wcs.skyToPixel(dest_corner_coords[0])) ur_corner = afw_geom.Point2I( src_wcs.skyToPixel(dest_corner_coords[2])) # Handle negative values for in expo_bbox. if ll_corner.getX() < 0: ll_corner.setX(0) if ll_corner.getY() < 0: ll_corner.setY(0) if ur_corner.getX() < 0: ur_corner.setX(0) self._log.warn("getSkyMap negative X for ur_corner") if ur_corner.getY() < 0: ur_corner.setY(0) self._log.warn("getSkyMap negative Y for ur_corner") expo_bbox = afw_geom.Box2I(ll_corner, ur_corner) self._log.info("j={} expo_bbox={} sBBox={}".format( j, expo_bbox, src_exposure.getBBox())) dest_exposure = afw_image.ExposureF(expo_bbox, src_wcs) dest_img = dest_exposure.getMaskedImage() begin_x = expo_bbox.getBeginX() - src_image.getX0() end_x = expo_bbox.getEndX() - src_image.getX0() begin_y = expo_bbox.getBeginY() - src_image.getY0() end_y = expo_bbox.getEndY() - src_image.getY0() new_width = src_exposure.getBBox().getEndX() - expo_bbox.getBeginX( ) new_height = src_exposure.getBBox().getEndY( ) - expo_bbox.getBeginY() # Do a final check to make sure that the we're not going past the # end of src_image. src_img_len_x = src_image.getWidth() if end_x > src_img_len_x: new_width = src_img_len_x - begin_x end_x = src_img_len_x s_img_len_y = src_image.getHeight() if end_y > s_img_len_y: new_width = s_img_len_y - begin_y end_y = s_img_len_y self._log.debug("begin_x={} end_x={}".format(begin_x, end_x)) self._log.debug( "new_width{} = sBBox.EndX{} - sBBox.BeginX{}".format( new_width, src_exposure.getBBox().getEndX(), expo_bbox.getBeginX())) self._log.debug("begin_y={} end_y={}".format(begin_y, end_y)) self._log.debug( "new_height{} = sBBox.EndY{} - sBBox.BeginY{}".format( new_height, src_exposure.getBBox().getEndY(), expo_bbox.getBeginY())) if isinstance(src_exposure, afw_image.Exposure): dest_exposure = afw_image.ExposureF(src_exposure, expo_bbox) else: dest_img[0:new_width, 0:new_height] = src_image[begin_x:end_x, begin_y:end_y] # notice that dest_img is operating on dest_exposure dest_exposure_list.append(dest_exposure) # If there's only one exposure in the list (and there usually is) just # return it. if len(dest_exposure_list) == 1: return dest_exposure_list[0] # Need to stitch together the multiple destination exposures. self._log.debug( "SkymapImage: stitching together multiple destExposures") warper_config = afw_math.WarperConfig() warper = afw_math.Warper.fromConfig(warper_config) stitched_exposure = self._stitch_exposures_good_pixel_copy( dest_wcs, dest_bbox, dest_exposure_list, warper) return stitched_exposure