lsst.meas.algorithms  14.0-9-g82279ae0+1
detection.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 #
4 # Copyright 2008-2017 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <https://www.lsstcorp.org/LegalNotices/>.
22 #
23 __all__ = ("SourceDetectionConfig", "SourceDetectionTask", "addExposures")
24 
25 import lsst.afw.detection as afwDet
26 import lsst.afw.display.ds9 as ds9
27 import lsst.afw.geom as afwGeom
28 import lsst.afw.image as afwImage
29 import lsst.afw.math as afwMath
30 import lsst.afw.table as afwTable
31 import lsst.pex.config as pexConfig
32 import lsst.pipe.base as pipeBase
33 from .subtractBackground import SubtractBackgroundTask
34 
35 
36 class SourceDetectionConfig(pexConfig.Config):
37  """!Configuration parameters for the SourceDetectionTask
38  """
39  minPixels = pexConfig.RangeField(
40  doc="detected sources with fewer than the specified number of pixels will be ignored",
41  dtype=int, optional=False, default=1, min=0,
42  )
43  isotropicGrow = pexConfig.Field(
44  doc="Pixels should be grown as isotropically as possible (slower)",
45  dtype=bool, optional=False, default=False,
46  )
47  nSigmaToGrow = pexConfig.Field(
48  doc="Grow detections by nSigmaToGrow * sigma; if 0 then do not grow",
49  dtype=float, default=2.4, # 2.4 pixels/sigma is roughly one pixel/FWHM
50  )
51  returnOriginalFootprints = pexConfig.Field(
52  doc="Grow detections to set the image mask bits, but return the original (not-grown) footprints",
53  dtype=bool, optional=False, default=False,
54  )
55  thresholdValue = pexConfig.RangeField(
56  doc="Threshold for footprints",
57  dtype=float, optional=False, default=5.0, min=0.0,
58  )
59  includeThresholdMultiplier = pexConfig.RangeField(
60  doc="Include threshold relative to thresholdValue",
61  dtype=float, default=1.0, min=0.0,
62  )
63  thresholdType = pexConfig.ChoiceField(
64  doc="specifies the desired flavor of Threshold",
65  dtype=str, optional=False, default="stdev",
66  allowed={
67  "variance": "threshold applied to image variance",
68  "stdev": "threshold applied to image std deviation",
69  "value": "threshold applied to image value",
70  "pixel_stdev": "threshold applied to per-pixel std deviation",
71  },
72  )
73  thresholdPolarity = pexConfig.ChoiceField(
74  doc="specifies whether to detect positive, or negative sources, or both",
75  dtype=str, optional=False, default="positive",
76  allowed={
77  "positive": "detect only positive sources",
78  "negative": "detect only negative sources",
79  "both": "detect both positive and negative sources",
80  },
81  )
82  adjustBackground = pexConfig.Field(
83  dtype=float,
84  doc="Fiddle factor to add to the background; debugging only",
85  default=0.0,
86  )
87  reEstimateBackground = pexConfig.Field(
88  dtype=bool,
89  doc="Estimate the background again after final source detection?",
90  default=True, optional=False,
91  )
92  background = pexConfig.ConfigurableField(
93  doc="Background re-estimation; ignored if reEstimateBackground false",
94  target=SubtractBackgroundTask,
95  )
96  tempLocalBackground = pexConfig.ConfigurableField(
97  doc=("A seperate background estimation and removal before footprint and peak detection. "
98  "It is added back into the image after detection."),
99  target=SubtractBackgroundTask,
100  )
101  doTempLocalBackground = pexConfig.Field(
102  dtype=bool,
103  doc="Do temporary interpolated background subtraction before footprint detection?",
104  default=True,
105  )
106  nPeaksMaxSimple = pexConfig.Field(
107  dtype=int,
108  doc=("The maximum number of peaks in a Footprint before trying to "
109  "replace its peaks using the temporary local background"),
110  default=1,
111  )
112 
113  def setDefaults(self):
114  self.tempLocalBackground.binSize = 64
115  self.tempLocalBackground.algorithm = "AKIMA_SPLINE"
116  self.tempLocalBackground.useApprox = False
117 
118 
124 
125 
126 class SourceDetectionTask(pipeBase.Task):
127  """!
128 \anchor SourceDetectionTask_
129 
130 \brief Detect positive and negative sources on an exposure and return a new \link table.SourceCatalog\endlink.
131 
132 \section meas_algorithms_detection_Contents Contents
133 
134  - \ref meas_algorithms_detection_Purpose
135  - \ref meas_algorithms_detection_Initialize
136  - \ref meas_algorithms_detection_Invoke
137  - \ref meas_algorithms_detection_Config
138  - \ref meas_algorithms_detection_Debug
139  - \ref meas_algorithms_detection_Example
140 
141 \section meas_algorithms_detection_Purpose Description
142 
143 \copybrief SourceDetectionTask
144 
145 \section meas_algorithms_detection_Initialize Task initialisation
146 
147 \copydoc \_\_init\_\_
148 
149 \section meas_algorithms_detection_Invoke Invoking the Task
150 
151 \copydoc run
152 
153 \section meas_algorithms_detection_Config Configuration parameters
154 
155 See \ref SourceDetectionConfig
156 
157 \section meas_algorithms_detection_Debug Debug variables
158 
159 The \link lsst.pipe.base.cmdLineTask.CmdLineTask command line task\endlink interface supports a
160 flag \c -d to import \b debug.py from your \c PYTHONPATH; see \ref baseDebug for more about \b debug.py files.
161 
162 The available variables in SourceDetectionTask are:
163 <DL>
164  <DT> \c display
165  <DD>
166  - If True, display the exposure on ds9's frame 0. +ve detections in blue, -ve detections in cyan
167  - If display > 1, display the convolved exposure on frame 1
168 </DL>
169 
170 \section meas_algorithms_detection_Example A complete example of using SourceDetectionTask
171 
172 This code is in \link measAlgTasks.py\endlink in the examples directory, and can be run as \em e.g.
173 \code
174 examples/measAlgTasks.py --ds9
175 \endcode
176 \dontinclude measAlgTasks.py
177 The example also runs the SourceMeasurementTask; see \ref meas_algorithms_measurement_Example for more
178 explanation.
179 
180 Import the task (there are some other standard imports; read the file if you're confused)
181 \skipline SourceDetectionTask
182 
183 We need to create our task before processing any data as the task constructor
184 can add an extra column to the schema, but first we need an almost-empty Schema
185 \skipline makeMinimalSchema
186 after which we can call the constructor:
187 \skip SourceDetectionTask.ConfigClass
188 @until detectionTask
189 
190 We're now ready to process the data (we could loop over multiple exposures/catalogues using the same
191 task objects). First create the output table:
192 \skipline afwTable
193 
194 And process the image
195 \skipline result
196 (You may not be happy that the threshold was set in the config before creating the Task rather than being set
197 separately for each exposure. You \em can reset it just before calling the run method if you must, but we
198 should really implement a better solution).
199 
200 We can then unpack and use the results:
201 \skip sources
202 @until print
203 
204 <HR>
205 To investigate the \ref meas_algorithms_detection_Debug, put something like
206 \code{.py}
207  import lsstDebug
208  def DebugInfo(name):
209  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
210  if name == "lsst.meas.algorithms.detection":
211  di.display = 1
212 
213  return di
214 
215  lsstDebug.Info = DebugInfo
216 \endcode
217 into your debug.py file and run measAlgTasks.py with the \c --debug flag.
218  """
219  ConfigClass = SourceDetectionConfig
220  _DefaultName = "sourceDetection"
221 
222  def __init__(self, schema=None, **kwds):
223  """!Create the detection task. Most arguments are simply passed onto pipe.base.Task.
224 
225  \param schema An lsst::afw::table::Schema used to create the output lsst.afw.table.SourceCatalog
226  \param **kwds Keyword arguments passed to lsst.pipe.base.task.Task.__init__.
227 
228  If schema is not None and configured for 'both' detections,
229  a 'flags.negative' field will be added to label detections made with a
230  negative threshold.
231 
232  \note This task can add fields to the schema, so any code calling this task must ensure that
233  these columns are indeed present in the input match list; see \ref Example
234  """
235  pipeBase.Task.__init__(self, **kwds)
236  if schema is not None and self.config.thresholdPolarity == "both":
237  self.negativeFlagKey = schema.addField(
238  "flags_negative", type="Flag",
239  doc="set if source was detected as significantly negative"
240  )
241  else:
242  if self.config.thresholdPolarity == "both":
243  self.log.warn("Detection polarity set to 'both', but no flag will be "
244  "set to distinguish between positive and negative detections")
245  self.negativeFlagKey = None
246  if self.config.reEstimateBackground:
247  self.makeSubtask("background")
248  if self.config.doTempLocalBackground:
249  self.makeSubtask("tempLocalBackground")
250 
251  @pipeBase.timeMethod
252  def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True):
253  """!Run source detection and create a SourceCatalog.
254 
255  \param table lsst.afw.table.SourceTable object that will be used to create the SourceCatalog.
256  \param exposure Exposure to process; DETECTED mask plane will be set in-place.
257  \param doSmooth if True, smooth the image before detection using a Gaussian of width sigma
258  (default: True)
259  \param sigma sigma of PSF (pixels); used for smoothing and to grow detections;
260  if None then measure the sigma of the PSF of the exposure (default: None)
261  \param clearMask Clear DETECTED{,_NEGATIVE} planes before running detection (default: True)
262 
263  \return a lsst.pipe.base.Struct with:
264  - sources -- an lsst.afw.table.SourceCatalog object
265  - fpSets --- lsst.pipe.base.Struct returned by \link detectFootprints \endlink
266 
267  \throws ValueError if flags.negative is needed, but isn't in table's schema
268  \throws lsst.pipe.base.TaskError if sigma=None, doSmooth=True and the exposure has no PSF
269 
270  \note
271  If you want to avoid dealing with Sources and Tables, you can use detectFootprints()
272  to just get the afw::detection::FootprintSet%s.
273  """
274  if self.negativeFlagKey is not None and self.negativeFlagKey not in table.getSchema():
275  raise ValueError("Table has incorrect Schema")
276  fpSets = self.detectFootprints(exposure=exposure, doSmooth=doSmooth, sigma=sigma,
277  clearMask=clearMask)
278  sources = afwTable.SourceCatalog(table)
279  table.preallocate(fpSets.numPos + fpSets.numNeg) # not required, but nice
280  if fpSets.negative:
281  fpSets.negative.makeSources(sources)
282  if self.negativeFlagKey:
283  for record in sources:
284  record.set(self.negativeFlagKey, True)
285  if fpSets.positive:
286  fpSets.positive.makeSources(sources)
287  return pipeBase.Struct(
288  sources=sources,
289  fpSets=fpSets
290  )
291 
292 
293  makeSourceCatalog = run
294 
295  @pipeBase.timeMethod
296  def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True):
297  """!Detect footprints.
298 
299  \param exposure Exposure to process; DETECTED{,_NEGATIVE} mask plane will be set in-place.
300  \param doSmooth if True, smooth the image before detection using a Gaussian of width sigma
301  \param sigma sigma of PSF (pixels); used for smoothing and to grow detections;
302  if None then measure the sigma of the PSF of the exposure
303  \param clearMask Clear both DETECTED and DETECTED_NEGATIVE planes before running detection
304 
305  \return a lsst.pipe.base.Struct with fields:
306  - positive: lsst.afw.detection.FootprintSet with positive polarity footprints (may be None)
307  - negative: lsst.afw.detection.FootprintSet with negative polarity footprints (may be None)
308  - numPos: number of footprints in positive or 0 if detection polarity was negative
309  - numNeg: number of footprints in negative or 0 if detection polarity was positive
310  - background: re-estimated background. None if reEstimateBackground==False
311 
312  \throws lsst.pipe.base.TaskError if sigma=None and the exposure has no PSF
313  """
314  try:
315  import lsstDebug
316  display = lsstDebug.Info(__name__).display
317  except ImportError:
318  try:
319  display
320  except NameError:
321  display = False
322 
323  if exposure is None:
324  raise RuntimeError("No exposure for detection")
325 
326  maskedImage = exposure.getMaskedImage()
327  region = maskedImage.getBBox()
328 
329  if clearMask:
330  mask = maskedImage.getMask()
331  mask &= ~(mask.getPlaneBitMask("DETECTED") | mask.getPlaneBitMask("DETECTED_NEGATIVE"))
332  del mask
333 
334  if self.config.doTempLocalBackground:
335  # Estimate the background, but add it back in instead of leaving
336  # it subtracted (for now); we'll want to smooth before we
337  # subtract it.
338  tempBg = self.tempLocalBackground.fitBackground(
339  exposure.getMaskedImage()
340  )
341  tempLocalBkgdImage = tempBg.getImageF()
342 
343  if sigma is None:
344  psf = exposure.getPsf()
345  if psf is None:
346  raise pipeBase.TaskError("exposure has no PSF; must specify sigma")
347  shape = psf.computeShape()
348  sigma = shape.getDeterminantRadius()
349 
350  self.metadata.set("sigma", sigma)
351  self.metadata.set("doSmooth", doSmooth)
352 
353  if not doSmooth:
354  convolvedImage = maskedImage.Factory(maskedImage)
355  middle = convolvedImage
356  else:
357  # smooth using a Gaussian (which is separate, hence fast) of width sigma
358  # make a SingleGaussian (separable) kernel with the 'sigma'
359  psf = exposure.getPsf()
360  kWidth = (int(sigma * 7 + 0.5) // 2) * 2 + 1 # make sure it is odd
361  self.metadata.set("smoothingKernelWidth", kWidth)
362  gaussFunc = afwMath.GaussianFunction1D(sigma)
363  gaussKernel = afwMath.SeparableKernel(kWidth, kWidth, gaussFunc, gaussFunc)
364 
365  convolvedImage = maskedImage.Factory(maskedImage.getBBox())
366 
367  afwMath.convolve(convolvedImage, maskedImage, gaussKernel, afwMath.ConvolutionControl())
368  #
369  # Only search psf-smooth part of frame
370  #
371  goodBBox = gaussKernel.shrinkBBox(convolvedImage.getBBox())
372  middle = convolvedImage.Factory(convolvedImage, goodBBox, afwImage.PARENT, False)
373  #
374  # Mark the parts of the image outside goodBBox as EDGE
375  #
376  self.setEdgeBits(maskedImage, goodBBox, maskedImage.getMask().getPlaneBitMask("EDGE"))
377 
378  fpSets = pipeBase.Struct(positive=None, negative=None)
379 
380  # Detect the Footprints (peaks may be replaced if doTempLocalBackground)
381  if self.config.thresholdPolarity != "negative":
382  threshold = self.makeThreshold(middle, "positive")
383  fpSets.positive = afwDet.FootprintSet(
384  middle,
385  threshold,
386  "DETECTED",
387  self.config.minPixels
388  )
389  if self.config.reEstimateBackground or self.config.thresholdPolarity != "positive":
390  threshold = self.makeThreshold(middle, "negative")
391  fpSets.negative = afwDet.FootprintSet(
392  middle,
393  threshold,
394  "DETECTED_NEGATIVE",
395  self.config.minPixels
396  )
397 
398  if self.config.doTempLocalBackground:
399  # Subtract the local background from the smoothed image. Since we
400  # never use the smoothed again we don't need to worry about adding
401  # it back in.
402  tempLocalBkgdImage = tempLocalBkgdImage.Factory(tempLocalBkgdImage,
403  middle.getBBox())
404  middle -= tempLocalBkgdImage
405  thresholdPos = self.makeThreshold(middle, "positive")
406  thresholdNeg = self.makeThreshold(middle, "negative")
407  if self.config.thresholdPolarity != "negative":
408  self.updatePeaks(fpSets.positive, middle, thresholdPos)
409  if self.config.thresholdPolarity != "positive":
410  self.updatePeaks(fpSets.negative, middle, thresholdNeg)
411 
412  for polarity, maskName in (("positive", "DETECTED"), ("negative", "DETECTED_NEGATIVE")):
413  fpSet = getattr(fpSets, polarity)
414  if fpSet is None:
415  continue
416  fpSet.setRegion(region)
417  if self.config.nSigmaToGrow > 0:
418  nGrow = int((self.config.nSigmaToGrow * sigma) + 0.5)
419  self.metadata.set("nGrow", nGrow)
420  fpSet = afwDet.FootprintSet(fpSet, nGrow, self.config.isotropicGrow)
421  fpSet.setMask(maskedImage.getMask(), maskName)
422  if not self.config.returnOriginalFootprints:
423  setattr(fpSets, polarity, fpSet)
424 
425  fpSets.numPos = len(fpSets.positive.getFootprints()) if fpSets.positive is not None else 0
426  fpSets.numNeg = len(fpSets.negative.getFootprints()) if fpSets.negative is not None else 0
427 
428  if self.config.thresholdPolarity != "negative":
429  self.log.info("Detected %d positive sources to %g sigma.",
430  fpSets.numPos, self.config.thresholdValue*self.config.includeThresholdMultiplier)
431 
432  fpSets.background = None
433  if self.config.reEstimateBackground:
434  mi = exposure.getMaskedImage()
435  bkgd = self.background.fitBackground(mi)
436 
437  if self.config.adjustBackground:
438  self.log.warn("Fiddling the background by %g", self.config.adjustBackground)
439 
440  bkgd += self.config.adjustBackground
441  fpSets.background = bkgd
442  self.log.info("Resubtracting the background after object detection")
443 
444  mi -= bkgd.getImageF()
445  del mi
446 
447  if self.config.thresholdPolarity == "positive":
448  if self.config.reEstimateBackground:
449  mask = maskedImage.getMask()
450  mask &= ~mask.getPlaneBitMask("DETECTED_NEGATIVE")
451  del mask
452  fpSets.negative = None
453  else:
454  self.log.info("Detected %d negative sources to %g %s",
455  fpSets.numNeg, self.config.thresholdValue,
456  ("DN" if self.config.thresholdType == "value" else "sigma"))
457 
458  if display:
459  ds9.mtv(exposure, frame=0, title="detection")
460  x0, y0 = exposure.getXY0()
461 
462  def plotPeaks(fps, ctype):
463  if fps is None:
464  return
465  with ds9.Buffering():
466  for fp in fps.getFootprints():
467  for pp in fp.getPeaks():
468  ds9.dot("+", pp.getFx() - x0, pp.getFy() - y0, ctype=ctype)
469  plotPeaks(fpSets.positive, "yellow")
470  plotPeaks(fpSets.negative, "red")
471 
472  if convolvedImage and display and display > 1:
473  ds9.mtv(convolvedImage, frame=1, title="PSF smoothed")
474 
475  return fpSets
476 
477  def makeThreshold(self, image, thresholdParity):
478  """Make an afw.detection.Threshold object corresponding to the task's
479  configuration and the statistics of the given image.
480 
481  Parameters
482  ----------
483  image : `afw.image.MaskedImage`
484  Image to measure noise statistics from if needed.
485  thresholdParity: `str`
486  One of "positive" or "negative", to set the kind of fluctuations
487  the Threshold will detect.
488  """
489  parity = False if thresholdParity == "negative" else True
490  threshold = afwDet.createThreshold(self.config.thresholdValue,
491  self.config.thresholdType, parity)
492  threshold.setIncludeMultiplier(self.config.includeThresholdMultiplier)
493 
494  if self.config.thresholdType == 'stdev':
495  bad = image.getMask().getPlaneBitMask(['BAD', 'SAT', 'EDGE',
496  'NO_DATA', ])
497  sctrl = afwMath.StatisticsControl()
498  sctrl.setAndMask(bad)
499  stats = afwMath.makeStatistics(image, afwMath.STDEVCLIP, sctrl)
500  thres = (stats.getValue(afwMath.STDEVCLIP) *
501  self.config.thresholdValue)
502  threshold = afwDet.createThreshold(thres, 'value', parity)
503  threshold.setIncludeMultiplier(
504  self.config.includeThresholdMultiplier
505  )
506 
507  return threshold
508 
509  def updatePeaks(self, fpSet, image, threshold):
510  """Update the Peaks in a FootprintSet by detecting new Footprints and
511  Peaks in an image and using the new Peaks instead of the old ones.
512 
513  Parameters
514  ----------
515  fpSet : `afw.detection.FootprintSet`
516  Set of Footprints whose Peaks should be updated.
517  image : `afw.image.MaskedImage`
518  Image to detect new Footprints and Peak in.
519  threshold : `afw.detection.Threshold`
520  Threshold object for detection.
521 
522  Input Footprints with fewer Peaks than self.config.nPeaksMaxSimple
523  are not modified, and if no new Peaks are detected in an input
524  Footprint, the brightest original Peak in that Footprint is kept.
525  """
526  for footprint in fpSet.getFootprints():
527  oldPeaks = footprint.getPeaks()
528  if len(oldPeaks) <= self.config.nPeaksMaxSimple:
529  continue
530  # We detect a new FootprintSet within each non-simple Footprint's
531  # bbox to avoid a big O(N^2) comparison between the two sets of
532  # Footprints.
533  sub = image.Factory(image, footprint.getBBox())
534  fpSetForPeaks = afwDet.FootprintSet(
535  sub,
536  threshold,
537  "", # don't set a mask plane
538  self.config.minPixels
539  )
540  newPeaks = afwDet.PeakCatalog(oldPeaks.getTable())
541  for fpForPeaks in fpSetForPeaks.getFootprints():
542  for peak in fpForPeaks.getPeaks():
543  if footprint.contains(peak.getI()):
544  newPeaks.append(peak)
545  if len(newPeaks) > 0:
546  del oldPeaks[:]
547  oldPeaks.extend(newPeaks)
548  else:
549  del oldPeaks[1:]
550 
551  @staticmethod
552  def setEdgeBits(maskedImage, goodBBox, edgeBitmask):
553  """!Set the edgeBitmask bits for all of maskedImage outside goodBBox
554 
555  \param[in,out] maskedImage image on which to set edge bits in the mask
556  \param[in] goodBBox bounding box of good pixels, in LOCAL coordinates
557  \param[in] edgeBitmask bit mask to OR with the existing mask bits in the region outside goodBBox
558  """
559  msk = maskedImage.getMask()
560 
561  mx0, my0 = maskedImage.getXY0()
562  for x0, y0, w, h in ([0, 0,
563  msk.getWidth(), goodBBox.getBeginY() - my0],
564  [0, goodBBox.getEndY() - my0, msk.getWidth(),
565  maskedImage.getHeight() - (goodBBox.getEndY() - my0)],
566  [0, 0,
567  goodBBox.getBeginX() - mx0, msk.getHeight()],
568  [goodBBox.getEndX() - mx0, 0,
569  maskedImage.getWidth() - (goodBBox.getEndX() - mx0), msk.getHeight()],
570  ):
571  edgeMask = msk.Factory(msk, afwGeom.BoxI(afwGeom.PointI(x0, y0),
572  afwGeom.ExtentI(w, h)), afwImage.LOCAL)
573  edgeMask |= edgeBitmask
574 
575 
576 def addExposures(exposureList):
577  """!Add a set of exposures together.
578 
579  \param[in] exposureList sequence of exposures to add
580 
581  \return an exposure of the same size as each exposure in exposureList,
582  with the metadata from exposureList[0] and a masked image equal to the
583  sum of all the exposure's masked images.
584 
585  \throw LsstException if the exposures do not all have the same dimensions (but does not check xy0)
586  """
587  exposure0 = exposureList[0]
588  image0 = exposure0.getMaskedImage()
589 
590  addedImage = image0.Factory(image0, True)
591  addedImage.setXY0(image0.getXY0())
592 
593  for exposure in exposureList[1:]:
594  image = exposure.getMaskedImage()
595  addedImage += image
596 
597  addedExposure = exposure0.Factory(addedImage, exposure0.getWcs())
598  return addedExposure
def updatePeaks(self, fpSet, image, threshold)
Definition: detection.py:509
def addExposures(exposureList)
Add a set of exposures together.
Definition: detection.py:576
def makeThreshold(self, image, thresholdParity)
Definition: detection.py:477
Detect positive and negative sources on an exposure and return a new table.SourceCatalog.
Definition: detection.py:126
def run(self, table, exposure, doSmooth=True, sigma=None, clearMask=True)
Run source detection and create a SourceCatalog.
Definition: detection.py:252
Statistics makeStatistics(lsst::afw::math::MaskedVector< EntryT > const &mv, std::vector< WeightPixel > const &vweights, int const flags, StatisticsControl const &sctrl=StatisticsControl())
Configuration parameters for the SourceDetectionTask.
Definition: detection.py:36
def detectFootprints(self, exposure, doSmooth=True, sigma=None, clearMask=True)
Detect footprints.
Definition: detection.py:296
def __init__(self, schema=None, kwds)
Create the detection task.
Definition: detection.py:222
def setEdgeBits(maskedImage, goodBBox, edgeBitmask)
Set the edgeBitmask bits for all of maskedImage outside goodBBox.
Definition: detection.py:552
void convolve(OutImageT &convolvedImage, InImageT const &inImage, KernelT const &kernel, bool doNormalize, bool doCopyEdge=false)