LSST Applications g0265f82a02+0e5473021a,g02d81e74bb+bd2ed33bd6,g1470d8bcf6+de7501a2e0,g14a832a312+ff425fae3c,g2079a07aa2+86d27d4dc4,g2305ad1205+91a32aca49,g295015adf3+762506a1ad,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g3ddfee87b4+c34e8be1fa,g487adcacf7+5fae3daba8,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+ea1711114f,g5a732f18d5+53520f316c,g64a986408d+bd2ed33bd6,g858d7b2824+bd2ed33bd6,g8a8a8dda67+585e252eca,g99cad8db69+016a06b37a,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+ef4e3a5875,gb0e22166c9+60f28cb32d,gb6a65358fc+0e5473021a,gba4ed39666+c2a2e4ac27,gbb8dafda3b+09e12c87ab,gc120e1dc64+bc2e06c061,gc28159a63d+0e5473021a,gcf0d15dbbd+c34e8be1fa,gdaeeff99f8+f9a426f77a,ge6526c86ff+508d0e0a30,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gf18bd8381d+8d59551888,gf1cff7945b+bd2ed33bd6,w.2024.16
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Static Public Attributes | Protected Member Functions | Static Protected Attributes | List of all members
lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask Class Reference
Inheritance diagram for lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask:

Public Member Functions

 __init__ (self, initInputs=None, *args, **kwargs)
 
 runQuantum (self, butlerQC, inputRefs, outputRefs)
 
 run (self, inputExposure, refObjLoader=None, dataId=None, skyCorr=None)
 
 applySkyCorr (self, calexp, skyCorr)
 
 extractStamps (self, inputExposure, filterName="phot_g_mean", refObjLoader=None, inputBrightStarStamps=None)
 
 warpStamps (self, stamps, pixCenters)
 
 setModelStamp (self)
 

Public Attributes

 modelStampSize
 
 modelCenter
 

Static Public Attributes

 ConfigClass = ProcessBrightStarsConfig
 

Protected Member Functions

 _getCutout (self, inputExposure, Point2D coordPix, list[int] stampSize)
 
 _replaceSecondaryFootprints (self, stamp, coordPix, objectId, find="DETECTED", replace="BAD")
 

Static Protected Attributes

str _DefaultName = "processBrightStars"
 

Detailed Description

Extract bright star cutouts; normalize and warp to the same pixel grid.

This task is used to extract, process, and store small image cut-outs
(or "postage stamps") around bright stars. It relies on three methods,
called in succession:

`extractStamps`
    Find bright stars within the exposure using a reference catalog and
    extract a stamp centered on each.
`warpStamps`
    Shift and warp each stamp to remove optical distortions and sample all
    stars on the same pixel grid.
`measureAndNormalize`
    Compute the flux of an object in an annulus and normalize it. This is
    required to normalize each bright star stamp as their central pixels
    are likely saturated and/or contain ghosts, and cannot be used.

Definition at line 165 of file processBrightStars.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.__init__ ( self,
initInputs = None,
* args,
** kwargs )

Definition at line 187 of file processBrightStars.py.

187 def __init__(self, initInputs=None, *args, **kwargs):
188 super().__init__(*args, **kwargs)
189 self.setModelStamp()
190

Member Function Documentation

◆ _getCutout()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask._getCutout ( self,
inputExposure,
Point2D coordPix,
list[int] stampSize )
protected
Get a cutout from an input exposure, handling edge cases.

Generate a cutout from an input exposure centered on a given position
and with a given size.
If any part of the cutout is outside the input exposure bounding box,
the cutout is padded with NaNs.

Parameters
----------
inputExposure : `~lsst.afw.image.ExposureF`
    The image to extract bright star stamps from.
coordPix : `~lsst.geom.Point2D`
    Center of the cutout in pixel space.
stampSize : `list` [`int`]
    Size of the cutout, in pixels.

Returns
-------
stamp : `~lsst.afw.image.ExposureF` or `None`
    The cutout, or `None` if the cutout is entirely outside the input
    exposure bounding box.

Notes
-----
This method is a short-term workaround until DM-40042 is implemented.
At that point, it should be replaced by a call to the Exposure method
``getCutout``, which will handle edge cases automatically.

Definition at line 415 of file processBrightStars.py.

415 def _getCutout(self, inputExposure, coordPix: Point2D, stampSize: list[int]):
416 """Get a cutout from an input exposure, handling edge cases.
417
418 Generate a cutout from an input exposure centered on a given position
419 and with a given size.
420 If any part of the cutout is outside the input exposure bounding box,
421 the cutout is padded with NaNs.
422
423 Parameters
424 ----------
425 inputExposure : `~lsst.afw.image.ExposureF`
426 The image to extract bright star stamps from.
427 coordPix : `~lsst.geom.Point2D`
428 Center of the cutout in pixel space.
429 stampSize : `list` [`int`]
430 Size of the cutout, in pixels.
431
432 Returns
433 -------
434 stamp : `~lsst.afw.image.ExposureF` or `None`
435 The cutout, or `None` if the cutout is entirely outside the input
436 exposure bounding box.
437
438 Notes
439 -----
440 This method is a short-term workaround until DM-40042 is implemented.
441 At that point, it should be replaced by a call to the Exposure method
442 ``getCutout``, which will handle edge cases automatically.
443 """
444 # TODO: Replace this method with exposure getCutout after DM-40042.
445 corner = Point2I(np.array(coordPix) - np.array(stampSize) / 2)
446 dimensions = Extent2I(stampSize)
447 stampBBox = Box2I(corner, dimensions)
448 overlapBBox = Box2I(stampBBox)
449 overlapBBox.clip(inputExposure.getBBox())
450 if overlapBBox.getArea() > 0:
451 # Create full-sized stamp with pixels initially flagged as NO_DATA.
452 stamp = ExposureF(bbox=stampBBox)
453 stamp.image[:] = np.nan
454 stamp.mask.set(inputExposure.mask.getPlaneBitMask("NO_DATA"))
455 # Restore pixels which overlap the input exposure.
456 inputMI = inputExposure.maskedImage
457 overlap = inputMI.Factory(inputMI, overlapBBox)
458 stamp.maskedImage[overlapBBox] = overlap
459 # Set detector and WCS.
460 stamp.setDetector(inputExposure.getDetector())
461 stamp.setWcs(inputExposure.getWcs())
462 else:
463 stamp = None
464 return stamp
465

◆ _replaceSecondaryFootprints()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask._replaceSecondaryFootprints ( self,
stamp,
coordPix,
objectId,
find = "DETECTED",
replace = "BAD" )
protected
Replace all secondary footprints in a stamp with another mask flag.

This method identifies all secondary footprints in a stamp as those
whose ``find`` footprints do not overlap the given pixel coordinates.
If then sets these secondary footprints to the ``replace`` flag.

Parameters
----------
stamp : `~lsst.afw.image.ExposureF`
    The postage stamp to modify.
coordPix : `~lsst.geom.Point2D`
    The pixel coordinates of the central primary object.
objectId : `int`
    The unique identifier of the central primary object.
find : `str`, optional
    The mask plane to use to identify secondary footprints.
replace : `str`, optional
    The mask plane to set secondary footprints to.

Notes
-----
This method modifies the input ``stamp`` in-place.

Definition at line 466 of file processBrightStars.py.

466 def _replaceSecondaryFootprints(self, stamp, coordPix, objectId, find="DETECTED", replace="BAD"):
467 """Replace all secondary footprints in a stamp with another mask flag.
468
469 This method identifies all secondary footprints in a stamp as those
470 whose ``find`` footprints do not overlap the given pixel coordinates.
471 If then sets these secondary footprints to the ``replace`` flag.
472
473 Parameters
474 ----------
475 stamp : `~lsst.afw.image.ExposureF`
476 The postage stamp to modify.
477 coordPix : `~lsst.geom.Point2D`
478 The pixel coordinates of the central primary object.
479 objectId : `int`
480 The unique identifier of the central primary object.
481 find : `str`, optional
482 The mask plane to use to identify secondary footprints.
483 replace : `str`, optional
484 The mask plane to set secondary footprints to.
485
486 Notes
487 -----
488 This method modifies the input ``stamp`` in-place.
489 """
490 # Find a FootprintSet given an Image and a threshold.
491 detThreshold = Threshold(stamp.mask.getPlaneBitMask(find), Threshold.BITMASK)
492 footprintSet = FootprintSet(stamp.mask, detThreshold)
493 allFootprints = footprintSet.getFootprints()
494 # Identify secondary objects (i.e., not the central primary object).
495 secondaryFootprints = []
496 for footprint in allFootprints:
497 if not footprint.contains(Point2I(coordPix)):
498 secondaryFootprints.append(footprint)
499 # Set secondary object footprints to BAD.
500 # Note: the value of numPrimaryFootprints can only be 0 or 1. If it is
501 # 0, then the primary object was not found overlapping a footprint.
502 # This can occur for low-S/N stars, for example. Processing can still
503 # continue beyond this point in an attempt to utilize this faint flux.
504 if (numPrimaryFootprints := len(allFootprints) - len(secondaryFootprints)) == 0:
505 self.log.info(
506 "Could not uniquely identify central %s footprint for star %s; "
507 "found %d footprints instead.",
508 find,
509 objectId,
510 numPrimaryFootprints,
511 )
512 footprintSet.setFootprints(secondaryFootprints)
513 footprintSet.setMask(stamp.mask, replace)
514

◆ applySkyCorr()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.applySkyCorr ( self,
calexp,
skyCorr )
Apply sky correction to the input exposure.

Sky corrections can be generated using the
`~lsst.pipe.tasks.skyCorrection.SkyCorrectionTask`.
As the sky model generated via that task extends over the full focal
plane, this should produce a more optimal sky subtraction solution.

Parameters
----------
calexp : `~lsst.afw.image.Exposure` or `~lsst.afw.image.MaskedImage`
    Calibrated exposure to correct.
skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`
    Full focal plane sky correction from ``SkyCorrectionTask``.

Notes
-----
This method modifies the input ``calexp`` in-place.

Definition at line 298 of file processBrightStars.py.

298 def applySkyCorr(self, calexp, skyCorr):
299 """Apply sky correction to the input exposure.
300
301 Sky corrections can be generated using the
302 `~lsst.pipe.tasks.skyCorrection.SkyCorrectionTask`.
303 As the sky model generated via that task extends over the full focal
304 plane, this should produce a more optimal sky subtraction solution.
305
306 Parameters
307 ----------
308 calexp : `~lsst.afw.image.Exposure` or `~lsst.afw.image.MaskedImage`
309 Calibrated exposure to correct.
310 skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`
311 Full focal plane sky correction from ``SkyCorrectionTask``.
312
313 Notes
314 -----
315 This method modifies the input ``calexp`` in-place.
316 """
317 if isinstance(calexp, Exposure):
318 calexp = calexp.getMaskedImage()
319 calexp -= skyCorr.getImage()
320

◆ extractStamps()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.extractStamps ( self,
inputExposure,
filterName = "phot_g_mean",
refObjLoader = None,
inputBrightStarStamps = None )
Identify the positions of bright stars within an input exposure using
a reference catalog and extract them.

Parameters
----------
inputExposure : `~lsst.afw.image.ExposureF`
    The image to extract bright star stamps from.
filterName : `str`, optional
    Name of the camera filter to use for reference catalog filtering.
refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
    Loader to find objects within a reference catalog.
inputBrightStarStamps:
    `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`, optional
    Provides information about the stars that have already been
    extracted from the inputExposure in other steps of the pipeline.
    For example, this is used in the `SubtractBrightStarsTask` to avoid
    extracting stars that already have been extracted when running
    `ProcessBrightStarsTask` to produce brightStarStamps.

Returns
-------
result : `~lsst.pipe.base.Struct`
    Results as a struct with attributes:

    ``starStamps``
        Postage stamps (`list`).
    ``pixCenters``
        Corresponding coords to each star's center, in pixels (`list`).
    ``gMags``
        Corresponding (Gaia) G magnitudes (`list`).
    ``gaiaIds``
        Corresponding unique Gaia identifiers (`np.ndarray`).

Definition at line 321 of file processBrightStars.py.

323 ):
324 """Identify the positions of bright stars within an input exposure using
325 a reference catalog and extract them.
326
327 Parameters
328 ----------
329 inputExposure : `~lsst.afw.image.ExposureF`
330 The image to extract bright star stamps from.
331 filterName : `str`, optional
332 Name of the camera filter to use for reference catalog filtering.
333 refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
334 Loader to find objects within a reference catalog.
335 inputBrightStarStamps:
336 `~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`, optional
337 Provides information about the stars that have already been
338 extracted from the inputExposure in other steps of the pipeline.
339 For example, this is used in the `SubtractBrightStarsTask` to avoid
340 extracting stars that already have been extracted when running
341 `ProcessBrightStarsTask` to produce brightStarStamps.
342
343 Returns
344 -------
345 result : `~lsst.pipe.base.Struct`
346 Results as a struct with attributes:
347
348 ``starStamps``
349 Postage stamps (`list`).
350 ``pixCenters``
351 Corresponding coords to each star's center, in pixels (`list`).
352 ``gMags``
353 Corresponding (Gaia) G magnitudes (`list`).
354 ``gaiaIds``
355 Corresponding unique Gaia identifiers (`np.ndarray`).
356 """
357 if refObjLoader is None:
358 refObjLoader = self.refObjLoader
359
360 wcs = inputExposure.getWcs()
361 inputBBox = inputExposure.getBBox()
362
363 # Trim the reference catalog to only those objects within the exposure
364 # bounding box dilated by half the bright star stamp size. This ensures
365 # all stars that overlap the exposure are included.
366 dilatationExtent = Extent2I(np.array(self.config.stampSize) // 2)
367 withinExposure = refObjLoader.loadPixelBox(
368 inputBBox.dilatedBy(dilatationExtent), wcs, filterName=filterName
369 )
370 refCat = withinExposure.refCat
371 fluxField = withinExposure.fluxField
372
373 # Define ref cat bright subset: objects brighter than the mag limit.
374 fluxLimit = ((self.config.magLimit * u.ABmag).to(u.nJy)).to_value() # AB magnitudes.
375 refCatBright = Table(
376 refCat.extract("id", "coord_ra", "coord_dec", fluxField, where=refCat[fluxField] > fluxLimit)
377 )
378 refCatBright["mag"] = (refCatBright[fluxField][:] * u.nJy).to(u.ABmag).to_value() # AB magnitudes.
379
380 # Remove input bright stars (if provided) from the bright subset.
381 if inputBrightStarStamps is not None:
382 # Extract the IDs of stars that have already been extracted.
383 existing = np.isin(refCatBright["id"][:], inputBrightStarStamps.getGaiaIds())
384 refCatBright = refCatBright[~existing]
385
386 # Loop over each reference bright star, extract a stamp around it.
387 pixCenters = []
388 starStamps = []
389 badRows = []
390 for row, object in enumerate(refCatBright):
391 coordSky = SpherePoint(object["coord_ra"], object["coord_dec"], radians)
392 coordPix = wcs.skyToPixel(coordSky)
393 # TODO: Replace this method with exposure getCutout after DM-40042.
394 starStamp = self._getCutout(inputExposure, coordPix, self.config.stampSize.list())
395 if not starStamp:
396 badRows.append(row)
397 continue
398 if self.config.doRemoveDetected:
399 self._replaceSecondaryFootprints(starStamp, coordPix, object["id"])
400 starStamps.append(starStamp)
401 pixCenters.append(coordPix)
402
403 # Remove bad rows from the reference catalog; set up return data.
404 refCatBright.remove_rows(badRows)
405 gMags = list(refCatBright["mag"][:])
406 ids = list(refCatBright["id"][:])
407
408 # Store the count number of all stars (within the given magnitude
409 # range) that overlap the exposure.
410 # TODO: Make sure self._getCutout only misses stars that don't have any
411 # valid pixel overlapped with the exposure.
412 self.metadata["allStarCount"] = len(starStamps)
413 return Struct(starStamps=starStamps, pixCenters=pixCenters, gMags=gMags, gaiaIds=ids)
414

◆ run()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.run ( self,
inputExposure,
refObjLoader = None,
dataId = None,
skyCorr = None )
Identify bright stars within an exposure using a reference catalog,
extract stamps around each, then preprocess them.

Bright star preprocessing steps are: shifting, warping and potentially
rotating them to the same pixel grid; computing their annular flux,
and; normalizing them.

Parameters
----------
inputExposure : `~lsst.afw.image.ExposureF`
    The image from which bright star stamps should be extracted.
refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
    Loader to find objects within a reference catalog.
dataId : `dict` or `~lsst.daf.butler.DataCoordinate`
    The dataId of the exposure (including detector) that bright stars
    should be extracted from.
skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`, optional
    Full focal plane sky correction obtained by `SkyCorrectionTask`.

Returns
-------
brightStarResults : `~lsst.pipe.base.Struct`
    Results as a struct with attributes:

    ``brightStarStamps``
        (`~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`)

Definition at line 206 of file processBrightStars.py.

206 def run(self, inputExposure, refObjLoader=None, dataId=None, skyCorr=None):
207 """Identify bright stars within an exposure using a reference catalog,
208 extract stamps around each, then preprocess them.
209
210 Bright star preprocessing steps are: shifting, warping and potentially
211 rotating them to the same pixel grid; computing their annular flux,
212 and; normalizing them.
213
214 Parameters
215 ----------
216 inputExposure : `~lsst.afw.image.ExposureF`
217 The image from which bright star stamps should be extracted.
218 refObjLoader : `~lsst.meas.algorithms.ReferenceObjectLoader`, optional
219 Loader to find objects within a reference catalog.
220 dataId : `dict` or `~lsst.daf.butler.DataCoordinate`
221 The dataId of the exposure (including detector) that bright stars
222 should be extracted from.
223 skyCorr : `~lsst.afw.math.backgroundList.BackgroundList`, optional
224 Full focal plane sky correction obtained by `SkyCorrectionTask`.
225
226 Returns
227 -------
228 brightStarResults : `~lsst.pipe.base.Struct`
229 Results as a struct with attributes:
230
231 ``brightStarStamps``
232 (`~lsst.meas.algorithms.brightStarStamps.BrightStarStamps`)
233 """
234 if self.config.doApplySkyCorr:
235 self.log.info("Applying sky correction to exposure %s (exposure modified in-place).", dataId)
236 self.applySkyCorr(inputExposure, skyCorr)
237
238 self.log.info("Extracting bright stars from exposure %s", dataId)
239 # Extract stamps around bright stars.
240 extractedStamps = self.extractStamps(inputExposure, refObjLoader=refObjLoader)
241 if not extractedStamps.starStamps:
242 self.log.info("No suitable bright star found.")
243 return None
244 # Warp (and shift, and potentially rotate) them.
245 self.log.info(
246 "Applying warp and/or shift to %i star stamps from exposure %s.",
247 len(extractedStamps.starStamps),
248 dataId,
249 )
250 warpOutputs = self.warpStamps(extractedStamps.starStamps, extractedStamps.pixCenters)
251 warpedStars = warpOutputs.warpedStars
252 xy0s = warpOutputs.xy0s
253 brightStarList = [
254 BrightStarStamp(
255 stamp_im=warp,
256 archive_element=transform,
257 position=xy0s[j],
258 gaiaGMag=extractedStamps.gMags[j],
259 gaiaId=extractedStamps.gaiaIds[j],
260 minValidAnnulusFraction=self.config.minValidAnnulusFraction,
261 )
262 for j, (warp, transform) in enumerate(zip(warpedStars, warpOutputs.warpTransforms))
263 ]
264 # Compute annularFlux and normalize
265 self.log.info(
266 "Computing annular flux and normalizing %i bright stars from exposure %s.",
267 len(warpedStars),
268 dataId,
269 )
270 # annularFlux statistic set-up, excluding mask planes
271 statsControl = StatisticsControl(
272 numSigmaClip=self.config.numSigmaClip,
273 numIter=self.config.numIter,
274 )
275
276 innerRadius, outerRadius = self.config.annularFluxRadii
277 statsFlag = stringToStatisticsProperty(self.config.annularFluxStatistic)
278 brightStarStamps = BrightStarStamps.initAndNormalize(
279 brightStarList,
280 innerRadius=innerRadius,
281 outerRadius=outerRadius,
282 nb90Rots=warpOutputs.nb90Rots,
283 imCenter=self.modelCenter,
284 use_archive=True,
285 statsControl=statsControl,
286 statsFlag=statsFlag,
287 badMaskPlanes=self.config.badMaskPlanes,
288 discardNanFluxObjects=(self.config.discardNanFluxStars),
289 )
290 # Store the count number of valid stars that overlap the exposure.
291 self.metadata["validStarCount"] = len(brightStarStamps)
292 # Do not create empty FITS files if there aren't any normalized stamps.
293 if not brightStarStamps._stamps:
294 self.log.info("No normalized stamps exist for this exposure.")
295 return None
296 return Struct(brightStarStamps=brightStarStamps)
297

◆ runQuantum()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.runQuantum ( self,
butlerQC,
inputRefs,
outputRefs )

Definition at line 191 of file processBrightStars.py.

191 def runQuantum(self, butlerQC, inputRefs, outputRefs):
192 inputs = butlerQC.get(inputRefs)
193 inputs["dataId"] = str(butlerQC.quantum.dataId)
194 refObjLoader = ReferenceObjectLoader(
195 dataIds=[ref.datasetRef.dataId for ref in inputRefs.refCat],
196 refCats=inputs.pop("refCat"),
197 name=self.config.connections.refCat,
198 config=self.config.refObjLoader,
199 )
200 output = self.run(**inputs, refObjLoader=refObjLoader)
201 # Only ingest stamp if it exists; prevent ingesting an empty FITS file.
202 if output:
203 butlerQC.put(output, outputRefs)
204

◆ setModelStamp()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.setModelStamp ( self)
Compute (model) stamp size depending on provided buffer value.

Definition at line 611 of file processBrightStars.py.

611 def setModelStamp(self):
612 """Compute (model) stamp size depending on provided buffer value."""
613 self.modelStampSize = [
614 int(self.config.stampSize[0] * self.config.modelStampBuffer),
615 int(self.config.stampSize[1] * self.config.modelStampBuffer),
616 ]
617 # Force stamp to be odd-sized so we have a central pixel.
618 if not self.modelStampSize[0] % 2:
619 self.modelStampSize[0] += 1
620 if not self.modelStampSize[1] % 2:
621 self.modelStampSize[1] += 1
622 # Central pixel.
623 self.modelCenter = self.modelStampSize[0] // 2, self.modelStampSize[1] // 2

◆ warpStamps()

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.warpStamps ( self,
stamps,
pixCenters )
Warps and shifts all given stamps so they are sampled on the same
pixel grid and centered on the central pixel. This includes rotating
the stamp depending on detector orientation.

Parameters
----------
stamps : `Sequence` [`~lsst.afw.image.ExposureF`]
    Image cutouts centered on a single object.
pixCenters : `Sequence` [`~lsst.geom.Point2D`]
    Positions of each object's center (from the refCat) in pixels.

Returns
-------
result : `~lsst.pipe.base.Struct`
    Results as a struct with attributes:

    ``warpedStars``
        Stamps of warped stars.
            (`list` [`~lsst.afw.image.MaskedImage`])
    ``warpTransforms``
        The corresponding Transform from the initial star stamp
        to the common model grid.
            (`list` [`~lsst.afw.geom.TransformPoint2ToPoint2`])
    ``xy0s``
        Coordinates of the bottom-left pixels of each stamp,
        before rotation.
            (`list` [`~lsst.geom.Point2I`])
    ``nb90Rots``
        The number of 90 degrees rotations required to compensate for
        detector orientation.
            (`int`)

Definition at line 515 of file processBrightStars.py.

515 def warpStamps(self, stamps, pixCenters):
516 """Warps and shifts all given stamps so they are sampled on the same
517 pixel grid and centered on the central pixel. This includes rotating
518 the stamp depending on detector orientation.
519
520 Parameters
521 ----------
522 stamps : `Sequence` [`~lsst.afw.image.ExposureF`]
523 Image cutouts centered on a single object.
524 pixCenters : `Sequence` [`~lsst.geom.Point2D`]
525 Positions of each object's center (from the refCat) in pixels.
526
527 Returns
528 -------
529 result : `~lsst.pipe.base.Struct`
530 Results as a struct with attributes:
531
532 ``warpedStars``
533 Stamps of warped stars.
534 (`list` [`~lsst.afw.image.MaskedImage`])
535 ``warpTransforms``
536 The corresponding Transform from the initial star stamp
537 to the common model grid.
538 (`list` [`~lsst.afw.geom.TransformPoint2ToPoint2`])
539 ``xy0s``
540 Coordinates of the bottom-left pixels of each stamp,
541 before rotation.
542 (`list` [`~lsst.geom.Point2I`])
543 ``nb90Rots``
544 The number of 90 degrees rotations required to compensate for
545 detector orientation.
546 (`int`)
547 """
548 # warping control; only contains shiftingALg provided in config
549 warpCont = WarpingControl(self.config.warpingKernelName)
550 # Compare model to star stamp sizes
551 bufferPix = (
552 self.modelStampSize[0] - self.config.stampSize[0],
553 self.modelStampSize[1] - self.config.stampSize[1],
554 )
555 # Initialize detector instance (note all stars were extracted from an
556 # exposure from the same detector)
557 det = stamps[0].getDetector()
558 # Define correction for optical distortions
559 if self.config.doApplyTransform:
560 pixToTan = det.getTransform(PIXELS, TAN_PIXELS)
561 else:
562 pixToTan = makeIdentityTransform()
563 # Array of all possible rotations for detector orientation:
564 possibleRots = np.array([k * np.pi / 2 for k in range(4)])
565 # determine how many, if any, rotations are required
566 yaw = det.getOrientation().getYaw()
567 nb90Rots = np.argmin(np.abs(possibleRots - float(yaw)))
568
569 # apply transformation to each star
570 warpedStars, warpTransforms, xy0s = [], [], []
571 for star, cent in zip(stamps, pixCenters):
572 # (re)create empty destination image
573 destImage = MaskedImageF(*self.modelStampSize)
574 bottomLeft = Point2D(star.image.getXY0())
575 newBottomLeft = pixToTan.applyForward(bottomLeft)
576 newBottomLeft.setX(newBottomLeft.getX() - bufferPix[0] / 2)
577 newBottomLeft.setY(newBottomLeft.getY() - bufferPix[1] / 2)
578 # Convert to int
579 newBottomLeft = Point2I(newBottomLeft)
580 # Set origin and save it
581 destImage.setXY0(newBottomLeft)
582 xy0s.append(newBottomLeft)
583
584 # Define linear shifting to recenter stamps
585 newCenter = pixToTan.applyForward(cent) # center of warped star
586 shift = (
587 self.modelCenter[0] + newBottomLeft[0] - newCenter[0],
588 self.modelCenter[1] + newBottomLeft[1] - newCenter[1],
589 )
590 affineShift = AffineTransform(shift)
591 shiftTransform = makeTransform(affineShift)
592
593 # Define full transform (warp and shift)
594 starWarper = pixToTan.then(shiftTransform)
595
596 # Apply it
597 goodPix = warpImage(destImage, star.getMaskedImage(), starWarper, warpCont)
598 if not goodPix:
599 self.log.debug("Warping of a star failed: no good pixel in output")
600
601 # Arbitrarily set origin of shifted star to 0
602 destImage.setXY0(0, 0)
603
604 # Apply rotation if appropriate
605 if nb90Rots:
606 destImage = rotateImageBy90(destImage, nb90Rots)
607 warpedStars.append(destImage.clone())
608 warpTransforms.append(starWarper)
609 return Struct(warpedStars=warpedStars, warpTransforms=warpTransforms, xy0s=xy0s, nb90Rots=nb90Rots)
610

Member Data Documentation

◆ _DefaultName

str lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask._DefaultName = "processBrightStars"
staticprotected

Definition at line 185 of file processBrightStars.py.

◆ ConfigClass

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.ConfigClass = ProcessBrightStarsConfig
static

Definition at line 184 of file processBrightStars.py.

◆ modelCenter

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.modelCenter

Definition at line 623 of file processBrightStars.py.

◆ modelStampSize

lsst.pipe.tasks.processBrightStars.ProcessBrightStarsTask.modelStampSize

Definition at line 613 of file processBrightStars.py.


The documentation for this class was generated from the following file: