Skip to content

Commit b2c1101

Browse files
authored
Merge pull request #20 from fcollman/feature/nonlin
adds non-linear transform classes and tests
2 parents 069ea4a + 3d70f0f commit b2c1101

4 files changed

Lines changed: 256 additions & 50 deletions

File tree

renderapi/render.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
#!/usr/bin/env python
22
import logging
33
import os
4-
from functools import wraps
54
import requests
65
from .utils import defaultifNone, NullHandler, fitargspec
76
from .errors import ClientScriptError, RenderError
87
from decorator import decorator
8+
99
logger = logging.getLogger(__name__)
1010
logger.addHandler(NullHandler())
1111

renderapi/transform.py

Lines changed: 155 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
13731518
def 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.

test/test_files/tilespecs.json

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@
1515
"maxIntensity": 65535,
1616
"mipmapLevels": {
1717
"0": {
18-
"imageUrl": "file:/data/20160710195316413_243774_7R_SID_01_redo_0_11_7_3_15_8.tif"
18+
"imageUrl": "file:///data/20160710195316413_243774_7R_SID_01_redo_0_11_7_3_15_8.tif"
19+
},
20+
"1": {
21+
"imageUrl": "file:///data/20160710195316413_243774_7R_SID_01_redo_0_11_7_3_15_8_mmL1.tif.tif",
22+
"maskUrl": "file:///data/20160710195316413_243774_7R_SID_01_redo_0_11_7_3_15_8_mmL1_mask.tif.tif"
23+
},
24+
"2": {
25+
"imageUrl": "file:///data/20160710195316413_243774_7R_SID_01_redo_0_11_7_3_15_8_mmL2.tif.tif"
1926
}
2027
},
2128
"transforms": {
2229
"type": "list",
2330
"specList": [
24-
{
25-
"type": "leaf",
26-
"className": "mpicbg.trakem2.transform.NonLinearCoordinateTransform",
27-
"dataString": "5 21 1103.117269905359 -5.606757285805906 5.321142212984271 1041.3480932107918 -10.43426929509782 7.428382306562735 -14.137269334106124 7.299563138046944 -15.904206050362355 18.284978789358718 3.4106705605908587 -23.24346650864392 -22.18066749731861 -3.583245180840507 3.2706525226745384 27.117126387399466 20.96651792381158 -1.2219610254066424 -10.531856407305256 0.3306037423046746 2.054811912746283 28.849184526610635 34.799030853758985 -7.4227129043141495 -8.211918715339516 -27.434469512200955 -3.1066643785881 3.8503170392714026 1.7124046587349628 1.8506627747180158 4.886666182237065 -2.949889582798017 -4.5150121503501515 -11.363818954372583 -9.8507389567363 8.672520277073502 5.89027776049669 4.924363838689751 -1.4446630732848895 -2.3876262067533727 19.9189118558668 21.72003155506043 1991.9406329917294 2171.99091870329 5136325.014398676 4300827.048910938 5862798.046430213 1.4793145755295639E10 1.1081068898569233E10 1.1535665428036394E10 1.737179414476557E10 4.5383202598685734E13 3.1913868517100258E13 2.9612848039584566E13 3.403565936230745E13 5.43037094200083E13 1.45059294093077376E17 9.790266764463008E16 8.5058013431605168E16 8.7104768756103424E16 1.06057724033609104E17 1.75771529104524608E17 100.0 1080.9907552180462 1070.1850841521746 4359136.9617994055 3334088.839525756 4464532.472685248 1.6068544862341637E10 1.1728566370432955E10 1.1733314229813484E10 1.6768452787562666E10 5.830517220342475E13 4.128824258570168E13 3.8519115805773336E13 4.149420039803858E13 6.153259860972069E13 2.11108412972822656E17 1.46312985770820672E17 1.31484322773016992E17 1.31813167980595536E17 1.47560207595069728E17 2.24412785271596352E17 0.0 3840 3840 "
28-
},
2931
{
3032
"type": "leaf",
3133
"className": "mpicbg.trakem2.transform.AffineModel2D",
@@ -57,16 +59,17 @@
5759
"mipmapLevels": {
5860
"0": {
5961
"imageUrl": "file:/data/20160710195316873_243774_7R_SID_01_redo_0_11_7_3_16_8.tif"
62+
},
63+
"1": {
64+
"imageUrl": "file:/data/20160710195316873_243774_7R_SID_01_redo_0_11_7_3_16_8_mmL1.tif.tif"
65+
},
66+
"2": {
67+
"imageUrl": "file:/data/20160710195316873_243774_7R_SID_01_redo_0_11_7_3_16_8_mmL2.tif.tif"
6068
}
6169
},
6270
"transforms": {
6371
"type": "list",
6472
"specList": [
65-
{
66-
"type": "leaf",
67-
"className": "mpicbg.trakem2.transform.NonLinearCoordinateTransform",
68-
"dataString": "5 21 1103.117269905359 -5.606757285805906 5.321142212984271 1041.3480932107918 -10.43426929509782 7.428382306562735 -14.137269334106124 7.299563138046944 -15.904206050362355 18.284978789358718 3.4106705605908587 -23.24346650864392 -22.18066749731861 -3.583245180840507 3.2706525226745384 27.117126387399466 20.96651792381158 -1.2219610254066424 -10.531856407305256 0.3306037423046746 2.054811912746283 28.849184526610635 34.799030853758985 -7.4227129043141495 -8.211918715339516 -27.434469512200955 -3.1066643785881 3.8503170392714026 1.7124046587349628 1.8506627747180158 4.886666182237065 -2.949889582798017 -4.5150121503501515 -11.363818954372583 -9.8507389567363 8.672520277073502 5.89027776049669 4.924363838689751 -1.4446630732848895 -2.3876262067533727 19.9189118558668 21.72003155506043 1991.9406329917294 2171.99091870329 5136325.014398676 4300827.048910938 5862798.046430213 1.4793145755295639E10 1.1081068898569233E10 1.1535665428036394E10 1.737179414476557E10 4.5383202598685734E13 3.1913868517100258E13 2.9612848039584566E13 3.403565936230745E13 5.43037094200083E13 1.45059294093077376E17 9.790266764463008E16 8.5058013431605168E16 8.7104768756103424E16 1.06057724033609104E17 1.75771529104524608E17 100.0 1080.9907552180462 1070.1850841521746 4359136.9617994055 3334088.839525756 4464532.472685248 1.6068544862341637E10 1.1728566370432955E10 1.1733314229813484E10 1.6768452787562666E10 5.830517220342475E13 4.128824258570168E13 3.8519115805773336E13 4.149420039803858E13 6.153259860972069E13 2.11108412972822656E17 1.46312985770820672E17 1.31484322773016992E17 1.31813167980595536E17 1.47560207595069728E17 2.24412785271596352E17 0.0 3840 3840 "
69-
},
7073
{
7174
"type": "leaf",
7275
"className": "mpicbg.trakem2.transform.AffineModel2D",
@@ -94,20 +97,24 @@
9497
"width": 3840,
9598
"height": 3840,
9699
"minIntensity": 0,
97-
"maxIntensity": 65535,
100+
"maxIntensity": 255,
98101
"mipmapLevels": {
99102
"0": {
100-
"imageUrl": "file:/data/20160710195317333_243774_7R_SID_01_redo_0_11_7_3_17_8.tif"
103+
"imageUrl": "file:///data/20160710195317333_243774_7R_SID_01_redo_0_11_7_3_17_8.tif"
104+
},
105+
"1": {
106+
"imageUrl": "file:///data/20160710195317333_243774_7R_SID_01_redo_0_11_7_3_17_8_mmL1.tif.tif"
107+
},
108+
"2": {
109+
"imageUrl": "file:///data/20160710195317333_243774_7R_SID_01_redo_0_11_7_3_17_8_mmL2.tif.tif"
110+
},
111+
"5": {
112+
"imageUrl": "file:///data/20160710195317333_243774_7R_SID_01_redo_0_11_7_3_17_8_mmL5.tif.tif"
101113
}
102114
},
103115
"transforms": {
104116
"type": "list",
105117
"specList": [
106-
{
107-
"type": "leaf",
108-
"className": "mpicbg.trakem2.transform.NonLinearCoordinateTransform",
109-
"dataString": "5 21 1103.117269905359 -5.606757285805906 5.321142212984271 1041.3480932107918 -10.43426929509782 7.428382306562735 -14.137269334106124 7.299563138046944 -15.904206050362355 18.284978789358718 3.4106705605908587 -23.24346650864392 -22.18066749731861 -3.583245180840507 3.2706525226745384 27.117126387399466 20.96651792381158 -1.2219610254066424 -10.531856407305256 0.3306037423046746 2.054811912746283 28.849184526610635 34.799030853758985 -7.4227129043141495 -8.211918715339516 -27.434469512200955 -3.1066643785881 3.8503170392714026 1.7124046587349628 1.8506627747180158 4.886666182237065 -2.949889582798017 -4.5150121503501515 -11.363818954372583 -9.8507389567363 8.672520277073502 5.89027776049669 4.924363838689751 -1.4446630732848895 -2.3876262067533727 19.9189118558668 21.72003155506043 1991.9406329917294 2171.99091870329 5136325.014398676 4300827.048910938 5862798.046430213 1.4793145755295639E10 1.1081068898569233E10 1.1535665428036394E10 1.737179414476557E10 4.5383202598685734E13 3.1913868517100258E13 2.9612848039584566E13 3.403565936230745E13 5.43037094200083E13 1.45059294093077376E17 9.790266764463008E16 8.5058013431605168E16 8.7104768756103424E16 1.06057724033609104E17 1.75771529104524608E17 100.0 1080.9907552180462 1070.1850841521746 4359136.9617994055 3334088.839525756 4464532.472685248 1.6068544862341637E10 1.1728566370432955E10 1.1733314229813484E10 1.6768452787562666E10 5.830517220342475E13 4.128824258570168E13 3.8519115805773336E13 4.149420039803858E13 6.153259860972069E13 2.11108412972822656E17 1.46312985770820672E17 1.31484322773016992E17 1.31813167980595536E17 1.47560207595069728E17 2.24412785271596352E17 0.0 3840 3840 "
110-
},
111118
{
112119
"type": "leaf",
113120
"className": "mpicbg.trakem2.transform.AffineModel2D",

0 commit comments

Comments
 (0)