38 """Result of deblending a single parent Footprint."""
42 Creates a result object for the given parent Footprint 'fp'.
44 @param[in] fp Footprint
45 @param[in,out] peaks If specified, the list of peaks to use; default is
52 for pki, pk
in enumerate(peaks):
56 self.peaks.append(pkres)
65 Result of deblending a single Peak within a parent Footprint.
67 There is one of these objects for each Peak in the Footprint.
139 return ((
'Per-peak deblend result: outOfBounds: %s, deblendedAsPsf: %s') %
153 Return a HeavyFootprint containing the flux apportioned to this peak.
155 @param[in] strayFlux include stray flux also?
164 self.strayFlux.normalize()
165 heavy = afwDet.mergeHeavyFootprintsF(heavy, self.
strayFlux)
223 def deblend(footprint, maskedImage, psf, psffwhm,
224 psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, fitPsfs=
True,
225 medianSmoothTemplate=
True, medianFilterHalfsize=2,
226 monotonicTemplate=
True, weightTemplates=
False,
227 log=
None, verbose=
False, sigma1=
None, maxNumberOfPeaks=0,
228 findStrayFlux=
True, assignStrayFlux=
True,
229 strayFluxToPointSources=
'necessary', strayFluxAssignment=
'r-to-peak',
230 rampFluxAtEdge=
False, patchEdges=
False, tinyFootprintSize=2,
231 getTemplateSum=
False,
232 clipStrayFluxFraction=0.001, clipFootprintToNonzero=
True,
235 Deblend a single ``footprint`` in a ``maskedImage``.
237 Each ``Peak`` in the ``Footprint`` will produce a deblended child.
239 psfChisqCut1, psfChisqCut2: used when deciding whether a given
240 peak looks like a point source. We build a small local model of
241 background + peak + neighboring peaks. These are the
242 chi-squared-per-degree-of-freedom cuts (1=without and 2=with terms
243 allowing the peak position to move); larger values will result in
244 more peaks being classified as PSFs.
246 psfChisqCut2b: if the with-decenter fit is accepted, we then
247 apply the computed dx,dy to the source position and re-fit without
248 decentering. The model is accepted if its chi-squared-per-DOF is
249 less than this value.
251 maxNumberOfPeaks: if positive, only deblend the brightest
252 maxNumberOfPeaks peaks in the parent
256 butils = deb.BaselineUtilsF
258 validStrayPtSrc = [
'never',
'necessary',
'always']
259 validStrayAssign = [
'r-to-peak',
'r-to-footprint',
'nearest-footprint',
'trim']
260 if not strayFluxToPointSources
in validStrayPtSrc:
261 raise ValueError(((
'strayFluxToPointSources: value \"%s\" not in the '
262 +
'set of allowed values: ')
263 % strayFluxToPointSources) + str(validStrayPtSrc))
264 if not strayFluxAssignment
in validStrayAssign:
265 raise ValueError(((
'strayFluxAssignment: value \"%s\" not in the '
266 +
'set of allowed values: ')
267 % strayFluxAssignment) + str(validStrayAssign))
272 component =
'meas_deblender.baseline'
276 pexLogging.Trace.setVerbosity(component, -pexLogging.Log.DEBUG)
278 img = maskedImage.getImage()
279 varimg = maskedImage.getVariance()
280 mask = maskedImage.getMask()
284 peaks = fp.getPeaks()
285 if maxNumberOfPeaks > 0:
286 peaks = peaks[:maxNumberOfPeaks]
291 if not imbb.contains(bb):
292 raise ValueError((
'Footprint bounding-box %s extends outside image '
293 +
'bounding-box %s') % (str(bb), str(imbb)))
294 W, H = bb.getWidth(), bb.getHeight()
295 x0, y0 = bb.getMinX(), bb.getMinY()
296 x1, y1 = bb.getMaxX(), bb.getMaxY()
302 sigma1 = math.sqrt(stats.getValue(afwMath.MEDIAN))
303 log.logdebug(
'Estimated sigma1 = %f' % sigma1)
310 _fitPsfs(fp, peaks, res, log, psf, psffwhm, img, varimg,
311 psfChisqCut1, psfChisqCut2, psfChisqCut2b,
312 tinyFootprintSize=tinyFootprintSize)
315 log.logdebug((
'Creating templates for footprint at x0,y0,W,H = ' +
316 '(%i, %i, %i, %i)') % (x0, y0, W, H))
317 for peaki, pkres
in enumerate(res.peaks):
318 log.logdebug(
'Deblending peak %i of %i' % (peaki, len(res.peaks)))
319 if pkres.skip
or pkres.deblendedAsPsf:
322 cx, cy = pk.getIx(), pk.getIy()
324 log.logdebug(
'Peak center is not inside image; skipping %i' % pkres.pki)
325 pkres.setOutOfBounds()
327 log.logdebug(
'computing template for peak %i at (%i, %i)' % (pkres.pki, cx, cy))
328 S, patched = butils.buildSymmetricTemplate(maskedImage, fp, pk, sigma1,
True, patchEdges)
331 t1, tfoot = S[0], S[1]
335 log.logdebug((
'Peak %i at (%i, %i): failed to build symmetric ' +
336 'template') % (pkres.pki, cx, cy))
337 pkres.setFailedSymmetricTemplate()
344 pkres.setOrigTemplate(t1, tfoot)
347 log.logdebug(
'Checking for significant flux at edge: sigma1=%g' % sigma1)
348 if (rampFluxAtEdge
and
349 butils.hasSignificantFluxAtEdge(t1, tfoot, 3*sigma1)):
350 log.logdebug(
"Template %i has significant flux at edge: ramping" % pkres.pki)
353 maskedImage, x0, x1, y0, y1,
354 psf, pk, sigma1, patchEdges)
356 if (isinstance(exc, lsst.pex.exceptions.InvalidParameterError)
and "CoaddPsf" in str(exc)):
357 pkres.setOutOfBounds()
360 pkres.setRampedTemplate(t2, tfoot2)
366 if medianSmoothTemplate:
367 filtsize = medianFilterHalfsize*2 + 1
368 if t1.getWidth() >= filtsize
and t1.getHeight() >= filtsize:
369 log.logdebug(
'Median filtering template %i' % pkres.pki)
372 inimg = t1.Factory(t1,
True)
373 butils.medianFilter(inimg, t1, medianFilterHalfsize)
375 pkres.setMedianFilteredTemplate(t1, tfoot)
377 log.logdebug((
'Not median-filtering template %i: size '
378 +
'%i x %i smaller than required %i x %i') %
379 (pkres.pki, t1.getWidth(), t1.getHeight(), filtsize, filtsize))
381 if monotonicTemplate:
382 log.logdebug(
'Making template %i monotonic' % pkres.pki)
383 butils.makeMonotonic(t1, pk)
385 if clipFootprintToNonzero:
386 tfoot.clipToNonzero(t1)
388 if not tfoot.getBBox().isEmpty()
and tfoot.getBBox() != t1.getBBox(afwImage.PARENT):
389 t1 = t1.Factory(t1, tfoot.getBBox(), afwImage.PARENT,
True)
391 pkres.setTemplate(t1, tfoot)
406 for peaki, pkres
in enumerate(res.peaks):
409 tmimgs.append(pkres.templateImage)
410 tfoots.append(pkres.templateFootprint)
412 dpsf.append(pkres.deblendedAsPsf)
414 pkx.append(pk.getIx())
415 pky.append(pk.getIy())
416 ibi.append(pkres.pki)
420 A = np.zeros((W*H, len(tmimgs)))
421 b = img.getArray()[y0:y1+1, x0:x1+1].ravel()
423 for mim, i
in zip(tmimgs, ibi):
425 ix0, iy0 = ibb.getMinX(), ibb.getMinY()
427 foot = pkres.templateFootprint
428 ima = mim.getImage().getArray()
429 for sp
in foot.getSpans():
430 sy, sx0, sx1 = sp.getY(), sp.getX0(), sp.getX1()
431 imrow = ima[sy-iy0, sx0-ix0 : 1+sx1-ix0]
433 A[r0 + sx0-x0: r0+1+sx1-x0, i] = imrow
435 X1, r1, rank1, s1 = np.linalg.lstsq(A, b)
439 for mim, i, w
in zip(tmimgs, ibi, X1):
442 res.peaks[i].setTemplateWeight(w)
447 log.logdebug(
'Apportioning flux among %i templates' % len(tmimgs))
448 sumimg = afwImage.ImageF(bb)
452 strayflux = afwDet.HeavyFootprintPtrListF()
455 if strayFluxAssignment ==
'trim':
456 findStrayFlux =
False
457 strayopts |= butils.STRAYFLUX_TRIM
459 strayopts |= butils.ASSIGN_STRAYFLUX
460 if strayFluxToPointSources ==
'necessary':
461 strayopts |= butils.STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY
462 elif strayFluxToPointSources ==
'always':
463 strayopts |= butils.STRAYFLUX_TO_POINT_SOURCES_ALWAYS
465 if strayFluxAssignment ==
'r-to-peak':
468 elif strayFluxAssignment ==
'r-to-footprint':
469 strayopts |= butils.STRAYFLUX_R_TO_FOOTPRINT
470 elif strayFluxAssignment ==
'nearest-footprint':
471 strayopts |= butils.STRAYFLUX_NEAREST_FOOTPRINT
473 portions = butils.apportionFlux(maskedImage, fp, tmimgs, tfoots, sumimg, dpsf,
474 pkx, pky, strayflux, strayopts, clipStrayFluxFraction)
477 if strayFluxAssignment ==
'trim':
478 fp.include(tfoots,
True)
481 res.setTemplateSum(sumimg)
485 for j, (pk, pkres)
in enumerate(zip(peaks, res.peaks)):
488 pkres.setFluxPortion(portions[ii])
493 stray = strayflux[ii]
498 pkres.setStrayFlux(stray)
501 for j, (pk, pkres)
in enumerate(zip(peaks, res.peaks)):
505 for foot, add
in [(pkres.templateFootprint,
True), (pkres.origFootprint,
True),
506 (pkres.strayFlux,
False)]:
509 pks = foot.getPeaks()
518 In the PSF fitting code, we request PSF models for all peaks near
519 the one being fit. This was turning out to be quite expensive in
520 some cases. Here, we cache the PSF models to bring the cost down
521 closer to O(N) rather than O(N^2).
527 im = self.cache.get((cx, cy),
None)
533 im = self.psf.computeImage()
534 self.
cache[(cx, cy)] = im
537 def _fitPsfs(fp, peaks, fpres, log, psf, psffwhm, img, varimg,
538 psfChisqCut1, psfChisqCut2, psfChisqCut2b,
541 Fit a PSF + smooth background models to a small region around each
542 peak (plus other peaks that are nearby) in the given list of
545 @param[in] fp Footprint containing the Peaks to model
546 @param[in] peaks a list of all the Peak objects within this Footprint
547 @param[in,out] fpres a PerFootprint result object where results will be placed
548 @param[in,out] log pex Log object
549 @param[in] psf afw PSF object
550 @param[in] psffwhm FWHM of the PSF, in pixels
551 @param[in] img the Image in which this Footprint finds itself
552 @param[in] varimg Variance plane
553 @param[in] psfChisqCut* floats: cuts in chisq-per-pixel at which to accept
556 Results go into the fpres.peaks objects.
562 fmask = afwImage.MaskU(fbb)
563 fmask.setXY0(fbb.getMinX(), fbb.getMinY())
569 peakF = [pk.getF()
for pk
in peaks]
571 for pki,(pk,pkres,pkF)
in enumerate(zip(peaks, fpres.peaks, peakF)):
572 log.logdebug(
'Peak %i' % pki)
573 _fitPsf(fp, fmask, pk, pkF, pkres, fbb, peaks, peakF, log, cpsf, psffwhm,
574 img, varimg, psfChisqCut1, psfChisqCut2, psfChisqCut2b,
578 def _fitPsf(fp, fmask, pk, pkF, pkres, fbb, peaks, peaksF, log, psf, psffwhm,
579 img, varimg, psfChisqCut1, psfChisqCut2, psfChisqCut2b,
583 Fit a PSF + smooth background model (linear) to a small region around the peak.
585 @param[in] fp Footprint
586 @param[in] fmask the Mask plane for pixels in the Footprint
587 @param[in] pk the Peak within the Footprint that we are going to fit a PSF model for
588 @param[in] pkF the floating-point coordinates of this peak
589 @param[in,out] pkres a PerPeak object that will hold the results for this peak
590 @param[in] fbb the bounding-box of this Footprint (a Box2I)
591 @param[in] peaks a list of all the Peak objects within this Footprint
592 @param[in] peaksF a python list of the floating-point (x,y) peak locations
593 @param[in,out] log pex Log object
594 @param[in] psf afw PSF object
595 @param[in] psffwhm FWHM of the PSF, in pixels
596 @param[in] img the Image in which this Footprint finds itself
597 @param[in] varimg Variance plane
598 @param[in] psfChisqCut* floats: cuts in chisq-per-pixel at which to accept the PSF model
607 R0 = int(math.ceil(psffwhm*1.))
609 R1 = int(math.ceil(psffwhm*1.5))
610 cx, cy = pkF.getX(), pkF.getY()
611 psfimg = psf.computeImage(cx, cy)
613 R2 = R1 + min(psfimg.getWidth(), psfimg.getHeight())/2.
615 pbb = psfimg.getBBox()
617 px0, py0 = psfimg.getX0(), psfimg.getY0()
622 pkres.setOutOfBounds()
626 xlo = int(math.floor(cx - R1))
627 ylo = int(math.floor(cy - R1))
628 xhi = int(math.ceil (cx + R1))
629 yhi = int(math.ceil (cy + R1))
632 xlo, xhi = stampbb.getMinX(), stampbb.getMaxX()
633 ylo, yhi = stampbb.getMinY(), stampbb.getMaxY()
634 if xlo > xhi
or ylo > yhi:
635 log.logdebug(
'Skipping this peak: out of bounds')
636 pkres.setOutOfBounds()
640 if tinyFootprintSize>0
and (((xhi - xlo) < tinyFootprintSize)
or
641 ((yhi - ylo) < tinyFootprintSize)):
642 log.logdebug(
'Skipping this peak: tiny footprint / close to edge')
643 pkres.setTinyFootprint()
648 for pk2, pkF2
in zip(peaks, peaksF):
651 if pkF.distanceSquared(pkF2) > R2**2:
653 opsfimg = psf.computeImage(pkF2.getX(), pkF2.getY())
654 if not opsfimg.getBBox(afwImage.LOCAL).overlaps(stampbb):
656 otherpeaks.append(opsfimg)
657 log.logdebug(
'%i other peaks within range' % len(otherpeaks))
663 NT1 = 4 + len(otherpeaks)
667 NP = (1 + yhi - ylo)*(1 + xhi - xlo)
679 ix0, iy0 = img.getX0(), img.getY0()
680 fx0, fy0 = fbb.getMinX(), fbb.getMinY()
681 fslice = (slice(ylo-fy0, yhi-fy0+1), slice(xlo-fx0, xhi-fx0+1))
682 islice = (slice(ylo-iy0, yhi-iy0+1), slice(xlo-ix0, xhi-ix0+1))
683 fmask_sub = fmask .getArray()[fslice]
684 var_sub = varimg.getArray()[islice]
685 img_sub = img .getArray()[islice]
688 psfarr = psfimg.getArray()[pbb.getMinY()-py0: 1+pbb.getMaxY()-py0,
689 pbb.getMinX()-px0: 1+pbb.getMaxX()-px0]
690 px0, px1 = pbb.getMinX(), pbb.getMaxX()
691 py0, py1 = pbb.getMinY(), pbb.getMaxY()
694 valid = (fmask_sub > 0)
695 xx, yy = np.arange(xlo, xhi+1), np.arange(ylo, yhi+1)
696 RR = ((xx - cx)**2)[np.newaxis, :] + ((yy - cy)**2)[:, np.newaxis]
697 valid *= (RR <= R1**2)
698 valid *= (var_sub > 0)
702 log.warn(
'Skipping peak at (%.1f, %.1f): no unmasked pixels nearby' % (cx, cy))
703 pkres.setNoValidPixels()
707 XX, YY = np.meshgrid(xx, yy)
708 ipixes = np.vstack((XX[valid] - xlo, YY[valid] - ylo)).T
710 inpsfx = (xx >= px0)*(xx <= px1)
711 inpsfy = (yy >= py0)*(yy <= py1)
712 inpsf = np.outer(inpsfy, inpsfx)
713 indx = np.outer(inpsfy, (xx > px0)*(xx < px1))
714 indy = np.outer((yy > py0)*(yy < py1), inpsfx)
719 def _overlap(xlo, xhi, xmin, xmax):
720 assert((xlo <= xmax)
and (xhi >= xmin)
and
721 (xlo <= xhi)
and (xmin <= xmax))
722 xloclamp = max(xlo, xmin)
724 xhiclamp = min(xhi, xmax)
725 Xhi = Xlo + (xhiclamp - xloclamp)
726 assert(xloclamp >= 0)
728 return (xloclamp, xhiclamp+1, Xlo, Xhi+1)
730 A = np.zeros((NP, NT2))
734 A[:, I_sky_ramp_x] = ipixes[:, 0] + (xlo-cx)
735 A[:, I_sky_ramp_y] = ipixes[:, 1] + (ylo-cy)
738 px0, px1 = pbb.getMinX(), pbb.getMaxX()
739 py0, py1 = pbb.getMinY(), pbb.getMaxY()
740 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0, px1)
741 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0, py1)
742 dpx0, dpy0 = px0 - xlo, py0 - ylo
743 psf_y_slice = slice(sy3 - dpy0, sy4 - dpy0)
744 psf_x_slice = slice(sx3 - dpx0, sx4 - dpx0)
745 psfsub = psfarr[psf_y_slice, psf_x_slice]
746 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
747 A[inpsf[valid], I_psf] = psfsub[vsub]
751 oldsx = (sx1, sx2, sx3, sx4)
752 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0+1, px1-1)
753 psfsub = (psfarr[psf_y_slice, sx3 - dpx0 + 1: sx4 - dpx0 + 1] -
754 psfarr[psf_y_slice, sx3 - dpx0 - 1: sx4 - dpx0 - 1])/2.
755 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
756 A[indx[valid], I_dx] = psfsub[vsub]
758 (sx1, sx2, sx3, sx4) = oldsx
761 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0+1, py1-1)
762 psfsub = (psfarr[sy3 - dpy0 + 1: sy4 - dpy0 + 1, psf_x_slice] -
763 psfarr[sy3 - dpy0 - 1: sy4 - dpy0 - 1, psf_x_slice])/2.
764 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
765 A[indy[valid], I_dy] = psfsub[vsub]
768 for j, opsf
in enumerate(otherpeaks):
770 ino = np.outer((yy >= obb.getMinY())*(yy <= obb.getMaxY()),
771 (xx >= obb.getMinX())*(xx <= obb.getMaxX()))
772 dpx0, dpy0 = obb.getMinX() - xlo, obb.getMinY() - ylo
773 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, obb.getMinX(), obb.getMaxX())
774 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, obb.getMinY(), obb.getMaxY())
775 opsfarr = opsf.getArray()
776 psfsub = opsfarr[sy3 - dpy0 : sy4 - dpy0, sx3 - dpx0: sx4 - dpx0]
777 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
778 A[ino[valid], I_opsf + j] = psfsub[vsub]
784 rw = np.ones_like(RR)
787 rw[ii] = np.maximum(0, 1. - ((rr - R0)/(R1 - R0)))
788 w = np.sqrt(rw[valid]/var_sub[valid])
790 sumr = np.sum(rw[valid])
791 log.log(-9,
'sumr = %g' % sumr)
795 Aw = A*w[:, np.newaxis]
804 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
805 im1[ipixes[:, 1], ipixes[:, 0]] = A[:, i]
806 plt.subplot(R, C, i+1)
807 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
808 plt.subplot(R, C, NT2+1)
809 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
810 im1[ipixes[:, 1], ipixes[:, 0]] = b
811 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
812 plt.subplot(R, C, NT2+2)
813 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
814 im1[ipixes[:, 1], ipixes[:, 0]] = w
815 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
827 X1, r1, rank1, s1 = np.linalg.lstsq(Aw[:, :NT1], bw)
829 X2, r2, rank2, s2 = np.linalg.lstsq(Aw, bw)
830 except np.linalg.LinAlgError, e:
831 log.log(log.WARN,
"Failed to fit PSF to child: %s" % e)
832 pkres.setPsfFitFailed()
835 log.log(-9,
'r1 r2 %s %s' % (r1, r2))
847 dof1 = sumr - len(X1)
848 dof2 = sumr - len(X2)
849 log.log(-9,
'dof1, dof2 %g %g' % (dof1, dof2))
852 if dof1 <= 0
or dof2 <= 0:
853 log.logdebug(
'Skipping this peak: bad DOF %g, %g' % (dof1, dof2))
859 log.logdebug(
'PSF fits: chisq/dof = %g, %g' % (q1, q2))
860 ispsf1 = (q1 < psfChisqCut1)
861 ispsf2 = (q2 < psfChisqCut2)
863 pkres.psfFit1 = (chisq1, dof1)
864 pkres.psfFit2 = (chisq2, dof2)
868 fdx, fdy = X2[I_dx], X2[I_dy]
873 ispsf2 = ispsf2
and (abs(dx) < 1.
and abs(dy) < 1.)
874 log.logdebug(
'isPSF2 -- checking derivatives: dx,dy = %g, %g -> %s' %
875 (dx, dy, str(ispsf2)))
877 pkres.psfFitBigDecenter =
True
882 psfimg2 = psf.computeImage(cx + dx, cy + dy)
884 pbb2 = psfimg2.getBBox()
893 px0, py0 = psfimg2.getX0(), psfimg2.getY0()
894 psfarr = psfimg2.getArray()[pbb2.getMinY()-py0:1+pbb2.getMaxY()-py0,
895 pbb2.getMinX()-px0:1+pbb2.getMaxX()-px0]
896 px0, py0 = pbb2.getMinX(), pbb2.getMinY()
897 px1, py1 = pbb2.getMaxX(), pbb2.getMaxY()
902 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0, px1)
903 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0, py1)
904 dpx0, dpy0 = px0 - xlo, py0 - ylo
905 psfsub = psfarr[sy3-dpy0:sy4-dpy0, sx3-dpx0:sx4-dpx0]
906 vsub = valid[sy1-ylo:sy2-ylo, sx1-xlo:sx2-xlo]
907 xx, yy = np.arange(xlo, xhi+1), np.arange(ylo, yhi+1)
908 inpsf = np.outer((yy >= py0)*(yy <= py1), (xx >= px0)*(xx <= px1))
909 Ab[inpsf[valid], I_psf] = psfsub[vsub]
911 Aw = Ab*w[:, np.newaxis]
913 Xb, rb, rankb, sb = np.linalg.lstsq(Aw, bw)
918 dofb = sumr - len(Xb)
920 ispsf2 = (qb < psfChisqCut2b)
923 log.logdebug(
'shifted PSF: new chisq/dof = %g; good? %s' %
925 pkres.psfFit3 = (chisqb, dofb)
928 if (((ispsf1
and ispsf2)
and (q2 < q1))
or
929 (ispsf2
and not ispsf1)):
933 log.log(-9,
'dof %g' % dof)
934 log.logdebug(
'Keeping shifted-PSF model')
937 pkres.psfFitWithDecenter =
True
943 log.log(-9,
'dof %g' % dof)
944 log.logdebug(
'Keeping unshifted PSF model')
946 ispsf = (ispsf1
or ispsf2)
950 SW, SH = 1+xhi-xlo, 1+yhi-ylo
951 psfmod = afwImage.ImageF(SW, SH)
952 psfmod.setXY0(xlo, ylo)
953 psfderivmodm = afwImage.MaskedImageF(SW, SH)
954 psfderivmod = psfderivmodm.getImage()
955 psfderivmod.setXY0(xlo, ylo)
956 model = afwImage.ImageF(SW, SH)
957 model.setXY0(xlo, ylo)
958 for i
in range(len(Xpsf)):
959 for (x, y),v
in zip(ipixes, A[:, i]*Xpsf[i]):
960 ix, iy = int(x), int(y)
961 model.set(ix, iy, model.get(ix, iy) + float(v))
962 if i
in [I_psf, I_dx, I_dy]:
963 psfderivmod.set(ix, iy, psfderivmod.get(ix, iy) + float(v))
966 psfmod.set(int(x), int(y), float(A[ii, I_psf]*Xpsf[I_psf]))
968 for (x, y)
in ipixes:
969 modelfp.addSpan(int(y+ylo), int(x+xlo), int(x+xlo))
972 pkres.psfFitDebugPsf0Img = psfimg
973 pkres.psfFitDebugPsfImg = psfmod
974 pkres.psfFitDebugPsfDerivImg = psfderivmod
975 pkres.psfFitDebugPsfModel = model
976 pkres.psfFitDebugStamp = img.Factory(img, stampbb,
True)
977 pkres.psfFitDebugValidPix = valid
978 pkres.psfFitDebugVar = varimg.Factory(varimg, stampbb,
True)
979 ww = np.zeros(valid.shape, np.float)
981 pkres.psfFitDebugWeight = ww
982 pkres.psfFitDebugRampWeight = rw
988 pkres.psfFitStampExtent = (xlo, xhi, ylo, yhi)
989 pkres.psfFitCenter = (cx, cy)
990 log.log(-9,
'saving chisq,dof %g %g' % (chisq, dof))
991 pkres.psfFitBest = (chisq, dof)
992 pkres.psfFitParams = Xpsf
993 pkres.psfFitFlux = Xpsf[I_psf]
994 pkres.psfFitNOthers = len(otherpeaks)
997 pkres.setDeblendedAsPsf()
1001 log.logdebug(
'Deblending as PSF; setting template to PSF model')
1004 psfimg = psf.computeImage(cx, cy)
1006 psfimg *= Xpsf[I_psf]
1007 psfimg = psfimg.convertF()
1011 psfbb = psfimg.getBBox()
1012 fpcopy.clipTo(psfbb)
1013 bb = fpcopy.getBBox()
1016 psfmod = afwImage.ImageF(bb)
1017 afwDet.copyWithinFootprintImage(fpcopy, psfimg, psfmod)
1019 fpcopy.clipToNonzero(psfmod)
1021 pkres.setTemplate(psfmod, fpcopy)
1024 pkres.setPsfTemplate(psfmod, fpcopy)
1028 x0, x1, y0, y1, psf, pk, sigma1, patchEdges):
1031 butils = deb.BaselineUtilsF
1033 log.logdebug(
'Found significant flux at template edge.')
1043 S = (int(S + 0.5)/2)*2 + 1
1045 tbb = tfoot.getBBox()
1054 padim = maskedImage.Factory(tbb)
1055 afwDet.copyWithinFootprintMaskedImage(fpcopy, maskedImage, padim)
1058 edgepix = butils.getSignificantEdgePixels(t1, tfoot, -1e6)
1061 xc = int((x0 + x1)/2)
1062 yc = int((y0 + y1)/2)
1064 pbb = psfim.getBBox()
1066 lx, ly = pbb.getMinX(), pbb.getMinY()
1067 psfim.setXY0(lx - xc, ly - yc)
1068 pbb = psfim.getBBox()
1071 if not Sbox.contains(pbb):
1073 psfim = psfim.Factory(psfim, Sbox, afwImage.PARENT,
True)
1074 pbb = psfim.getBBox()
1081 ramped = t1.Factory(tbb)
1082 Tout = ramped.getArray()
1084 tx0, ty0 = t1.getX0(), t1.getY0()
1085 ox0, oy0 = ramped.getX0(), ramped.getY0()
1086 P = psfim.getArray()
1089 for span
in edgepix.getSpans():
1091 for x
in range(span.getX0(), span.getX1()+1):
1092 slc = (slice(y+py0 - oy0, y+py1+1 - oy0),
1093 slice(x+px0 - ox0, x+px1+1 - ox0))
1094 Tout[slc] = np.maximum(Tout[slc], Tin[y-ty0, x-tx0]*P)
1098 I = (padim.getImage().getArray() == 0)
1099 padim.getImage().getArray()[I] = ramped.getArray()[I]
1101 rtn, patched = butils.buildSymmetricTemplate(padim, fpcopy, pk, sigma1,
True, patchEdges)
1103 t2, tfoot2 = rtn[0], rtn[1]
1109 imbb = maskedImage.getBBox()
1111 tbb = tfoot2.getBBox()
1113 t2 = t2.Factory(t2, tbb, afwImage.PARENT,
True)
1115 return t2, tfoot2, patched
def _fitPsf
Fit a PSF + smooth background model (linear) to a small region around the peak.
boost::shared_ptr< Footprint > growFootprint(Footprint const &foot, int nGrow, bool left, bool right, bool up, bool down)
Grow a Footprint in at least one of the cardinal directions, returning a new Footprint.
In the PSF fitting code, we request PSF models for all peaks near the one being fit.
a place to record messages and descriptions of the state of processing.
def _fitPsfs
Fit a PSF + smooth background models to a small region around each peak (plus other peaks that are ne...
An integer coordinate rectangle.
def setMedianFilteredTemplate
def getFluxPortion
Return a HeavyFootprint containing the flux apportioned to this peak.
def deblend
Deblend a single footprint in a maskedImage.
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask's pixels that are in the Footprint.
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Result of deblending a single Peak within a parent Footprint.
def setFailedSymmetricTemplate
HeavyFootprint< ImagePixelT, MaskPixelT, VariancePixelT > makeHeavyFootprint(Footprint const &foot, lsst::afw::image::MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > const &img, HeavyFootprintCtrl const *ctrl=NULL)