Spaces:
Sleeping
Sleeping
Franny Dean
commited on
Commit
•
97f0f9a
1
Parent(s):
5fa2298
attempt animation
Browse files- .DS_Store +0 -0
- .ipynb_checkpoints/app-checkpoint.py +570 -0
- EchoNet-Dynamic/.DS_Store +0 -0
- EchoNet-Dynamic/FileList.csv +0 -2
- EchoNet-Dynamic/Videos/.DS_Store +0 -0
- EchoNet-Dynamic/Videos/0X352D7150FCBFA7C1.avi +0 -0
- EchoNet-Dynamic/Videos/0X352D7150FCBFA7C1.mp4 +0 -0
- EchoNet-Dynamic/Videos/0X6382AE8EB4B73A3D.avi +0 -0
- EchoNet-Dynamic/Videos/0X6382AE8EB4B73A3D.mp4 +0 -0
- EchoNet-Dynamic/VolumeTracings.csv +0 -84
- app.py +16 -4
.DS_Store
CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
|
|
.ipynb_checkpoints/app-checkpoint.py
ADDED
@@ -0,0 +1,570 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
import os
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
from scipy.integrate import odeint
|
5 |
+
import torch
|
6 |
+
from torch.utils import data
|
7 |
+
from torch.utils.data import DataLoader, Dataset
|
8 |
+
from torch import nn, optim
|
9 |
+
from skimage.transform import rescale, resize
|
10 |
+
from torch import nn, optim
|
11 |
+
import torch.nn.functional as F
|
12 |
+
from torch.utils.data import Subset
|
13 |
+
from scipy.interpolate import interp1d
|
14 |
+
import collections
|
15 |
+
import numpy as np
|
16 |
+
import random
|
17 |
+
|
18 |
+
#for pvloop simulator:
|
19 |
+
import pandas as pd
|
20 |
+
from scipy.integrate import odeint
|
21 |
+
import torchvision
|
22 |
+
import echonet
|
23 |
+
import matplotlib.animation as animation
|
24 |
+
|
25 |
+
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
26 |
+
|
27 |
+
sequences_all = []
|
28 |
+
info_data_all = []
|
29 |
+
path = 'EchoNet-Dynamic'
|
30 |
+
output_path = ''
|
31 |
+
|
32 |
+
class Echo(torchvision.datasets.VisionDataset):
|
33 |
+
"""EchoNet-Dynamic Dataset.
|
34 |
+
Args:
|
35 |
+
root (string): Root directory of dataset (defaults to `echonet.config.DATA_DIR`)
|
36 |
+
split (string): One of {``train'', ``val'', ``test'', ``all'', or ``external_test''}
|
37 |
+
target_type (string or list, optional): Type of target to use,
|
38 |
+
``Filename'', ``EF'', ``EDV'', ``ESV'', ``LargeIndex'',
|
39 |
+
``SmallIndex'', ``LargeFrame'', ``SmallFrame'', ``LargeTrace'',
|
40 |
+
or ``SmallTrace''
|
41 |
+
Can also be a list to output a tuple with all specified target types.
|
42 |
+
The targets represent:
|
43 |
+
``Filename'' (string): filename of video
|
44 |
+
``EF'' (float): ejection fraction
|
45 |
+
``EDV'' (float): end-diastolic volume
|
46 |
+
``ESV'' (float): end-systolic volume
|
47 |
+
``LargeIndex'' (int): index of large (diastolic) frame in video
|
48 |
+
``SmallIndex'' (int): index of small (systolic) frame in video
|
49 |
+
``LargeFrame'' (np.array shape=(3, height, width)): normalized large (diastolic) frame
|
50 |
+
``SmallFrame'' (np.array shape=(3, height, width)): normalized small (systolic) frame
|
51 |
+
``LargeTrace'' (np.array shape=(height, width)): left ventricle large (diastolic) segmentation
|
52 |
+
value of 0 indicates pixel is outside left ventricle
|
53 |
+
1 indicates pixel is inside left ventricle
|
54 |
+
``SmallTrace'' (np.array shape=(height, width)): left ventricle small (systolic) segmentation
|
55 |
+
value of 0 indicates pixel is outside left ventricle
|
56 |
+
1 indicates pixel is inside left ventricle
|
57 |
+
Defaults to ``EF''.
|
58 |
+
mean (int, float, or np.array shape=(3,), optional): means for all (if scalar) or each (if np.array) channel.
|
59 |
+
Used for normalizing the video. Defaults to 0 (video is not shifted).
|
60 |
+
std (int, float, or np.array shape=(3,), optional): standard deviation for all (if scalar) or each (if np.array) channel.
|
61 |
+
Used for normalizing the video. Defaults to 0 (video is not scaled).
|
62 |
+
length (int or None, optional): Number of frames to clip from video. If ``None'', longest possible clip is returned.
|
63 |
+
Defaults to 16.
|
64 |
+
period (int, optional): Sampling period for taking a clip from the video (i.e. every ``period''-th frame is taken)
|
65 |
+
Defaults to 2.
|
66 |
+
max_length (int or None, optional): Maximum number of frames to clip from video (main use is for shortening excessively
|
67 |
+
long videos when ``length'' is set to None). If ``None'', shortening is not applied to any video.
|
68 |
+
Defaults to 250.
|
69 |
+
clips (int, optional): Number of clips to sample. Main use is for test-time augmentation with random clips.
|
70 |
+
Defaults to 1.
|
71 |
+
pad (int or None, optional): Number of pixels to pad all frames on each side (used as augmentation).
|
72 |
+
and a window of the original size is taken. If ``None'', no padding occurs.
|
73 |
+
Defaults to ``None''.
|
74 |
+
noise (float or None, optional): Fraction of pixels to black out as simulated noise. If ``None'', no simulated noise is added.
|
75 |
+
Defaults to ``None''.
|
76 |
+
target_transform (callable, optional): A function/transform that takes in the target and transforms it.
|
77 |
+
external_test_location (string): Path to videos to use for external testing.
|
78 |
+
"""
|
79 |
+
|
80 |
+
def __init__(self, root=None,
|
81 |
+
split="train", target_type="EF",
|
82 |
+
mean=0., std=1.,
|
83 |
+
length=16, period=2,
|
84 |
+
max_length=250,
|
85 |
+
clips=1,
|
86 |
+
pad=None,
|
87 |
+
noise=None,
|
88 |
+
target_transform=None,
|
89 |
+
external_test_location=None):
|
90 |
+
if root is None:
|
91 |
+
root = path
|
92 |
+
|
93 |
+
super().__init__(root, target_transform=target_transform)
|
94 |
+
|
95 |
+
self.split = split.upper()
|
96 |
+
if not isinstance(target_type, list):
|
97 |
+
target_type = [target_type]
|
98 |
+
self.target_type = target_type
|
99 |
+
self.mean = mean
|
100 |
+
self.std = std
|
101 |
+
self.length = length
|
102 |
+
self.max_length = max_length
|
103 |
+
self.period = period
|
104 |
+
self.clips = clips
|
105 |
+
self.pad = pad
|
106 |
+
self.noise = noise
|
107 |
+
self.target_transform = target_transform
|
108 |
+
self.external_test_location = external_test_location
|
109 |
+
|
110 |
+
self.fnames, self.outcome = [], []
|
111 |
+
|
112 |
+
if self.split == "EXTERNAL_TEST":
|
113 |
+
self.fnames = sorted(os.listdir(self.external_test_location))
|
114 |
+
else:
|
115 |
+
# Load video-level labels
|
116 |
+
with open(f"{self.root}/FileList.csv") as f:
|
117 |
+
data = pd.read_csv(f)
|
118 |
+
data["Split"].map(lambda x: x.upper())
|
119 |
+
|
120 |
+
if self.split != "ALL":
|
121 |
+
data = data[data["Split"] == self.split]
|
122 |
+
|
123 |
+
self.header = data.columns.tolist()
|
124 |
+
self.fnames = data["FileName"].tolist()
|
125 |
+
self.fnames = [fn + ".avi" for fn in self.fnames if os.path.splitext(fn)[1] == ""] # Assume avi if no suffix
|
126 |
+
self.outcome = data.values.tolist()
|
127 |
+
|
128 |
+
# Check that files are present
|
129 |
+
"""
|
130 |
+
missing = set(self.fnames) - set(os.listdir(os.path.join(self.root, "Videos")))
|
131 |
+
if len(missing) != 0:
|
132 |
+
print("{} videos could not be found in {}:".format(len(missing), os.path.join(self.root, "Videos")))
|
133 |
+
for f in sorted(missing):
|
134 |
+
print("\t", f)
|
135 |
+
raise FileNotFoundError(os.path.join(self.root, "Videos", sorted(missing)[0]))
|
136 |
+
"""
|
137 |
+
|
138 |
+
# Load traces
|
139 |
+
self.frames = collections.defaultdict(list)
|
140 |
+
self.trace = collections.defaultdict(_defaultdict_of_lists)
|
141 |
+
|
142 |
+
with open(f"{self.root}/VolumeTracings.csv") as f:
|
143 |
+
header = f.readline().strip().split(",")
|
144 |
+
assert header == ["FileName", "X1", "Y1", "X2", "Y2", "Frame"]
|
145 |
+
|
146 |
+
for line in f:
|
147 |
+
filename, x1, y1, x2, y2, frame = line.strip().split(',')
|
148 |
+
x1 = float(x1)
|
149 |
+
y1 = float(y1)
|
150 |
+
x2 = float(x2)
|
151 |
+
y2 = float(y2)
|
152 |
+
frame = int(frame)
|
153 |
+
if frame not in self.trace[filename]:
|
154 |
+
self.frames[filename].append(frame)
|
155 |
+
self.trace[filename][frame].append((x1, y1, x2, y2))
|
156 |
+
for filename in self.frames:
|
157 |
+
for frame in self.frames[filename]:
|
158 |
+
self.trace[filename][frame] = np.array(self.trace[filename][frame])
|
159 |
+
|
160 |
+
# A small number of videos are missing traces; remove these videos
|
161 |
+
keep = [len(self.frames[f]) >= 2 for f in self.fnames]
|
162 |
+
self.fnames = [f for (f, k) in zip(self.fnames, keep) if k]
|
163 |
+
self.outcome = [f for (f, k) in zip(self.outcome, keep) if k]
|
164 |
+
|
165 |
+
def __getitem__(self, index):
|
166 |
+
# Find filename of video
|
167 |
+
if self.split == "EXTERNAL_TEST":
|
168 |
+
video = os.path.join(self.external_test_location, self.fnames[index])
|
169 |
+
elif self.split == "CLINICAL_TEST":
|
170 |
+
video = os.path.join(self.root, "ProcessedStrainStudyA4c", self.fnames[index])
|
171 |
+
else:
|
172 |
+
video = os.path.join(self.root, "Videos", self.fnames[index])
|
173 |
+
|
174 |
+
# Load video into np.array
|
175 |
+
video = echonet.utils.loadvideo(video).astype(np.float32)
|
176 |
+
|
177 |
+
# Add simulated noise (black out random pixels)
|
178 |
+
# 0 represents black at this point (video has not been normalized yet)
|
179 |
+
if self.noise is not None:
|
180 |
+
n = video.shape[1] * video.shape[2] * video.shape[3]
|
181 |
+
ind = np.random.choice(n, round(self.noise * n), replace=False)
|
182 |
+
f = ind % video.shape[1]
|
183 |
+
ind //= video.shape[1]
|
184 |
+
i = ind % video.shape[2]
|
185 |
+
ind //= video.shape[2]
|
186 |
+
j = ind
|
187 |
+
video[:, f, i, j] = 0
|
188 |
+
|
189 |
+
# Apply normalization
|
190 |
+
if isinstance(self.mean, (float, int)):
|
191 |
+
video -= self.mean
|
192 |
+
else:
|
193 |
+
video -= self.mean.reshape(3, 1, 1, 1)
|
194 |
+
|
195 |
+
if isinstance(self.std, (float, int)):
|
196 |
+
video /= self.std
|
197 |
+
else:
|
198 |
+
video /= self.std.reshape(3, 1, 1, 1)
|
199 |
+
|
200 |
+
# Set number of frames
|
201 |
+
c, f, h, w = video.shape
|
202 |
+
if self.length is None:
|
203 |
+
# Take as many frames as possible
|
204 |
+
length = f // self.period
|
205 |
+
else:
|
206 |
+
# Take specified number of frames
|
207 |
+
length = self.length
|
208 |
+
|
209 |
+
if self.max_length is not None:
|
210 |
+
# Shorten videos to max_length
|
211 |
+
length = min(length, self.max_length)
|
212 |
+
|
213 |
+
if f < length * self.period:
|
214 |
+
# Pad video with frames filled with zeros if too short
|
215 |
+
# 0 represents the mean color (dark grey), since this is after normalization
|
216 |
+
video = np.concatenate((video, np.zeros((c, length * self.period - f, h, w), video.dtype)), axis=1)
|
217 |
+
c, f, h, w = video.shape # pylint: disable=E0633
|
218 |
+
|
219 |
+
if self.clips == "all":
|
220 |
+
# Take all possible clips of desired length
|
221 |
+
start = np.arange(f - (length - 1) * self.period)
|
222 |
+
else:
|
223 |
+
# Take random clips from video
|
224 |
+
start = np.random.choice(f - (length - 1) * self.period, self.clips)
|
225 |
+
|
226 |
+
# Gather targets
|
227 |
+
target = []
|
228 |
+
for t in self.target_type:
|
229 |
+
key = self.fnames[index]
|
230 |
+
if t == "Filename":
|
231 |
+
target.append(self.fnames[index])
|
232 |
+
elif t == "LargeIndex":
|
233 |
+
# Traces are sorted by cross-sectional area
|
234 |
+
# Largest (diastolic) frame is last
|
235 |
+
target.append(int(self.frames[key][-1]))
|
236 |
+
elif t == "SmallIndex":
|
237 |
+
# Largest (diastolic) frame is first
|
238 |
+
target.append(int(self.frames[key][0]))
|
239 |
+
elif t == "LargeFrame":
|
240 |
+
target.append(video[:, self.frames[key][-1], :, :])
|
241 |
+
elif t == "SmallFrame":
|
242 |
+
target.append(video[:, self.frames[key][0], :, :])
|
243 |
+
elif t in ["LargeTrace", "SmallTrace"]:
|
244 |
+
if t == "LargeTrace":
|
245 |
+
t = self.trace[key][self.frames[key][-1]]
|
246 |
+
else:
|
247 |
+
t = self.trace[key][self.frames[key][0]]
|
248 |
+
x1, y1, x2, y2 = t[:, 0], t[:, 1], t[:, 2], t[:, 3]
|
249 |
+
x = np.concatenate((x1[1:], np.flip(x2[1:])))
|
250 |
+
y = np.concatenate((y1[1:], np.flip(y2[1:])))
|
251 |
+
|
252 |
+
r, c = skimage.draw.polygon(np.rint(y).astype(np.int), np.rint(x).astype(np.int), (video.shape[2], video.shape[3]))
|
253 |
+
mask = np.zeros((video.shape[2], video.shape[3]), np.float32)
|
254 |
+
mask[r, c] = 1
|
255 |
+
target.append(mask)
|
256 |
+
else:
|
257 |
+
if self.split == "CLINICAL_TEST" or self.split == "EXTERNAL_TEST":
|
258 |
+
target.append(np.float32(0))
|
259 |
+
else:
|
260 |
+
target.append(np.float32(self.outcome[index][self.header.index(t)]))
|
261 |
+
|
262 |
+
if target != []:
|
263 |
+
target = tuple(target) if len(target) > 1 else target[0]
|
264 |
+
if self.target_transform is not None:
|
265 |
+
target = self.target_transform(target)
|
266 |
+
|
267 |
+
# Select clips from video
|
268 |
+
video = tuple(video[:, s + self.period * np.arange(length), :, :] for s in start)
|
269 |
+
if self.clips == 1:
|
270 |
+
video = video[0]
|
271 |
+
else:
|
272 |
+
video = np.stack(video)
|
273 |
+
|
274 |
+
if self.pad is not None:
|
275 |
+
# Add padding of zeros (mean color of videos)
|
276 |
+
# Crop of original size is taken out
|
277 |
+
# (Used as augmentation)
|
278 |
+
c, l, h, w = video.shape
|
279 |
+
temp = np.zeros((c, l, h + 2 * self.pad, w + 2 * self.pad), dtype=video.dtype)
|
280 |
+
temp[:, :, self.pad:-self.pad, self.pad:-self.pad] = video # pylint: disable=E1130
|
281 |
+
i, j = np.random.randint(0, 2 * self.pad, 2)
|
282 |
+
video = temp[:, :, i:(i + h), j:(j + w)]
|
283 |
+
|
284 |
+
return video, target
|
285 |
+
|
286 |
+
def __len__(self):
|
287 |
+
return len(self.fnames)
|
288 |
+
|
289 |
+
def extra_repr(self) -> str:
|
290 |
+
"""Additional information to add at end of __repr__."""
|
291 |
+
lines = ["Target type: {target_type}", "Split: {split}"]
|
292 |
+
return '\n'.join(lines).format(**self.__dict__)
|
293 |
+
|
294 |
+
|
295 |
+
def _defaultdict_of_lists():
|
296 |
+
"""Returns a defaultdict of lists.
|
297 |
+
This is used to avoid issues with Windows (if this function is anonymous,
|
298 |
+
the Echo dataset cannot be used in a dataloader).
|
299 |
+
"""
|
300 |
+
|
301 |
+
return collections.defaultdict(list)
|
302 |
+
##
|
303 |
+
print("Done loading training data!")
|
304 |
+
# define normalization layer to make sure output xi in an interval [ai, bi]:
|
305 |
+
# define normalization layer to make sure output xi in an interval [ai, bi]:
|
306 |
+
|
307 |
+
|
308 |
+
class IntervalNormalizationLayer(torch.nn.Module):
|
309 |
+
def __init__(self):
|
310 |
+
super().__init__()
|
311 |
+
# new_output = [Tc, start_p, Emax, Emin, Rm, Ra, Vd]
|
312 |
+
self.a = torch.tensor([0.4, 0., 0.5, 0.02, 0.005, 0.0001, 4.], dtype=torch.float32) #HR in 20-200->Tc in [0.3, 4]
|
313 |
+
self.b = torch.tensor([1.7, 280., 3.5, 0.1, 0.1, 0.25, 16.], dtype=torch.float32)
|
314 |
+
#taken out (initial conditions): a: 20, 5, 50; b: 400, 20, 100
|
315 |
+
def forward(self, inputs):
|
316 |
+
sigmoid_output = torch.sigmoid(inputs)
|
317 |
+
scaled_output = sigmoid_output * (self.b - self.a) + self.a
|
318 |
+
return scaled_output
|
319 |
+
|
320 |
+
class NEW3DCNN(nn.Module):
|
321 |
+
def __init__(self, num_parameters):
|
322 |
+
super(NEW3DCNN, self).__init__()
|
323 |
+
|
324 |
+
self.conv1 = nn.Conv3d(3, 8, kernel_size=3, padding=1)
|
325 |
+
self.batchnorm1 = nn.BatchNorm3d(8)
|
326 |
+
self.conv2 = nn.Conv3d(8, 16, kernel_size=3, padding=1)
|
327 |
+
self.batchnorm2 = nn.BatchNorm3d(16)
|
328 |
+
self.conv3 = nn.Conv3d(16, 32, kernel_size=3, padding=1)
|
329 |
+
self.batchnorm3 = nn.BatchNorm3d(32)
|
330 |
+
self.conv4 = nn.Conv3d(32, 64, kernel_size=3, padding=1)
|
331 |
+
self.batchnorm4 = nn.BatchNorm3d(64)
|
332 |
+
self.conv5 = nn.Conv3d(64, 128, kernel_size=3, padding=1)
|
333 |
+
self.batchnorm5 = nn.BatchNorm3d(128)
|
334 |
+
self.pool = nn.AdaptiveAvgPool3d(1)
|
335 |
+
self.fc1 = nn.Linear(128, 512)
|
336 |
+
self.fc2 = nn.Linear(512, num_parameters)
|
337 |
+
self.norm1 = IntervalNormalizationLayer()
|
338 |
+
|
339 |
+
def forward(self, x):
|
340 |
+
x = F.relu(self.batchnorm1(self.conv1(x)))
|
341 |
+
x = F.max_pool3d(x, kernel_size=2, stride=2)
|
342 |
+
x = F.relu(self.batchnorm2(self.conv2(x)))
|
343 |
+
x = F.max_pool3d(x, kernel_size=2, stride=2)
|
344 |
+
x = F.relu(self.batchnorm3(self.conv3(x)))
|
345 |
+
x = F.max_pool3d(x, kernel_size=2, stride=2)
|
346 |
+
x = F.relu(self.batchnorm4(self.conv4(x)))
|
347 |
+
x = F.max_pool3d(x, kernel_size=2, stride=2)
|
348 |
+
x = F.relu(self.batchnorm5(self.conv5(x)))
|
349 |
+
x = self.pool(x)
|
350 |
+
x = x.view(x.size(0), -1)
|
351 |
+
x = F.relu(self.fc1(x))
|
352 |
+
x = self.fc2(x)
|
353 |
+
x = self.norm1(x)
|
354 |
+
|
355 |
+
return x
|
356 |
+
|
357 |
+
|
358 |
+
# Define a neural network with one hidden layer
|
359 |
+
class Interpolator(nn.Module):
|
360 |
+
def __init__(self):
|
361 |
+
super().__init__()
|
362 |
+
self.fc1 = nn.Linear(6, 250).double()
|
363 |
+
self.fc2 = nn.Linear(250, 2).double()
|
364 |
+
|
365 |
+
def forward(self, x):
|
366 |
+
x = torch.relu(self.fc1(x))
|
367 |
+
x = self.fc2(x)
|
368 |
+
return x
|
369 |
+
|
370 |
+
# Initialize the neural network
|
371 |
+
net = Interpolator()
|
372 |
+
net.load_state_dict(torch.load('final_model_weights/interp6_7param_weight.pt'))
|
373 |
+
print("Done loading interpolator!")
|
374 |
+
|
375 |
+
weights_path = 'final_model_weights/202_full_echonet_7param_Vloss_epoch_200_lr_0.001_weight_best_model.pt'
|
376 |
+
model = NEW3DCNN(num_parameters = 7)
|
377 |
+
model.load_state_dict(torch.load(weights_path))
|
378 |
+
model.to(device)
|
379 |
+
|
380 |
+
## PV loops
|
381 |
+
|
382 |
+
#returns Plv at time t using Elastance(t) and Vlv(t)-Vd=x1
|
383 |
+
def Plv(volume, Emax, Emin, t, Tc, Vd):
|
384 |
+
return Elastance(Emax,Emin,t, Tc)*(volume - Vd)
|
385 |
+
|
386 |
+
#returns Elastance(t)
|
387 |
+
def Elastance(Emax,Emin, t, Tc):
|
388 |
+
t = t-int(t/Tc)*Tc #can remove this if only want 1st ED (and the 1st ES before)
|
389 |
+
tn = t/(0.2+0.15*Tc)
|
390 |
+
return (Emax-Emin)*1.55*(tn/0.7)**1.9/((tn/0.7)**1.9+1)*1/((tn/1.17)**21.9+1) + Emin
|
391 |
+
|
392 |
+
def solve_ODE_for_volume(Rm, Ra, Emax, Emin, Vd, Tc, start_v, t):
|
393 |
+
|
394 |
+
# the ODE from Simaan et al 2008
|
395 |
+
def heart_ode(y, t, Rs, Rm, Ra, Rc, Ca, Cs, Cr, Ls, Emax, Emin, Tc):
|
396 |
+
x1, x2, x3, x4, x5 = y #here y is a vector of 5 values (not functions), at time t, used for getting (dy/dt)(t)
|
397 |
+
P_lv = Plv(x1+Vd,Emax,Emin,t,Tc,Vd)
|
398 |
+
dydt = [r(x2-P_lv)/Rm-r(P_lv-x4)/Ra, (x3-x2)/(Rs*Cr)-r(x2-P_lv)/(Cr*Rm), (x2-x3)/(Rs*Cs)+x5/Cs, -x5/Ca+r(P_lv-x4)/(Ca*Ra), (x4-x3-Rc*x5)/Ls]
|
399 |
+
return dydt
|
400 |
+
|
401 |
+
# RELU for diodes
|
402 |
+
def r(u):
|
403 |
+
return max(u, 0.)
|
404 |
+
|
405 |
+
# Define fixed parameters
|
406 |
+
Rs = 1.0
|
407 |
+
Rc = 0.0398
|
408 |
+
Ca = 0.08
|
409 |
+
Cs = 1.33
|
410 |
+
Cr = 4.400
|
411 |
+
Ls = 0.0005
|
412 |
+
startp = 75.
|
413 |
+
|
414 |
+
# Initial conditions
|
415 |
+
start_pla = float(start_v*Elastance(Emax, Emin, 0, Tc))
|
416 |
+
start_pao = startp
|
417 |
+
start_pa = start_pao
|
418 |
+
start_qt = 0 #aortic flow is Q_T and is 0 at ED, also see Fig5 in simaan2008dynamical
|
419 |
+
y0 = [start_v, start_pla, start_pa, start_pao, start_qt]
|
420 |
+
|
421 |
+
# Solve
|
422 |
+
sol = odeint(heart_ode, y0, t, args = (Rs, Rm, Ra, Rc, Ca, Cs, Cr, Ls, Emax, Emin, Tc)) #t: list of values
|
423 |
+
|
424 |
+
# volume is the first state variable plus theoretical zero pressure volume
|
425 |
+
volumes = np.array(sol[:, 0]) + Vd
|
426 |
+
|
427 |
+
return volumes
|
428 |
+
|
429 |
+
def pvloop_simulator(Rm, Ra, Emax, Emin, Vd, Tc, start_v):
|
430 |
+
|
431 |
+
|
432 |
+
# Define initial parameters
|
433 |
+
init_Emax = Emax # 3.0 # .5 to 3.5
|
434 |
+
init_Emin = Emin # 0.04 # .02 to .1
|
435 |
+
# init_Tc = Tc # .4 # .4 to 1.7
|
436 |
+
init_Vd = Vd # 10.0 # 0 to 25
|
437 |
+
|
438 |
+
# DUMMY VOLUME
|
439 |
+
# def volume(t, Tc):
|
440 |
+
# return 50*np.sin(2 * np.pi * t*(1/Tc))+100
|
441 |
+
|
442 |
+
# SOLVE the ODE model for the VOLUME CURVE
|
443 |
+
N = 100
|
444 |
+
t = np.linspace(0, Tc*N, int(60000*N)) #np.linspace(1, 100, 1000000)
|
445 |
+
volumes = solve_ODE_for_volume(Rm, Ra, Emax, Emin, Vd, Tc, start_v, t)
|
446 |
+
|
447 |
+
# FUNCTIONS for PRESSURE CURVE
|
448 |
+
vectorized_Elastance = np.vectorize(Elastance)
|
449 |
+
vectorized_Plv = np.vectorize(Plv)
|
450 |
+
|
451 |
+
def pressure(t, volume, Emax, Emin, Tc, Vd):
|
452 |
+
return vectorized_Plv(volume, Emax, Emin, t, Tc, Vd)
|
453 |
+
|
454 |
+
# calculate PRESSURE
|
455 |
+
pressures = pressure(t, volumes, init_Emax, init_Emin, Tc, init_Vd)
|
456 |
+
|
457 |
+
# Create the figure and the loop that we will manipulate
|
458 |
+
fig, ax = plt.subplots()
|
459 |
+
plt.ylim((0,220))
|
460 |
+
plt.xlim((0,250))
|
461 |
+
line = ax.plot(volumes[(N-2)*60000], pressures[(N-2)*60000], lw=1)
|
462 |
+
#line = ax.plot(volumes[(N-2)*60000:(N)*60000], pressures[(N-2)*60000:(N)*60000], lw=1)
|
463 |
+
#print(line)
|
464 |
+
line = line[0]
|
465 |
+
#print(line)
|
466 |
+
|
467 |
+
fig.suptitle('Predicted PI-SSL LV Pressure Volume Loop', fontsize=16)
|
468 |
+
#plt.rcParams['fig.suptitle'] = -2.0
|
469 |
+
#ax.set_title(f'Mitral valve circuit resistance (Rm): {Rm} mmHg*s/ml \n Aortic valve circuit resistance (Ra): {Ra} mmHg*s/ml', fontsize=6)
|
470 |
+
ax.set_xlabel('LV Volume (ml)')
|
471 |
+
ax.set_ylabel('LV Pressure (mmHg)')
|
472 |
+
|
473 |
+
# adjust the main plot to make room for the sliders
|
474 |
+
# fig.subplots_adjust(left=0.25, bottom=0.25)
|
475 |
+
|
476 |
+
def update(frame):
|
477 |
+
# for each frame, update the data stored on each artist.
|
478 |
+
x = volumes[:(N-2)*60000+frame]
|
479 |
+
y = pressures[:(N-2)*60000:(N)+frame]
|
480 |
+
line.set_xdata(x)
|
481 |
+
line.set_ydata(y)
|
482 |
+
return line
|
483 |
+
|
484 |
+
anim = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=30)
|
485 |
+
|
486 |
+
return plt, Rm, Ra, Emax, Emin, Vd, Tc, start_v
|
487 |
+
|
488 |
+
def pvloop_simulator_plot_only(Rm, Ra, Emax, Emin, Vd, Tc, start_v):
|
489 |
+
plot,_,_,_,_,_,_,_ =pvloop_simulator(Rm, Ra, Emax, Emin, Vd, Tc, start_v)
|
490 |
+
return plot
|
491 |
+
|
492 |
+
## Demo
|
493 |
+
|
494 |
+
def generate_example():
|
495 |
+
# get random input
|
496 |
+
data_path = 'EchoNet-Dynamic'
|
497 |
+
image_data = Echo(root = data_path, split = 'all', target_type=['Filename','LargeIndex','SmallIndex'])
|
498 |
+
image_loaded_data = DataLoader(image_data, batch_size=30, shuffle=True)
|
499 |
+
val_data = next(iter(image_loaded_data))
|
500 |
+
#create_echo_clip(val_data,'test')
|
501 |
+
val_seq = val_data[0]
|
502 |
+
|
503 |
+
val_tensor = torch.tensor(val_seq, dtype=torch.float32)
|
504 |
+
n=random.randint(0, 29)
|
505 |
+
results = model(val_tensor)[n]
|
506 |
+
|
507 |
+
filename = val_data[1][0][n]
|
508 |
+
video = f"EchoNet-Dynamic/Videos/{filename}"
|
509 |
+
|
510 |
+
plot, Rm, Ra, Emax, Emin, Vd,Tc, start_v = pvloop_simulator(Rm=round(results[4].item(),2), Ra=round(results[5].item(),2), Emax=results[2].item(), Emin=round(results[3].item(),2), Vd=round(results[6].item(),2), Tc=round(results[0].item(),2), start_v=round(results[1].item(),2))
|
511 |
+
video = video.replace("avi", "mp4")
|
512 |
+
return video, plot, Rm, Ra, Emax, Emin, Vd, Tc, start_v
|
513 |
+
|
514 |
+
title = "Physics-informed self-supervised learning for predicting cardiac digital twins with echocardiography"
|
515 |
+
|
516 |
+
description = """
|
517 |
+
<p style='text-align: center'> Keying Kuang, Frances Dean, Jack B. Jedlicki, David Ouyang, Anthony Philippakis, David Sontag, Ahmed Alaa <br></p>
|
518 |
+
<p> We develop methodology for predicting digital twins from non-invasive cardiac ultrasound images in <a href='https://arxiv.org/abs/2403.00177'>Non-Invasive Medical Digital Twins using Physics-Informed Self-Supervised Learning</a>. Check out our <a href='https://github.com/AlaaLab/CardioPINN' target='_blank'>code.</a> \n \n
|
519 |
+
We demonstrate the ability of our model to predict left ventricular pressure-volume loops using image data here. To run example predictions on samples from the <a href='https://echonet.github.io/dynamic/'>EchoNet</a> dataset, click the first button. \n \n
|
520 |
+
Below you can input values of predicted parameters and output a simulated pressure-volume loop predicted by the <a href='https://ieeexplore.ieee.org/document/4729737/keywords#keywords'>Simaan et al 2008</a> hydraulic analogy model by pressing 'Run simulation.'</p>
|
521 |
+
"""
|
522 |
+
|
523 |
+
gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>" + title + "</h1>")
|
524 |
+
gr.Markdown(description)
|
525 |
+
|
526 |
+
with gr.Blocks() as demo:
|
527 |
+
|
528 |
+
# text
|
529 |
+
gr.Markdown("<h1 style='text-align: center; margin-bottom: 1rem'>" + title + "</h1>")
|
530 |
+
gr.Markdown(description)
|
531 |
+
|
532 |
+
with gr.Row():
|
533 |
+
with gr.Column(scale=1.5, min_width=100):
|
534 |
+
|
535 |
+
generate_button = gr.Button("Load sample echocardiogram and generate result")
|
536 |
+
with gr.Row():
|
537 |
+
video = gr.PlayableVideo() #format="avi"
|
538 |
+
plot = gr.Plot()
|
539 |
+
|
540 |
+
with gr.Row():
|
541 |
+
Rm = gr.Number(label="Mitral valve circuit resistance (Rm) mmHg*s/ml:")
|
542 |
+
Ra = gr.Number(label="Aortic valve circuit resistance (Ra) mmHg*s/ml:")
|
543 |
+
Emax = gr.Number(label="Maximum elastance (Emax) mmHg/ml:")
|
544 |
+
Emin = gr.Number(label="Minimum elastance (Emin) mmHg/ml:")
|
545 |
+
Vd = gr.Number(label="Theoretical zero pressure volume (Vd) ml:")
|
546 |
+
Tc = gr.Number(label="Cycle duration (Tc) s:")
|
547 |
+
start_v = gr.Number(label="Initial volume (start_v) ml:")
|
548 |
+
|
549 |
+
simulation_button = gr.Button("Run simulation")
|
550 |
+
|
551 |
+
|
552 |
+
|
553 |
+
with gr.Row():
|
554 |
+
sl1 = gr.Slider(0.005, 0.1, value=Rm, label="Rm")
|
555 |
+
sl2 = gr.Slider(0.0001, 0.25, value=Ra, label="Ra")
|
556 |
+
sl3 = gr.Slider(0.5, 3.5, value=Emax, label="Emax")
|
557 |
+
sl4 = gr.Slider(0.02, 0.1, value= Emin, label="Emin")
|
558 |
+
sl5 = gr.Slider(4.0, 25.0, value=Vd, label="Vd")
|
559 |
+
sl6 = gr.Slider(0.4, 1.7, value=Tc, label="Tc")
|
560 |
+
sl7 = gr.Slider(0.0, 280.0, value=start_v, label="start_v")
|
561 |
+
|
562 |
+
|
563 |
+
generate_button.click(fn=generate_example, outputs = [video,plot,Rm,Ra,Emax,Emin,Vd,Tc,start_v])
|
564 |
+
|
565 |
+
|
566 |
+
simulation_button.click(fn=pvloop_simulator_plot_only, inputs = [sl1,sl2,sl3,sl4,sl5,sl6,sl7], outputs = [gr.Plot()])
|
567 |
+
|
568 |
+
|
569 |
+
|
570 |
+
demo.launch()
|
EchoNet-Dynamic/.DS_Store
CHANGED
Binary files a/EchoNet-Dynamic/.DS_Store and b/EchoNet-Dynamic/.DS_Store differ
|
|
EchoNet-Dynamic/FileList.csv
CHANGED
@@ -2,7 +2,6 @@ FileName,EF,ESV,EDV,FrameHeight,FrameWidth,FPS,NumberOfFrames,Split
|
|
2 |
0X2CE2BBE899FB30A,69.3733509,15.07375645,49.21777894,112,112,50,208,TRAIN
|
3 |
0X310589D4CDC13146,45.54886748,49.07256162,90.12220564,112,112,53,151,TRAIN
|
4 |
0X34D6A77674B8E6F2,55.01383234,30.59875717,68.01814594,112,112,50,166,TRAIN
|
5 |
-
0X352D7150FCBFA7C1,28.89583936,58.48777087,82.25646762,112,112,50,61,TRAIN
|
6 |
0X36B33D2B6530F83E,57.65061751,33.64751654,79.45220108,112,112,50,161,VAL
|
7 |
0X3B6528FD917A0E82,58.58439974,38.07170832,91.92600876,112,112,50,201,TRAIN
|
8 |
0X49B360CA6BB04B97,57.87742067,25.5427545,60.63910355,112,112,50,155,TRAIN
|
@@ -11,7 +10,6 @@ FileName,EF,ESV,EDV,FrameHeight,FrameWidth,FPS,NumberOfFrames,Split
|
|
11 |
0X55AEA1223ADFB9E8,58.42788325,51.81422337,124.636962,112,112,47,126,VAL
|
12 |
0X5D98E2C64E1625FB,27.7459176,118.5770238,164.1111753,112,112,43,136,TRAIN
|
13 |
0X623F4667A42B8338,60.35354935,30.37659467,76.61869895,112,112,50,127,VAL
|
14 |
-
0X6382AE8EB4B73A3D,49.96284792,40.07870013,80.09788419,112,112,73,138,TRAIN
|
15 |
0X63FECBA90BA79F81,64.86754791,21.00386139,59.78478627,112,112,50,198,VAL
|
16 |
0X6532C54260D0231,55.73785825,29.72626047,67.15956186,112,112,50,140,TRAIN
|
17 |
0X665E43AF6FE1563D,65.64105652,21.3883945,62.24986083,112,112,50,148,TRAIN
|
|
|
2 |
0X2CE2BBE899FB30A,69.3733509,15.07375645,49.21777894,112,112,50,208,TRAIN
|
3 |
0X310589D4CDC13146,45.54886748,49.07256162,90.12220564,112,112,53,151,TRAIN
|
4 |
0X34D6A77674B8E6F2,55.01383234,30.59875717,68.01814594,112,112,50,166,TRAIN
|
|
|
5 |
0X36B33D2B6530F83E,57.65061751,33.64751654,79.45220108,112,112,50,161,VAL
|
6 |
0X3B6528FD917A0E82,58.58439974,38.07170832,91.92600876,112,112,50,201,TRAIN
|
7 |
0X49B360CA6BB04B97,57.87742067,25.5427545,60.63910355,112,112,50,155,TRAIN
|
|
|
10 |
0X55AEA1223ADFB9E8,58.42788325,51.81422337,124.636962,112,112,47,126,VAL
|
11 |
0X5D98E2C64E1625FB,27.7459176,118.5770238,164.1111753,112,112,43,136,TRAIN
|
12 |
0X623F4667A42B8338,60.35354935,30.37659467,76.61869895,112,112,50,127,VAL
|
|
|
13 |
0X63FECBA90BA79F81,64.86754791,21.00386139,59.78478627,112,112,50,198,VAL
|
14 |
0X6532C54260D0231,55.73785825,29.72626047,67.15956186,112,112,50,140,TRAIN
|
15 |
0X665E43AF6FE1563D,65.64105652,21.3883945,62.24986083,112,112,50,148,TRAIN
|
EchoNet-Dynamic/Videos/.DS_Store
CHANGED
Binary files a/EchoNet-Dynamic/Videos/.DS_Store and b/EchoNet-Dynamic/Videos/.DS_Store differ
|
|
EchoNet-Dynamic/Videos/0X352D7150FCBFA7C1.avi
DELETED
Binary file (228 kB)
|
|
EchoNet-Dynamic/Videos/0X352D7150FCBFA7C1.mp4
DELETED
Binary file (46.7 kB)
|
|
EchoNet-Dynamic/Videos/0X6382AE8EB4B73A3D.avi
DELETED
Binary file (454 kB)
|
|
EchoNet-Dynamic/Videos/0X6382AE8EB4B73A3D.mp4
DELETED
Binary file (32.9 kB)
|
|
EchoNet-Dynamic/VolumeTracings.csv
CHANGED
@@ -125,48 +125,6 @@ FileName,X1,Y1,X2,Y2,Frame
|
|
125 |
0X34D6A77674B8E6F2.avi,49.34517087,68.20596855,71.0245205,62.02791555,97
|
126 |
0X34D6A77674B8E6F2.avi,49.63605055,70.06759853,71.56193286,63.8192901,97
|
127 |
0X34D6A77674B8E6F2.avi,59.82206211,69.10937228,71.56568191,65.76274487,97
|
128 |
-
0X352D7150FCBFA7C1.avi,49.80208333,13.70833333,66.75520833,54.90625,58
|
129 |
-
0X352D7150FCBFA7C1.avi,49.9160378,14.90485525,51.40619797,14.29164775,58
|
130 |
-
0X352D7150FCBFA7C1.avi,50.14394674,17.29789908,54.61442725,15.45827657,58
|
131 |
-
0X352D7150FCBFA7C1.avi,50.37185567,19.69094292,57.82265652,16.6249054,58
|
132 |
-
0X352D7150FCBFA7C1.avi,50.37217339,22.17764154,61.0308858,17.79153423,58
|
133 |
-
0X352D7150FCBFA7C1.avi,49.84301648,24.88222133,64.23911507,18.95816306,58
|
134 |
-
0X352D7150FCBFA7C1.avi,49.31385957,27.58680111,66.76347424,20.40620746,58
|
135 |
-
0X352D7150FCBFA7C1.avi,48.92888294,30.23205006,68.60351955,22.13585004,58
|
136 |
-
0X352D7150FCBFA7C1.avi,49.12000837,32.64023047,70.44356485,23.86549263,58
|
137 |
-
0X352D7150FCBFA7C1.avi,49.3111338,35.04841088,72.28361015,25.59513521,58
|
138 |
-
0X352D7150FCBFA7C1.avi,49.50225923,37.45659129,74.12365546,27.3247778,58
|
139 |
-
0X352D7150FCBFA7C1.avi,49.69338466,39.8647717,75.41063515,29.28200933,58
|
140 |
-
0X352D7150FCBFA7C1.avi,49.78129389,42.31542603,76.23844775,31.42819015,58
|
141 |
-
0X352D7150FCBFA7C1.avi,49.73308878,44.82209202,77.06626035,33.57437097,58
|
142 |
-
0X352D7150FCBFA7C1.avi,49.68488366,47.32875801,77.89407295,35.72055179,58
|
143 |
-
0X352D7150FCBFA7C1.avi,49.63667855,49.83542399,78.72188556,37.86673261,58
|
144 |
-
0X352D7150FCBFA7C1.avi,50.4411498,51.99120988,79.54969816,40.01291343,58
|
145 |
-
0X352D7150FCBFA7C1.avi,51.70538648,53.95780026,79.65767974,42.4553079,58
|
146 |
-
0X352D7150FCBFA7C1.avi,52.96962315,55.92439065,79.2872573,45.09456774,58
|
147 |
-
0X352D7150FCBFA7C1.avi,54.23385983,57.89098103,78.91683487,47.73382758,58
|
148 |
-
0X352D7150FCBFA7C1.avi,69.24867506,54.1991475,78.54641244,50.37308742,58
|
149 |
-
0X352D7150FCBFA7C1.avi,52.171875,16.98958333,64.56770833,53.99479167,46
|
150 |
-
0X352D7150FCBFA7C1.avi,51.86474412,18.1522931,54.03930391,17.42386913,46
|
151 |
-
0X352D7150FCBFA7C1.avi,51.25048236,20.47771263,57.77416174,18.29244071,46
|
152 |
-
0X352D7150FCBFA7C1.avi,50.63622059,22.80313216,60.71332962,19.42754884,46
|
153 |
-
0X352D7150FCBFA7C1.avi,50.02195883,25.12855169,62.4651479,20.96038983,46
|
154 |
-
0X352D7150FCBFA7C1.avi,49.58600989,27.39424081,64.21696618,22.49323082,46
|
155 |
-
0X352D7150FCBFA7C1.avi,49.48817215,29.54667101,65.96878446,24.02607182,46
|
156 |
-
0X352D7150FCBFA7C1.avi,49.39033441,31.69910121,67.72060274,25.55891281,46
|
157 |
-
0X352D7150FCBFA7C1.avi,49.29249668,33.85153141,69.13705572,27.20409292,46
|
158 |
-
0X352D7150FCBFA7C1.avi,49.25520833,35.98367906,70.06373992,29.0133335,46
|
159 |
-
0X352D7150FCBFA7C1.avi,49.25520833,38.10333603,70.99042413,30.82257409,46
|
160 |
-
0X352D7150FCBFA7C1.avi,49.25520833,40.222993,71.91710833,32.63181467,46
|
161 |
-
0X352D7150FCBFA7C1.avi,49.25520833,42.34264996,72.81011857,34.45233521,46
|
162 |
-
0X352D7150FCBFA7C1.avi,49.25520833,44.46230693,73.61454998,36.30252746,46
|
163 |
-
0X352D7150FCBFA7C1.avi,49.25520833,46.5819639,74.4189814,38.15271972,46
|
164 |
-
0X352D7150FCBFA7C1.avi,49.41717731,48.64736525,75.22341282,40.00291198,46
|
165 |
-
0X352D7150FCBFA7C1.avi,50.0527613,50.55411724,76.02784423,41.85310424,46
|
166 |
-
0X352D7150FCBFA7C1.avi,50.6883453,52.46086922,76.36473964,43.85990954,46
|
167 |
-
0X352D7150FCBFA7C1.avi,51.32392929,54.36762121,76.54013569,45.92081315,46
|
168 |
-
0X352D7150FCBFA7C1.avi,51.95951329,56.27437319,76.71553175,47.98171676,46
|
169 |
-
0X352D7150FCBFA7C1.avi,66.33136696,53.57981317,76.8909278,50.04262037,46
|
170 |
0X36B33D2B6530F83E.avi,47.61458333,12.796875,51.625,57.82291667,106
|
171 |
0X36B33D2B6530F83E.avi,47.03179306,14.01795939,49.25192682,13.82021468,106
|
172 |
0X36B33D2B6530F83E.avi,45.8662125,16.46012817,52.57323857,15.86274123,106
|
@@ -503,48 +461,6 @@ FileName,X1,Y1,X2,Y2,Frame
|
|
503 |
0X623F4667A42B8338.avi,51.15840311,63.83187801,70.09225933,58.82733452,47
|
504 |
0X623F4667A42B8338.avi,51.40727935,66.07176411,70.21849828,61.09963576,47
|
505 |
0X623F4667A42B8338.avi,52.82458486,68.00281428,59.16708248,66.32638319,47
|
506 |
-
0X6382AE8EB4B73A3D.avi,42.69270833,32.11979167,64.75,79.88020833,105
|
507 |
-
0X6382AE8EB4B73A3D.avi,42.75418306,33.59518516,45.04089118,32.53911003,105
|
508 |
-
0X6382AE8EB4B73A3D.avi,42.87704877,36.54601082,49.10540384,33.66955675,105
|
509 |
-
0X6382AE8EB4B73A3D.avi,42.99516945,39.49902788,52.27247629,35.21447014,105
|
510 |
-
0X6382AE8EB4B73A3D.avi,43.2041047,42.41010386,55.39453828,36.78017079,105
|
511 |
-
0X6382AE8EB4B73A3D.avi,43.51378561,45.27465227,57.71668879,38.71529622,105
|
512 |
-
0X6382AE8EB4B73A3D.avi,43.84747576,48.12811244,60.0388393,40.65042164,105
|
513 |
-
0X6382AE8EB4B73A3D.avi,44.3580637,50.89987554,62.07196445,42.71902825,105
|
514 |
-
0X6382AE8EB4B73A3D.avi,44.86865164,53.67163864,63.9801778,44.84532312,105
|
515 |
-
0X6382AE8EB4B73A3D.avi,45.79554623,56.25113798,65.88839115,46.971618,105
|
516 |
-
0X6382AE8EB4B73A3D.avi,46.97722542,58.71296963,67.57281822,49.20126455,105
|
517 |
-
0X6382AE8EB4B73A3D.avi,48.15890461,61.17480127,68.85008614,51.61895026,105
|
518 |
-
0X6382AE8EB4B73A3D.avi,49.3405838,63.63663292,70.12735406,54.03663596,105
|
519 |
-
0X6382AE8EB4B73A3D.avi,49.98025454,66.34878144,71.40462198,56.45432167,105
|
520 |
-
0X6382AE8EB4B73A3D.avi,50.57150052,69.08329407,72.59497827,58.91214595,105
|
521 |
-
0X6382AE8EB4B73A3D.avi,50.84050148,71.96662979,73.62983127,61.44178663,105
|
522 |
-
0X6382AE8EB4B73A3D.avi,50.7179345,75.03080412,74.66468428,63.97142732,105
|
523 |
-
0X6382AE8EB4B73A3D.avi,50.97807563,77.91823159,75.55919254,66.56588371,105
|
524 |
-
0X6382AE8EB4B73A3D.avi,52.01791822,80.44556792,75.84667268,69.44068514,105
|
525 |
-
0X6382AE8EB4B73A3D.avi,55.49621283,81.84674894,75.95152344,72.39983068,105
|
526 |
-
0X6382AE8EB4B73A3D.avi,67.64628257,79.24302617,75.59927352,75.57007996,105
|
527 |
-
0X6382AE8EB4B73A3D.avi,49.61979167,33.03125,64.203125,76.96354167,90
|
528 |
-
0X6382AE8EB4B73A3D.avi,49.48283763,34.30948768,50.85427487,33.8542388,90
|
529 |
-
0X6382AE8EB4B73A3D.avi,49.20892955,36.86596305,53.32324129,35.50021641,90
|
530 |
-
0X6382AE8EB4B73A3D.avi,49.14252472,39.35355766,55.35684419,37.29071303,90
|
531 |
-
0X6382AE8EB4B73A3D.avi,49.28079067,41.77321178,56.96626433,39.2220172,90
|
532 |
-
0X6382AE8EB4B73A3D.avi,49.41905662,44.19286589,58.57568448,41.15332137,90
|
533 |
-
0X6382AE8EB4B73A3D.avi,49.57686062,46.60603434,60.18510462,43.08462554,90
|
534 |
-
0X6382AE8EB4B73A3D.avi,49.73767197,49.0182045,61.54893279,45.09745402,90
|
535 |
-
0X6382AE8EB4B73A3D.avi,49.89848331,51.43037466,62.70540985,47.17911274,90
|
536 |
-
0X6382AE8EB4B73A3D.avi,50.01643199,53.8567731,63.86188692,49.26077146,90
|
537 |
-
0X6382AE8EB4B73A3D.avi,50.08524073,56.29948354,65.01836399,51.34243018,90
|
538 |
-
0X6382AE8EB4B73A3D.avi,50.15404948,58.74219398,66.04575691,53.46693841,90
|
539 |
-
0X6382AE8EB4B73A3D.avi,50.22285822,61.18490443,66.98764672,55.61982941,90
|
540 |
-
0X6382AE8EB4B73A3D.avi,50.29166697,63.62761487,67.92953653,57.77272041,90
|
541 |
-
0X6382AE8EB4B73A3D.avi,50.36433888,66.06904294,68.87142635,59.92561141,90
|
542 |
-
0X6382AE8EB4B73A3D.avi,50.45622753,68.504092,69.61306673,62.14497526,90
|
543 |
-
0X6382AE8EB4B73A3D.avi,50.54811617,70.93914107,70.18222182,64.42159563,90
|
544 |
-
0X6382AE8EB4B73A3D.avi,50.64000482,73.37419014,70.75137692,66.698216,90
|
545 |
-
0X6382AE8EB4B73A3D.avi,51.00395115,75.7189296,71.17584133,69.02286647,90
|
546 |
-
0X6382AE8EB4B73A3D.avi,52.45805061,77.7017925,71.52398717,71.3728509,90
|
547 |
-
0X6382AE8EB4B73A3D.avi,57.28586759,78.56474918,71.19545567,73.94745853,90
|
548 |
0X63FECBA90BA79F81.avi,57.16666667,28,66.03333333,95.66666667,151
|
549 |
0X63FECBA90BA79F81.avi,52.8280287,30.354879,62.43932692,29.09546751,151
|
550 |
0X63FECBA90BA79F81.avi,49.80404232,34.32386112,67.42054487,32.01549182,151
|
|
|
125 |
0X34D6A77674B8E6F2.avi,49.34517087,68.20596855,71.0245205,62.02791555,97
|
126 |
0X34D6A77674B8E6F2.avi,49.63605055,70.06759853,71.56193286,63.8192901,97
|
127 |
0X34D6A77674B8E6F2.avi,59.82206211,69.10937228,71.56568191,65.76274487,97
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
0X36B33D2B6530F83E.avi,47.61458333,12.796875,51.625,57.82291667,106
|
129 |
0X36B33D2B6530F83E.avi,47.03179306,14.01795939,49.25192682,13.82021468,106
|
130 |
0X36B33D2B6530F83E.avi,45.8662125,16.46012817,52.57323857,15.86274123,106
|
|
|
461 |
0X623F4667A42B8338.avi,51.15840311,63.83187801,70.09225933,58.82733452,47
|
462 |
0X623F4667A42B8338.avi,51.40727935,66.07176411,70.21849828,61.09963576,47
|
463 |
0X623F4667A42B8338.avi,52.82458486,68.00281428,59.16708248,66.32638319,47
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
0X63FECBA90BA79F81.avi,57.16666667,28,66.03333333,95.66666667,151
|
465 |
0X63FECBA90BA79F81.avi,52.8280287,30.354879,62.43932692,29.09546751,151
|
466 |
0X63FECBA90BA79F81.avi,49.80404232,34.32386112,67.42054487,32.01549182,151
|
app.py
CHANGED
@@ -20,6 +20,7 @@ import pandas as pd
|
|
20 |
from scipy.integrate import odeint
|
21 |
import torchvision
|
22 |
import echonet
|
|
|
23 |
|
24 |
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
25 |
|
@@ -455,9 +456,10 @@ def pvloop_simulator(Rm, Ra, Emax, Emin, Vd, Tc, start_v):
|
|
455 |
|
456 |
# Create the figure and the loop that we will manipulate
|
457 |
fig, ax = plt.subplots()
|
458 |
-
plt.ylim((0,
|
459 |
-
plt.xlim((0,
|
460 |
-
line = ax.plot(volumes[(N-2)*60000
|
|
|
461 |
#print(line)
|
462 |
line = line[0]
|
463 |
#print(line)
|
@@ -469,7 +471,17 @@ def pvloop_simulator(Rm, Ra, Emax, Emin, Vd, Tc, start_v):
|
|
469 |
ax.set_ylabel('LV Pressure (mmHg)')
|
470 |
|
471 |
# adjust the main plot to make room for the sliders
|
472 |
-
fig.subplots_adjust(left=0.25, bottom=0.25)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
473 |
|
474 |
return plt, Rm, Ra, Emax, Emin, Vd, Tc, start_v
|
475 |
|
|
|
20 |
from scipy.integrate import odeint
|
21 |
import torchvision
|
22 |
import echonet
|
23 |
+
import matplotlib.animation as animation
|
24 |
|
25 |
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
|
26 |
|
|
|
456 |
|
457 |
# Create the figure and the loop that we will manipulate
|
458 |
fig, ax = plt.subplots()
|
459 |
+
plt.ylim((0,220))
|
460 |
+
plt.xlim((0,250))
|
461 |
+
line = ax.plot(volumes[(N-2)*60000], pressures[(N-2)*60000], lw=1)
|
462 |
+
#line = ax.plot(volumes[(N-2)*60000:(N)*60000], pressures[(N-2)*60000:(N)*60000], lw=1)
|
463 |
#print(line)
|
464 |
line = line[0]
|
465 |
#print(line)
|
|
|
471 |
ax.set_ylabel('LV Pressure (mmHg)')
|
472 |
|
473 |
# adjust the main plot to make room for the sliders
|
474 |
+
# fig.subplots_adjust(left=0.25, bottom=0.25)
|
475 |
+
|
476 |
+
def update(frame):
|
477 |
+
# for each frame, update the data stored on each artist.
|
478 |
+
x = volumes[:(N-2)*60000+frame]
|
479 |
+
y = pressures[:(N-2)*60000:(N)+frame]
|
480 |
+
line.set_xdata(x)
|
481 |
+
line.set_ydata(y)
|
482 |
+
return line
|
483 |
+
|
484 |
+
anim = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=30)
|
485 |
|
486 |
return plt, Rm, Ra, Emax, Emin, Vd, Tc, start_v
|
487 |
|