Diff of /utils/strain.py [000000] .. [4cda31]

Switch to unified view

a b/utils/strain.py
1
import numpy as np
2
from scipy.ndimage import rotate
3
from scipy.ndimage import gaussian_filter
4
from scipy.interpolate import interp1d, interp2d
5
from scipy.ndimage.measurements import center_of_mass
6
7
class MyocardialStrain():
8
    
9
    def __init__(self, mask, flow):
10
                
11
        self.mask  = mask
12
        self.flow  = flow
13
        
14
        assert len(mask.shape) == 3
15
        assert len(flow.shape) == 4
16
        assert mask.shape == flow.shape[:3]
17
        assert flow.shape[-1] == 3
18
        
19
    def calculate_strain(self, dx=1, dy=1, dz=1, lv_label=3):
20
        
21
        cx, cy, cz = center_of_mass(self.mask==lv_label)
22
        nx, ny, nz = self.mask.shape
23
        
24
        self.flow_rot = _roll_to_center(self.flow, cx, cy)
25
        self.mask_rot = _roll_to_center(self.mask, cx, cy)
26
27
        ux, uy, uz  = np.array_split(self.flow_rot, 3, -1)
28
        Uxx,Uxy,Uxz = np.gradient(np.squeeze(ux),dx,dy,dz)
29
        Uyx,Uyy,Uyz = np.gradient(np.squeeze(uy),dx,dy,dz)
30
        Uzx,Uzy,Uzz = np.gradient(np.squeeze(uz),dx,dy,dz)
31
32
        self.E_cart = np.zeros((nx,ny,nz,3,3))
33
        for i in range(nx):
34
            for j in range(ny):
35
                for k in range(nz):
36
                    Ugrad = [[Uxx[i,j,k], Uxy[i,j,k], Uxz[i,j,k]], 
37
                             [Uyx[i,j,k], Uyy[i,j,k], Uyz[i,j,k]],
38
                             [Uzx[i,j,k], Uzy[i,j,k], Uzz[i,j,k]]]
39
                    F = np.array(Ugrad) + np.identity(3)
40
                    e = 0.5*(np.matmul(F.T, F) - np.identity(3))
41
                    self.E_cart[i,j,k] += e
42
43
        self.Ezz = self.E_cart[:,:,:,2,2]
44
        self.Err, self.Ecc = self._convert_to_polar(self.E_cart[:,:,:,:2,:2])
45
46
        
47
        
48
        
49
    def _convert_to_polar(self, E):
50
51
        phi = _polar_grid(*E.shape[:2])[0]
52
        Err = np.zeros(self.mask.shape)
53
        Ecc = np.zeros(self.mask.shape)
54
        for k in range(self.mask.shape[-1]):
55
            cos = np.cos(np.deg2rad(phi))
56
            sin = np.sin(np.deg2rad(phi))
57
        
58
            Exx, Exy, Eyx, Eyy = E[:,:,k,0,0],E[:,:,k,0,1],E[:,:,k,1,0],E[:,:,k,1,1]
59
            Err[:,:,k] +=  cos*( cos*Exx+sin*Exy) +sin*( cos*Eyx+sin*Eyy)
60
            Ecc[:,:,k] += -sin*(-sin*Exx+cos*Exy) +cos*(-sin*Eyx+cos*Eyy)
61
62
        return Err, Ecc
63
    
64
   
65
66
def _roll(x, rx, ry):
67
    x = np.roll(x, rx, axis=0)
68
    return np.roll(x, ry, axis=1)
69
70
def _roll_to_center(x, cx, cy):
71
    nx, ny = x.shape[:2]
72
    return _roll(x,  int(nx//2-cx), int(ny//2-cy))
73
74
def _polar_grid(nx=128, ny=128):
75
    x, y = np.meshgrid(np.linspace(-nx//2, nx//2, nx), np.linspace(-ny//2, ny//2, ny))
76
    phi  = (np.rad2deg(np.arctan2(y, x)) + 180).T
77
    r    = np.sqrt(x**2+y**2+1e-8)
78
    return phi, r