LSSTApplications  20.0.0
LSSTDataManagementBasePackage
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 . import mathLib
28 
29 
30 def computeWarpedBBox(destWcs, srcBBox, srcWcs):
31  """Compute the bounding box of a warped image.
32 
33  The bounding box includes all warped pixels and it may be a bit oversize.
34 
35  Parameters
36  ----------
37  destWcs : `lsst.afw.geom.SkyWcs`
38  WCS of warped exposure
39  srcBBox : `lsst.geom.Box2I`
40  parent bounding box of unwarped image
41  srcWcs : `lsst.afw.geom.SkyWcs`
42  WCS of unwarped image
43 
44  Returns
45  -------
46  destBBox: `lsst.geom.Box2I`
47  bounding box of warped exposure
48  """
49  srcPosBox = lsst.geom.Box2D(srcBBox)
50  destPosBox = lsst.geom.Box2D()
51  for inX in (srcPosBox.getMinX(), srcPosBox.getMaxX()):
52  for inY in (srcPosBox.getMinY(), srcPosBox.getMaxY()):
53  destPos = destWcs.skyToPixel(srcWcs.pixelToSky(inX, inY))
54  destPosBox.include(destPos)
55  destBBox = lsst.geom.Box2I(destPosBox, lsst.geom.Box2I.EXPAND)
56  return destBBox
57 
58 
59 _DefaultInterpLength = 10
60 _DefaultCacheSize = 1000000
61 
62 
63 class WarperConfig(pexConfig.Config):
64  warpingKernelName = pexConfig.ChoiceField(
65  dtype=str,
66  doc="Warping kernel",
67  default="lanczos3",
68  allowed={
69  "bilinear": "bilinear interpolation",
70  "lanczos3": "Lanczos kernel of order 3",
71  "lanczos4": "Lanczos kernel of order 4",
72  "lanczos5": "Lanczos kernel of order 5",
73  }
74  )
75  maskWarpingKernelName = pexConfig.ChoiceField(
76  dtype=str,
77  doc="Warping kernel for mask (use ``warpingKernelName`` if '')",
78  default="bilinear",
79  allowed={
80  "": "use the regular warping kernel for the mask plane, as well as the image and variance planes",
81  "bilinear": "bilinear interpolation",
82  "lanczos3": "Lanczos kernel of order 3",
83  "lanczos4": "Lanczos kernel of order 4",
84  "lanczos5": "Lanczos kernel of order 5",
85  }
86  )
87  interpLength = pexConfig.Field(
88  dtype=int,
89  doc="``interpLength`` argument to `lsst.afw.math.warpExposure`",
90  default=_DefaultInterpLength,
91  )
92  cacheSize = pexConfig.Field(
93  dtype=int,
94  doc="``cacheSize`` argument to `lsst.afw.math.SeparableKernel.computeCache`",
95  default=_DefaultCacheSize,
96  )
97  growFullMask = pexConfig.Field(
98  dtype=int,
99  doc="mask bits to grow to full width of image/variance kernel,",
100  default=afwImage.Mask.getPlaneBitMask("EDGE"),
101  )
102 
103 
104 class Warper:
105  """Warp images.
106 
107  Parameters
108  ----------
109  warpingKernelName : `str`
110  see `WarperConfig.warpingKernelName`
111  interpLength : `int`, optional
112  ``interpLength`` argument to `lsst.afw.math.warpExposure`
113  cacheSize : `int`, optional
114  size of computeCache
115  maskWarpingKernelName : `str`, optional
116  name of mask warping kernel (if ``""`` then use ``warpingKernelName``);
117  see `WarperConfig.maskWarpingKernelName`
118  growFullMask : `int`, optional
119  mask bits to grow to full width of image/variance kernel
120  """
121  ConfigClass = WarperConfig
122 
123  def __init__(self,
124  warpingKernelName,
125  interpLength=_DefaultInterpLength,
126  cacheSize=_DefaultCacheSize,
127  maskWarpingKernelName="",
128  growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"),):
129  self._warpingControl = mathLib.WarpingControl(
130  warpingKernelName, maskWarpingKernelName, cacheSize, interpLength, growFullMask)
131 
132  @classmethod
133  def fromConfig(cls, config):
134  """Create a Warper from a config.
135 
136  Parameters
137  ----------
138  config : `WarperConfig`
139  The config to initialize the Warper with.
140  """
141  return cls(
142  warpingKernelName=config.warpingKernelName,
143  maskWarpingKernelName=config.maskWarpingKernelName,
144  interpLength=config.interpLength,
145  cacheSize=config.cacheSize,
146  growFullMask=config.growFullMask,
147  )
148 
149  def getWarpingKernel(self):
150  """Get the warping kernel.
151  """
152  return self._warpingControl.getWarpingKernel()
153 
155  """Get the mask warping kernel.
156  """
158 
159  def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None):
160  """Warp an exposure.
161 
162  Parameters
163  -----------
164  destWcs : `lsst.afw.geom.SkyWcs`
165  WCS of warped exposure
166  srcExposure
167  exposure to warp
168  border : `int`, optional
169  grow bbox of warped exposure by this amount in all directions
170  (in pixels); if negative then the bbox is shrunk; border is applied
171  before ``maxBBox``; ignored if ``destBBox`` is not `None`
172  maxBBox : `lsst.geom.Box2I`, optional
173  maximum allowed parent bbox of warped exposure; if `None` then the
174  warped exposure will be just big enough to contain all warped pixels;
175  if provided then the warped exposure may be smaller, and so
176  missing some warped pixels; ignored if ``destBBox`` is not `None`
177  destBBox : `lsst.geom.Box2I`, optional
178  exact parent bbox of warped exposure; if `None` then ``border`` and
179  ``maxBBox`` are used to determine the bbox, otherwise ``border``
180  and ``maxBBox`` are ignored
181 
182  Returns
183  -------
184  destExposure : same type as ``srcExposure``
185  warped exposure
186 
187  Notes
188  -----
189  calls `lsst.afw.math.warpExposure` insted of `~Warper.warpImage` because the former
190  copies attributes such as ``Calib``, and that should be done in one place
191 
192  The PSF is not warped. To warp the PSF, use `lsst.meas.algorithms.WarpedPsf`
193  """
194  destBBox = self._computeDestBBox(
195  destWcs=destWcs,
196  srcImage=srcExposure.getMaskedImage(),
197  srcWcs=srcExposure.getWcs(),
198  border=border,
199  maxBBox=maxBBox,
200  destBBox=destBBox,
201  )
202  destExposure = srcExposure.Factory(destBBox, destWcs)
203  mathLib.warpExposure(destExposure, srcExposure, self._warpingControl)
204  return destExposure
205 
206  def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None):
207  """Warp an image or masked image.
208 
209  Parameters
210  ----------
211  destWcs : `lsst.afw.geom.SkyWcs`
212  WCS of warped image
213  srcImage
214  image or masked image to warp
215  srcWcs : `lsst.afw.geom.SkyWcs`
216  WCS of image
217  border : `int`, optional
218  grow bbox of warped image by this amount in all directions
219  (in pixels); if negative then the bbox is shrunk; border is applied
220  before ``maxBBox``; ignored if ``destBBox`` is not `None`
221  maxBBox : `lsst.geom.Box2I`, optional
222  maximum allowed parent bbox of warped image; if `None` then the
223  warped image will be just big enough to contain all warped pixels;
224  if provided then the warped image may be smaller, and so
225  missing some warped pixels; ignored if ``destBBox`` is not `None`
226  destBBox : `lsst.geom.Box2I`, optional
227  exact parent bbox of warped image; if `None` then ``border`` and
228  ``maxBBox`` are used to determine the bbox, otherwise ``border``
229  and ``maxBBox`` are ignored
230 
231  Returns
232  -------
233  destImage : same type as ``srcExposure``
234  warped image or masked image
235  """
236  destBBox = self._computeDestBBox(
237  destWcs=destWcs,
238  srcImage=srcImage,
239  srcWcs=srcWcs,
240  border=border,
241  maxBBox=maxBBox,
242  destBBox=destBBox,
243  )
244  destImage = srcImage.Factory(destBBox)
245  mathLib.warpImage(destImage, destWcs, srcImage,
246  srcWcs, self._warpingControl)
247  return destImage
248 
249  def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox):
250  """Process destBBox argument for warpImage and warpExposure.
251 
252  Parameters
253  ----------
254  destWcs : `lsst.afw.geom.SkyWcs`
255  WCS of warped image
256  srcImage
257  image or masked image to warp
258  srcWcs : `lsst.afw.geom.SkyWcs`
259  WCS of image
260  border : `int`, optional
261  grow bbox of warped image by this amount in all directions
262  (in pixels); if negative then the bbox is shrunk; border is applied
263  before ``maxBBox``; ignored if ``destBBox`` is not `None`
264  maxBBox : `lsst.geom.Box2I`, optional
265  maximum allowed parent bbox of warped image; if `None` then the
266  warped image will be just big enough to contain all warped pixels;
267  if provided then the warped image may be smaller, and so
268  missing some warped pixels; ignored if ``destBBox`` is not `None`
269  destBBox : `lsst.geom.Box2I`, optional
270  exact parent bbox of warped image; if `None` then ``border`` and
271  ``maxBBox`` are used to determine the bbox, otherwise ``border``
272  and ``maxBBox`` are ignored
273  """
274  if destBBox is None: # warning: == None fails due to Box2I.__eq__
275  destBBox = computeWarpedBBox(
276  destWcs, srcImage.getBBox(afwImage.PARENT), srcWcs)
277  if border:
278  destBBox.grow(border)
279  if maxBBox is not None:
280  destBBox.clip(maxBBox)
281  return destBBox
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::afw::math.warper.Warper._warpingControl
_warpingControl
Definition: warper.py:124
lsst::afw::math.warper.WarperConfig
Definition: warper.py:63
lsst::afw::math.warper.Warper.__init__
def __init__(self, warpingKernelName, interpLength=_DefaultInterpLength, cacheSize=_DefaultCacheSize, maskWarpingKernelName="", growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"))
Definition: warper.py:123
lsst::afw::geom.transform.transformContinued.cls
cls
Definition: transformContinued.py:33
lsst::afw::math.warper.Warper.getMaskWarpingKernel
def getMaskWarpingKernel(self)
Definition: warper.py:154
lsst::afw::math.warper.computeWarpedBBox
def computeWarpedBBox(destWcs, srcBBox, srcWcs)
Definition: warper.py:30
lsst::afw::math.warper.Warper.warpExposure
def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None)
Definition: warper.py:159
lsst::geom
Definition: geomOperators.dox:4
lsst::afw::math.warper.Warper.getWarpingKernel
def getWarpingKernel(self)
Definition: warper.py:149
lsst::geom::Box2I
An integer coordinate rectangle.
Definition: Box.h:55
lsst::afw::math.warper.Warper
Definition: warper.py:104
lsst::afw::math.warper.Warper._computeDestBBox
def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox)
Definition: warper.py:249
lsst::afw::math.warper.Warper.warpImage
def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None)
Definition: warper.py:206
lsst::geom::Box2D
A floating-point coordinate rectangle geometry.
Definition: Box.h:413
lsst::afw::math.warper.Warper.fromConfig
def fromConfig(cls, config)
Definition: warper.py:133