Coverage for python/lsst/meas/algorithms/skyObjects.py: 28%

48 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-18 02:44 -0800

1 

2__all__ = ["SkyObjectsConfig", "SkyObjectsTask", "generateSkyObjects"] 

3 

4from lsst.pex.config import Config, Field, ListField 

5from lsst.pipe.base import Task 

6 

7import lsst.afw.detection 

8import lsst.afw.geom 

9import lsst.afw.math 

10 

11 

12class SkyObjectsConfig(Config): 

13 """Configuration for generating sky objects""" 

14 avoidMask = ListField(dtype=str, default=["DETECTED", "DETECTED_NEGATIVE", "BAD", "NO_DATA"], 

15 doc="Avoid pixels masked with these mask planes") 

16 growMask = Field(dtype=int, default=0, 

17 doc="Number of pixels to grow the masked pixels when adding sky objects") 

18 sourceRadius = Field(dtype=float, default=8, doc="Radius, in pixels, of sky objects") 

19 nSources = Field(dtype=int, default=100, doc="Try to add this many sky objects") 

20 nTrialSources = Field(dtype=int, default=None, optional=True, 

21 doc="Maximum number of trial sky object positions " 

22 "(default: nSkySources*nTrialSkySourcesMultiplier)") 

23 nTrialSourcesMultiplier = Field(dtype=int, default=5, 

24 doc="Set nTrialSkySources to " 

25 "nSkySources*nTrialSkySourcesMultiplier " 

26 "if nTrialSkySources is None") 

27 

28 

29def generateSkyObjects(mask, seed, config): 

30 """Generate a list of Footprints of sky objects 

31 

32 Sky objects don't overlap with other objects. This is determined 

33 through the provided `mask` (in which objects are typically flagged 

34 as `DETECTED`). 

35 

36 The algorithm for determining sky objects is random trial and error: 

37 we try up to `nTrialSkySources` random positions to find `nSources` 

38 sky objects. 

39 

40 Parameters 

41 ---------- 

42 mask : `lsst.afw.image.Mask` 

43 Input mask plane, which identifies pixels to avoid for the sky 

44 objects. 

45 seed : `int` 

46 Random number generator seed. 

47 config : `SkyObjectsConfig` 

48 Configuration for finding sky objects. 

49 

50 Returns 

51 ------- 

52 skyFootprints : `list` of `lsst.afw.detection.Footprint` 

53 Footprints of sky objects. Each will have a peak at the center 

54 of the sky object. 

55 """ 

56 if config.nSources <= 0: 

57 return [] 

58 

59 skySourceRadius = config.sourceRadius 

60 nSkySources = config.nSources 

61 nTrialSkySources = config.nTrialSources 

62 if nTrialSkySources is None: 

63 nTrialSkySources = config.nTrialSourcesMultiplier*nSkySources 

64 

65 box = mask.getBBox() 

66 box.grow(-(int(skySourceRadius) + 1)) # Avoid objects partially off the image 

67 xMin, yMin = box.getMin() 

68 xMax, yMax = box.getMax() 

69 

70 avoid = lsst.afw.geom.SpanSet.fromMask(mask, mask.getPlaneBitMask(config.avoidMask)) 

71 if config.growMask > 0: 

72 avoid = avoid.dilated(config.growMask) 

73 

74 rng = lsst.afw.math.Random(seed=seed) 

75 

76 skyFootprints = [] 

77 for _ in range(nTrialSkySources): 

78 if len(skyFootprints) == nSkySources: 

79 break 

80 

81 x = int(rng.flat(xMin, xMax)) 

82 y = int(rng.flat(yMin, yMax)) 

83 spans = lsst.afw.geom.SpanSet.fromShape(int(skySourceRadius), offset=(x, y)) 

84 if spans.overlaps(avoid): 

85 continue 

86 

87 fp = lsst.afw.detection.Footprint(spans, mask.getBBox()) 

88 fp.addPeak(x, y, 0) 

89 skyFootprints.append(fp) 

90 

91 return skyFootprints 

92 

93 

94class SkyObjectsTask(Task): 

95 """Generate a list of Footprints of sky objects. 

96 """ 

97 ConfigClass = SkyObjectsConfig 

98 

99 def run(self, mask, seed): 

100 """Generate a list of Footprints of sky objects 

101 

102 Sky objects don't overlap with other objects. This is determined 

103 through the provided `mask` (in which objects are typically flagged 

104 as `DETECTED`). 

105 

106 The algorithm for determining sky objects is random trial and error: 

107 we try up to `nTrialSkySources` random positions to find `nSources` 

108 sky objects. 

109 

110 Parameters 

111 ---------- 

112 mask : `lsst.afw.image.Mask` 

113 Input mask plane, which identifies pixels to avoid for the sky 

114 objects. 

115 seed : `int` 

116 Random number generator seed. 

117 

118 Returns 

119 ------- 

120 skyFootprints : `list` of `lsst.afw.detection.Footprint` 

121 Footprints of sky objects. Each will have a peak at the center 

122 of the sky object. 

123 """ 

124 skyFootprints = generateSkyObjects(mask, seed, self.config) 

125 self.log.info("Added %d of %d requested sky sources (%.0f%%)", len(skyFootprints), 

126 self.config.nSources, 100*len(skyFootprints)/self.config.nSources) 

127 return skyFootprints