LSST Applications g0f08755f38+82efc23009,g12f32b3c4e+e7bdf1200e,g1653933729+a8ce1bb630,g1a0ca8cf93+50eff2b06f,g28da252d5a+52db39f6a5,g2bbee38e9b+37c5a29d61,g2bc492864f+37c5a29d61,g2cdde0e794+c05ff076ad,g3156d2b45e+41e33cbcdc,g347aa1857d+37c5a29d61,g35bb328faa+a8ce1bb630,g3a166c0a6a+37c5a29d61,g3e281a1b8c+fb992f5633,g414038480c+7f03dfc1b0,g41af890bb2+11b950c980,g5fbc88fb19+17cd334064,g6b1c1869cb+12dd639c9a,g781aacb6e4+a8ce1bb630,g80478fca09+72e9651da0,g82479be7b0+04c31367b4,g858d7b2824+82efc23009,g9125e01d80+a8ce1bb630,g9726552aa6+8047e3811d,ga5288a1d22+e532dc0a0b,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+37c5a29d61,gcf0d15dbbd+2acd6d4d48,gd7358e8bfb+778a810b6e,gda3e153d99+82efc23009,gda6a2b7d83+2acd6d4d48,gdaeeff99f8+1711a396fd,ge2409df99d+6b12de1076,ge79ae78c31+37c5a29d61,gf0baf85859+d0a5978c5a,gf3967379c6+4954f8c433,gfb92a5be7c+82efc23009,gfec2e1e490+2aaed99252,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
_warper.py
Go to the documentation of this file.
1# This file is part of afw.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
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 GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22__all__ = ["Warper", "WarperConfig"]
23
24import lsst.pex.config as pexConfig
25import lsst.geom
26import lsst.afw.image as afwImage
27from ._math import warpImage
28from ._math import WarpingControl
29from ._math import warpExposure
30
31
32def computeWarpedBBox(destWcs, srcBBox, srcWcs):
33 """Compute the bounding box of a warped image.
34
35 The bounding box includes all warped pixels and it may be a bit oversize.
36
37 Parameters
38 ----------
39 destWcs : `lsst.afw.geom.SkyWcs`
40 WCS of warped exposure
41 srcBBox : `lsst.geom.Box2I`
42 parent bounding box of unwarped image
43 srcWcs : `lsst.afw.geom.SkyWcs`
44 WCS of unwarped image
45
46 Returns
47 -------
48 destBBox: `lsst.geom.Box2I`
49 bounding box of warped exposure
50 """
51 srcPosBox = lsst.geom.Box2D(srcBBox)
52 destPosBox = lsst.geom.Box2D()
53 for inX in (srcPosBox.getMinX(), srcPosBox.getMaxX()):
54 for inY in (srcPosBox.getMinY(), srcPosBox.getMaxY()):
55 destPos = destWcs.skyToPixel(srcWcs.pixelToSky(inX, inY))
56 destPosBox.include(destPos)
57 destBBox = lsst.geom.Box2I(destPosBox, lsst.geom.Box2I.EXPAND)
58 return destBBox
59
60
61_DefaultInterpLength = 10
62_DefaultCacheSize = 1000000
63
64
65class WarperConfig(pexConfig.Config):
66 warpingKernelName = pexConfig.ChoiceField(
67 dtype=str,
68 doc="Warping kernel",
69 default="lanczos3",
70 allowed={
71 "bilinear": "bilinear interpolation",
72 "lanczos3": "Lanczos kernel of order 3",
73 "lanczos4": "Lanczos kernel of order 4",
74 "lanczos5": "Lanczos kernel of order 5",
75 }
76 )
77 maskWarpingKernelName = pexConfig.ChoiceField(
78 dtype=str,
79 doc="Warping kernel for mask (use ``warpingKernelName`` if '')",
80 default="bilinear",
81 allowed={
82 "": "use the regular warping kernel for the mask plane, as well as the image and variance planes",
83 "bilinear": "bilinear interpolation",
84 "lanczos3": "Lanczos kernel of order 3",
85 "lanczos4": "Lanczos kernel of order 4",
86 "lanczos5": "Lanczos kernel of order 5",
87 }
88 )
89 interpLength = pexConfig.Field(
90 dtype=int,
91 doc="``interpLength`` argument to `lsst.afw.math.warpExposure`",
92 default=_DefaultInterpLength,
93 )
94 cacheSize = pexConfig.Field(
95 dtype=int,
96 doc="``cacheSize`` argument to `lsst.afw.math.SeparableKernel.computeCache`",
97 default=_DefaultCacheSize,
98 )
99 growFullMask = pexConfig.Field(
100 dtype=int,
101 doc="mask bits to grow to full width of image/variance kernel,",
102 default=afwImage.Mask.getPlaneBitMask("EDGE"),
103 )
104
105
106class Warper:
107 """Warp images.
108
109 Parameters
110 ----------
111 warpingKernelName : `str`
112 see `WarperConfig.warpingKernelName`
113 interpLength : `int`, optional
114 ``interpLength`` argument to `lsst.afw.math.warpExposure`
115 cacheSize : `int`, optional
116 size of computeCache
117 maskWarpingKernelName : `str`, optional
118 name of mask warping kernel (if ``""`` then use ``warpingKernelName``);
119 see `WarperConfig.maskWarpingKernelName`
120 growFullMask : `int`, optional
121 mask bits to grow to full width of image/variance kernel
122 """
123 ConfigClass = WarperConfig
124
125 def __init__(self,
126 warpingKernelName,
127 interpLength=_DefaultInterpLength,
128 cacheSize=_DefaultCacheSize,
129 maskWarpingKernelName="",
130 growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"),):
131 self._warpingControl = WarpingControl(
132 warpingKernelName, maskWarpingKernelName, cacheSize, interpLength, growFullMask)
133
134 @classmethod
135 def fromConfig(cls, config):
136 """Create a Warper from a config.
137
138 Parameters
139 ----------
140 config : `WarperConfig`
141 The config to initialize the Warper with.
142 """
143 return cls(
144 warpingKernelName=config.warpingKernelName,
145 maskWarpingKernelName=config.maskWarpingKernelName,
146 interpLength=config.interpLength,
147 cacheSize=config.cacheSize,
148 growFullMask=config.growFullMask,
149 )
150
152 """Get the warping kernel.
153 """
155
157 """Get the mask warping kernel.
158 """
160
161 def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None):
162 """Warp an exposure.
163
164 Parameters
165 -----------
166 destWcs : `lsst.afw.geom.SkyWcs`
167 WCS of warped exposure
168 srcExposure
169 exposure to warp
170 border : `int`, optional
171 grow bbox of warped exposure by this amount in all directions
172 (in pixels); if negative then the bbox is shrunk; border is applied
173 before ``maxBBox``; ignored if ``destBBox`` is not `None`
174 maxBBox : `lsst.geom.Box2I`, optional
175 maximum allowed parent bbox of warped exposure; if `None` then the
176 warped exposure will be just big enough to contain all warped pixels;
177 if provided then the warped exposure may be smaller, and so
178 missing some warped pixels; ignored if ``destBBox`` is not `None`
179 destBBox : `lsst.geom.Box2I`, optional
180 exact parent bbox of warped exposure; if `None` then ``border`` and
181 ``maxBBox`` are used to determine the bbox, otherwise ``border``
182 and ``maxBBox`` are ignored
183
184 Returns
185 -------
186 destExposure : same type as ``srcExposure``
187 warped exposure
188
189 Notes
190 -----
191 calls `lsst.afw.math.warpExposure` insted of `~Warper.warpImage` because the former
192 copies attributes such as ``Calib``, and that should be done in one place
193
194 The PSF is not warped. To warp the PSF, use `lsst.meas.algorithms.WarpedPsf`
195 """
196 destBBox = self._computeDestBBox(
197 destWcs=destWcs,
198 srcImage=srcExposure.getMaskedImage(),
199 srcWcs=srcExposure.getWcs(),
200 border=border,
201 maxBBox=maxBBox,
202 destBBox=destBBox,
203 )
204 destExposure = srcExposure.Factory(destBBox, destWcs)
205 warpExposure(destExposure, srcExposure, self._warpingControl)
206 return destExposure
207
208 def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None):
209 """Warp an image or masked image.
210
211 Parameters
212 ----------
213 destWcs : `lsst.afw.geom.SkyWcs`
214 WCS of warped image
215 srcImage
216 image or masked image to warp
217 srcWcs : `lsst.afw.geom.SkyWcs`
218 WCS of image
219 border : `int`, optional
220 grow bbox of warped image by this amount in all directions
221 (in pixels); if negative then the bbox is shrunk; border is applied
222 before ``maxBBox``; ignored if ``destBBox`` is not `None`
223 maxBBox : `lsst.geom.Box2I`, optional
224 maximum allowed parent bbox of warped image; if `None` then the
225 warped image will be just big enough to contain all warped pixels;
226 if provided then the warped image may be smaller, and so
227 missing some warped pixels; ignored if ``destBBox`` is not `None`
228 destBBox : `lsst.geom.Box2I`, optional
229 exact parent bbox of warped image; if `None` then ``border`` and
230 ``maxBBox`` are used to determine the bbox, otherwise ``border``
231 and ``maxBBox`` are ignored
232
233 Returns
234 -------
235 destImage : same type as ``srcExposure``
236 warped image or masked image
237 """
238 destBBox = self._computeDestBBox(
239 destWcs=destWcs,
240 srcImage=srcImage,
241 srcWcs=srcWcs,
242 border=border,
243 maxBBox=maxBBox,
244 destBBox=destBBox,
245 )
246 destImage = srcImage.Factory(destBBox)
247 warpImage(destImage, destWcs, srcImage,
248 srcWcs, self._warpingControl)
249 return destImage
250
251 def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox):
252 """Process destBBox argument for warpImage and warpExposure.
253
254 Parameters
255 ----------
256 destWcs : `lsst.afw.geom.SkyWcs`
257 WCS of warped image
258 srcImage
259 image or masked image to warp
260 srcWcs : `lsst.afw.geom.SkyWcs`
261 WCS of image
262 border : `int`, optional
263 grow bbox of warped image by this amount in all directions
264 (in pixels); if negative then the bbox is shrunk; border is applied
265 before ``maxBBox``; ignored if ``destBBox`` is not `None`
266 maxBBox : `lsst.geom.Box2I`, optional
267 maximum allowed parent bbox of warped image; if `None` then the
268 warped image will be just big enough to contain all warped pixels;
269 if provided then the warped image may be smaller, and so
270 missing some warped pixels; ignored if ``destBBox`` is not `None`
271 destBBox : `lsst.geom.Box2I`, optional
272 exact parent bbox of warped image; if `None` then ``border`` and
273 ``maxBBox`` are used to determine the bbox, otherwise ``border``
274 and ``maxBBox`` are ignored
275 """
276 if destBBox is None: # warning: == None fails due to Box2I.__eq__
277 destBBox = computeWarpedBBox(
278 destWcs, srcImage.getBBox(afwImage.PARENT), srcWcs)
279 if border:
280 destBBox.grow(border)
281 if maxBBox is not None:
282 destBBox.clip(maxBBox)
283 return destBBox
warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None)
Definition _warper.py:161
_computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox)
Definition _warper.py:251
__init__(self, warpingKernelName, interpLength=_DefaultInterpLength, cacheSize=_DefaultCacheSize, maskWarpingKernelName="", growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"))
Definition _warper.py:130
warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None)
Definition _warper.py:208
A floating-point coordinate rectangle geometry.
Definition Box.h:413
An integer coordinate rectangle.
Definition Box.h:55
computeWarpedBBox(destWcs, srcBBox, srcWcs)
Definition _warper.py:32