LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
_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 
24 import lsst.pex.config as pexConfig
25 import lsst.geom
26 import lsst.afw.image as afwImage
27 from ._math import warpImage
28 from ._math import WarpingControl
29 from ._math import warpExposure
30 
31 
32 def 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 
65 class 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 
106 class 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 = 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 
151  def getWarpingKernel(self):
152  """Get the warping kernel.
153  """
154  return self._warpingControl_warpingControl.getWarpingKernel()
155 
157  """Get the mask warping kernel.
158  """
159  return self._warpingControl_warpingControl.getMaskWarpingKernel()
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_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_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_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_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
def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None)
Definition: _warper.py:208
def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox)
Definition: _warper.py:251
def fromConfig(cls, config)
Definition: _warper.py:135
def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None)
Definition: _warper.py:161
def __init__(self, warpingKernelName, interpLength=_DefaultInterpLength, cacheSize=_DefaultCacheSize, maskWarpingKernelName="", growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"))
Definition: _warper.py:130
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
An integer coordinate rectangle.
Definition: Box.h:55
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def computeWarpedBBox(destWcs, srcBBox, srcWcs)
Definition: _warper.py:32