LSST Applications  21.0.0+c4f5df5339,21.0.0+e70536a077,21.0.0-1-ga51b5d4+7c60f8a6ea,21.0.0-10-gcf60f90+74aa0801fd,21.0.0-12-g63909ac9+643a1044a5,21.0.0-15-gedb9d5423+1041c3824f,21.0.0-2-g103fe59+a356b2badb,21.0.0-2-g1367e85+6d3f3f41db,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g5242d73+6d3f3f41db,21.0.0-2-g7f82c8f+8d7c04eab9,21.0.0-2-g8f08a60+9c9a9cfcc8,21.0.0-2-ga326454+8d7c04eab9,21.0.0-2-gde069b7+bedfc5e1fb,21.0.0-2-gecfae73+6cb6558258,21.0.0-2-gfc62afb+6d3f3f41db,21.0.0-3-g21c7a62+f6e98b25aa,21.0.0-3-g357aad2+bd62456bea,21.0.0-3-g4be5c26+6d3f3f41db,21.0.0-3-g65f322c+03a4076c01,21.0.0-3-g7d9da8d+c4f5df5339,21.0.0-3-gaa929c8+c6b98066dc,21.0.0-3-gc44e71e+a26d5c1aea,21.0.0-3-ge02ed75+04b527a9d5,21.0.0-35-g64f566ff+b27e5ef93e,21.0.0-4-g591bb35+04b527a9d5,21.0.0-4-g88306b8+8773047b2e,21.0.0-4-gc004bbf+80a0b7acb7,21.0.0-4-gccdca77+a5c54364a0,21.0.0-4-ge8fba5a+ccfc328107,21.0.0-5-gdf36809+87b8d260e6,21.0.0-6-g00874e7+7eeda2b6ba,21.0.0-6-g2d4f3f3+e70536a077,21.0.0-6-g4e60332+04b527a9d5,21.0.0-6-g5ef7dad+f53629abd8,21.0.0-7-gc8ca178+b63e69433b,21.0.0-8-gfbe0b4b+c6b98066dc,w.2021.06
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 .warpExposure import warpImage
28 from .warpExposure import WarpingControl
29 from .warpExposure 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 __init__(self, warpingKernelName, interpLength=_DefaultInterpLength, cacheSize=_DefaultCacheSize, maskWarpingKernelName="", growFullMask=afwImage.Mask.getPlaneBitMask("EDGE"))
Definition: warper.py:130
def _computeDestBBox(self, destWcs, srcImage, srcWcs, border, maxBBox, destBBox)
Definition: warper.py:251
def getMaskWarpingKernel(self)
Definition: warper.py:156
def warpExposure(self, destWcs, srcExposure, border=0, maxBBox=None, destBBox=None)
Definition: warper.py:161
def fromConfig(cls, config)
Definition: warper.py:135
def 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
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def computeWarpedBBox(destWcs, srcBBox, srcWcs)
Definition: warper.py:32