8
8
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
9
9
"""Common interface for transforms."""
10
10
from pathlib import Path
11
- from collections .abc import Iterable
12
11
import numpy as np
13
12
import h5py
14
13
import warnings
@@ -168,10 +167,10 @@ def __ne__(self, other):
168
167
return not self == other
169
168
170
169
171
- class TransformBase ( object ) :
170
+ class TransformBase :
172
171
"""Abstract image class to represent transforms."""
173
172
174
- __slots__ = [ '_reference' ]
173
+ __slots__ = ( '_reference' , )
175
174
176
175
def __init__ (self , reference = None ):
177
176
"""Instantiate a transform."""
@@ -191,13 +190,11 @@ def __add__(self, b):
191
190
-------
192
191
>>> T1 = TransformBase()
193
192
>>> added = T1 + TransformBase()
194
- >>> isinstance(added, TransformChain)
195
- True
196
-
197
193
>>> len(added.transforms)
198
194
2
199
195
200
196
"""
197
+ from .manip import TransformChain
201
198
return TransformChain (transforms = [self , b ])
202
199
203
200
@property
@@ -322,127 +319,6 @@ def _to_hdf5(self, x5_root):
322
319
raise NotImplementedError
323
320
324
321
325
- class TransformChain (TransformBase ):
326
- """Implements the concatenation of transforms."""
327
-
328
- __slots__ = ['_transforms' ]
329
-
330
- def __init__ (self , transforms = None ):
331
- """Initialize a chain of transforms."""
332
- self ._transforms = None
333
- if transforms is not None :
334
- self .transforms = transforms
335
-
336
- def __add__ (self , b ):
337
- """
338
- Compose this and other transforms.
339
-
340
- Example
341
- -------
342
- >>> T1 = TransformBase()
343
- >>> added = T1 + TransformBase() + TransformBase()
344
- >>> isinstance(added, TransformChain)
345
- True
346
-
347
- >>> len(added.transforms)
348
- 3
349
-
350
- """
351
- self .append (b )
352
- return self
353
-
354
- def __getitem__ (self , i ):
355
- """
356
- Enable indexed access of transform chains.
357
-
358
- Example
359
- -------
360
- >>> T1 = TransformBase()
361
- >>> chain = T1 + TransformBase()
362
- >>> chain[0] is T1
363
- True
364
-
365
- """
366
- return self .transforms [i ]
367
-
368
- def __len__ (self ):
369
- """Enable using len()."""
370
- return len (self .transforms )
371
-
372
- @property
373
- def transforms (self ):
374
- """Get the internal list of transforms."""
375
- return self ._transforms
376
-
377
- @transforms .setter
378
- def transforms (self , value ):
379
- self ._transforms = _as_chain (value )
380
- if self .transforms [0 ].reference :
381
- self .reference = self .transforms [0 ].reference
382
-
383
- def append (self , x ):
384
- """
385
- Concatenate one element to the chain.
386
-
387
- Example
388
- -------
389
- >>> chain = TransformChain(transforms=TransformBase())
390
- >>> chain.append((TransformBase(), TransformBase()))
391
- >>> len(chain)
392
- 3
393
-
394
- """
395
- self .transforms += _as_chain (x )
396
-
397
- def insert (self , i , x ):
398
- """
399
- Insert an item at a given position.
400
-
401
- Example
402
- -------
403
- >>> chain = TransformChain(transforms=[TransformBase(), TransformBase()])
404
- >>> chain.insert(1, TransformBase())
405
- >>> len(chain)
406
- 3
407
-
408
- >>> chain.insert(1, TransformChain(chain))
409
- >>> len(chain)
410
- 6
411
-
412
- """
413
- self .transforms = self .transforms [:i ] + _as_chain (x ) + self .transforms [i :]
414
-
415
- def map (self , x , inverse = False ):
416
- """
417
- Apply a succession of transforms, e.g., :math:`y = f_3(f_2(f_1(f_0(x))))`.
418
-
419
- Example
420
- -------
421
- >>> chain = TransformChain(transforms=[TransformBase(), TransformBase()])
422
- >>> chain([(0., 0., 0.), (1., 1., 1.), (-1., -1., -1.)])
423
- [(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (-1.0, -1.0, -1.0)]
424
-
425
- >>> chain([(0., 0., 0.), (1., 1., 1.), (-1., -1., -1.)], inverse=True)
426
- [(0.0, 0.0, 0.0), (1.0, 1.0, 1.0), (-1.0, -1.0, -1.0)]
427
-
428
- >>> TransformChain()((0., 0., 0.)) # doctest: +IGNORE_EXCEPTION_DETAIL
429
- Traceback (most recent call last):
430
- TransformError:
431
-
432
- """
433
- if not self .transforms :
434
- raise TransformError ('Cannot apply an empty transforms chain.' )
435
-
436
- transforms = self .transforms
437
- if inverse :
438
- transforms = reversed (self .transforms )
439
-
440
- for xfm in transforms :
441
- x = xfm (x , inverse = inverse )
442
-
443
- return x
444
-
445
-
446
322
def _as_homogeneous (xyz , dtype = 'float32' , dim = 3 ):
447
323
"""
448
324
Convert 2D and 3D coordinates into homogeneous coordinates.
@@ -473,12 +349,3 @@ def _as_homogeneous(xyz, dtype='float32', dim=3):
473
349
def _apply_affine (x , affine , dim ):
474
350
"""Get the image array's indexes corresponding to coordinates."""
475
351
return affine .dot (_as_homogeneous (x , dim = dim ).T )[:dim , ...].T
476
-
477
-
478
- def _as_chain (x ):
479
- """Convert a value into a transform chain."""
480
- if isinstance (x , TransformChain ):
481
- return x .transforms
482
- if isinstance (x , Iterable ):
483
- return list (x )
484
- return [x ]
0 commit comments