Skip to content

Commit cd2ec0c

Browse files
committed
STEVE is a standalone project!
1 parent 1f855b7 commit cd2ec0c

File tree

760 files changed

+323891
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

760 files changed

+323891
-2
lines changed

.gitattributes

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Library
2+
Logs
3+
Packages
4+
UserSettings
5+
ProjectSettings
6+
Unity-Robotics-Hub-main
7+
Temp
8+
Task_Data/*/*/
9+
Assets/Tasks/OBJ_scenes
10+
# !Task_Data/*/*.stl
11+
# !Task_Data/*/*.m
12+
Build
13+
Assessment/Task_Data
14+
Assessment/PlotSTLs
15+
Assessment/Pre-Study
16+
Assessment/subjects.csv
17+
Assets/3d_models
18+
Assets/Tasks/Setup_files/*.blend
19+
Assets/Tasks/Setup_files/*.blend1
20+
Assets/Tasks
21+
rosws/src/CMakeLists.txt
22+
PlotSTLs
23+
*.meta
24+
*.csproj
25+
*.sln
26+
ActiveConstraints_Package.unitypackage
27+
/Notes/graphs.ipynb
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
"C:/Users/alber/AppData/Local/Programs/Python/Python39/python.exe" "%~dp0/LiverResection_graph.py"
3+
pause
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
import matplotlib.pyplot as plt
2+
import matplotlib as mpl
3+
mpl.rcParams.update(mpl.rcParamsDefault)
4+
import numpy as np
5+
from matplotlib import cm
6+
import pandas as pd
7+
import os
8+
import json
9+
from stl import mesh
10+
from mpl_toolkits import mplot3d
11+
12+
def m4(m):
13+
m = np.concatenate((m, np.ones((np.shape(m)[0],1))),axis=1).transpose()
14+
return m
15+
16+
def u2r(df):
17+
dff=df.copy()
18+
dff['X'] = df['X']*(-1)
19+
dff['Y'] = df['Z']*(-1)
20+
dff['Z'] = df['Y']*(+1)
21+
return dff
22+
23+
24+
def plotPosDist(ax,pos,err):
25+
for i in range(np.shape(pos)[0]-1):
26+
ax.plot3D(pos.iloc[i:(i+2),0],pos.iloc[i:(i+2),1],pos.iloc[i:(i+2),2],
27+
c=cm.RdYlGn_r(err[i]/np.max(err)),
28+
linewidth=2
29+
)
30+
31+
def plotPosForce(ax,pos,force):
32+
for i in range(np.shape(pos)[0]-1):
33+
ax.plot3D(pos.iloc[i:(i+2),0],pos.iloc[i:(i+2),1],pos.iloc[i:(i+2),2],
34+
c=cm.RdYlGn_r(err[i]/np.max(force)),
35+
linewidth=2
36+
)
37+
38+
def plotObstacles(ax, path,c):
39+
for o in os.listdir(path):
40+
if o.endswith("_vertices.csv"):
41+
obv = u2r(pd.read_csv(os.path.join(path,o))).to_numpy()
42+
obt = pd.read_csv(os.path.join(path,o.split("_")[0]+"_triangulation.csv")).to_numpy()
43+
m = mesh.Mesh(np.zeros(obt.shape[0], dtype=mesh.Mesh.dtype))
44+
for i, f in enumerate(obt):
45+
for j in range(3):
46+
m.vectors[i][j] = obv[f[j],:]
47+
ax.add_collection3d(mplot3d.art3d.Poly3DCollection(m.vectors,alpha=0.05, ec=c,fc=c,linewidth=0.1))
48+
49+
def centerandequal(ax,pos):
50+
xlim = [np.amin(pos.to_numpy()[:,0]), np.amax(pos.to_numpy()[:,0])]; xrange = xlim[1] - xlim[0]
51+
ylim = [np.amin(pos.to_numpy()[:,1]), np.amax(pos.to_numpy()[:,1])]; yrange = ylim[1] - ylim[0]
52+
zlim = [np.amin(pos.to_numpy()[:,2]), np.amax(pos.to_numpy()[:,2])]; zrange = zlim[1] - zlim[0]
53+
maxrange = max(xrange, yrange, zrange)
54+
BORDERS = 1.5
55+
ax.set_xlim3d([(xlim[0]+xlim[1])/2-maxrange/BORDERS,(xlim[0]+xlim[1])/2+maxrange/BORDERS])
56+
ax.set_ylim3d([(ylim[0]+ylim[1])/2-maxrange/BORDERS,(ylim[0]+ylim[1])/2+maxrange/BORDERS])
57+
ax.set_zlim3d([(zlim[0]+zlim[1])/2-maxrange/BORDERS,(zlim[0]+zlim[1])/2+maxrange/BORDERS])
58+
59+
def clean_axes(ax):
60+
ax.xaxis.pane.set_facecolor('w')
61+
ax.yaxis.pane.set_facecolor('w')
62+
ax.zaxis.pane.set_facecolor('w')
63+
ax.get_xaxis().set_ticklabels([])
64+
ax.get_yaxis().set_ticklabels([])
65+
ax.get_zaxis().set_ticklabels([])
66+
67+
def on_move(event):
68+
if event.inaxes == axerr:
69+
if axerr.button_pressed in axerr._rotate_btn:
70+
axforce.view_init(elev=axerr.elev, azim=axerr.azim)
71+
elif axerr.button_pressed in axerr._zoom_btn:
72+
axforce.set_xlim3d(axerr.get_xlim3d())
73+
axforce.set_ylim3d(axerr.get_ylim3d())
74+
axforce.set_zlim3d(axerr.get_zlim3d())
75+
elif event.inaxes == axforce:
76+
if axforce.button_pressed in axforce._rotate_btn:
77+
axerr.view_init(elev=axforce.elev, azim=axforce.azim)
78+
elif axforce.button_pressed in axforce._zoom_btn:
79+
axerr.set_xlim3d(axforce.get_xlim3d())
80+
axerr.set_ylim3d(axforce.get_ylim3d())
81+
axerr.set_zlim3d(axforce.get_zlim3d())
82+
else:
83+
return
84+
fig.canvas.draw_idle()
85+
86+
wd = os.path.join(os.path.dirname(os.path.realpath(__file__)))
87+
wd = os.path.join(wd, os.path.basename(wd))
88+
89+
def rms(data):
90+
return np.sqrt(np.mean(data**2))
91+
92+
wd = os.path.join(os.path.dirname(os.path.realpath(__file__)))
93+
wd = os.path.join(wd, os.path.basename(wd))
94+
95+
# ob0 = u2r(pd.read_csv(wd+'_obst0.csv'))
96+
task = pd.read_csv(wd+'_VFs.csv')
97+
pos = u2r(task[['PositionX','PositionY','PositionZ']].rename(
98+
columns={'PositionX':'X','PositionY':'Y','PositionZ':'Z'}
99+
))
100+
force = u2r(task[['SurfaceOrientationGuidanceVF_forceX0','SurfaceOrientationGuidanceVF_forceY0','SurfaceOrientationGuidanceVF_forceZ0']].rename(
101+
columns={'SurfaceOrientationGuidanceVF_forceX0':'X','SurfaceOrientationGuidanceVF_forceY0':'Y','SurfaceOrientationGuidanceVF_forceZ0':'Z'}
102+
))
103+
torque = u2r(task[['SurfaceOrientationGuidanceVF_torqueX0','SurfaceOrientationGuidanceVF_torqueY0','SurfaceOrientationGuidanceVF_torqueZ0']].rename(
104+
columns={'SurfaceOrientationGuidanceVF_torqueX0':'X','SurfaceOrientationGuidanceVF_torqueY0':'Y','SurfaceOrientationGuidanceVF_torqueZ0':'Z'}
105+
))
106+
107+
err = task['SurfaceOrientationGuidanceVF_dist0'].to_numpy()
108+
angle = task['SurfaceOrientationGuidanceVF_angle0'].to_numpy()
109+
time = task['Time'].to_numpy()
110+
111+
eval = dict()
112+
eval["subject"] = wd.split("\\")[-4][-1]
113+
eval["task"] = wd.split("\\")[-3]
114+
eval["repetition"] = wd.split("\\")[-2].split("_")[-1]
115+
eval["assisted"] = np.count_nonzero(task["Assisted"]) > 0.8*len(task)
116+
eval["assistance"] = np.mean(task["Assistance"])
117+
eval["time"] = time[-1]-time[0]
118+
eval["clutch_time"] = np.count_nonzero(task["Clutch"])/len(task)
119+
eval["avg_dist"] = rms(err)
120+
eval["avg_angle"] = rms(angle)
121+
eval["avg_force"] = rms(np.linalg.norm(force.to_numpy(),axis=1))
122+
eval["avg_torque"] = rms(np.linalg.norm(torque.to_numpy(),axis=1))
123+
eval_json = json.dumps(eval, indent=4)
124+
with open(wd+'_eval.json', 'w') as f:
125+
f.write(eval_json)
126+
127+
128+
fig = plt.figure(figsize=plt.figaspect(0.5))
129+
130+
axerr = fig.add_subplot(1,2,1,projection='3d'); clean_axes(axerr)
131+
plotPosDist(axerr,pos,err)
132+
plotObstacles(axerr, "C:\\Users\\alber\\Desktop\\Active_Constraints\\Assessment\\PlotSTLs\\"+wd.split("\\")[-3]+"stl","#42b9f5")
133+
centerandequal(axerr,pos)
134+
plt.title("D = "+str(eval['avg_dist']))
135+
136+
axforce = fig.add_subplot(1,2,2,projection='3d'); clean_axes(axforce)
137+
plotPosForce(axforce,pos,force['X']**2 + force['Y']**2 + force['Z']**2)
138+
plotObstacles(axforce, "C:\\Users\\alber\\Desktop\\Active_Constraints\\Assessment\\PlotSTLs\\"+wd.split("\\")[-3]+"stl","#42b9f5")
139+
centerandequal(axerr,pos)
140+
STRIDE = 5
141+
axforce.quiver(pos['X'].to_numpy()[::STRIDE], pos['Y'].to_numpy()[::STRIDE], pos['Z'].to_numpy()[::STRIDE],
142+
force['X'].to_numpy()[::STRIDE], force['Y'].to_numpy()[::STRIDE], force['Z'].to_numpy()[::STRIDE],
143+
color= "#0000ff",length=0.005,linewidth=0.5)
144+
plt.title("F = "+str(eval['avg_force']))
145+
146+
c1 = fig.canvas.mpl_connect('motion_notify_event', on_move)
147+
148+
plt.show()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@echo off
2+
"C:/Users/alber/AppData/Local/Programs/Python/Python39/python.exe" "%~dp0/LiverResection_post.py"
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import numpy as np
2+
import pandas as pd
3+
import os
4+
import json
5+
6+
def m4(m):
7+
m = np.concatenate((m, np.ones((np.shape(m)[0],1))),axis=1).transpose()
8+
return m
9+
10+
def u2r(df):
11+
dff=df.copy()
12+
dff['X'] = df['X']*(-1)
13+
dff['Y'] = df['Z']*(-1)
14+
dff['Z'] = df['Y']*(+1)
15+
return dff
16+
17+
def rms(data):
18+
return np.sqrt(np.mean(data**2))
19+
20+
wd = os.path.join(os.path.dirname(os.path.realpath(__file__)))
21+
wd = os.path.join(wd, os.path.basename(wd))
22+
23+
# ob0 = u2r(pd.read_csv(wd+'_obst0.csv'))
24+
task = pd.read_csv(wd+'_VFs.csv')
25+
pos = u2r(task[['PositionX','PositionY','PositionZ']].rename(
26+
columns={'PositionX':'X','PositionY':'Y','PositionZ':'Z'}
27+
))
28+
force = u2r(task[['SurfaceOrientationGuidanceVF_forceX0','SurfaceOrientationGuidanceVF_forceY0','SurfaceOrientationGuidanceVF_forceZ0']].rename(
29+
columns={'SurfaceOrientationGuidanceVF_forceX0':'X','SurfaceOrientationGuidanceVF_forceY0':'Y','SurfaceOrientationGuidanceVF_forceZ0':'Z'}
30+
))
31+
torque = u2r(task[['SurfaceOrientationGuidanceVF_torqueX0','SurfaceOrientationGuidanceVF_torqueY0','SurfaceOrientationGuidanceVF_torqueZ0']].rename(
32+
columns={'SurfaceOrientationGuidanceVF_torqueX0':'X','SurfaceOrientationGuidanceVF_torqueY0':'Y','SurfaceOrientationGuidanceVF_torqueZ0':'Z'}
33+
))
34+
35+
err = task['SurfaceOrientationGuidanceVF_dist0'].to_numpy()
36+
angle = task['SurfaceOrientationGuidanceVF_angle0'].to_numpy()
37+
time = task['Time'].to_numpy()
38+
39+
eval = dict()
40+
eval["subject"] = wd.split("\\")[-4][-1]
41+
eval["task"] = wd.split("\\")[-3]
42+
eval["repetition"] = wd.split("\\")[-2].split("_")[-1]
43+
eval["assisted"] = np.count_nonzero(task["Assisted"]) > 0.8*len(task)
44+
eval["assistance"] = np.mean(task["Assistance"])
45+
eval["time"] = time[-1]-time[0]
46+
eval["clutch_time"] = np.count_nonzero(task["Clutch"])/len(task)
47+
eval["avg_dist"] = rms(err)
48+
eval["avg_angle"] = rms(angle)
49+
eval["avg_force"] = rms(np.linalg.norm(force.to_numpy(),axis=1))
50+
eval["avg_torque"] = rms(np.linalg.norm(torque.to_numpy(),axis=1))
51+
eval_json = json.dumps(eval, indent=4)
52+
with open(wd+'_eval.json', 'w') as f:
53+
f.write(eval_json)
54+
55+
print(eval)
56+
print("> JSON written to dir: "+wd+'_eval.json\n')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
"C:/Users/alber/AppData/Local/Programs/Python/Python39/python.exe" "%~dp0/Nephrectomy_graph.py"
3+
pause
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import matplotlib.pyplot as plt
2+
import matplotlib as mpl
3+
mpl.rcParams.update(mpl.rcParamsDefault)
4+
import numpy as np
5+
from matplotlib import cm
6+
import pandas as pd
7+
from stl import mesh
8+
from mpl_toolkits import mplot3d
9+
import os
10+
import json
11+
12+
def m4(m):
13+
m = np.concatenate((m, np.ones((np.shape(m)[0],1))),axis=1).transpose()
14+
return m
15+
16+
def u2r(df):
17+
dff=df.copy()
18+
dff['X'] = df['X']*(-1)
19+
dff['Y'] = df['Z']*(-1)
20+
dff['Z'] = df['Y']*(+1)
21+
return dff
22+
23+
def plotPosDist(ax,pos,err):
24+
for i in range(np.shape(pos)[0]-1):
25+
ax.plot3D(pos.iloc[i:(i+2),0],pos.iloc[i:(i+2),1],pos.iloc[i:(i+2),2],
26+
c=cm.RdYlGn_r(err[i]/np.max(err)),
27+
linewidth=2
28+
)
29+
30+
def plotPosForce(ax,pos,force):
31+
for i in range(np.shape(pos)[0]-1):
32+
ax.plot3D(pos.iloc[i:(i+2),0],pos.iloc[i:(i+2),1],pos.iloc[i:(i+2),2],
33+
c=cm.RdYlGn_r(err[i]/np.max(force)),
34+
linewidth=2
35+
)
36+
37+
def plotObstacles(ax, path,c):
38+
for o in os.listdir(path):
39+
if o.endswith("_vertices.csv"):
40+
obv = u2r(pd.read_csv(os.path.join(path,o))).to_numpy()
41+
obt = pd.read_csv(os.path.join(path,o.split("_")[0]+"_triangulation.csv")).to_numpy()
42+
m = mesh.Mesh(np.zeros(obt.shape[0], dtype=mesh.Mesh.dtype))
43+
for i, f in enumerate(obt):
44+
for j in range(3):
45+
m.vectors[i][j] = obv[f[j],:]
46+
ax.add_collection3d(mplot3d.art3d.Poly3DCollection(m.vectors,alpha=0.05, ec=c,fc=c,linewidth=0.1))
47+
48+
def clean_axes(ax):
49+
ax.xaxis.pane.set_facecolor('w')
50+
ax.yaxis.pane.set_facecolor('w')
51+
ax.zaxis.pane.set_facecolor('w')
52+
ax.get_xaxis().set_ticklabels([])
53+
ax.get_yaxis().set_ticklabels([])
54+
ax.get_zaxis().set_ticklabels([])
55+
56+
def on_move(event):
57+
if event.inaxes == axerr:
58+
if axerr.button_pressed in axerr._rotate_btn:
59+
axforce.view_init(elev=axerr.elev, azim=axerr.azim)
60+
elif axerr.button_pressed in axerr._zoom_btn:
61+
axforce.set_xlim3d(axerr.get_xlim3d())
62+
axforce.set_ylim3d(axerr.get_ylim3d())
63+
axforce.set_zlim3d(axerr.get_zlim3d())
64+
elif event.inaxes == axforce:
65+
if axforce.button_pressed in axforce._rotate_btn:
66+
axerr.view_init(elev=axforce.elev, azim=axforce.azim)
67+
elif axforce.button_pressed in axforce._zoom_btn:
68+
axerr.set_xlim3d(axforce.get_xlim3d())
69+
axerr.set_ylim3d(axforce.get_ylim3d())
70+
axerr.set_zlim3d(axforce.get_zlim3d())
71+
else:
72+
return
73+
fig.canvas.draw_idle()
74+
75+
def centerandequal(ax,pos):
76+
xlim = [np.amin(pos.to_numpy()[:,0]), np.amax(pos.to_numpy()[:,0])]; xrange = xlim[1] - xlim[0]
77+
ylim = [np.amin(pos.to_numpy()[:,1]), np.amax(pos.to_numpy()[:,1])]; yrange = ylim[1] - ylim[0]
78+
zlim = [np.amin(pos.to_numpy()[:,2]), np.amax(pos.to_numpy()[:,2])]; zrange = zlim[1] - zlim[0]
79+
maxrange = max(xrange, yrange, zrange)
80+
BORDERS = 2
81+
ax.set_xlim3d([(xlim[0]+xlim[1])/2-maxrange/BORDERS,(xlim[0]+xlim[1])/2+maxrange/BORDERS])
82+
ax.set_ylim3d([(ylim[0]+ylim[1])/2-maxrange/BORDERS,(ylim[0]+ylim[1])/2+maxrange/BORDERS])
83+
ax.set_zlim3d([(zlim[0]+zlim[1])/2-maxrange/BORDERS,(zlim[0]+zlim[1])/2+maxrange/BORDERS])
84+
85+
wd = os.path.join(os.path.dirname(os.path.realpath(__file__)))
86+
wd = os.path.join(wd, os.path.basename(wd))
87+
88+
traj = u2r(pd.read_csv(wd+'_coneapproach0.csv'))
89+
task = pd.read_csv(wd+'_VFs.csv')
90+
pos = u2r(task[['PositionX','PositionY','PositionZ']].rename(
91+
columns={'PositionX':'X','PositionY':'Y','PositionZ':'Z'}
92+
))
93+
force = u2r(task[['ConeApproachGuidanceVF_forceX0','ConeApproachGuidanceVF_forceY0','ConeApproachGuidanceVF_forceZ0']].rename(
94+
columns={'ConeApproachGuidanceVF_forceX0':'X','ConeApproachGuidanceVF_forceY0':'Y','ConeApproachGuidanceVF_forceZ0':'Z'}
95+
))
96+
err = task['ConeApproachGuidanceVF_dist0'].to_numpy()
97+
time = task['Time'].to_numpy()
98+
99+
eval = dict()
100+
eval["subject"] = wd.split("\\")[-4][-1]
101+
eval["task"] = wd.split("\\")[-3]
102+
eval["repetition"] = wd.split("\\")[-2].split("_")[-1]
103+
eval["time"] = time[-1]-time[0]
104+
eval["avg_dist"] = np.mean(err)
105+
eval["avg_force"] = np.mean(np.linalg.norm(force.to_numpy(),axis=1))
106+
eval_json = json.dumps(eval, indent=4)
107+
with open(wd+'_eval.json', 'w') as f:
108+
f.write(eval_json)
109+
110+
fig = plt.figure(figsize=plt.figaspect(0.5))
111+
112+
axerr = fig.add_subplot(1,2,1,projection='3d'); clean_axes(axerr)
113+
plotPosDist(axerr,pos,err)
114+
axerr.plot(traj['X'].to_numpy(),traj['Y'].to_numpy(),traj['Z'].to_numpy(),color='#00aaff',linewidth=2)
115+
plotObstacles(axerr, "C:\\Users\\alber\\Desktop\\Active_Constraints\\Assessment\\PlotSTLs\\"+wd.split("\\")[-3]+"stl","#42b9f5")
116+
centerandequal(axerr,pos)
117+
plt.title("D = "+str(eval['avg_dist']))
118+
119+
axforce = fig.add_subplot(1,2,2,projection='3d'); clean_axes(axforce)
120+
plotPosForce(axforce,pos,force['X']**2 + force['Y']**2 + force['Z']**2)
121+
STRIDE = 5
122+
axforce.quiver(pos['X'].to_numpy()[::STRIDE], pos['Y'].to_numpy()[::STRIDE], pos['Z'].to_numpy()[::STRIDE],
123+
force['X'].to_numpy()[::STRIDE], force['Y'].to_numpy()[::STRIDE], force['Z'].to_numpy()[::STRIDE],
124+
color= "#0000ff",length=0.005,linewidth=0.5)
125+
axforce.plot(traj['X'].to_numpy(),traj['Y'].to_numpy(),traj['Z'].to_numpy(),color='#00aaff',linewidth=2)
126+
plotObstacles(axforce, "C:\\Users\\alber\\Desktop\\Active_Constraints\\Assessment\\PlotSTLs\\"+wd.split("\\")[-3]+"stl","#42b9f5")
127+
centerandequal(axforce,pos)
128+
plt.title("F = "+str(eval['avg_force']))
129+
130+
c1 = fig.canvas.mpl_connect('motion_notify_event', on_move)
131+
132+
plt.show()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@echo off
2+
"C:/Users/alber/AppData/Local/Programs/Python/Python39/python.exe" "%~dp0/Nephrectomy_post.py"

0 commit comments

Comments
 (0)