|
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 |