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