1- """ Registration methods based on cross correlation """
1+ """ Registration methods based on Lucas-Kanade registration """
22
3- from numpy import ndarray
4- import numpy as np
3+ from numpy import array , ndarray , inf , zeros
54
65from thunder .rdds .images import Images
76from thunder .imgprocessing .registration import RegistrationMethod
8- #from thunder.imgprocessing.regmethods.utils import computeDisplacement, computeReferenceMean, checkReference
97from thunder .imgprocessing .transformation import GridTransformer , TRANSFORMATION_TYPES
108from thunder .imgprocessing .regmethods .utils import volumesToMatrix , imageJacobian , solveLinearized , computeReferenceMean , checkReference
119
1210
1311class 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+ """
1741 self .transformationType = transformationType
42+ self .border = border
43+ self .maxIter = maxIter
1844 self .tol = tol
1945 self .robust = robust
20- self .border = border
2146
2247 def prepare (self , images , startidx = None , stopidx = None ):
2348 """
24- Prepare Lucas Kanade registration by computing or specifying a reference image.
49+ Prepare Lucas- Kanade registration by computing or specifying a reference image.
2550
2651 Parameters
2752 ----------
@@ -36,6 +61,7 @@ def prepare(self, images, startidx=None, stopidx=None):
3661 self .reference = images
3762 else :
3863 raise Exception ('Must provide either an Images object or a reference' )
64+ # Convert references to matrix to speed up solving linearized system
3965 self .referenceMat = volumesToMatrix (self .reference )
4066 return self
4167
@@ -52,15 +78,17 @@ def isPrepared(self, images):
5278 checkReference (self .reference , images )
5379
5480 def getTransform (self , vol ):
81+ from numpy .linalg import norm
5582 # 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
5785 grid = GridTransformer (vol .shape )
5886 iter = 0
59- normDelta = np . inf
87+ normDelta = inf
6088 while iter < self .maxIter and normDelta > self .tol :
6189 iter += 1
6290 volTfm , jacobian = imageJacobian (vol , tfm , grid , border = self .border )
6391 deltaTransformParams , coeff = solveLinearized (volumesToMatrix (volTfm ), volumesToMatrix (jacobian ), self .referenceMat , self .robust )
6492 tfm .updateParams (- deltaTransformParams )
65- normDelta = np . linalg . norm (- deltaTransformParams )
93+ normDelta = norm (deltaTransformParams )
6694 return tfm
0 commit comments