LSSTApplications  8.0.0.0+107,8.0.0.1+13,9.1+18,9.2,master-g084aeec0a4,master-g0aced2eed8+6,master-g15627eb03c,master-g28afc54ef9,master-g3391ba5ea0,master-g3d0fb8ae5f,master-g4432ae2e89+36,master-g5c3c32f3ec+17,master-g60f1e072bb+1,master-g6a3ac32d1b,master-g76a88a4307+1,master-g7bce1f4e06+57,master-g8ff4092549+31,master-g98e65bf68e,master-ga6b77976b1+53,master-gae20e2b580+3,master-gb584cd3397+53,master-gc5448b162b+1,master-gc54cf9771d,master-gc69578ece6+1,master-gcbf758c456+22,master-gcec1da163f+63,master-gcf15f11bcc,master-gd167108223,master-gf44c96c709
LSSTDataManagementBasePackage
dipoleMeasurement.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2011 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 import numpy as np
23 import lsst.afw.geom as afwGeom
24 import lsst.afw.image as afwImage
25 import lsst.afw.detection as afwDetect
26 import lsst.pipe.base as pipeBase
27 import lsst.pex.logging as pexLog
28 import lsst.pex.config as pexConfig
29 import lsst.meas.algorithms as measAlg
30 import lsst.meas.deblender.baseline as deblendBaseline
31 from lsst.meas.algorithms import SourceMeasurementTask, SourceMeasurementConfig
32 import lsst.afw.display.ds9 as ds9
33 
34 
35 class DipoleClassificationConfig(pexConfig.Config):
36  """!Classification of detected diaSources as dipole or not"""
37  minSn = pexConfig.Field(
38  doc="Minimum quadrature sum of positive+negative lobe S/N to be considered a dipole",
39  dtype=float, default=np.sqrt(2) * 5.0,
40  )
41  maxFluxRatio = pexConfig.Field(
42  doc = "Maximum flux ratio in either lobe to be considered a dipole",
43  dtype = float, default = 0.65
44  )
45 
46 class DipoleMeasurementConfig(SourceMeasurementConfig):
47  """!Measurement of detected diaSources as dipoles"""
48  classification = pexConfig.ConfigField(
49  dtype=DipoleClassificationConfig,
50  doc="Dipole classification config"
51  )
52 
53  def setDefaults(self):
54  self.algorithms.names.add("centroid.dipole.naive")
55  self.algorithms.names.add("flux.dipole.naive")
56  self.algorithms.names.add("flux.dipole.psf")
57  self.doReplaceWithNoise = False
58 
59 ## \addtogroup LSST_task_documentation
60 ## \{
61 ## \page DipoleMeasurementTask
62 ## \ref DipoleMeasurementTask_ "DipoleMeasurementTask"
63 ## \copybrief DipoleMeasurementTask
64 ## \}
65 class DipoleMeasurementTask(SourceMeasurementTask):
66  """!
67 \anchor DipoleMeasurementTask_
68 
69 \brief Measurement of Sources, specifically ones from difference images, for characterization as dipoles
70 
71 \section ip_diffim_dipolemeas_Contents Contents
72 
73  - \ref ip_diffim_dipolemeas_Purpose
74  - \ref ip_diffim_dipolemeas_Initialize
75  - \ref ip_diffim_dipolemeas_IO
76  - \ref ip_diffim_dipolemeas_Config
77  - \ref ip_diffim_dipolemeas_Metadata
78  - \ref ip_diffim_dipolemeas_Debug
79  - \ref ip_diffim_dipolemeas_Example
80 
81 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
82 
83 \section ip_diffim_dipolemeas_Purpose Description
84 
85 This class provies a specialized set of Source measurements that allow the user to test the hypothesis that
86 the Source is a dipole. This includes a set of measurements derived from intermediate base classes
87 DipoleCentroidAlgorithm and DipoleFluxAlgorithm. Their respective algorithm control classes are defined in
88 DipoleCentroidControl and DipoleFluxControl. Each centroid and flux measurement will have .neg (negative)
89 and .pos (positive lobe) fields.
90 
91 The first set of measurements uses a "naive" alrogithm for centroid and flux measurements, implemented in
92 NaiveDipoleCentroidControl and NaiveDipoleFluxControl. The algorithm uses a naive 3x3 weighted moment around
93 the nominal centroids of each peak in the Source Footprint. These algorithms fill the table fields
94 centroid.dipole.naive.* and flux.dipole.naive.*.
95 
96 The second set of measurements undertakes a joint-Psf model on the negative and positive lobe simultaneously.
97 This fit simultaneously solves for the negative and positive lobe centroids and fluxes using non-linear
98 least squares minimization. The fields are stored in table elements flux.dipole.psf.*.
99 
100 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
101 
102 \section ip_diffim_dipolemeas_Initialize Task initialization
103 
104 \copydoc \_\_init\_\_
105 
106 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
107 
108 \section ip_diffim_dipolemeas_IO Invoking the Task
109 
110 \copydoc run
111 
112 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
113 
114 \section ip_diffim_dipolemeas_Config Configuration parameters
115 
116 See \ref DipoleMeasurementConfig and \ref DipoleClassificationConfig
117 
118 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
119 
120 \section ip_diffim_dipolemeas_Metadata Quantities set in Metadata
121 
122 No specific values are set in the Task metadata. However, the Source schema are modified to store the
123 results of the dipole-specific measurements. These additional fields include:
124 
125  . classification.dipole : probability of being a dipole
126 
127  . centroid.dipole.naive.pos : unweighted 3x3 first moment centroid
128 
129  . centroid.dipole.naive.pos.err : covariance matrix for centroid.dipole.naive.pos
130 
131  . centroid.dipole.naive.pos.flags : set if the centroid.dipole.naive.pos measurement did not fully succeed
132 
133  . centroid.dipole.naive.neg : unweighted 3x3 first moment centroid
134 
135  . centroid.dipole.naive.neg.err : covariance matrix for centroid.dipole.naive.neg
136 
137  . centroid.dipole.naive.neg.flags : set if the centroid.dipole.naive.neg measurement did not fully succeed
138 
139  . flux.dipole.naive.pos : raw flux counts
140 
141  . flux.dipole.naive.pos.err : uncertainty for flux.dipole.naive.pos
142 
143  . flux.dipole.naive.pos.flags : set if the flux.dipole.naive.pos measurement failed
144 
145  . flux.dipole.naive.neg : raw flux counts
146 
147  . flux.dipole.naive.neg.err : uncertainty for flux.dipole.naive.neg
148 
149  . flux.dipole.naive.neg.flags : set if the flux.dipole.naive.neg measurement failed
150 
151  . flux.dipole.naive.npos : number of positive pixels
152 
153  . flux.dipole.naive.nneg : number of negative pixels
154 
155  . flux.dipole.psf.pos : jointly fitted psf flux counts
156 
157  . flux.dipole.psf.pos.err : uncertainty for flux.dipole.psf.pos
158 
159  . flux.dipole.psf.pos.flags : set if the flux.dipole.psf.pos measurement failed
160 
161  . flux.dipole.psf.neg : jointly fitted psf flux counts
162 
163  . flux.dipole.psf.neg.err : uncertainty for flux.dipole.psf.neg
164 
165  . flux.dipole.psf.neg.flags : set if the flux.dipole.psf.neg measurement failed
166 
167  . flux.dipole.psf.chi2dof : chi2 per degree of freedom of fit
168 
169  . flux.dipole.psf.centroid : average of the postive and negative lobe positions
170 
171  . flux.dipole.psf.centroid.err : covariance matrix for flux.dipole.psf.centroid
172 
173  . flux.dipole.psf.centroid.flags : set if the flux.dipole.psf.centroid measurement did not fully succeed
174 
175  . flux.dipole.psf.neg.centroid : psf fitted center of negative lobe
176 
177  . flux.dipole.psf.neg.centroid.err : covariance matrix for flux.dipole.psf.neg.centroid
178 
179  . flux.dipole.psf.neg.centroid.flags : set if the flux.dipole.psf.neg.centroid measurement did not fully succeed
180 
181  . flux.dipole.psf.pos.centroid : psf fitted center of positive lobe
182 
183  . flux.dipole.psf.pos.centroid.err : covariance matrix for flux.dipole.psf.pos.centroid
184 
185  . flux.dipole.psf.pos.centroid.flags : set if the flux.dipole.psf.pos.centroid measurement did not fully succeed
186 
187  . flux.dipole.psf.flags.maxpix : set if too large a footprint was sent to the algorithm
188 
189 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
190 
191 \section ip_diffim_dipolemeas_Debug Debug variables
192 
193 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
194 flag \c -d/--debug to import \b debug.py from your \c PYTHONPATH. The relevant contents of debug.py
195 for this Task include:
196 
197 \code{.py}
198  import sys
199  import lsstDebug
200  def DebugInfo(name):
201  di = lsstDebug.getInfo(name)
202  if name == "lsst.ip.diffim.dipoleMeasurement":
203  di.display = True # enable debug output
204  di.maskTransparency = 90 # ds9 mask transparency
205  di.displayDiaSources = True # show exposure with dipole results
206  return di
207  lsstDebug.Info = DebugInfo
208  lsstDebug.frame = 1
209 \endcode
210 
211 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
212 
213 \section ip_diffim_dipolemeas_Example A complete example of using DipoleMeasurementTask
214 
215 This code is dipoleMeasTask.py in the examples directory, and can be run as \em e.g.
216 \code
217 examples/dipoleMeasTask.py
218 examples/dipoleMeasTask.py --debug
219 examples/dipoleMeasTask.py --debug --image /path/to/image.fits
220 \endcode
221 
222 \dontinclude dipoleMeasTask.py
223 Start the processing by parsing the command line, where the user has the option of enabling debugging output
224 and/or sending their own image for demonstration (in case they have not downloaded the afwdata package).
225 \skip main
226 \until run
227 
228 \dontinclude dipoleMeasTask.py
229 The processing occurs in the run function. We first extract an exposure from disk or afwdata, displaying
230 it if requested:
231 \skip args
232 \until mtv
233 
234 Create a default source schema that we will append fields to as we add more algorithms:
235 \skip makeMinimalSchema
236 \until makeMinimalSchema
237 
238 Create the detection and measurement Tasks, with some minor tweaking of their configs:
239 \skip Create
240 \until measureTask
241 
242 Having fully initialied the schema, we create a Source table from it:
243 \skip output
244 \until SourceTable
245 
246 Run detection:
247 \skip Process
248 \until detectionTask
249 
250 Because we are looking for dipoles, we need to merge the positive and negative detections:
251 \skip Merge
252 \until numNeg
253 
254 Finally, perform measurement (both standard and dipole-specialized) on the merged sources:
255 \skip measureTask
256 \until measureTask
257 
258 Optionally display debugging information:
259 \skip Display
260 \until displayDipoles
261 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
262 
263  """
264  ConfigClass = DipoleMeasurementConfig
265  _DefaultName = "dipoleMeasurement"
266  _ClassificationFlag = "classification.dipole"
267 
268  def __init__(self, schema, algMetadata=None, **kwds):
269  """!Create the Task, and add Task-specific fields to the provided measurement table schema.
270 
271  @param[in,out] schema Schema object for measurement fields; modified in-place.
272  @param[in,out] algMetadata Passed to MeasureSources object to be filled with
273  metadata by algorithms (e.g. radii for aperture photometry).
274  @param **kwds Passed to Task.__init__.
275  """
276  SourceMeasurementTask.__init__(self, schema, algMetadata, **kwds)
278 
279  @pipeBase.timeMethod
280  def classify(self, sources):
281  """!Create the records needed for dipole classification, and run classifier
282 
283  @param[in,out] sources The diaSources to run classification on; modified in in-place
284  """
285 
286  self.log.log(self.log.INFO, "Classifying %d sources" % len(sources))
287  if not sources:
288  return
289 
290  ctrl = self.config.classification
291  try:
292  key = sources[0].getSchema().find(self._ClassificationFlag).getKey()
293  except:
294  self.log.warn("Key %s not found in table" % (self._ClassificationFlag))
295  return
296 
297  for source in sources:
298  passesSn = self.dipoleAnalysis.getSn(source) > ctrl.minSn
299 
300  negFlux = np.abs(source.get("flux.dipole.psf.neg"))
301  posFlux = np.abs(source.get("flux.dipole.psf.pos"))
302  totalFlux = negFlux + posFlux
303  passesFluxNeg = (negFlux / (negFlux + posFlux)) < ctrl.maxFluxRatio
304  passesFluxPos = (posFlux / (negFlux + posFlux)) < ctrl.maxFluxRatio
305 
306  if (passesSn and passesFluxPos and passesFluxNeg):
307  val = 1.0
308  else:
309  val = 0.0
310 
311  source.set(key, val)
312 
313  def run(self, exposure, sources, **kwds):
314  """!Run dipole measurement and classification
315  @param exposure Exposure on which the diaSources were detected
316  @param sources diaSources that will be measured using dipole measurement
317  @param **kwds Sent to SourceMeasurementTask
318  """
319 
320  SourceMeasurementTask.run(self, exposure, sources, **kwds)
321  self.classify(sources)
322 
323 #########
324 # Other Support classs
325 #########
326 
327 class SourceFlagChecker(object):
328  """!Functor class to check whether a diaSource has flags set that should cause it to be labeled bad."""
329  def __init__(self, sources, badFlags=None):
330  """!Constructor
331 
332  @param sources Sources that will be measured
333  @param badFlags A list of flags that will be used to determine if there was a measurement problem
334 
335  The list of badFlags will be used to make a list of keys to check for measurement flags on. By
336  default the centroid keys are added to this list"""
337 
338  self.badFlags = ['flags.pixel.edge', 'flags.pixel.interpolated.center', 'flags.pixel.saturated.center']
339  if badFlags is not None:
340  for flag in badFlags:
341  self.badFlags.append(flag)
342  self.keys = [sources.getSchema().find(name).key for name in self.badFlags]
343  self.keys.append(sources.table.getCentroidFlagKey())
344 
345  def __call__(self, source):
346  """!Call the source flag checker on a single Source
347 
348  @param source Source that will be examined"""
349  for k in self.keys:
350  if source.get(k):
351  return False
352  return True
353 
354 class DipoleAnalysis(object):
355  """!Functor class that provides (S/N, position, orientation) of measured dipoles"""
356  def __init__(self):
357  """!Constructor"""
358  pass
359 
360  def __call__(self, source):
361  """!Parse information returned from dipole measurement
362 
363  @param source The source that will be examined"""
364  return self.getSn(source), self.getCentroid(source), self.getOrientation(source)
365 
366  def getSn(self, source):
367  """!Get the total signal-to-noise of the dipole; total S/N is from positive and negative lobe
368 
369  @param source The source that will be examined"""
370 
371  posflux = source.get("flux.dipole.psf.pos")
372  posfluxErr = source.get("flux.dipole.psf.pos.err")
373  negflux = source.get("flux.dipole.psf.neg")
374  negfluxErr = source.get("flux.dipole.psf.neg.err")
375 
376  # Not a dipole!
377  if (posflux < 0) is (negflux < 0):
378  return 0
379 
380  return np.sqrt((posflux/posfluxErr)**2 + (negflux/negfluxErr)**2)
381 
382  def getCentroid(self, source):
383  """!Get the centroid of the dipole; average of positive and negative lobe
384 
385  @param source The source that will be examined"""
386 
387  negCen = source.get("flux.dipole.psf.neg.centroid")
388  posCen = source.get("flux.dipole.psf.pos.centroid")
389  if (False in np.isfinite(negCen)) or (False in np.isfinite(posCen)):
390  return None
391 
392  center = afwGeom.Point2D(0.5*(negCen[0]+posCen[0]),
393  0.5*(negCen[1]+posCen[1]))
394  return center
395 
396  def getOrientation(self, source):
397  """!Calculate the orientation of dipole; vector from negative to positive lobe
398 
399  @param source The source that will be examined"""
400 
401  negCen = source.get("flux.dipole.psf.neg.centroid")
402  posCen = source.get("flux.dipole.psf.pos.centroid")
403  if (False in np.isfinite(negCen)) or (False in np.isfinite(posCen)):
404  return None
405 
406  dx, dy = posCen[0]-negCen[0], posCen[1]-negCen[1]
407  angle = afwGeom.Angle(np.arctan2(dx, dy), afwGeom.radians)
408  return angle
409 
410  def displayDipoles(self, exposure, sources):
411  """!Display debugging information on the detected dipoles
412 
413  @param exposure Image the dipoles were measured on
414  @param sources The set of diaSources that were measured"""
415 
416  try:
417  import debug
418  except:
419  return
420  import lsstDebug
421  display = lsstDebug.Info(__name__).display
422  displayDiaSources = lsstDebug.Info(__name__).displayDiaSources
423  maskTransparency = lsstDebug.Info(__name__).maskTransparency
424  if not maskTransparency:
425  maskTransparency = 90
426  ds9.setMaskTransparency(maskTransparency)
427  ds9.mtv(exposure, frame=lsstDebug.frame)
428 
429  if display and displayDiaSources:
430  with ds9.Buffering():
431  for source in sources:
432  cenX, cenY = source.get("flux.dipole.psf.centroid")
433  if np.isinf(cenX) or np.isinf(cenY):
434  cenX, cenY = source.getCentroid()
435 
436  isdipole = source.get("classification.dipole")
437  if isdipole and np.isfinite(isdipole):
438  # Dipole
439  ctype= "green"
440  else:
441  # Not dipole
442  ctype = "red"
443 
444  ds9.dot("o", cenX, cenY, size=2, ctype=ctype, frame=lsstDebug.frame)
445 
446  negCenX, negCenY = source.get("flux.dipole.psf.neg.centroid")
447  posCenX, posCenY = source.get("flux.dipole.psf.pos.centroid")
448  if (np.isinf(negCenX) or np.isinf(negCenY) or np.isinf(posCenX) or np.isinf(posCenY)):
449  continue
450 
451  ds9.line([(negCenX, negCenY), (posCenX, posCenY)], ctype="yellow", frame=lsstDebug.frame)
452 
453  lsstDebug.frame += 1
454 
455 
456 
457 class DipoleDeblender(object):
458  """!Functor to deblend a source as a dipole, and return a new source with deblended footprints.
459 
460  This necessarily overrides some of the functionality from
461  meas_algorithms/python/lsst/meas/algorithms/deblend.py since we
462  need a single source that contains the blended peaks, not
463  multiple children sources. This directly calls the core
464  deblending code deblendBaseline.deblend (optionally _fitPsf for
465  debugging).
466 
467  Not actively being used, but there is a unit test for it in
468  dipoleAlgorithm.py.
469  """
470  def __init__(self):
471  # Set up defaults to send to deblender
472 
473  # Always deblend as Psf
474  self.psfChisqCut1 = self.psfChisqCut2 = self.psfChisqCut2b = np.inf
475  self.log = pexLog.Log(pexLog.Log.getDefaultLog(),
476  'lsst.ip.diffim.DipoleDeblender', pexLog.Log.INFO)
477  self.sigma2fwhm = 2. * np.sqrt(2. * np.log(2.))
478 
479  def __call__(self, source, exposure):
480  fp = source.getFootprint()
481  peaks = fp.getPeaks()
482  peaksF = [pk.getF() for pk in peaks]
483  fbb = fp.getBBox()
484  fmask = afwImage.MaskU(fbb)
485  fmask.setXY0(fbb.getMinX(), fbb.getMinY())
486  afwDetect.setMaskFromFootprint(fmask, fp, 1)
487 
488  psf = exposure.getPsf()
489  psfSigPix = psf.computeShape().getDeterminantRadius()
490  psfFwhmPix = psfSigPix * self.sigma2fwhm
491  subimage = afwImage.ExposureF(exposure, fbb, True)
492  cpsf = deblendBaseline.CachingPsf(psf)
493 
494  # if fewer than 2 peaks, just return a copy of the source
495  if len(peaks) < 2:
496  return source.getTable().copyRecord(source)
497 
498  # make sure you only deblend 2 peaks; take the brighest and faintest
499  speaks = [(p.getPeakValue(), p) for p in peaks]
500  speaks.sort()
501  dpeaks = [speaks[0][1], speaks[-1][1]]
502 
503  # and only set these peaks in the footprint (peaks is mutable)
504  peaks.clear()
505  for peak in dpeaks:
506  peaks.push_back(peak)
507 
508  if True:
509  # Call top-level deblend task
510  fpres = deblendBaseline.deblend(fp, exposure.getMaskedImage(), psf, psfFwhmPix,
511  log = self.log,
512  psfChisqCut1 = self.psfChisqCut1,
513  psfChisqCut2 = self.psfChisqCut2,
514  psfChisqCut2b = self.psfChisqCut2b)
515  else:
516  # Call lower-level _fit_psf task
517 
518  # Prepare results structure
519  fpres = deblendBaseline.PerFootprint()
520  fpres.peaks = []
521  for pki,pk in enumerate(dpeaks):
522  pkres = deblendBaseline.PerPeak()
523  pkres.peak = pk
524  pkres.pki = pki
525  fpres.peaks.append(pkres)
526 
527  for pki,(pk,pkres,pkF) in enumerate(zip(dpeaks, fpres.peaks, peaksF)):
528  self.log.logdebug('Peak %i' % pki)
529  deblendBaseline._fitPsf(fp, fmask, pk, pkF, pkres, fbb, dpeaks, peaksF, self.log,
530  cpsf, psfFwhmPix,
531  subimage.getMaskedImage().getImage(),
532  subimage.getMaskedImage().getVariance(),
533  self.psfChisqCut1, self.psfChisqCut2, self.psfChisqCut2b)
534 
535 
536  deblendedSource = source.getTable().copyRecord(source)
537  deblendedSource.setParent(source.getId())
538  peakList = deblendedSource.getFootprint().getPeaks()
539  peakList.clear()
540 
541  for i, peak in enumerate(fpres.peaks):
542  if peak.psfFitFlux > 0:
543  suffix = "pos"
544  else:
545  suffix = "neg"
546  c = peak.psfFitCenter
547  self.log.info("deblended.centroid.dipole.psf.%s %f %f" % (
548  suffix, c[0], c[1]))
549  self.log.info("deblended.chi2dof.dipole.%s %f" % (
550  suffix, peak.psfFitChisq / peak.psfFitDof))
551  self.log.info("deblended.flux.dipole.psf.%s %f" % (
552  suffix, peak.psfFitFlux * np.sum(peak.templateMaskedImage.getImage().getArray())))
553  peakList.push_back(peak.peak)
554  return deblendedSource
555 
def getCentroid
Get the centroid of the dipole; average of positive and negative lobe.
Classification of detected diaSources as dipole or not.
def displayDipoles
Display debugging information on the detected dipoles.
def classify
Create the records needed for dipole classification, and run classifier.
a place to record messages and descriptions of the state of processing.
Definition: Log.h:154
def run
Run dipole measurement and classification.
Measurement of Sources, specifically ones from difference images, for characterization as dipoles...
def __init__
Create the Task, and add Task-specific fields to the provided measurement table schema.
Functor class that provides (S/N, position, orientation) of measured dipoles.
Functor to deblend a source as a dipole, and return a new source with deblended footprints.
def __call__
Parse information returned from dipole measurement.
MaskT setMaskFromFootprint(lsst::afw::image::Mask< MaskT > *mask, Footprint const &footprint, MaskT const bitmask)
OR bitmask into all the Mask&#39;s pixels that are in the Footprint.
Functor class to check whether a diaSource has flags set that should cause it to be labeled bad...
Measurement of detected diaSources as dipoles.
def getOrientation
Calculate the orientation of dipole; vector from negative to positive lobe.
def getSn
Get the total signal-to-noise of the dipole; total S/N is from positive and negative lobe...
def __call__
Call the source flag checker on a single Source.