1#!python
2#cython: boundscheck=False
3#cython: wraparound=False
4#cython: cdivision=True
5
6import numpy as np
7cimport numpy as cnp
8cimport cython
9
10cdef extern from "dpy_math.h" nogil:
11    double cos(double)
12    double sin(double)
13    double log(double)
14
15cdef class Transform:
16    r""" Base class (contract) for all transforms for affine image registration
17    Each transform must define the following (fast, nogil) methods:
18
19    1. _jacobian(theta, x, J): receives a parameter vector theta, a point in
20       x, and a matrix J with shape (dim, len(theta)). It must writes in J, the
21       Jacobian of the transform with parameters theta evaluated at x.
22
23    2. _get_identity_parameters(theta): receives a vector theta whose length is
24       the number of parameters of the transform and sets in theta the values
25       that define the identity transform.
26
27    3. _param_to_matrix(theta, T): receives a parameter vector theta, and a
28       matrix T of shape (dim + 1, dim + 1) and writes in T the matrix
29       representation of the transform with parameters theta
30
31    This base class defines the (slow, convenient) python wrappers for each
32    of the above functions, which also do parameter checking and raise
33    a ValueError in case the provided parameters are invalid.
34    """
35    def __cinit__(self):
36        r""" Default constructor
37        Sets transform dimension and number of parameter to invalid values (-1)
38        """
39        self.dim = -1
40        self.number_of_parameters = -1
41
42    cdef int _jacobian(self, double[:] theta, double[:] x,
43                       double[:, :] J)nogil:
44        return -1
45
46    cdef void _get_identity_parameters(self, double[:] theta) nogil:
47        return
48
49    cdef void _param_to_matrix(self, double[:] theta, double[:, :] T)nogil:
50        return
51
52    def jacobian(self, double[:] theta, double[:] x):
53        r""" Jacobian function of this transform
54
55        Parameters
56        ----------
57        theta : array, shape (n,)
58            vector containing the n parameters of this transform
59        x : array, shape (dim,)
60            vector containing the point where the Jacobian must be evaluated
61
62        Returns
63        -------
64        J : array, shape (dim, n)
65            Jacobian matrix of the transform with parameters theta at point x
66        """
67        n = theta.shape[0]
68        if n != self.number_of_parameters:
69            raise ValueError("Invalid number of parameters: %d"%(n,))
70        m = x.shape[0]
71        if m < self.dim:
72            raise ValueError("Invalid point dimension: %d"%(m,))
73        J = np.zeros((self.dim, n))
74        ret = self._jacobian(theta, x, J)
75        return np.asarray(J)
76
77    def get_identity_parameters(self):
78        r""" Parameter values corresponding to the identity transform
79
80        Returns
81        -------
82        theta : array, shape (n,)
83            the n parameter values corresponding to the identity transform
84        """
85        if self.number_of_parameters < 0:
86            raise ValueError("Invalid transform.")
87        theta = np.zeros(self.number_of_parameters)
88        self._get_identity_parameters(theta)
89        return np.asarray(theta)
90
91    def param_to_matrix(self, double[:] theta):
92        r""" Matrix representation of this transform with the given parameters
93
94        Parameters
95        ----------
96        theta : array, shape (n,)
97            the parameter values of the transform
98
99        Returns
100        -------
101        T : array, shape (dim + 1, dim + 1)
102            the matrix representation of this transform with parameters theta
103        """
104        n = len(theta)
105        if n != self.number_of_parameters:
106            raise ValueError("Invalid number of parameters: %d"%(n,))
107        T = np.eye(self.dim + 1)
108        self._param_to_matrix(theta, T)
109        return np.asarray(T)
110
111    def get_number_of_parameters(self):
112        return self.number_of_parameters
113
114    def get_dim(self):
115        return self.dim
116
117
118cdef class TranslationTransform2D(Transform):
119    def __init__(self):
120        r""" Translation transform in 2D
121        """
122        self.dim = 2
123        self.number_of_parameters = 2
124
125    cdef int _jacobian(self, double[:] theta, double[:] x,
126                       double[:, :] J)nogil:
127        r""" Jacobian matrix of the 2D translation transform
128        The transformation is given by:
129
130        T(x) = (T1(x), T2(x)) = (x0 + t0, x1 + t1)
131
132        The derivative w.r.t. t1 and t2 is given by
133
134        T'(x) = [[1, 0], # derivatives of [T1, T2] w.r.t. t0
135                 [0, 1]] # derivatives of [T1, T2] w.r.t. t1
136
137        Parameters
138        ----------
139        theta : array, shape (2,)
140            the parameters of the 2D translation transform (the Jacobian does
141            not depend on the parameters, but we receive the buffer so all
142            Jacobian functions receive the same parameters)
143        x : array, shape (2,)
144            the point at which to compute the Jacobian (the Jacobian does not
145            depend on x, but we receive the buffer so all Jacobian functions
146            receive the same parameters)
147        J : array, shape (2, 2)
148            the buffer in which to write the Jacobian
149
150        Returns
151        -------
152        is_constant : int
153            always returns 1, indicating that the Jacobian is constant
154            (independent of x)
155        """
156        J[0, 0], J[0, 1] = 1.0, 0.0
157        J[1, 0], J[1, 1] = 0.0, 1.0
158        # This Jacobian does not depend on x (it's constant): return 1
159        return 1
160
161    cdef void _get_identity_parameters(self, double[:] theta) nogil:
162        r""" Parameter values corresponding to the identity
163        Sets in theta the parameter values corresponding to the identity
164        transform
165
166        Parameters
167        ----------
168        theta : array, shape (2,)
169            buffer to write the parameters of the 2D translation transform
170        """
171        theta[:2] = 0
172
173    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
174        r""" Matrix associated with the 2D translation transform
175
176        Parameters
177        ----------
178        theta : array, shape (2,)
179            the parameters of the 2D translation transform
180        R : array, shape (3, 3)
181            the buffer in which to write the translation matrix
182        """
183        R[0, 0], R[0, 1], R[0, 2] = 1, 0, theta[0]
184        R[1, 0], R[1, 1], R[1, 2] = 0, 1, theta[1]
185        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
186
187
188cdef class TranslationTransform3D(Transform):
189    def __init__(self):
190        r""" Translation transform in 3D
191        """
192        self.dim = 3
193        self.number_of_parameters = 3
194
195    cdef int _jacobian(self, double[:] theta, double[:] x,
196                       double[:, :] J)nogil:
197        r""" Jacobian matrix of the 3D translation transform
198        The transformation is given by:
199
200        T(x) = (T1(x), T2(x), T3(x)) = (x0 + t0, x1 + t1, x2 + t2)
201
202        The derivative w.r.t. t1, t2 and t3 is given by
203
204        T'(x) = [[1, 0, 0], # derivatives of [T1, T2, T3] w.r.t. t0
205                 [0, 1, 0], # derivatives of [T1, T2, T3] w.r.t. t1
206                 [0, 0, 1]] # derivatives of [T1, T2, T3] w.r.t. t2
207        Parameters
208        ----------
209        theta : array, shape (3,)
210            the parameters of the 3D translation transform (the Jacobian does
211            not depend on the parameters, but we receive the buffer so all
212            Jacobian functions receive the same parameters)
213        x : array, shape (3,)
214            the point at which to compute the Jacobian (the Jacobian does not
215            depend on x, but we receive the buffer so all Jacobian functions
216            receive the same parameters)
217        J : array, shape (3, 3)
218            the buffer in which to write the Jacobian
219
220        Returns
221        -------
222        is_constant : int
223            always returns 1, indicating that the Jacobian is constant
224            (independent of x)
225        """
226        J[0, 0], J[0, 1], J[0, 2] = 1.0, 0.0, 0.0
227        J[1, 0], J[1, 1], J[1, 2] = 0.0, 1.0, 0.0
228        J[2, 0], J[2, 1], J[2, 2] = 0.0, 0.0, 1.0
229        # This Jacobian does not depend on x (it's constant): return 1
230        return 1
231
232    cdef void _get_identity_parameters(self, double[:] theta) nogil:
233        r""" Parameter values corresponding to the identity
234        Sets in theta the parameter values corresponding to the identity
235        transform
236
237        Parameters
238        ----------
239        theta : array, shape (3,)
240            buffer to write the parameters of the 3D translation transform
241        """
242        theta[:3] = 0
243
244    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
245        r""" Matrix associated with the 3D translation transform
246
247        Parameters
248        ----------
249        theta : array, shape (3,)
250            the parameters of the 3D translation transform
251        R : array, shape (4, 4)
252            the buffer in which to write the translation matrix
253        """
254        R[0, 0], R[0, 1], R[0, 2], R[0, 3] = 1, 0, 0, theta[0]
255        R[1, 0], R[1, 1], R[1, 2], R[1, 3] = 0, 1, 0, theta[1]
256        R[2, 0], R[2, 1], R[2, 2], R[2, 3] = 0, 0, 1, theta[2]
257        R[3, 0], R[3, 1], R[3, 2], R[3, 3] = 0, 0, 0, 1
258
259
260cdef class RotationTransform2D(Transform):
261    def __init__(self):
262        r""" Rotation transform in 2D
263        """
264        self.dim = 2
265        self.number_of_parameters = 1
266
267    cdef int _jacobian(self, double[:] theta, double[:] x,
268                       double[:, :] J)nogil:
269        r""" Jacobian matrix of a 2D rotation with parameter theta, at x
270
271        The transformation is given by:
272
273        T(x,y) = (T1(x,y), T2(x,y)) = (x cost - y sint, x sint + y cost)
274
275        The derivatives w.r.t. the rotation angle, t, are:
276
277        T'(x,y) = [-x sint - y cost, # derivative of T1 w.r.t. t
278                    x cost - y sint] # derivative of T2 w.r.t. t
279
280        Parameters
281        ----------
282        theta : array, shape (1,)
283            the rotation angle
284        x : array, shape (2,)
285            the point at which to compute the Jacobian
286        J : array, shape (2, 1)
287            the buffer in which to write the Jacobian
288
289        Returns
290        -------
291        is_constant : int
292            always returns 0, indicating that the Jacobian is not
293            constant (it depends on the value of x)
294        """
295        cdef:
296            double st = sin(theta[0])
297            double ct = cos(theta[0])
298            double px = x[0], py = x[1]
299
300        J[0, 0] = -px * st - py * ct
301        J[1, 0] = px * ct - py * st
302        # This Jacobian depends on x (it's not constant): return 0
303        return 0
304
305    cdef void _get_identity_parameters(self, double[:] theta) nogil:
306        r""" Parameter values corresponding to the identity
307        Sets in theta the parameter values corresponding to the identity
308        transform
309
310        Parameters
311        ----------
312        theta : array, shape (1,)
313            buffer to write the parameters of the 2D rotation transform
314        """
315        theta[0] = 0
316
317    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
318        r""" Matrix associated with the 2D rotation transform
319
320        Parameters
321        ----------
322        theta : array, shape (1,)
323            the rotation angle
324        R : array, shape (3,3)
325            the buffer in which to write the matrix
326        """
327        cdef:
328            double ct = cos(theta[0])
329            double st = sin(theta[0])
330        R[0, 0], R[0, 1], R[0, 2] = ct, -st, 0
331        R[1, 0], R[1, 1], R[1, 2] = st, ct, 0
332        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
333
334
335cdef class RotationTransform3D(Transform):
336    def __init__(self):
337        r""" Rotation transform in 3D
338        """
339        self.dim = 3
340        self.number_of_parameters = 3
341
342    cdef int _jacobian(self, double[:] theta, double[:] x,
343                       double[:, :] J)nogil:
344        r""" Jacobian matrix of a 3D rotation with parameters theta, at x
345
346        Parameters
347        ----------
348        theta : array, shape (3,)
349            the rotation angles about the canonical axes
350        x : array, shape (3,)
351            the point at which to compute the Jacobian
352        J : array, shape (3, 3)
353            the buffer in which to write the Jacobian
354
355        Returns
356        -------
357        is_constant : int
358            always returns 0, indicating that the Jacobian is not
359            constant (it depends on the value of x)
360        """
361        cdef:
362            double sa = sin(theta[0])
363            double ca = cos(theta[0])
364            double sb = sin(theta[1])
365            double cb = cos(theta[1])
366            double sc = sin(theta[2])
367            double cc = cos(theta[2])
368            double px = x[0], py = x[1], z = x[2]
369
370        J[0, 0] = (-sc * ca * sb) * px + (sc * sa) * py + (sc * ca * cb) * z
371        J[1, 0] = (cc * ca * sb) * px + (-cc * sa) * py + (-cc * ca * cb) * z
372        J[2, 0] = (sa * sb) * px + ca * py + (-sa * cb) * z
373
374        J[0, 1] = (-cc * sb - sc * sa * cb) * px + (cc * cb - sc * sa * sb) * z
375        J[1, 1] = (-sc * sb + cc * sa * cb) * px + (sc * cb + cc * sa * sb) * z
376        J[2, 1] = (-ca * cb) * px + (-ca * sb) * z
377
378        J[0, 2] = (-sc * cb - cc * sa * sb) * px + (-cc * ca) * py + \
379                  (-sc * sb + cc * sa * cb) * z
380        J[1, 2] = (cc * cb - sc * sa * sb) * px + (-sc * ca) * py + \
381                  (cc * sb + sc * sa * cb) * z
382        J[2, 2] = 0
383        # This Jacobian depends on x (it's not constant): return 0
384        return 0
385
386    cdef void _get_identity_parameters(self, double[:] theta) nogil:
387        r""" Parameter values corresponding to the identity
388        Sets in theta the parameter values corresponding to the identity
389        transform
390
391        Parameters
392        ----------
393        theta : array, shape (3,)
394            buffer to write the parameters of the 3D rotation transform
395        """
396        theta[:3] = 0
397
398    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
399        r""" Matrix associated with the 3D rotation transform
400
401        The matrix is the product of rotation matrices of angles theta[0],
402        theta[1], theta[2] around axes x, y, z applied in the following
403        order: y, x, z. This order was chosen for consistency with ANTS.
404
405        Parameters
406        ----------
407        theta : array, shape (3,)
408            the rotation angles about each axis:
409            theta[0] : rotation angle around x axis
410            theta[1] : rotation angle around y axis
411            theta[2] : rotation angle around z axis
412        R : array, shape (4, 4)
413            buffer in which to write the rotation matrix
414        """
415        cdef:
416            double sa = sin(theta[0])
417            double ca = cos(theta[0])
418            double sb = sin(theta[1])
419            double cb = cos(theta[1])
420            double sc = sin(theta[2])
421            double cc = cos(theta[2])
422
423        R[0,0], R[0,1], R[0,2] = cc*cb-sc*sa*sb, -sc*ca, cc*sb+sc*sa*cb
424        R[1,0], R[1,1], R[1,2] = sc*cb+cc*sa*sb, cc*ca, sc*sb-cc*sa*cb
425        R[2,0], R[2,1], R[2,2] = -ca*sb, sa, ca*cb
426        R[3,0], R[3,1], R[3,2] = 0, 0, 0
427        R[0, 3] = 0
428        R[1, 3] = 0
429        R[2, 3] = 0
430        R[3, 3] = 1
431
432
433cdef class RigidTransform2D(Transform):
434    def __init__(self):
435        r""" Rigid transform in 2D (rotation + translation)
436        The parameter vector theta of length 3 is interpreted as follows:
437        theta[0] : rotation angle
438        theta[1] : translation along the x axis
439        theta[2] : translation along the y axis
440        """
441        self.dim = 2
442        self.number_of_parameters = 3
443
444    cdef int _jacobian(self, double[:] theta, double[:] x,
445                       double[:, :] J)nogil:
446        r""" Jacobian matrix of a 2D rigid transform (rotation + translation)
447
448        The transformation is given by:
449
450        T(x,y) = (T1(x,y), T2(x,y)) =
451                 (x cost - y sint + dx, x sint + y cost + dy)
452
453        The derivatives w.r.t. t, dx and dy are:
454
455        T'(x,y) = [-x sint - y cost, 1, 0, # derivative of T1 w.r.t. t, dx, dy
456                    x cost - y sint, 0, 1] # derivative of T2 w.r.t. t, dx, dy
457
458        Parameters
459        ----------
460        theta : array, shape (3,)
461            the parameters of the 2D rigid transform
462            theta[0] : rotation angle (t)
463            theta[1] : translation along the x axis (dx)
464            theta[2] : translation along the y axis (dy)
465        x : array, shape (2,)
466            the point at which to compute the Jacobian
467        J : array, shape (2, 3)
468            the buffer in which to write the Jacobian
469
470        Returns
471        -------
472        is_constant : int
473            always returns 0, indicating that the Jacobian is not
474            constant (it depends on the value of x)
475        """
476        cdef:
477            double st = sin(theta[0])
478            double ct = cos(theta[0])
479            double px = x[0], py = x[1]
480
481        J[0, 0], J[0, 1], J[0, 2] = -px * st - py * ct, 1, 0
482        J[1, 0], J[1, 1], J[1, 2] = px * ct - py * st, 0, 1
483        # This Jacobian depends on x (it's not constant): return 0
484        return 0
485
486    cdef void _get_identity_parameters(self, double[:] theta) nogil:
487        r""" Parameter values corresponding to the identity
488        Sets in theta the parameter values corresponding to the identity
489        transform
490
491        Parameters
492        ----------
493        theta : array, shape (3,)
494            buffer to write the parameters of the 2D rigid transform
495            theta[0] : rotation angle
496            theta[1] : translation along the x axis
497            theta[2] : translation along the y axis
498        """
499        theta[:3] = 0
500
501    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
502        r""" Matrix associated with the 2D rigid transform
503
504        Parameters
505        ----------
506        theta : array, shape (3,)
507            the parameters of the 2D rigid transform
508            theta[0] : rotation angle
509            theta[1] : translation along the x axis
510            theta[2] : translation along the y axis
511        R : array, shape (3, 3)
512            buffer in which to write the rigid matrix
513        """
514        cdef:
515            double ct = cos(theta[0])
516            double st = sin(theta[0])
517        R[0, 0], R[0, 1], R[0, 2] = ct, -st, theta[1]
518        R[1, 0], R[1, 1], R[1, 2] = st, ct, theta[2]
519        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
520
521
522cdef class RigidTransform3D(Transform):
523    def __init__(self):
524        r""" Rigid transform in 3D (rotation + translation)
525        The parameter vector theta of length 6 is interpreted as follows:
526        theta[0] : rotation about the x axis
527        theta[1] : rotation about the y axis
528        theta[2] : rotation about the z axis
529        theta[3] : translation along the x axis
530        theta[4] : translation along the y axis
531        theta[5] : translation along the z axis
532        """
533        self.dim = 3
534        self.number_of_parameters = 6
535
536    cdef int _jacobian(self, double[:] theta, double[:] x,
537                       double[:, :] J)nogil:
538        r""" Jacobian matrix of a 3D rigid transform (rotation + translation)
539
540        Parameters
541        ----------
542        theta : array, shape (6,)
543            the parameters of the 3D rigid transform
544            theta[0] : rotation about the x axis
545            theta[1] : rotation about the y axis
546            theta[2] : rotation about the z axis
547            theta[3] : translation along the x axis
548            theta[4] : translation along the y axis
549            theta[5] : translation along the z axis
550        x : array, shape (3,)
551            the point at which to compute the Jacobian
552        J : array, shape (3, 6)
553            the buffer in which to write the Jacobian
554
555        Returns
556        -------
557        is_constant : int
558            always returns 0, indicating that the Jacobian is not
559            constant (it depends on the value of x)
560        """
561        cdef:
562            double sa = sin(theta[0])
563            double ca = cos(theta[0])
564            double sb = sin(theta[1])
565            double cb = cos(theta[1])
566            double sc = sin(theta[2])
567            double cc = cos(theta[2])
568            double px = x[0], py = x[1], pz = x[2]
569
570        J[0, 0] = (-sc * ca * sb) * px + (sc * sa) * py + (sc * ca * cb) * pz
571        J[1, 0] = (cc * ca * sb) * px + (-cc * sa) * py + (-cc * ca * cb) * pz
572        J[2, 0] = (sa * sb) * px + ca * py + (-sa * cb) * pz
573
574        J[0, 1] = (-cc * sb - sc * sa * cb) * px + (cc * cb - sc * sa * sb) * pz
575        J[1, 1] = (-sc * sb + cc * sa * cb) * px + (sc * cb + cc * sa * sb) * pz
576        J[2, 1] = (-ca * cb) * px + (-ca * sb) * pz
577
578        J[0, 2] = (-sc * cb - cc * sa * sb) * px + (-cc * ca) * py + \
579                  (-sc * sb + cc * sa * cb) * pz
580        J[1, 2] = (cc * cb - sc * sa * sb) * px + (-sc * ca) * py + \
581                  (cc * sb + sc * sa * cb) * pz
582        J[2, 2] = 0
583
584        J[0, 3:6] = 0
585        J[1, 3:6] = 0
586        J[2, 3:6] = 0
587        J[0, 3], J[1, 4], J[2, 5] = 1, 1, 1
588        # This Jacobian depends on x (it's not constant): return 0
589        return 0
590
591    cdef void _get_identity_parameters(self, double[:] theta) nogil:
592        r""" Parameter values corresponding to the identity
593        Sets in theta the parameter values corresponding to the identity
594        transform
595
596        Parameters
597        ----------
598        theta : array, shape (6,)
599            buffer to write the parameters of the 3D rigid transform
600            theta[0] : rotation about the x axis
601            theta[1] : rotation about the y axis
602            theta[2] : rotation about the z axis
603            theta[3] : translation along the x axis
604            theta[4] : translation along the y axis
605            theta[5] : translation along the z axis
606        """
607        theta[:6] = 0
608
609    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
610        r""" Matrix associated with the 3D rigid transform
611
612        Parameters
613        ----------
614        theta : array, shape (6,)
615            the parameters of the 3D rigid transform
616            theta[0] : rotation about the x axis
617            theta[1] : rotation about the y axis
618            theta[2] : rotation about the z axis
619            theta[3] : translation along the x axis
620            theta[4] : translation along the y axis
621            theta[5] : translation along the z axis
622        R : array, shape (4, 4)
623            buffer in which to write the rigid matrix
624        """
625        cdef:
626            double sa = sin(theta[0])
627            double ca = cos(theta[0])
628            double sb = sin(theta[1])
629            double cb = cos(theta[1])
630            double sc = sin(theta[2])
631            double cc = cos(theta[2])
632            double dx = theta[3]
633            double dy = theta[4]
634            double dz = theta[5]
635
636        R[0,0], R[0,1], R[0,2] = cc*cb-sc*sa*sb, -sc*ca, cc*sb+sc*sa*cb
637        R[1,0], R[1,1], R[1,2] = sc*cb+cc*sa*sb, cc*ca, sc*sb-cc*sa*cb
638        R[2,0], R[2,1], R[2,2] = -ca*sb, sa, ca*cb
639        R[3,0], R[3,1], R[3,2] = 0, 0, 0
640        R[0,3] = dx
641        R[1,3] = dy
642        R[2,3] = dz
643        R[3,3] = 1
644
645
646cdef class RigidIsoScalingTransform2D(Transform):
647    def __init__(self):
648        """ Rigid isoscaling transform in 2D.
649
650        (rotation + translation + scaling)
651
652        The parameter vector theta of length 4 is interpreted as follows:
653        theta[0] : rotation angle
654        theta[1] : translation along the x axis
655        theta[2] : translation along the y axis
656        theta[3] : isotropic scaling
657        """
658        self.dim = 2
659        self.number_of_parameters = 4
660
661    cdef int _jacobian(self, double[:] theta, double[:] x,
662                       double[:, :] J)nogil:
663        r""" Jacobian matrix of a 2D rigid isoscaling transform.
664
665        The transformation (rotation + translation + isoscaling) is given by:
666
667        T(x,y) = (T1(x,y), T2(x,y)) =
668            (sx * x * cost -  sx * y * sint + dx, sy * x * sint + sy * y * cost + dy)
669
670        Parameters
671        ----------
672        theta : array, shape (4,)
673            the parameters of the 2D rigid isoscaling transform
674            theta[0] : rotation angle (t)
675            theta[1] : translation along the x axis (dx)
676            theta[2] : translation along the y axis (dy)
677            theta[3] : isotropic scaling (s)
678        x : array, shape (2,)
679            the point at which to compute the Jacobian
680        J : array, shape (2, 4)
681            the buffer in which to write the Jacobian
682
683        Returns
684        -------
685        is_constant : int
686            always returns 0, indicating that the Jacobian is not
687            constant (it depends on the value of x)
688        """
689        cdef:
690            double st = sin(theta[0])
691            double ct = cos(theta[0])
692            double px = x[0], py = x[1]
693            double scale = theta[3]
694
695        J[0, 0], J[0, 1], J[0, 2] = -px * scale * st - py * scale * ct, 1, 0
696        J[1, 0], J[1, 1], J[1, 2] = px * scale * ct - py * scale * st, 0, 1
697
698        J[0, 3] = px * ct - py * st
699        J[1, 3] = px * st + py * ct
700        # This Jacobian depends on x (it's not constant): return 0
701        return 0
702
703    cdef void _get_identity_parameters(self, double[:] theta) nogil:
704        """ Parameter values corresponding to the identity
705        Sets in theta the parameter values corresponding to the identity
706        transform
707
708        Parameters
709        ----------
710        theta : array, shape (4,)
711            buffer to write the parameters of the 2D isoscaling rigid transform
712            theta[0] : rotation angle
713            theta[1] : translation along the x axis
714            theta[2] : translation along the y axis
715            theta[3] : isotropic scaling
716        """
717        theta[:3] = 0
718        theta[3] = 1
719
720    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
721        r""" Matrix associated with the 2D rigid isoscaling transform
722
723        Parameters
724        ----------
725        theta : array, shape (4,)
726            the parameters of the 2D rigid isoscaling transform
727            theta[0] : rotation angle
728            theta[1] : translation along the x axis
729            theta[2] : translation along the y axis
730            theta[3] : isotropic scaling
731        R : array, shape (3, 3)
732            buffer in which to write the rigid isoscaling matrix
733        """
734        cdef:
735            double ct = cos(theta[0])
736            double st = sin(theta[0])
737        R[0, 0], R[0, 1], R[0, 2] = ct*theta[3], -st*theta[3], theta[1]
738        R[1, 0], R[1, 1], R[1, 2] = st*theta[3], ct*theta[3], theta[2]
739        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
740
741
742cdef class RigidIsoScalingTransform3D(Transform):
743    def __init__(self):
744        """Rigid isoscaling transform in 3D.
745
746        (rotation + translation + scaling)
747        The parameter vector theta of length 7 is interpreted as follows:
748        theta[0] : rotation about the x axis
749        theta[1] : rotation about the y axis
750        theta[2] : rotation about the z axis
751        theta[3] : translation along the x axis
752        theta[4] : translation along the y axis
753        theta[5] : translation along the z axis
754        theta[6] : isotropic scaling
755
756        """
757        self.dim = 3
758        self.number_of_parameters = 7
759
760    cdef int _jacobian(self, double[:] theta, double[:] x,
761                       double[:, :] J)nogil:
762        r""" Jacobian matrix of a 3D isoscaling rigid transform.
763
764        (rotation + translation + scaling)
765
766        Parameters
767        ----------
768        theta : array, shape (7,)
769            the parameters of the 3D rigid isoscaling transform
770            theta[0] : rotation about the x axis
771            theta[1] : rotation about the y axis
772            theta[2] : rotation about the z axis
773            theta[3] : translation along the x axis
774            theta[4] : translation along the y axis
775            theta[5] : translation along the z axis
776            theta[6] : isotropic scaling
777        x : array, shape (3,)
778            the point at which to compute the Jacobian
779        J : array, shape (3, 7)
780            the buffer in which to write the Jacobian
781
782        Returns
783        -------
784        is_constant : int
785            always returns 0, indicating that the Jacobian is not
786            constant (it depends on the value of x)
787        """
788        cdef:
789            double sa = sin(theta[0])
790            double ca = cos(theta[0])
791            double sb = sin(theta[1])
792            double cb = cos(theta[1])
793            double sc = sin(theta[2])
794            double cc = cos(theta[2])
795            double px = x[0], py = x[1], pz = x[2]
796            double scale = theta[6]
797
798        J[0, 0] = (-sc * ca * sb) * px * scale + (sc * sa) * py * scale + \
799                  (sc * ca * cb) * pz * scale
800        J[1, 0] = (cc * ca * sb) * px * scale + (-cc * sa) * py * scale + \
801                  (-cc * ca * cb) * pz  * scale
802        J[2, 0] = (sa * sb) * px * scale + ca * py * scale + \
803                  (-sa * cb) * pz * scale
804
805        J[0, 1] = (-cc * sb - sc * sa * cb) * px * scale + \
806                  (cc * cb - sc * sa * sb) * pz * scale
807        J[1, 1] = (-sc * sb + cc * sa * cb) * px * scale + \
808                  (sc * cb + cc * sa * sb) * pz * scale
809        J[2, 1] = (-ca * cb) * px * scale + (-ca * sb) * pz * scale
810
811        J[0, 2] = (-sc * cb - cc * sa * sb) * px * scale + \
812                  (-cc * ca) * py  * scale + \
813                  (-sc * sb + cc * sa * cb) * pz * scale
814        J[1, 2] = (cc * cb - sc * sa * sb) * px * scale + \
815                  (-sc * ca) * py * scale + \
816                  (cc * sb + sc * sa * cb) * pz * scale
817        J[2, 2] = 0
818
819        J[0, 3:6] = 0
820        J[1, 3:6] = 0
821        J[2, 3:6] = 0
822        J[0, 3], J[1, 4], J[2, 5] = 1, 1, 1
823        J[0, 6] = (cc*cb-sc*sa*sb) * px - sc*ca*py + (cc*sb+sc*sa*cb) * pz
824        J[1, 6] = (sc*cb+cc*sa*sb) * px + cc*ca*py + (sc*sb-cc*sa*cb) * pz
825        J[2, 6] = -ca*sb*px + sa*py + ca*cb*pz
826        # This Jacobian depends on x (it's not constant): return 0
827        return 0
828
829    cdef void _get_identity_parameters(self, double[:] theta) nogil:
830        """ Parameter values corresponding to the identity
831
832        Sets in theta the parameter values corresponding to the identity
833        transform
834
835        Parameters
836        ----------
837        theta : array, shape (7,)
838            buffer to write the parameters of the 3D rigid isoscaling transform
839            theta[0] : rotation about the x axis
840            theta[1] : rotation about the y axis
841            theta[2] : rotation about the z axis
842            theta[3] : translation along the x axis
843            theta[4] : translation along the y axis
844            theta[5] : translation along the z axis
845            theta[6] : isotropic scaling
846
847        """
848        theta[:6] = 0
849        theta[6] = 1
850
851    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
852        """ Matrix associated with the 3D rigid isoscaling transform
853
854        Parameters
855        ----------
856        theta : array, shape (7,)
857            the parameters of the 3D rigid isoscaling transform
858            theta[0] : rotation about the x axis
859            theta[1] : rotation about the y axis
860            theta[2] : rotation about the z axis
861            theta[3] : translation along the x axis
862            theta[4] : translation along the y axis
863            theta[5] : translation along the z axis
864            theta[6] : isotropic scaling
865        R : array, shape (4, 4)
866            buffer in which to write the rigid isoscaling matrix
867        """
868        cdef:
869            double sa = sin(theta[0])
870            double ca = cos(theta[0])
871            double sb = sin(theta[1])
872            double cb = cos(theta[1])
873            double sc = sin(theta[2])
874            double cc = cos(theta[2])
875            double dx = theta[3]
876            double dy = theta[4]
877            double dz = theta[5]
878            double sxyz = theta[6]
879
880        R[0,0], R[0,1], R[0,2] = (cc*cb-sc*sa*sb)*sxyz, -sc*ca*sxyz, (cc*sb+sc*sa*cb)*sxyz
881        R[1,0], R[1,1], R[1,2] = (sc*cb+cc*sa*sb)*sxyz, cc*ca*sxyz, (sc*sb-cc*sa*cb)*sxyz
882        R[2,0], R[2,1], R[2,2] = -ca*sb*sxyz, sa*sxyz, ca*cb*sxyz
883        R[3,0], R[3,1], R[3,2] = 0, 0, 0
884        R[0,3] = dx
885        R[1,3] = dy
886        R[2,3] = dz
887        R[3,3] = 1
888
889
890cdef class RigidScalingTransform2D(Transform):
891    def __init__(self):
892        """ Rigid scaling transform in 2D.
893
894        (rotation + translation + scaling)
895
896        The parameter vector theta of length 5 is interpreted as follows:
897        theta[0] : rotation angle
898        theta[1] : translation along the x axis
899        theta[2] : translation along the y axis
900        theta[3] : scaling along the x axis
901        theta[4] : scaling along the y axis
902        """
903        self.dim = 2
904        self.number_of_parameters = 5
905
906    cdef int _jacobian(self, double[:] theta, double[:] x,
907                       double[:, :] J)nogil:
908        r""" Jacobian matrix of a 2D rigid scaling transform.
909
910        The transformation (rotation + translation + scaling) is given by:
911
912        T(x,y) = (T1(x,y), T2(x,y)) =
913            (sx * x * cost -  sx * y * sint + dx, sy * x * sint + sy * y * cost + dy)
914
915        Parameters
916        ----------
917        theta : array, shape (5,)
918            the parameters of the 2D rigid isoscaling transform
919            theta[0] : rotation angle (t)
920            theta[1] : translation along the x axis (dx)
921            theta[2] : translation along the y axis (dy)
922            theta[3] : scaling along the x axis
923            theta[4] : scaling along the y axis
924        x : array, shape (2,)
925            the point at which to compute the Jacobian
926        J : array, shape (2, 5)
927            the buffer in which to write the Jacobian
928
929        Returns
930        -------
931        is_constant : int
932            always returns 0, indicating that the Jacobian is not
933            constant (it depends on the value of x)
934        """
935        cdef:
936            double st = sin(theta[0])
937            double ct = cos(theta[0])
938            double px = x[0], py = x[1]
939            double fx = theta[3]
940            double fy = theta[4]
941
942        J[0, 0], J[0, 1], J[0, 2] = -px * fx * st - py * fx * ct, 1, 0
943        J[1, 0], J[1, 1], J[1, 2] = px * fy * ct - py * fy * st, 0, 1
944
945        J[0, 3], J[0, 4] = px * ct - py * st, 0
946        J[1, 3], J[1, 4] = 0, px * st + py * ct
947        # This Jacobian depends on x (it's not constant): return 0
948        return 0
949
950    cdef void _get_identity_parameters(self, double[:] theta) nogil:
951        """ Parameter values corresponding to the identity
952        Sets in theta the parameter values corresponding to the identity
953        transform
954
955        Parameters
956        ----------
957        theta : array, shape (5,)
958            buffer to write the parameters of the 2D scaling rigid transform
959            theta[0] : rotation angle
960            theta[1] : translation along the x axis
961            theta[2] : translation along the y axis
962            theta[3] : scaling along the x axis
963            theta[4] : scaling along the y axis
964        """
965        theta[:3] = 0
966        theta[3], theta[4] = 1, 1
967
968    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
969        r""" Matrix associated with the 2D rigid scaling transform
970
971        Parameters
972        ----------
973        theta : array, shape (5,)
974            the parameters of the 2D rigid scaling transform
975            theta[0] : rotation angle
976            theta[1] : translation along the x axis
977            theta[2] : translation along the y axis
978            theta[3] : scaling along the x axis
979            theta[4] : scaling along the y axis
980        R : array, shape (3, 3)
981            buffer in which to write the rigid scaling matrix
982        """
983        cdef:
984            double ct = cos(theta[0])
985            double st = sin(theta[0])
986        R[0, 0], R[0, 1], R[0, 2] = ct*theta[3], -st*theta[3], theta[1]
987        R[1, 0], R[1, 1], R[1, 2] = st*theta[4], ct*theta[4], theta[2]
988        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
989
990
991cdef class RigidScalingTransform3D(Transform):
992    def __init__(self):
993        """Rigid Scaling transform in 3D (rotation + translation + scaling).
994
995        The parameter vector theta of length 9 is interpreted as follows:
996        theta[0] : rotation about the x axis
997        theta[1] : rotation about the y axis
998        theta[2] : rotation about the z axis
999        theta[3] : translation along the x axis
1000        theta[4] : translation along the y axis
1001        theta[5] : translation along the z axis
1002        theta[6] : scaling in the x axis
1003        theta[7] : scaling in the y axis
1004        theta[8] : scaling in the z axis
1005
1006        """
1007        self.dim = 3
1008        self.number_of_parameters = 9
1009
1010    cdef int _jacobian(self, double[:] theta, double[:] x,
1011                       double[:, :] J)nogil:
1012        """Jacobian matrix of a 3D rigid scaling transform.
1013
1014        (rotation + translation + scaling)
1015
1016        Parameters
1017        ----------
1018        theta : array, shape (9,)
1019            the parameters of the 3D rigid transform
1020            theta[0] : rotation about the x axis
1021            theta[1] : rotation about the y axis
1022            theta[2] : rotation about the z axis
1023            theta[3] : translation along the x axis
1024            theta[4] : translation along the y axis
1025            theta[5] : translation along the z axis
1026            theta[6] : scaling in the x axis
1027            theta[7] : scaling in the y axis
1028            theta[8] : scaling in the z axis
1029        x : array, shape (3,)
1030            the point at which to compute the Jacobian
1031        J : array, shape (3, 9)
1032            the buffer in which to write the Jacobian
1033
1034        Returns
1035        -------
1036        is_constant : int
1037            always returns 0, indicating that the Jacobian is not
1038            constant (it depends on the value of x)
1039        """
1040        cdef:
1041            double sa = sin(theta[0])
1042            double ca = cos(theta[0])
1043            double sb = sin(theta[1])
1044            double cb = cos(theta[1])
1045            double sc = sin(theta[2])
1046            double cc = cos(theta[2])
1047            double px = x[0], py = x[1], pz = x[2]
1048            double fx = theta[6]
1049            double fy = theta[7]
1050            double fz = theta[8]
1051
1052        J[0, 0] = (-sc * ca * sb) * px * fx + (sc * sa) * py * fx + \
1053                  (sc * ca * cb) * pz * fx
1054        J[1, 0] = (cc * ca * sb) * px * fy + (-cc * sa) * py * fy + \
1055                  (-cc * ca * cb) * pz * fy
1056        J[2, 0] = (sa * sb) * px * fz + ca * py * fz + (-sa * cb) * pz * fz
1057
1058        J[0, 1] = (-cc * sb - sc * sa * cb) * px * fx + \
1059                  (cc * cb - sc * sa * sb) * pz * fx
1060        J[1, 1] = (-sc * sb + cc * sa * cb) * px * fy + \
1061                  (sc * cb + cc * sa * sb) * pz * fy
1062        J[2, 1] = (-ca * cb) * px * fz + (-ca * sb) * pz * fz
1063
1064        J[0, 2] = (-sc * cb - cc * sa * sb) * px * fx + (-cc * ca) * py * fx + \
1065                  (-sc * sb + cc * sa * cb) * pz * fx
1066        J[1, 2] = (cc * cb - sc * sa * sb) * px * fy + (-sc * ca) * py * fy + \
1067                  (cc * sb + sc * sa * cb) * pz * fy
1068        J[2, 2] = 0
1069
1070        J[0, 3:6] = 0
1071        J[1, 3:6] = 0
1072        J[2, 3:6] = 0
1073        J[0, 3], J[1, 4], J[2, 5] = 1, 1, 1
1074        J[0, 6] = (cc*cb-sc*sa*sb) * px - sc*ca*py + (cc*sb+sc*sa*cb) * pz
1075        J[1, 6], J[2, 6] = 0, 0
1076        J[1, 7] = (sc*cb+cc*sa*sb) * px + cc*ca*py + (sc*sb-cc*sa*cb) * pz
1077        J[0, 7], J[2, 7] = 0, 0
1078        J[0, 8], J[1, 8] = 0, 0
1079        J[2, 8] = -ca*sb*px + sa*py + ca*cb*pz
1080        # This Jacobian depends on x (it's not constant): return 0
1081        return 0
1082
1083    cdef void _get_identity_parameters(self, double[:] theta) nogil:
1084        r""" Parameter values corresponding to the identity
1085        Sets in theta the parameter values corresponding to the identity
1086        transform
1087
1088        Parameters
1089        ----------
1090        theta : array, shape (9,)
1091            buffer to write the parameters of the 3D rigid scaling transform
1092            theta[0] : rotation about the x axis
1093            theta[1] : rotation about the y axis
1094            theta[2] : rotation about the z axis
1095            theta[3] : translation along the x axis
1096            theta[4] : translation along the y axis
1097            theta[5] : translation along the z axis
1098            theta[6] : scaling in the x axis
1099            theta[7] : scaling in the y axis
1100            theta[8] : scaling in the z axis
1101        """
1102        theta[:6] = 0
1103        theta[6:9] = 1
1104
1105    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
1106        r""" Matrix associated with the 3D rigid scaling transform
1107
1108        Parameters
1109        ----------
1110        theta : array, shape (9,)
1111            the parameters of the 3D rigid scaling transform
1112            theta[0] : rotation about the x axis
1113            theta[1] : rotation about the y axis
1114            theta[2] : rotation about the z axis
1115            theta[3] : translation along the x axis
1116            theta[4] : translation along the y axis
1117            theta[5] : translation along the z axis
1118            theta[6] : scaling in the x axis
1119            theta[7] : scaling in the y axis
1120            theta[8] : scaling in the z axis
1121        R : array, shape (4, 4)
1122            buffer in which to write the rigid matrix
1123        """
1124        cdef:
1125            double sa = sin(theta[0])
1126            double ca = cos(theta[0])
1127            double sb = sin(theta[1])
1128            double cb = cos(theta[1])
1129            double sc = sin(theta[2])
1130            double cc = cos(theta[2])
1131            double dx = theta[3]
1132            double dy = theta[4]
1133            double dz = theta[5]
1134            double fx = theta[6]
1135            double fy = theta[7]
1136            double fz = theta[8]
1137
1138        R[0,0], R[0,1], R[0,2] = (cc*cb-sc*sa*sb)*fx, -sc*ca*fx, (cc*sb+sc*sa*cb)*fx
1139        R[1,0], R[1,1], R[1,2] = (sc*cb+cc*sa*sb)*fy, cc*ca*fy, (sc*sb-cc*sa*cb)*fy
1140        R[2,0], R[2,1], R[2,2] = -ca*sb*fz, sa*fz, ca*cb*fz
1141        R[3,0], R[3,1], R[3,2] = 0, 0, 0
1142        R[0,3] = dx
1143        R[1,3] = dy
1144        R[2,3] = dz
1145        R[3,3] = 1
1146
1147
1148cdef class ScalingTransform2D(Transform):
1149    def __init__(self):
1150        r""" Scaling transform in 2D
1151        """
1152        self.dim = 2
1153        self.number_of_parameters = 1
1154
1155    cdef int _jacobian(self, double[:] theta, double[:] x,
1156                       double[:, :] J)nogil:
1157        r""" Jacobian matrix of the isotropic 2D scale transform
1158        The transformation is given by:
1159
1160        T(x) = (s*x0, s*x1)
1161
1162        The derivative w.r.t. s is T'(x) = [x0, x1]
1163
1164        Parameters
1165        ----------
1166        theta : array, shape (1,)
1167            the scale factor (the Jacobian does not depend on the scale factor,
1168            but we receive the buffer to make it consistent with other Jacobian
1169            functions)
1170        x : array, shape (2,)
1171            the point at which to compute the Jacobian
1172        J : array, shape (2, 1)
1173            the buffer in which to write the Jacobian
1174
1175        Returns
1176        -------
1177        is_constant : int
1178            always returns 0, indicating that the Jacobian is not
1179            constant (it depends on the value of x)
1180        """
1181        J[0, 0], J[1, 0] = x[0], x[1]
1182        # This Jacobian depends on x (it's not constant): return 0
1183        return 0
1184
1185    cdef void _get_identity_parameters(self, double[:] theta) nogil:
1186        r""" Parameter values corresponding to the identity
1187        Sets in theta the parameter values corresponding to the identity
1188        transform
1189
1190        Parameters
1191        ----------
1192        theta : array, shape (1,)
1193            buffer to write the parameters of the 2D scale transform
1194        """
1195        theta[0] = 1
1196
1197    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
1198        r""" Matrix associated with the 2D (isotropic) scaling transform
1199
1200        Parameters
1201        ----------
1202        theta : array, shape (1,)
1203            the scale factor
1204        R : array, shape (3, 3)
1205            the buffer in which to write the scaling matrix
1206        """
1207        R[0, 0], R[0, 1], R[0, 2] = theta[0], 0, 0
1208        R[1, 0], R[1, 1], R[1, 2] = 0, theta[0], 0
1209        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
1210
1211
1212cdef class ScalingTransform3D(Transform):
1213    def __init__(self):
1214        r""" Scaling transform in 3D
1215        """
1216        self.dim = 3
1217        self.number_of_parameters = 1
1218
1219    cdef int _jacobian(self, double[:] theta, double[:] x,
1220                       double[:, :] J)nogil:
1221        r""" Jacobian matrix of the isotropic 3D scale transform
1222        The transformation is given by:
1223
1224        T(x) = (s*x0, s*x1, s*x2)
1225
1226        The derivative w.r.t. s is T'(x) = [x0, x1, x2]
1227
1228        Parameters
1229        ----------
1230        theta : array, shape (1,)
1231            the scale factor (the Jacobian does not depend on the scale factor,
1232            but we receive the buffer to make it consistent with other Jacobian
1233            functions)
1234        x : array, shape (3,)
1235            the point at which to compute the Jacobian
1236        J : array, shape (3, 1)
1237            the buffer in which to write the Jacobian
1238
1239        Returns
1240        -------
1241        is_constant : int
1242            always returns 0, indicating that the Jacobian is not
1243            constant (it depends on the value of x)
1244        """
1245        J[0, 0], J[1, 0], J[2, 0]= x[0], x[1], x[2]
1246        # This Jacobian depends on x (it's not constant): return 0
1247        return 0
1248
1249    cdef void _get_identity_parameters(self, double[:] theta) nogil:
1250        r""" Parameter values corresponding to the identity
1251        Sets in theta the parameter values corresponding to the identity
1252        transform
1253
1254        Parameters
1255        ----------
1256        theta : array, shape (1,)
1257            buffer to write the parameters of the 3D scale transform
1258        """
1259        theta[0] = 1
1260
1261    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
1262        r""" Matrix associated with the 3D (isotropic) scaling transform
1263
1264        Parameters
1265        ----------
1266        theta : array, shape (1,)
1267            the scale factor
1268        R : array, shape (4, 4)
1269            the buffer in which to write the scaling matrix
1270        """
1271        R[0, 0], R[0, 1], R[0, 2], R[0, 3] = theta[0], 0, 0, 0
1272        R[1, 0], R[1, 1], R[1, 2], R[1, 3] = 0, theta[0], 0, 0
1273        R[2, 0], R[2, 1], R[2, 2], R[2, 3] = 0, 0, theta[0], 0
1274        R[3, 0], R[3, 1], R[3, 2], R[3, 3] = 0, 0, 0, 1
1275
1276
1277cdef class AffineTransform2D(Transform):
1278    def __init__(self):
1279        r""" Affine transform in 2D
1280        """
1281        self.dim = 2
1282        self.number_of_parameters = 6
1283
1284    cdef int _jacobian(self, double[:] theta, double[:] x,
1285                       double[:, :] J)nogil:
1286        r""" Jacobian matrix of the 2D affine transform
1287        The transformation is given by:
1288
1289        T(x) = |a0, a1, a2 |   |x0|   | T1(x) |   |a0*x0 + a1*x1 + a2|
1290               |a3, a4, a5 | * |x1| = | T2(x) | = |a3*x0 + a4*x1 + a5|
1291                               | 1|
1292
1293        The derivatives w.r.t. each parameter are given by
1294
1295        T'(x) = [[x0,  0], #derivatives of [T1, T2] w.r.t a0
1296                 [x1,  0], #derivatives of [T1, T2] w.r.t a1
1297                 [ 1,  0], #derivatives of [T1, T2] w.r.t a2
1298                 [ 0, x0], #derivatives of [T1, T2] w.r.t a3
1299                 [ 0, x1], #derivatives of [T1, T2] w.r.t a4
1300                 [ 0,  1]] #derivatives of [T1, T2, T3] w.r.t a5
1301
1302        The Jacobian matrix is the transpose of the above matrix.
1303
1304        Parameters
1305        ----------
1306        theta : array, shape (6,)
1307            the parameters of the 2D affine transform
1308        x : array, shape (2,)
1309            the point at which to compute the Jacobian
1310        J : array, shape (2, 6)
1311            the buffer in which to write the Jacobian
1312
1313        Returns
1314        -------
1315        is_constant : int
1316            always returns 0, indicating that the Jacobian is not
1317            constant (it depends on the value of x)
1318        """
1319        J[0, :6] = 0
1320        J[1, :6] = 0
1321
1322        J[0, :2] = x[:2]
1323        J[0, 2] = 1
1324        J[1, 3:5] = x[:2]
1325        J[1, 5] = 1
1326        # This Jacobian depends on x (it's not constant): return 0
1327        return 0
1328
1329    cdef void _get_identity_parameters(self, double[:] theta) nogil:
1330        r""" Parameter values corresponding to the identity
1331        Sets in theta the parameter values corresponding to the identity
1332        transform
1333
1334        Parameters
1335        ----------
1336        theta : array, shape (6,)
1337            buffer to write the parameters of the 2D affine transform
1338        """
1339        theta[0], theta[1], theta[2] = 1, 0, 0
1340        theta[3], theta[4], theta[5] = 0, 1, 0
1341
1342    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
1343        r""" Matrix associated with a general 2D affine transform
1344
1345        The transformation is given by the matrix:
1346
1347        A = [[a0, a1, a2],
1348             [a3, a4, a5],
1349             [ 0,  0,  1]]
1350
1351        Parameters
1352        ----------
1353        theta : array, shape (6,)
1354            the parameters of the 2D affine transform
1355        R : array, shape (3,3)
1356            the buffer in which to write the matrix
1357        """
1358        R[0, 0], R[0, 1], R[0, 2] = theta[0], theta[1], theta[2]
1359        R[1, 0], R[1, 1], R[1, 2] = theta[3], theta[4], theta[5]
1360        R[2, 0], R[2, 1], R[2, 2] = 0, 0, 1
1361
1362
1363cdef class AffineTransform3D(Transform):
1364    def __init__(self):
1365        r""" Affine transform in 3D
1366        """
1367        self.dim = 3
1368        self.number_of_parameters = 12
1369
1370    cdef int _jacobian(self, double[:] theta, double[:] x,
1371                       double[:, :] J)nogil:
1372        r""" Jacobian matrix of the 3D affine transform
1373        The transformation is given by:
1374
1375        T(x)= |a0, a1, a2,  a3 |  |x0|  | T1(x) |  |a0*x0 + a1*x1 + a2*x2 + a3|
1376              |a4, a5, a6,  a7 |* |x1|= | T2(x) |= |a4*x0 + a5*x1 + a6*x2 + a7|
1377              |a8, a9, a10, a11|  |x2|  | T3(x) |  |a8*x0 + a9*x1 + a10*x2+a11|
1378                                  | 1|
1379
1380        The derivatives w.r.t. each parameter are given by
1381
1382        T'(x) = [[x0,  0,  0], #derivatives of [T1, T2, T3] w.r.t a0
1383                 [x1,  0,  0], #derivatives of [T1, T2, T3] w.r.t a1
1384                 [x2,  0,  0], #derivatives of [T1, T2, T3] w.r.t a2
1385                 [ 1,  0,  0], #derivatives of [T1, T2, T3] w.r.t a3
1386                 [ 0, x0,  0], #derivatives of [T1, T2, T3] w.r.t a4
1387                 [ 0, x1,  0], #derivatives of [T1, T2, T3] w.r.t a5
1388                 [ 0, x2,  0], #derivatives of [T1, T2, T3] w.r.t a6
1389                 [ 0,  1,  0], #derivatives of [T1, T2, T3] w.r.t a7
1390                 [ 0,  0, x0], #derivatives of [T1, T2, T3] w.r.t a8
1391                 [ 0,  0, x1], #derivatives of [T1, T2, T3] w.r.t a9
1392                 [ 0,  0, x2], #derivatives of [T1, T2, T3] w.r.t a10
1393                 [ 0,  0,  1]] #derivatives of [T1, T2, T3] w.r.t a11
1394
1395        The Jacobian matrix is the transpose of the above matrix.
1396
1397        Parameters
1398        ----------
1399        theta : array, shape (12,)
1400            the parameters of the 3D affine transform
1401        x : array, shape (3,)
1402            the point at which to compute the Jacobian
1403        J : array, shape (3, 12)
1404            the buffer in which to write the Jacobian
1405
1406        Returns
1407        -------
1408        is_constant : int
1409            always returns 0, indicating that the Jacobian is not
1410            constant (it depends on the value of x)
1411        """
1412        cdef:
1413            cnp.npy_intp j
1414
1415        for j in range(3):
1416            J[j, :12] = 0
1417        J[0, :3] = x[:3]
1418        J[0, 3] = 1
1419        J[1, 4:7] = x[:3]
1420        J[1, 7] = 1
1421        J[2, 8:11] = x[:3]
1422        J[2, 11] = 1
1423        # This Jacobian depends on x (it's not constant): return 0
1424        return 0
1425
1426    cdef void _get_identity_parameters(self, double[:] theta) nogil:
1427        r""" Parameter values corresponding to the identity
1428        Sets in theta the parameter values corresponding to the identity
1429        transform
1430
1431        Parameters
1432        ----------
1433        theta : array, shape (12,)
1434            buffer to write the parameters of the 3D affine transform
1435        """
1436        theta[0], theta[1], theta[2], theta[3] = 1, 0, 0, 0
1437        theta[4], theta[5], theta[6], theta[7] = 0, 1, 0, 0
1438        theta[8], theta[9], theta[10], theta[11] = 0, 0, 1, 0
1439
1440    cdef void _param_to_matrix(self, double[:] theta, double[:, :] R) nogil:
1441        r""" Matrix associated with a general 3D affine transform
1442
1443        The transformation is given by the matrix:
1444
1445        A = [[a0, a1, a2, a3],
1446             [a4, a5, a6, a7],
1447             [a8, a9, a10, a11],
1448             [ 0,   0,   0,   1]]
1449
1450        Parameters
1451        ----------
1452        theta : array, shape (12,)
1453            the parameters of the 3D affine transform
1454        R : array, shape (4,4)
1455            the buffer in which to write the matrix
1456        """
1457        R[0, 0], R[0, 1], R[0, 2] = theta[0], theta[1], theta[2]
1458        R[1, 0], R[1, 1], R[1, 2] = theta[4], theta[5], theta[6]
1459        R[2, 0], R[2, 1], R[2, 2] = theta[8], theta[9], theta[10]
1460        R[3, 0], R[3, 1], R[3, 2] = 0, 0, 0
1461        R[0, 3] = theta[3]
1462        R[1, 3] = theta[7]
1463        R[2, 3] = theta[11]
1464        R[3, 3] = 1
1465
1466
1467regtransforms = {}
1468regtransforms [('TRANSLATION', 2)] = TranslationTransform2D()
1469regtransforms [('TRANSLATION', 3)] = TranslationTransform3D()
1470regtransforms [('ROTATION', 2)] = RotationTransform2D()
1471regtransforms [('ROTATION', 3)] = RotationTransform3D()
1472regtransforms [('RIGID', 2)] = RigidTransform2D()
1473regtransforms [('RIGID', 3)] = RigidTransform3D()
1474regtransforms [('SCALING', 2)] = ScalingTransform2D()
1475regtransforms [('SCALING', 3)] = ScalingTransform3D()
1476regtransforms [('AFFINE', 2)] = AffineTransform2D()
1477regtransforms [('AFFINE', 3)] = AffineTransform3D()
1478regtransforms [('RIGIDSCALING', 2)] = RigidScalingTransform2D()
1479regtransforms [('RIGIDSCALING', 3)] = RigidScalingTransform3D()
1480regtransforms [('RIGIDISOSCALING', 2)] = RigidIsoScalingTransform2D()
1481regtransforms [('RIGIDISOSCALING', 3)] = RigidIsoScalingTransform3D()
1482