LSSTApplications  16.0-10-g0ee56ad+5,16.0-11-ga33d1f2+5,16.0-12-g3ef5c14+3,16.0-12-g71e5ef5+18,16.0-12-gbdf3636+3,16.0-13-g118c103+3,16.0-13-g8f68b0a+3,16.0-15-gbf5c1cb+4,16.0-16-gfd17674+3,16.0-17-g7c01f5c+3,16.0-18-g0a50484+1,16.0-20-ga20f992+8,16.0-21-g0e05fd4+6,16.0-21-g15e2d33+4,16.0-22-g62d8060+4,16.0-22-g847a80f+4,16.0-25-gf00d9b8+1,16.0-28-g3990c221+4,16.0-3-gf928089+3,16.0-32-g88a4f23+5,16.0-34-gd7987ad+3,16.0-37-gc7333cb+2,16.0-4-g10fc685+2,16.0-4-g18f3627+26,16.0-4-g5f3a788+26,16.0-5-gaf5c3d7+4,16.0-5-gcc1f4bb+1,16.0-6-g3b92700+4,16.0-6-g4412fcd+3,16.0-6-g7235603+4,16.0-69-g2562ce1b+2,16.0-8-g14ebd58+4,16.0-8-g2df868b+1,16.0-8-g4cec79c+6,16.0-8-gadf6c7a+1,16.0-8-gfc7ad86,16.0-82-g59ec2a54a+1,16.0-9-g5400cdc+2,16.0-9-ge6233d7+5,master-g2880f2d8cf+3,v17.0.rc1
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  destBBox = self._computeDestBBox(
193  destWcs=destWcs,
194  srcImage=srcExposure.getMaskedImage(),
195  srcWcs=srcExposure.getWcs(),
196  border=border,
197  maxBBox=maxBBox,
198  destBBox=destBBox,
199  )
200  destExposure = srcExposure.Factory(destBBox, destWcs)
201  mathLib.warpExposure(destExposure, srcExposure, self._warpingControl)
202  return destExposure
203 
204  def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None):
205  """Warp an image or masked image.
206 
207  Parameters
208  ----------
209  destWcs : `lsst.afw.geom.SkyWcs`
210  WCS of warped image
211  srcImage
212  image or masked image to warp
213  srcWcs : `lsst.afw.geom.SkyWcs`
214  WCS of image
215  border : `int`, optional
216  grow bbox of warped image by this amount in all directions
217  (in pixels); if negative then the bbox is shrunk; border is applied
218  before ``maxBBox``; ignored if ``destBBox`` is not `None`
219  maxBBox : `lsst.geom.Box2I`, optional
220  maximum allowed parent bbox of warped image; if `None` then the
221  warped image will be just big enough to contain all warped pixels;
222  if provided then the warped image may be smaller, and so
223  missing some warped pixels; ignored if ``destBBox`` is not `None`
224  destBBox : `lsst.geom.Box2I`, optional
225  exact parent bbox of warped image; if `None` then ``border`` and
226  ``maxBBox`` are used to determine the bbox, otherwise ``border``
227  and ``maxBBox`` are ignored
228 
229  Returns
230  -------
231  destImage : same type as ``srcExposure``
232  warped image or masked image
233  """
234  destBBox = self._computeDestBBox(
235  destWcs=destWcs,
236  srcImage=srcImage,
237  srcWcs=srcWcs,
238  border=border,
239  maxBBox=maxBBox,
240  destBBox=destBBox,
241  )
242  destImage = srcImage.Factory(destBBox)
243  mathLib.warpImage(destImage, destWcs, srcImage,
244  srcWcs, self._warpingControl)
245  return destImage
246 
247  def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox):
248  """Process destBBox argument for warpImage and warpExposure.
249 
250  Parameters
251  ----------
252  destWcs : `lsst.afw.geom.SkyWcs`
253  WCS of warped image
254  srcImage
255  image or masked image to warp
256  srcWcs : `lsst.afw.geom.SkyWcs`
257  WCS of image
258  border : `int`, optional
259  grow bbox of warped image by this amount in all directions
260  (in pixels); if negative then the bbox is shrunk; border is applied
261  before ``maxBBox``; ignored if ``destBBox`` is not `None`
262  maxBBox : `lsst.geom.Box2I`, optional
263  maximum allowed parent bbox of warped image; if `None` then the
264  warped image will be just big enough to contain all warped pixels;
265  if provided then the warped image may be smaller, and so
266  missing some warped pixels; ignored if ``destBBox`` is not `None`
267  destBBox : `lsst.geom.Box2I`, optional
268  exact parent bbox of warped image; if `None` then ``border`` and
269  ``maxBBox`` are used to determine the bbox, otherwise ``border``
270  and ``maxBBox`` are ignored
271  """
272  if destBBox is None: # warning: == None fails due to Box2I.__eq__
273  destBBox = computeWarpedBBox(
274  destWcs, srcImage.getBBox(afwImage.PARENT), srcWcs)
275  if border:
276  destBBox.grow(border)
277  if maxBBox is not None:
278  destBBox.clip(maxBBox)
279  return destBBox
def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox)
Definition: warper.py:247
A floating-point coordinate rectangle geometry.
Definition: Box.h:294
def getMaskWarpingKernel(self)
Definition: warper.py:154
def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None)
Definition: warper.py:159
def computeWarpedBBox(destWcs, srcBBox, srcWcs)
Definition: warper.py:30
def __init__(self, warpingKernelName, interpLength=_DefaultInterpLength, cacheSize=_DefaultCacheSize, maskWarpingKernelName="", growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"))
Definition: warper.py:128
def warpImage(self, destWcs, srcImage, srcWcs, border=0, maxBBox=None, destBBox=None)
Definition: warper.py:204
def fromConfig(cls, config)
Definition: warper.py:133
An integer coordinate rectangle.
Definition: Box.h:54