LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
transformConfig.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 import functools
24 import numpy
25 
26 import lsst.geom
27 from lsst.pex.config import Config, ListField, makeRegistry, \
28  ConfigDictField, ConfigurableField
29 from .transformFactory import makeTransform, makeIdentityTransform, \
30  makeRadialTransform
31 
32 __all__ = ["transformRegistry", "OneTransformConfig", "TransformConfig",
33  "IdentityTransformConfig", "AffineTransformConfig", "RadialTransformConfig",
34  "MultiTransformConfig"]
35 
36 transformRegistry = makeRegistry(
37  """"A registry of ``Transform`` factories
38 
39  A ``Transform`` factory is a function that obeys these rules:
40  - has an attribute ``ConfigClass``
41  - takes one argument, ``config`` (an instance of ``ConfigClass``) by name
42  - returns a ``Transform``
43  """
44 )
45 
46 
48  """A Config representing a ``Transform`` that does nothing.
49 
50  See Also
51  --------
52  lsst.afw.geom.makeIdentityTransform
53  """
54  pass
55 
56 
57 def identityFactory(config):
58  """Make an identity ``Transform``
59  """
60  return makeIdentityTransform()
61 
62 
63 identityFactory.ConfigClass = IdentityTransformConfig
64 transformRegistry.register("identity", identityFactory)
65 
66 
67 class OneTransformConfig(Config):
68  """A Config representing a single ``Transform`` in a compound ``Transform``.
69 
70  See Also
71  --------
72  lsst.afw.geom.MultiTransformConfig
73  """
74  transform = ConfigurableField(
75  doc="Transform factory",
76  target=identityFactory,
77  )
78 
79 
80 def invertingFactory(config):
81  """Invert a ``Transform`` specified by config.
82  """
83  return config.transform.apply().inverted()
84 
85 
86 invertingFactory.ConfigClass = OneTransformConfig
87 transformRegistry.register("inverted", invertingFactory)
88 
89 
90 class AffineTransformConfig(Config):
91  """A Config representing an affine ``Transform``.
92 
93  See Also
94  --------
95  lsst.afw.geom.makeTransform
96  """
97  linear = ListField(
98  doc="2x2 linear matrix in the usual numpy order; "
99  "to rotate a vector by theta use: cos(theta), sin(theta), "
100  "-sin(theta), cos(theta)",
101  dtype=float,
102  length=4,
103  default=(1, 0, 0, 1),
104  )
105  translation = ListField(
106  doc="x, y translation vector",
107  dtype=float,
108  length=2,
109  default=(0, 0),
110  )
111 
112 
113 def affineFactory(config):
114  """Make an affine ``Transform``
115  """
116  linear = numpy.array(config.linear)
117  linear.shape = (2, 2)
118  translation = numpy.array(config.translation)
119  return makeTransform(lsst.geom.AffineTransform(linear, translation))
120 
121 
122 affineFactory.ConfigClass = AffineTransformConfig
123 transformRegistry.register("affine", affineFactory)
124 
125 
126 class RadialTransformConfig(Config):
127  """A Config representing a radially symmetric ``Transform``.
128 
129  See Also
130  --------
131  lsst.afw.geom.makeRadialTransform
132  """
133  coeffs = ListField(
134  doc="Coefficients for the radial polynomial; coeff[0] must be 0",
135  dtype=float,
136  minLength=1,
137  optional=False,
138  )
139 
140  def validate(self):
141  if len(self.coeffs) == 0:
142  return
143  if len(self.coeffs) == 1 or self.coeffs[0] != 0 or self.coeffs[1] == 0:
144  raise RuntimeError(
145  "invalid radial transform coeffs %s: " % (self.coeffs,) +
146  "need len(coeffs)=0 or len(coeffs)>1, coeffs[0]==0, "
147  "and coeffs[1]!=0")
148 
149 
150 def radialFactory(config):
151  """Make a radial ``Transform``
152  """
153  return makeRadialTransform(config.coeffs._list)
154 
155 
156 radialFactory.ConfigClass = RadialTransformConfig
157 transformRegistry.register("radial", radialFactory)
158 
159 
160 class MultiTransformConfig(Config):
161  """A Config representing a chain of consecutive ``Transforms``.
162  """
163  transformDict = ConfigDictField(
164  doc="Dict of index: OneTransformConfig (a transform wrapper); "
165  "key order is transform order",
166  keytype=int,
167  itemtype=OneTransformConfig,
168  )
169 
170 
171 def multiFactory(config):
172  """Concatenate multiple ``Transforms``
173  """
174  transformKeys = sorted(config.transformDict.keys())
175  transformList = [config.transformDict[key].transform.apply()
176  for key in transformKeys]
177 
178  # Can't use then(self, other) directly because no single Transform class
179  def concat(transform1, transform2):
180  return transform1.then(transform2)
181 
182  return functools.reduce(concat, transformList)
183 
184 
185 multiFactory.ConfigClass = MultiTransformConfig
186 transformRegistry.register("multi", multiFactory)
187 
188 
189 class TransformConfig(Config):
190  """Config that identifies ``Transforms`` by keyword.
191 
192  Supported configs:
193 
194  ``"identity"``
195  `IdentityTransformConfig`
196  ``"inverted"``
197  `OneTransformConfig`
198  ``"affine"``
199  `AffineTransformConfig`
200  ``"radial"``
201  `RadialTransformConfig`
202  ``"multi"``
203  `MultiTransformConfig`
204  """
205  transform = transformRegistry.makeField(
206  doc="a Transform from the registry"
207  )
std::shared_ptr< TransformPoint2ToPoint2 > makeIdentityTransform()
Trivial Transform x → x.
std::shared_ptr< TransformPoint2ToPoint2 > makeRadialTransform(std::vector< double > const &coeffs)
A purely radial polynomial distortion.
An affine coordinate transformation consisting of a linear transformation and an offset.
def makeRegistry(doc, configBaseType=Config)
Definition: registry.py:336
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.