LSST Applications  21.0.0-147-g0e635eb1+1acddb5be5,22.0.0+052faf71bd,22.0.0+1ea9a8b2b2,22.0.0+6312710a6c,22.0.0+729191ecac,22.0.0+7589c3a021,22.0.0+9f079a9461,22.0.1-1-g7d6de66+b8044ec9de,22.0.1-1-g87000a6+536b1ee016,22.0.1-1-g8e32f31+6312710a6c,22.0.1-10-gd060f87+016f7cdc03,22.0.1-12-g9c3108e+df145f6f68,22.0.1-16-g314fa6d+c825727ab8,22.0.1-19-g93a5c75+d23f2fb6d8,22.0.1-19-gb93eaa13+aab3ef7709,22.0.1-2-g8ef0a89+b8044ec9de,22.0.1-2-g92698f7+9f079a9461,22.0.1-2-ga9b0f51+052faf71bd,22.0.1-2-gac51dbf+052faf71bd,22.0.1-2-gb66926d+6312710a6c,22.0.1-2-gcb770ba+09e3807989,22.0.1-20-g32debb5+b8044ec9de,22.0.1-23-gc2439a9a+fb0756638e,22.0.1-3-g496fd5d+09117f784f,22.0.1-3-g59f966b+1e6ba2c031,22.0.1-3-g849a1b8+f8b568069f,22.0.1-3-gaaec9c0+c5c846a8b1,22.0.1-32-g5ddfab5d3+60ce4897b0,22.0.1-4-g037fbe1+64e601228d,22.0.1-4-g8623105+b8044ec9de,22.0.1-5-g096abc9+d18c45d440,22.0.1-5-g15c806e+57f5c03693,22.0.1-7-gba73697+57f5c03693,master-g6e05de7fdc+c1283a92b8,master-g72cdda8301+729191ecac,w.2021.39
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