1
- """ Registration methods based on cross correlation """
1
+ """ Registration methods based on Lucas-Kanade registration """
2
2
3
- from numpy import ndarray
4
- import numpy as np
3
+ from numpy import array , ndarray , inf , zeros
5
4
6
5
from thunder .rdds .images import Images
7
6
from thunder .imgprocessing .registration import RegistrationMethod
8
- #from thunder.imgprocessing.regmethods.utils import computeDisplacement, computeReferenceMean, checkReference
9
7
from thunder .imgprocessing .transformation import GridTransformer , TRANSFORMATION_TYPES
10
8
from thunder .imgprocessing .regmethods .utils import volumesToMatrix , imageJacobian , solveLinearized , computeReferenceMean , checkReference
11
9
12
10
13
11
class LucasKanadeRegistration (RegistrationMethod ):
14
- def __init__ (self , maxIter = 10 , transformationType = 'Translation' , tol = 1e-3 , robust = False , border = 0 ):
15
- # self.jacobian_args = kwargs
16
- self .maxIter = maxIter
12
+ """Lucas-Kanade registration method.
13
+
14
+ Lucas-Kanade (LK) is an iterative algorithm for aligning an image to a reference. It aims to minimize the squared
15
+ error between the transformed image and the reference. As the relationship between transformation parameters and
16
+ transformed pixels is nonlinear, we have to perform a series of linearizations similar to Levenberg-Marquardt.
17
+ At each iteration, we compute the Jacobian of the output image with respect to the input parameters, and solve a
18
+ least squares problem to identify a change in parameters. We update the parameters and repeat.
19
+
20
+ To increase robustness, we extend the traditional LK algorithm to use a set of reference images.
21
+ We minimize the squared error of the difference of the transformed image and a learned weighting of the references.
22
+ """
23
+
24
+ def __init__ (self , transformationType = 'Translation' , border = 0 , tol = 1e-5 , maxIter = 10 , robust = False ):
25
+ """
26
+ Parameters
27
+ ----------
28
+ transformationType : one of 'Translation', 'Euclidean', optional, default = 'Translation'
29
+ type of transformation to use
30
+ border : int or tuple, optional, default = 0
31
+ Border to be zeroed out after transformations. For most datasets, it is
32
+ critical that this value be larger than the maximum translation to get
33
+ good results and avoid boundary artifacts.
34
+ maxIter : int, optional, default = 10
35
+ maximum number of iterations
36
+ tol : float, optional, default = 1e-5
37
+ stopping criterion on the L2 norm of the change in parameters
38
+ robust : bool, optional, default = False
39
+ solve a least absolute deviation problem instead of least squares
40
+ """
17
41
self .transformationType = transformationType
42
+ self .border = border
43
+ self .maxIter = maxIter
18
44
self .tol = tol
19
45
self .robust = robust
20
- self .border = border
21
46
22
47
def prepare (self , images , startidx = None , stopidx = None ):
23
48
"""
24
- Prepare Lucas Kanade registration by computing or specifying a reference image.
49
+ Prepare Lucas- Kanade registration by computing or specifying a reference image.
25
50
26
51
Parameters
27
52
----------
@@ -36,6 +61,7 @@ def prepare(self, images, startidx=None, stopidx=None):
36
61
self .reference = images
37
62
else :
38
63
raise Exception ('Must provide either an Images object or a reference' )
64
+ # Convert references to matrix to speed up solving linearized system
39
65
self .referenceMat = volumesToMatrix (self .reference )
40
66
return self
41
67
@@ -52,15 +78,17 @@ def isPrepared(self, images):
52
78
checkReference (self .reference , images )
53
79
54
80
def getTransform (self , vol ):
81
+ from numpy .linalg import norm
55
82
# Create initial transformation
56
- tfm = TRANSFORMATION_TYPES [self .transformationType ](shift = np .zeros (vol .ndim ))
83
+ tfm = TRANSFORMATION_TYPES [self .transformationType ](shift = zeros (vol .ndim ))
84
+ # Grid of coordinates needed to transform images using map_coordinates
57
85
grid = GridTransformer (vol .shape )
58
86
iter = 0
59
- normDelta = np . inf
87
+ normDelta = inf
60
88
while iter < self .maxIter and normDelta > self .tol :
61
89
iter += 1
62
90
volTfm , jacobian = imageJacobian (vol , tfm , grid , border = self .border )
63
91
deltaTransformParams , coeff = solveLinearized (volumesToMatrix (volTfm ), volumesToMatrix (jacobian ), self .referenceMat , self .robust )
64
92
tfm .updateParams (- deltaTransformParams )
65
- normDelta = np . linalg . norm (- deltaTransformParams )
93
+ normDelta = norm (deltaTransformParams )
66
94
return tfm
0 commit comments