@@ -161,7 +161,11 @@ def load_leaf_json(d):
161161 lambda x : Polynomial2DTransform (json = x ),
162162 TranslationModel .className : lambda x : TranslationModel (json = x ),
163163 RigidModel .className : lambda x : RigidModel (json = x ),
164- SimilarityModel .className : lambda x : SimilarityModel (json = x )}
164+ SimilarityModel .className : lambda x : SimilarityModel (json = x ),
165+ NonLinearTransform .className : lambda x : NonLinearTransform (json = x ),
166+ LensCorrection .className : lambda x : LensCorrection (json = x ),
167+ NonLinearCoordinateTransform .className :
168+ lambda x : NonLinearCoordinateTransform (json = x )}
165169
166170 tform_type = d .get ('type' , 'leaf' )
167171 if tform_type != 'leaf' :
@@ -358,7 +362,7 @@ def to_dict(self):
358362 d ['className' ] = self .className
359363 d ['dataString' ] = self .dataString
360364 if self .transformId is not None :
361- d ['transformId ' ] = self .transformId
365+ d ['id ' ] = self .transformId
362366 return d
363367
364368 def from_dict (self , d ):
@@ -370,7 +374,7 @@ def from_dict(self, d):
370374 json compatible representation of this transform
371375 """
372376 self .className = d ['className' ]
373- self .transformId = d .get ('transformId ' , None )
377+ self .transformId = d .get ('id ' , None )
374378 self ._process_dataString (d ['dataString' ])
375379
376380 def _process_dataString (self , datastring ):
@@ -568,7 +572,7 @@ def estimate(self, A, B, return_params=True, **kwargs):
568572 def concatenate (self , model ):
569573 """concatenate a model to this model -- ported from trakEM2 below:
570574 ::
571-
575+
572576 final double a00 = m00 * model.m00 + m01 * model.m10;
573577 final double a01 = m00 * model.m01 + m01 * model.m11;
574578 final double a02 = m00 * model.m02 + m01 * model.m12 + m02;
@@ -749,8 +753,6 @@ class TranslationModel(AffineModel):
749753
750754 def __init__ (self , * args , ** kwargs ):
751755 super (TranslationModel , self ).__init__ (* args , ** kwargs )
752- # raise NotImplementedError(
753- # 'TranslationModel not implemented. please use Affine')
754756
755757 def _process_dataString (self , dataString ):
756758 """expected dataString is 'tx ty'"""
@@ -840,8 +842,6 @@ class RigidModel(AffineModel):
840842
841843 def __init__ (self , * args , ** kwargs ):
842844 super (RigidModel , self ).__init__ (* args , ** kwargs )
843- # raise NotImplementedError(
844- # 'RigidModel not implemented. please use Affine')
845845
846846 def _process_dataString (self , dataString ):
847847 """expected datastring is 'theta tx ty'"""
@@ -969,8 +969,6 @@ class SimilarityModel(RigidModel):
969969
970970 def __init__ (self , * args , ** kwargs ):
971971 super (SimilarityModel , self ).__init__ (* args , ** kwargs )
972- # raise NotImplementedError(
973- # 'SimilarityModel not implemented. please use Affine')
974972
975973 def _process_dataString (self , dataString ):
976974 """expected datastring is 's theta tx ty'"""
@@ -1370,6 +1368,153 @@ def estimate_dstpts(transformlist, src=None):
13701368 return dstpts
13711369
13721370
1371+ class NonLinearCoordinateTransform (Transform ):
1372+ """
1373+ render-python class that implements the
1374+ mpicbg.trakem2.transform.NonLinearCoordinateTransform class
1375+
1376+ Parameters
1377+ ----------
1378+ dataString: str or None
1379+ data string of transformation
1380+ json: dict or None
1381+ json compatible dictionary representation of the transformation
1382+
1383+ Returns
1384+ -------
1385+ :class:`NonLinearTransform`
1386+ a transform instance
1387+
1388+
1389+ """
1390+
1391+ className = 'mpicbg.trakem2.transform.NonLinearCoordinateTransform'
1392+
1393+ def __init__ (self , dataString = None , json = None , transformId = None ):
1394+ if json is not None :
1395+ self .from_dict (json )
1396+ else :
1397+ if dataString is not None :
1398+ self ._process_dataString (dataString )
1399+ self .transformId = transformId
1400+ self .className = 'mpicbg.trakem2.transform.NonLinearCoordinateTransform'
1401+
1402+ def _process_dataString (self , dataString ):
1403+
1404+ fields = dataString .split (" " )
1405+
1406+ self .dimension = int (fields [0 ])
1407+ self .length = int (fields [1 ])
1408+
1409+ # cutoff whitespace if there
1410+ fields = fields [0 :2 + 4 * self .length + 2 ]
1411+ # last 2 fields are width and height
1412+ self .width = int (fields [- 2 ])
1413+ self .height = int (fields [- 1 ])
1414+
1415+ data = np .array (fields [2 :- 2 ], dtype = 'float32' )
1416+ try :
1417+ self .beta = data [0 :2 * self .length ].reshape (self .length , 2 )
1418+ except ValueError as e :
1419+ raise RenderError (
1420+ 'Incorrect number of coefficients in '
1421+ 'NonLinearCoordinateTransform. msg: {}' .format (e ))
1422+ if not (self .beta .shape [0 ] == self .length ):
1423+ raise RenderError ("not correct number of coefficents" )
1424+
1425+ # normMean and normVar follow
1426+ self .normMean = data [self .length * 2 :self .length * 3 ]
1427+ self .normVar = data [self .length * 3 :self .length * 4 ]
1428+ if not (self .normMean .shape [0 ] == self .length ):
1429+ raise RenderError (
1430+ "incorrect number of normMean coefficents "
1431+ "{} != length {}" .format (self .normMean .shape [0 ], self .length ))
1432+ if not (self .normVar .shape [0 ] == self .length ):
1433+ raise RenderError (
1434+ "incorrect number of normVar coefficents "
1435+ "{} != {}" .format (self .normVar .shape [0 ], self .length ))
1436+
1437+ def kernelExpand (self , src ):
1438+ """creates an expanded representation of the x,y
1439+ src points in a polynomial form
1440+
1441+ Parameters
1442+ ----------
1443+ points : numpy.array
1444+ a Nx2 array of x,y points
1445+
1446+ Returns
1447+ -------
1448+ numpy.array
1449+ a (N x self.length) array of coefficents
1450+ """
1451+ x = src [:, 0 ]
1452+ y = src [:, 1 ]
1453+
1454+ expanded = np .zeros ([len (x ), self .length ])
1455+ pidx = 0
1456+ for i in range (1 , self .dimension + 1 ):
1457+ for j in range (i , - 1 , - 1 ):
1458+ expanded [:, pidx ] = (
1459+ np .power (x , j ) * np .power (y , i - j ))
1460+ pidx += 1
1461+
1462+ expanded [:, :- 1 ] = ((expanded [:, :- 1 ] - self .normMean [:- 1 ]) /
1463+ self .normVar [:- 1 ])
1464+ expanded [:, - 1 ] = 100.0
1465+ return expanded
1466+
1467+ def tform (self , src ):
1468+ """transform a set of points through this transformation
1469+
1470+ Parameters
1471+ ----------
1472+ points : numpy.array
1473+ a Nx2 array of x,y points
1474+
1475+ Returns
1476+ -------
1477+ numpy.array
1478+ a Nx2 array of x,y points after transformation
1479+ """
1480+
1481+ # final double[] featureVector = kernelExpand(position);
1482+ # return multiply(beta, featureVector);
1483+ nsrc = np .array (src , dtype = np .float64 )
1484+ featureVector = self .kernelExpand (nsrc )
1485+
1486+ dst = np .zeros (src .shape )
1487+ for i in range (0 , featureVector .shape [1 ]):
1488+ dst [:, 0 ] = dst [:, 0 ] + (featureVector [:, i ] * self .beta [i , 0 ])
1489+ dst [:, 1 ] = dst [:, 1 ] + (featureVector [:, i ] * self .beta [i , 1 ])
1490+ return np .array (dst , dtype = src .dtype )
1491+
1492+ @property
1493+ def dataString (self ):
1494+ shapestring = '{} {}' .format (self .dimension , self .length )
1495+ betastring = ' ' .join ([str (i ).replace ('e-0' , 'e-' ).replace ('e+0' , 'e+' )
1496+ for i in self .beta .ravel ()]).replace ('e' , 'E' )
1497+ meanstring = ' ' .join ([str (i ).replace ('e-0' , 'e-' ).replace ('e+0' , 'e+' )
1498+ for i in self .normMean ]).replace ('e' , 'E' )
1499+ varstring = ' ' .join ([str (i ).replace ('e-0' , 'e-' ).replace ('e+0' , 'e+' )
1500+ for i in self .normVar ]).replace ('e' , 'E' )
1501+ dimstring = '{} {}' .format (self .height , self .width )
1502+ return '{} {} {} {} {} ' .format (
1503+ shapestring , betastring , meanstring , varstring , dimstring )
1504+
1505+
1506+ class NonLinearTransform (NonLinearCoordinateTransform ):
1507+ className = 'mpicbg.trakem2.transform.nonLinearTransform'
1508+
1509+
1510+ class LensCorrection (NonLinearCoordinateTransform ):
1511+ """
1512+ a placeholder for the lenscorrection transform, same as NonLinearTransform
1513+ for now
1514+ """
1515+ className = 'lenscorrection.NonLinearTransform'
1516+
1517+
13731518def estimate_transformsum (transformlist , src = None , order = 2 ):
13741519 """pseudo-composition of transforms in list of transforms
13751520 using source point transformation and a single estimation.
0 commit comments