1 from builtins
import zip
2 from builtins
import str
3 from builtins
import range
4 from builtins
import object
43 """Result of deblending a single parent Footprint."""
47 Creates a result object for the given parent Footprint 'fp'.
49 @param[in] fp Footprint
50 @param[in,out] peaks If specified, the list of peaks to use; default is
57 for pki, pk
in enumerate(peaks):
61 self.peaks.append(pkres)
71 Result of deblending a single Peak within a parent Footprint.
73 There is one of these objects for each Peak in the Footprint.
146 return ((
'Per-peak deblend result: outOfBounds: %s, deblendedAsPsf: %s') %
161 Return a HeavyFootprint containing the flux apportioned to this peak.
163 @param[in] strayFlux include stray flux also?
172 self.strayFlux.normalize()
173 heavy = afwDet.mergeHeavyFootprintsF(heavy, self.
strayFlux)
235 def deblend(footprint, maskedImage, psf, psffwhm,
236 psfChisqCut1=1.5, psfChisqCut2=1.5, psfChisqCut2b=1.5, fitPsfs=
True,
237 medianSmoothTemplate=
True, medianFilterHalfsize=2,
238 monotonicTemplate=
True, weightTemplates=
False,
239 log=
None, verbose=
False, sigma1=
None, maxNumberOfPeaks=0,
240 findStrayFlux=
True, assignStrayFlux=
True,
241 strayFluxToPointSources=
'necessary', strayFluxAssignment=
'r-to-peak',
242 rampFluxAtEdge=
False, patchEdges=
False, tinyFootprintSize=2,
243 getTemplateSum=
False,
244 clipStrayFluxFraction=0.001, clipFootprintToNonzero=
True,
247 Deblend a single ``footprint`` in a ``maskedImage``.
249 Each ``Peak`` in the ``Footprint`` will produce a deblended child.
251 psfChisqCut1, psfChisqCut2: used when deciding whether a given
252 peak looks like a point source. We build a small local model of
253 background + peak + neighboring peaks. These are the
254 chi-squared-per-degree-of-freedom cuts (1=without and 2=with terms
255 allowing the peak position to move); larger values will result in
256 more peaks being classified as PSFs.
258 psfChisqCut2b: if the with-decenter fit is accepted, we then
259 apply the computed dx,dy to the source position and re-fit without
260 decentering. The model is accepted if its chi-squared-per-DOF is
261 less than this value.
263 maxNumberOfPeaks: if positive, only deblend the brightest
264 maxNumberOfPeaks peaks in the parent
268 butils = deb.BaselineUtilsF
270 validStrayPtSrc = [
'never',
'necessary',
'always']
271 validStrayAssign = [
'r-to-peak',
'r-to-footprint',
'nearest-footprint',
'trim']
272 if not strayFluxToPointSources
in validStrayPtSrc:
273 raise ValueError(((
'strayFluxToPointSources: value \"%s\" not in the '
274 'set of allowed values: ')
275 % strayFluxToPointSources) + str(validStrayPtSrc))
276 if not strayFluxAssignment
in validStrayAssign:
277 raise ValueError(((
'strayFluxAssignment: value \"%s\" not in the '
278 'set of allowed values: ')
279 % strayFluxAssignment) + str(validStrayAssign))
284 component =
'meas_deblender.baseline'
285 log = lsstLog.Log.getLogger(component)
288 log.setLevel(lsstLog.Log.TRACE)
290 img = maskedImage.getImage()
291 varimg = maskedImage.getVariance()
292 mask = maskedImage.getMask()
296 peaks = fp.getPeaks()
297 if maxNumberOfPeaks > 0:
298 peaks = peaks[:maxNumberOfPeaks]
303 if not imbb.contains(bb):
304 raise ValueError((
'Footprint bounding-box %s extends outside image '
305 +
'bounding-box %s') % (str(bb), str(imbb)))
306 W, H = bb.getWidth(), bb.getHeight()
307 x0, y0 = bb.getMinX(), bb.getMinY()
308 x1, y1 = bb.getMaxX(), bb.getMaxY()
314 sigma1 = math.sqrt(stats.getValue(afwMath.MEDIAN))
315 log.trace(
'Estimated sigma1 = %f', sigma1)
322 _fitPsfs(fp, peaks, res, log, psf, psffwhm, img, varimg,
323 psfChisqCut1, psfChisqCut2, psfChisqCut2b,
324 tinyFootprintSize=tinyFootprintSize)
327 log.trace(
'Creating templates for footprint at x0,y0,W,H = ' +
328 '(%i, %i, %i, %i)', x0, y0, W, H)
329 for peaki, pkres
in enumerate(res.peaks):
330 log.trace(
'Deblending peak %i of %i', peaki, len(res.peaks))
331 if pkres.skip
or pkres.deblendedAsPsf:
334 cx, cy = pk.getIx(), pk.getIy()
336 log.trace(
'Peak center is not inside image; skipping %i', pkres.pki)
337 pkres.setOutOfBounds()
339 log.trace(
'computing template for peak %i at (%i, %i)', pkres.pki, cx, cy)
340 S, patched = butils.buildSymmetricTemplate(maskedImage, fp, pk, sigma1,
True, patchEdges)
343 t1, tfoot = S[0], S[1]
347 log.trace(
'Peak %i at (%i, %i): failed to build symmetric ' +
348 'template', pkres.pki, cx, cy)
349 pkres.setFailedSymmetricTemplate()
356 pkres.setOrigTemplate(t1, tfoot)
359 log.trace(
'Checking for significant flux at edge: sigma1=%g', sigma1)
360 if (rampFluxAtEdge
and butils.hasSignificantFluxAtEdge(t1, tfoot, 3*sigma1)):
361 log.trace(
"Template %i has significant flux at edge: ramping", pkres.pki)
364 maskedImage, x0, x1, y0, y1,
365 psf, pk, sigma1, patchEdges)
367 if (isinstance(exc, lsst.pex.exceptions.InvalidParameterError)
and "CoaddPsf" in str(exc)):
368 pkres.setOutOfBounds()
371 pkres.setRampedTemplate(t2, tfoot2)
377 if medianSmoothTemplate:
378 filtsize = medianFilterHalfsize*2 + 1
379 if t1.getWidth() >= filtsize
and t1.getHeight() >= filtsize:
380 log.trace(
'Median filtering template %i', pkres.pki)
383 inimg = t1.Factory(t1,
True)
384 butils.medianFilter(inimg, t1, medianFilterHalfsize)
386 pkres.setMedianFilteredTemplate(t1, tfoot)
388 log.trace(
'Not median-filtering template %i: size ' +
389 '%i x %i smaller than required %i x %i',
390 pkres.pki, t1.getWidth(), t1.getHeight(), filtsize, filtsize)
391 if monotonicTemplate:
392 log.trace(
'Making template %i monotonic', pkres.pki)
393 butils.makeMonotonic(t1, pk)
395 if clipFootprintToNonzero:
396 tfoot.clipToNonzero(t1)
398 if not tfoot.getBBox().isEmpty()
and tfoot.getBBox() != t1.getBBox(afwImage.PARENT):
399 t1 = t1.Factory(t1, tfoot.getBBox(), afwImage.PARENT,
True)
401 pkres.setTemplate(t1, tfoot)
416 for peaki, pkres
in enumerate(res.peaks):
419 tmimgs.append(pkres.templateImage)
420 tfoots.append(pkres.templateFootprint)
422 dpsf.append(pkres.deblendedAsPsf)
424 pkx.append(pk.getIx())
425 pky.append(pk.getIy())
426 ibi.append(pkres.pki)
430 A = np.zeros((W*H, len(tmimgs)))
431 b = img.getArray()[y0:y1+1, x0:x1+1].ravel()
433 for mim, i
in zip(tmimgs, ibi):
435 ix0, iy0 = ibb.getMinX(), ibb.getMinY()
437 foot = pkres.templateFootprint
438 ima = mim.getImage().getArray()
439 for sp
in foot.getSpans():
440 sy, sx0, sx1 = sp.getY(), sp.getX0(), sp.getX1()
441 imrow = ima[sy-iy0, sx0-ix0: 1+sx1-ix0]
443 A[r0 + sx0-x0: r0+1+sx1-x0, i] = imrow
445 X1, r1, rank1, s1 = np.linalg.lstsq(A, b)
449 for mim, i, w
in zip(tmimgs, ibi, X1):
452 res.peaks[i].setTemplateWeight(w)
457 log.trace(
'Apportioning flux among %i templates', len(tmimgs))
458 sumimg = afwImage.ImageF(bb)
462 strayflux = afwDet.HeavyFootprintPtrListF()
465 if strayFluxAssignment ==
'trim':
466 findStrayFlux =
False
467 strayopts |= butils.STRAYFLUX_TRIM
469 strayopts |= butils.ASSIGN_STRAYFLUX
470 if strayFluxToPointSources ==
'necessary':
471 strayopts |= butils.STRAYFLUX_TO_POINT_SOURCES_WHEN_NECESSARY
472 elif strayFluxToPointSources ==
'always':
473 strayopts |= butils.STRAYFLUX_TO_POINT_SOURCES_ALWAYS
475 if strayFluxAssignment ==
'r-to-peak':
478 elif strayFluxAssignment ==
'r-to-footprint':
479 strayopts |= butils.STRAYFLUX_R_TO_FOOTPRINT
480 elif strayFluxAssignment ==
'nearest-footprint':
481 strayopts |= butils.STRAYFLUX_NEAREST_FOOTPRINT
483 portions = butils.apportionFlux(maskedImage, fp, tmimgs, tfoots, sumimg, dpsf,
484 pkx, pky, strayflux, strayopts, clipStrayFluxFraction)
487 if strayFluxAssignment ==
'trim':
488 fp.include(tfoots,
True)
491 res.setTemplateSum(sumimg)
495 for j, (pk, pkres)
in enumerate(zip(peaks, res.peaks)):
498 pkres.setFluxPortion(portions[ii])
503 stray = strayflux[ii]
508 pkres.setStrayFlux(stray)
511 for j, (pk, pkres)
in enumerate(zip(peaks, res.peaks)):
515 for foot, add
in [(pkres.templateFootprint,
True), (pkres.origFootprint,
True),
516 (pkres.strayFlux,
False)]:
519 pks = foot.getPeaks()
529 In the PSF fitting code, we request PSF models for all peaks near
530 the one being fit. This was turning out to be quite expensive in
531 some cases. Here, we cache the PSF models to bring the cost down
532 closer to O(N) rather than O(N^2).
540 im = self.cache.get((cx, cy),
None)
546 im = self.psf.computeImage()
547 self.
cache[(cx, cy)] = im
551 def _fitPsfs(fp, peaks, fpres, log, psf, psffwhm, img, varimg,
552 psfChisqCut1, psfChisqCut2, psfChisqCut2b,
555 Fit a PSF + smooth background models to a small region around each
556 peak (plus other peaks that are nearby) in the given list of
559 @param[in] fp Footprint containing the Peaks to model
560 @param[in] peaks a list of all the Peak objects within this Footprint
561 @param[in,out] fpres a PerFootprint result object where results will be placed
562 @param[in,out] log pex Log object
563 @param[in] psf afw PSF object
564 @param[in] psffwhm FWHM of the PSF, in pixels
565 @param[in] img the Image in which this Footprint finds itself
566 @param[in] varimg Variance plane
567 @param[in] psfChisqCut* floats: cuts in chisq-per-pixel at which to accept
570 Results go into the fpres.peaks objects.
576 fmask = afwImage.MaskU(fbb)
577 fmask.setXY0(fbb.getMinX(), fbb.getMinY())
583 peakF = [pk.getF()
for pk
in peaks]
585 for pki,(pk,pkres,pkF)
in enumerate(zip(peaks, fpres.peaks, peakF)):
586 log.trace(
'Peak %i', pki)
587 _fitPsf(fp, fmask, pk, pkF, pkres, fbb, peaks, peakF, log, cpsf, psffwhm,
588 img, varimg, psfChisqCut1, psfChisqCut2, psfChisqCut2b,
592 def _fitPsf(fp, fmask, pk, pkF, pkres, fbb, peaks, peaksF, log, psf, psffwhm,
593 img, varimg, psfChisqCut1, psfChisqCut2, psfChisqCut2b,
597 Fit a PSF + smooth background model (linear) to a small region around the peak.
599 @param[in] fp Footprint
600 @param[in] fmask the Mask plane for pixels in the Footprint
601 @param[in] pk the Peak within the Footprint that we are going to fit a PSF model for
602 @param[in] pkF the floating-point coordinates of this peak
603 @param[in,out] pkres a PerPeak object that will hold the results for this peak
604 @param[in] fbb the bounding-box of this Footprint (a Box2I)
605 @param[in] peaks a list of all the Peak objects within this Footprint
606 @param[in] peaksF a python list of the floating-point (x,y) peak locations
607 @param[in,out] log pex Log object
608 @param[in] psf afw PSF object
609 @param[in] psffwhm FWHM of the PSF, in pixels
610 @param[in] img the Image in which this Footprint finds itself
611 @param[in] varimg Variance plane
612 @param[in] psfChisqCut* floats: cuts in chisq-per-pixel at which to accept the PSF model
621 R0 = int(math.ceil(psffwhm*1.))
623 R1 = int(math.ceil(psffwhm*1.5))
624 cx, cy = pkF.getX(), pkF.getY()
625 psfimg = psf.computeImage(cx, cy)
627 R2 = R1 + min(psfimg.getWidth(), psfimg.getHeight())/2.
629 pbb = psfimg.getBBox()
631 px0, py0 = psfimg.getX0(), psfimg.getY0()
636 pkres.setOutOfBounds()
640 xlo = int(math.floor(cx - R1))
641 ylo = int(math.floor(cy - R1))
642 xhi = int(math.ceil(cx + R1))
643 yhi = int(math.ceil(cy + R1))
646 xlo, xhi = stampbb.getMinX(), stampbb.getMaxX()
647 ylo, yhi = stampbb.getMinY(), stampbb.getMaxY()
648 if xlo > xhi
or ylo > yhi:
649 log.trace(
'Skipping this peak: out of bounds')
650 pkres.setOutOfBounds()
654 if min(stampbb.getWidth(), stampbb.getHeight()) <= max(tinyFootprintSize, 2):
657 log.trace(
'Skipping this peak: tiny footprint / close to edge')
658 pkres.setTinyFootprint()
663 for pk2, pkF2
in zip(peaks, peaksF):
666 if pkF.distanceSquared(pkF2) > R2**2:
668 opsfimg = psf.computeImage(pkF2.getX(), pkF2.getY())
669 if not opsfimg.getBBox(afwImage.LOCAL).overlaps(stampbb):
671 otherpeaks.append(opsfimg)
672 log.trace(
'%i other peaks within range', len(otherpeaks))
678 NT1 = 4 + len(otherpeaks)
682 NP = (1 + yhi - ylo)*(1 + xhi - xlo)
694 ix0, iy0 = img.getX0(), img.getY0()
695 fx0, fy0 = fbb.getMinX(), fbb.getMinY()
696 fslice = (slice(ylo-fy0, yhi-fy0+1), slice(xlo-fx0, xhi-fx0+1))
697 islice = (slice(ylo-iy0, yhi-iy0+1), slice(xlo-ix0, xhi-ix0+1))
698 fmask_sub = fmask .getArray()[fslice]
699 var_sub = varimg.getArray()[islice]
700 img_sub = img .getArray()[islice]
703 psfarr = psfimg.getArray()[pbb.getMinY()-py0: 1+pbb.getMaxY()-py0,
704 pbb.getMinX()-px0: 1+pbb.getMaxX()-px0]
705 px0, px1 = pbb.getMinX(), pbb.getMaxX()
706 py0, py1 = pbb.getMinY(), pbb.getMaxY()
709 valid = (fmask_sub > 0)
710 xx, yy = np.arange(xlo, xhi+1), np.arange(ylo, yhi+1)
711 RR = ((xx - cx)**2)[np.newaxis, :] + ((yy - cy)**2)[:, np.newaxis]
712 valid *= (RR <= R1**2)
713 valid *= (var_sub > 0)
717 log.warn(
'Skipping peak at (%.1f, %.1f): no unmasked pixels nearby' % (cx, cy))
718 pkres.setNoValidPixels()
722 XX, YY = np.meshgrid(xx, yy)
723 ipixes = np.vstack((XX[valid] - xlo, YY[valid] - ylo)).T
725 inpsfx = (xx >= px0)*(xx <= px1)
726 inpsfy = (yy >= py0)*(yy <= py1)
727 inpsf = np.outer(inpsfy, inpsfx)
728 indx = np.outer(inpsfy, (xx > px0)*(xx < px1))
729 indy = np.outer((yy > py0)*(yy < py1), inpsfx)
734 def _overlap(xlo, xhi, xmin, xmax):
735 assert((xlo <= xmax)
and (xhi >= xmin)
and
736 (xlo <= xhi)
and (xmin <= xmax))
737 xloclamp = max(xlo, xmin)
739 xhiclamp = min(xhi, xmax)
740 Xhi = Xlo + (xhiclamp - xloclamp)
741 assert(xloclamp >= 0)
743 return (xloclamp, xhiclamp+1, Xlo, Xhi+1)
745 A = np.zeros((NP, NT2))
749 A[:, I_sky_ramp_x] = ipixes[:, 0] + (xlo-cx)
750 A[:, I_sky_ramp_y] = ipixes[:, 1] + (ylo-cy)
753 px0, px1 = pbb.getMinX(), pbb.getMaxX()
754 py0, py1 = pbb.getMinY(), pbb.getMaxY()
755 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0, px1)
756 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0, py1)
757 dpx0, dpy0 = px0 - xlo, py0 - ylo
758 psf_y_slice = slice(sy3 - dpy0, sy4 - dpy0)
759 psf_x_slice = slice(sx3 - dpx0, sx4 - dpx0)
760 psfsub = psfarr[psf_y_slice, psf_x_slice]
761 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
762 A[inpsf[valid], I_psf] = psfsub[vsub]
766 oldsx = (sx1, sx2, sx3, sx4)
767 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0+1, px1-1)
768 psfsub = (psfarr[psf_y_slice, sx3 - dpx0 + 1: sx4 - dpx0 + 1] -
769 psfarr[psf_y_slice, sx3 - dpx0 - 1: sx4 - dpx0 - 1])/2.
770 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
771 A[indx[valid], I_dx] = psfsub[vsub]
773 (sx1, sx2, sx3, sx4) = oldsx
776 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0+1, py1-1)
777 psfsub = (psfarr[sy3 - dpy0 + 1: sy4 - dpy0 + 1, psf_x_slice] -
778 psfarr[sy3 - dpy0 - 1: sy4 - dpy0 - 1, psf_x_slice])/2.
779 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
780 A[indy[valid], I_dy] = psfsub[vsub]
783 for j, opsf
in enumerate(otherpeaks):
785 ino = np.outer((yy >= obb.getMinY())*(yy <= obb.getMaxY()),
786 (xx >= obb.getMinX())*(xx <= obb.getMaxX()))
787 dpx0, dpy0 = obb.getMinX() - xlo, obb.getMinY() - ylo
788 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, obb.getMinX(), obb.getMaxX())
789 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, obb.getMinY(), obb.getMaxY())
790 opsfarr = opsf.getArray()
791 psfsub = opsfarr[sy3 - dpy0: sy4 - dpy0, sx3 - dpx0: sx4 - dpx0]
792 vsub = valid[sy1-ylo: sy2-ylo, sx1-xlo: sx2-xlo]
793 A[ino[valid], I_opsf + j] = psfsub[vsub]
799 rw = np.ones_like(RR)
802 rw[ii] = np.maximum(0, 1. - ((rr - R0)/(R1 - R0)))
803 w = np.sqrt(rw[valid]/var_sub[valid])
805 sumr = np.sum(rw[valid])
806 log.debug(
'sumr = %g' % sumr)
810 Aw = A*w[:, np.newaxis]
819 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
820 im1[ipixes[:, 1], ipixes[:, 0]] = A[:, i]
821 plt.subplot(R, C, i+1)
822 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
823 plt.subplot(R, C, NT2+1)
824 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
825 im1[ipixes[:, 1], ipixes[:, 0]] = b
826 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
827 plt.subplot(R, C, NT2+2)
828 im1 = np.zeros((1+yhi-ylo, 1+xhi-xlo))
829 im1[ipixes[:, 1], ipixes[:, 0]] = w
830 plt.imshow(im1, interpolation=
'nearest', origin=
'lower')
842 X1, r1, rank1, s1 = np.linalg.lstsq(Aw[:, :NT1], bw)
844 X2, r2, rank2, s2 = np.linalg.lstsq(Aw, bw)
845 except np.linalg.LinAlgError
as e:
846 log.log(log.WARN,
"Failed to fit PSF to child: %s" % e)
847 pkres.setPsfFitFailed()
850 log.debug(
'r1 r2 %s %s' % (r1, r2))
862 dof1 = sumr - len(X1)
863 dof2 = sumr - len(X2)
864 log.debug(
'dof1, dof2 %g %g' % (dof1, dof2))
867 if dof1 <= 0
or dof2 <= 0:
868 log.trace(
'Skipping this peak: bad DOF %g, %g', dof1, dof2)
874 log.trace(
'PSF fits: chisq/dof = %g, %g', q1, q2)
875 ispsf1 = (q1 < psfChisqCut1)
876 ispsf2 = (q2 < psfChisqCut2)
878 pkres.psfFit1 = (chisq1, dof1)
879 pkres.psfFit2 = (chisq2, dof2)
883 fdx, fdy = X2[I_dx], X2[I_dy]
888 ispsf2 = ispsf2
and (abs(dx) < 1.
and abs(dy) < 1.)
889 log.trace(
'isPSF2 -- checking derivatives: dx,dy = %g, %g -> %s',
892 pkres.psfFitBigDecenter =
True
897 psfimg2 = psf.computeImage(cx + dx, cy + dy)
899 pbb2 = psfimg2.getBBox()
908 px0, py0 = psfimg2.getX0(), psfimg2.getY0()
909 psfarr = psfimg2.getArray()[pbb2.getMinY()-py0:1+pbb2.getMaxY()-py0,
910 pbb2.getMinX()-px0:1+pbb2.getMaxX()-px0]
911 px0, py0 = pbb2.getMinX(), pbb2.getMinY()
912 px1, py1 = pbb2.getMaxX(), pbb2.getMaxY()
917 sx1, sx2, sx3, sx4 = _overlap(xlo, xhi, px0, px1)
918 sy1, sy2, sy3, sy4 = _overlap(ylo, yhi, py0, py1)
919 dpx0, dpy0 = px0 - xlo, py0 - ylo
920 psfsub = psfarr[sy3-dpy0:sy4-dpy0, sx3-dpx0:sx4-dpx0]
921 vsub = valid[sy1-ylo:sy2-ylo, sx1-xlo:sx2-xlo]
922 xx, yy = np.arange(xlo, xhi+1), np.arange(ylo, yhi+1)
923 inpsf = np.outer((yy >= py0)*(yy <= py1), (xx >= px0)*(xx <= px1))
924 Ab[inpsf[valid], I_psf] = psfsub[vsub]
926 Aw = Ab*w[:, np.newaxis]
928 Xb, rb, rankb, sb = np.linalg.lstsq(Aw, bw)
933 dofb = sumr - len(Xb)
935 ispsf2 = (qb < psfChisqCut2b)
938 log.trace(
'shifted PSF: new chisq/dof = %g; good? %s',
940 pkres.psfFit3 = (chisqb, dofb)
943 if (((ispsf1
and ispsf2)
and (q2 < q1))
or
944 (ispsf2
and not ispsf1)):
948 log.debug(
'dof %g' % dof)
949 log.trace(
'Keeping shifted-PSF model')
952 pkres.psfFitWithDecenter =
True
958 log.debug(
'dof %g' % dof)
959 log.trace(
'Keeping unshifted PSF model')
961 ispsf = (ispsf1
or ispsf2)
965 SW, SH = 1+xhi-xlo, 1+yhi-ylo
966 psfmod = afwImage.ImageF(SW, SH)
967 psfmod.setXY0(xlo, ylo)
968 psfderivmodm = afwImage.MaskedImageF(SW, SH)
969 psfderivmod = psfderivmodm.getImage()
970 psfderivmod.setXY0(xlo, ylo)
971 model = afwImage.ImageF(SW, SH)
972 model.setXY0(xlo, ylo)
973 for i
in range(len(Xpsf)):
974 for (x, y), v
in zip(ipixes, A[:, i]*Xpsf[i]):
975 ix, iy = int(x), int(y)
976 model.set(ix, iy, model.get(ix, iy) + float(v))
977 if i
in [I_psf, I_dx, I_dy]:
978 psfderivmod.set(ix, iy, psfderivmod.get(ix, iy) + float(v))
981 psfmod.set(int(x), int(y), float(A[ii, I_psf]*Xpsf[I_psf]))
983 for (x, y)
in ipixes:
984 modelfp.addSpan(int(y+ylo), int(x+xlo), int(x+xlo))
987 pkres.psfFitDebugPsf0Img = psfimg
988 pkres.psfFitDebugPsfImg = psfmod
989 pkres.psfFitDebugPsfDerivImg = psfderivmod
990 pkres.psfFitDebugPsfModel = model
991 pkres.psfFitDebugStamp = img.Factory(img, stampbb,
True)
992 pkres.psfFitDebugValidPix = valid
993 pkres.psfFitDebugVar = varimg.Factory(varimg, stampbb,
True)
994 ww = np.zeros(valid.shape, np.float)
996 pkres.psfFitDebugWeight = ww
997 pkres.psfFitDebugRampWeight = rw
1002 pkres.psfFitStampExtent = (xlo, xhi, ylo, yhi)
1003 pkres.psfFitCenter = (cx, cy)
1004 log.debug(
'saving chisq,dof %g %g' % (chisq, dof))
1005 pkres.psfFitBest = (chisq, dof)
1006 pkres.psfFitParams = Xpsf
1007 pkres.psfFitFlux = Xpsf[I_psf]
1008 pkres.psfFitNOthers = len(otherpeaks)
1011 pkres.setDeblendedAsPsf()
1015 log.trace(
'Deblending as PSF; setting template to PSF model')
1018 psfimg = psf.computeImage(cx, cy)
1020 psfimg *= Xpsf[I_psf]
1021 psfimg = psfimg.convertF()
1025 psfbb = psfimg.getBBox()
1026 fpcopy.clipTo(psfbb)
1027 bb = fpcopy.getBBox()
1030 psfmod = afwImage.ImageF(bb)
1031 afwDet.copyWithinFootprintImage(fpcopy, psfimg, psfmod)
1033 fpcopy.clipToNonzero(psfmod)
1035 pkres.setTemplate(psfmod, fpcopy)
1038 pkres.setPsfTemplate(psfmod, fpcopy)
1042 x0, x1, y0, y1, psf, pk, sigma1, patchEdges):
1045 butils = deb.BaselineUtilsF
1047 log.trace(
'Found significant flux at template edge.')
1057 S = int((S + 0.5)/2)*2 + 1
1059 tbb = tfoot.getBBox()
1068 padim = maskedImage.Factory(tbb)
1069 afwDet.copyWithinFootprintMaskedImage(fpcopy, maskedImage, padim)
1072 edgepix = butils.getSignificantEdgePixels(t1, tfoot, -1e6)
1075 xc = int((x0 + x1)/2)
1076 yc = int((y0 + y1)/2)
1078 pbb = psfim.getBBox()
1080 lx, ly = pbb.getMinX(), pbb.getMinY()
1081 psfim.setXY0(lx - xc, ly - yc)
1082 pbb = psfim.getBBox()
1085 if not Sbox.contains(pbb):
1087 psfim = psfim.Factory(psfim, Sbox, afwImage.PARENT,
True)
1088 pbb = psfim.getBBox()
1095 ramped = t1.Factory(tbb)
1096 Tout = ramped.getArray()
1098 tx0, ty0 = t1.getX0(), t1.getY0()
1099 ox0, oy0 = ramped.getX0(), ramped.getY0()
1100 P = psfim.getArray()
1103 for span
in edgepix.getSpans():
1105 for x
in range(span.getX0(), span.getX1()+1):
1106 slc = (slice(y+py0 - oy0, y+py1+1 - oy0),
1107 slice(x+px0 - ox0, x+px1+1 - ox0))
1108 Tout[slc] = np.maximum(Tout[slc], Tin[y-ty0, x-tx0]*P)
1112 I = (padim.getImage().getArray() == 0)
1113 padim.getImage().getArray()[I] = ramped.getArray()[I]
1115 rtn, patched = butils.buildSymmetricTemplate(padim, fpcopy, pk, sigma1,
True, patchEdges)
1117 t2, tfoot2 = rtn[0], rtn[1]
1123 imbb = maskedImage.getBBox()
1125 tbb = tfoot2.getBBox()
1127 t2 = t2.Factory(t2, tbb, afwImage.PARENT,
True)
1129 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.
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)