add dataset parsers

This commit is contained in:
Brian Delhaisse committed 2019-06-21 20:17:09 +02:00
1 parent 2598e973ab
commit 477c258cd7
20 files changed
+14147

No files matched your search

View File
Whitespace-only changes.
+54
View File
@@ -0,0 +1,54 @@
## 3D datasets
This repo contains a brief description of 3D datasets that I could find online. It also contains the Python code to load, parse, and plot some of these datasets.
### List of datasets
Here is a non-exhaustive list of datasets that could be used:
* [**TUM Kitchen**: "The TUM Kitchen Data Set of Everyday Manipulation Activities for Motion Tracking and Action Recognition", 2009](https://ias.in.tum.de/dokuwiki/software/kitchen-activity-data)
* scenarios: "everyday manipulation activities in a natural kitchen environment"
* labeled segmented data: 51 DOF articulated human model, 3D joint positions, videos and labels
* [**CMU-MMAC**: "Guide to the Carnegie Mellon University Multimodal Activity database", 2009](http://kitchen.cs.cmu.edu/)
* scenarios: human activity of subjects performing the tasks involved in cooking and food preparation
* [**HumanEva**: "HumanEva: Synchronized Video and Motion Capture Dataset and Baseline Algorithm for Evaluation of Articulated Human Motion", 2010](http://humaneva.is.tue.mpg.de/)
* 6 scenarios: walking, jogging, gesturing, throwing and catching a ball, boxing, combo (=walking+jogging+balancing)
* nb of subjects: 4
* data: 2D and 3D pose estimation
* [**MPII Cooking**: "A database for fine grained activity detection of cooking activities", 2012](https://www.mpi-inf.mpg.de/departments/computer-vision-and-multimodal-computing/research/human-activity-recognition/mpii-cooking-activities-dataset/)
<img src="figures/MPIICooking-comparison-datasets.png" alt="Datasets" style="width: 400px;"/>
* nb of subjects: 12
* 65 fine-grained cooking activities: background activity, change temperature, cut apart, cut dice, cut in, cut off ends, cut out inside, cut slices, cut stripes, dry, fill water from tap, grate, lid: put on, lid: remove, mix, move from X to Y, open egg, open tin, open/close cupboard, open/close drawer, open/close fridge, open/close oven, package X, peel, plug in/out, pour, pull out, puree, put in bowl, put in pan/pot, put on bread/dough, put on cutting-board, put on plate, read, remove from package, rip open, scratch off, screw close, screw open, shake, smell, spice, spread, squeeze, stamp, stir, strew, take & put in cupboard, take & put in drawer, take & put in fridge, take & put in oven, take & put in spice holder, take ingredient apart, take out from cupboard, take out from drawer, take out from fridge, take out from oven, take out from spice holder, taste, throw in garbage, unroll dough, wash hands, wash objects, whisk, wipe clean
* labeled and segmented data: 2D body joint positions
* [**J-HMDB**: "Joint-annotated Human Motion Data Base", 2013](http://jhmdb.is.tue.mpg.de/)
<img src="figures/JHMDB-comparison-datasets.png" alt="Datasets" style="width: 400px;"/>
* 21 scenarios: brush hair, catch, clap, climb stairs, golf, jump, kick ball, pick, pour, pull-up, push, run, shoot
ball, shoot bow, shoot gun, sit, stand, swing baseball, throw, walk, wave
* labeled and segmented data: 36-55 clips per action class with each clip containing 15-40 frames + 2D joint positions. 10 body parts connected by 13 joints (shoulder, elbow, wrist, hip, knee, ankle, neck) and two landmarks (face and belly).
* [**Human 3.6M**: "Human3.6M: Large Scale Datasets and Predictive Methods for 3D Human Sensing in Natural Environments", 2014](http://vision.imar.ro/human3.6m/description.php)
* 3.6 million 3D human poses and corresponding images
* nb of subjects: 11
* 15 scenarios: direction, discussion, eating, activitie while seated, greeting, taking photo, posing, making purchases, smoking, waiting, walking, sitting on chair, talking on the phone, walking dog, walking together
* data: 3D joint positions and joint angles
* [**UTD-MHAD**: "UTD-MHAD: A Multimodal Dataset for Human Action Recognition utilizing a Depth Camera and a Wearable Inertial Sensor", 2015](http://www.utdallas.edu/~kehtar/UTD-MHAD.html)
* nb of subjects: 8
* 27 different actions: (1) right arm swipe to the left, (2) right arm swipe to the right, (3) right hand wave, (4) two hand front clap, (5) right arm throw, (6) cross arms in the chest, (7) basketball shoot, (8) right hand draw x, (9) right hand draw circle (clockwise), (10) right hand draw circle (counter clockwise), (11) draw triangle, (12) bowling (right hand), (13) front boxing, (14) baseball swing from right, (15) tennis right hand forehand swing, (16) arm curl (two arms), (17) tennis serve, (18) two hand push, (19) right hand knock on door, (20) right hand catch an object, (21) right hand pick up and throw, (22) jogging in place, (23) walking in place, (24) sit to stand, (25) stand to sit, (26) forward lunge (left foot forward), (27) squat (two arms stretch out).
* labeled and segmented data: 861 data sequences, 3D skeleton joint positions
* [**G3D**: "G3D: A Gaming Action Dataset and Real Time Action Recognition Evaluation Framework", 2012](http://dipersec.king.ac.uk/G3D/index.html)
* nb of subjects: 10
* 20 gaming actions: punch right, punch left, kick right, kick left, defend, golf swing, tennis swing forehand, tennis swing backhand, tennis serve, throw bowling ball, aim and fire gun, walk, run, jump, climb, crouch, steer a car, wave, flap and clap
* data: 3D joint positions
* [**CMU-Datasets**](mocap.cs.cmu.edu/search.php)
* dataset: very diverse, contains data such as sport activities (soccer, dancing, etc), everyday movements/activities, locomotion (walk/run, jump, etc), interaction with environment and other agents, human subjects imitating animal behaviors (such as snake, dog, chicken, etc), stretching, finegrained movements, and so on.
* data: 3D joint positions and videos.
* Others: MSRC-12 Kinect Gesture Datase, MPI HDM05 Motion Capture Database, MSR Action3D Database, VGG Human Pose Estimation datasets, etc.
### Python Code
The python code to load, parse, and plot (using animations) has been implemented for the following datasets:
* UTD-MHAD: see `utd-mhad.ipynb`
* CMU-Datasets: see `cmu.ipynb`
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,338 @@
# AST/ASF file generated using VICON BodyLanguage
# -----------------------------------------------
:version 1.10
:name VICON
:units
mass 1.0
length 0.45
angle deg
:documentation
.ast/.asf automatically generated from VICON data using
VICON BodyBuilder and BodyLanguage model FoxedUp or BRILLIANT.MOD
:root
order TX TY TZ RX RY RZ
axis XYZ
position 0 0 0
orientation 0 0 0
:bonedata
begin
id 1
name lhipjoint
direction 0.655637 -0.713449 0.247245
length 2.52691
axis 0 0 0 XYZ
end
begin
id 2
name lfemur
direction 0.34202 -0.939693 0
length 7.59371
axis 0 0 20 XYZ
dof rx ry rz
limits (-160.0 20.0)
(-70.0 70.0)
(-60.0 70.0)
end
begin
id 3
name ltibia
direction 0.34202 -0.939693 0
length 7.28717
axis 0 0 20 XYZ
dof rx
limits (-10.0 170.0)
end
begin
id 4
name lfoot
direction 0.0886837 -0.243657 0.965798
length 2.2218
axis -90 7.62852e-016 20 XYZ
dof rx rz
limits (-45.0 90.0)
(-70.0 20.0)
end
begin
id 5
name ltoes
direction 1.53547e-011 -4.22004e-011 1
length 1.11249
axis -90 7.62852e-016 20 XYZ
dof rx
limits (-90.0 20.0)
end
begin
id 6
name rhipjoint
direction -0.645062 -0.722004 0.250209
length 2.49697
axis 0 0 0 XYZ
end
begin
id 7
name rfemur
direction -0.34202 -0.939693 0
length 7.58734
axis 0 0 -20 XYZ
dof rx ry rz
limits (-160.0 20.0)
(-70.0 70.0)
(-70.0 60.0)
end
begin
id 8
name rtibia
direction -0.34202 -0.939693 0
length 7.21538
axis 0 0 -20 XYZ
dof rx
limits (-10.0 170.0)
end
begin
id 9
name rfoot
direction -0.102907 -0.282735 0.953662
length 2.23735
axis -90 -7.62852e-016 -20 XYZ
dof rx rz
limits (-45.0 90.0)
(-20.0 70.0)
end
begin
id 10
name rtoes
direction -1.5354e-011 -4.21751e-011 1
length 1.11569
axis -90 -7.62852e-016 -20 XYZ
dof rx
limits (-90.0 20.0)
end
begin
id 11
name lowerback
direction 0.00952301 0.997604 -0.0685217
length 2.05943
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 12
name upperback
direction 0.00494399 0.999577 -0.0286701
length 2.06523
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 13
name thorax
direction 0.000729686 0.999992 0.00388603
length 2.06807
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 14
name lowerneck
direction 0.00452882 0.995459 0.0950816
length 1.57426
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 15
name upperneck
direction 0.021922 0.997711 -0.0639762
length 1.56399
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 16
name head
direction 0.008024 0.999444 -0.0323691
length 1.6265
axis 0 0 0 XYZ
dof rx ry rz
limits (-20.0 45.0)
(-30.0 30.0)
(-30.0 30.0)
end
begin
id 17
name lclavicle
direction 0.967826 0.247107 -0.0474446
length 3.6598
axis 0 0 0 XYZ
dof ry rz
limits (-20.0 10.0)
(0.0 20.0)
end
begin
id 18
name lhumerus
direction 1 -4.48971e-011 -2.90544e-027
length 4.86513
axis 180 -30 -90 XYZ
dof rx ry rz
limits (-60.0 90.0)
(-90.0 90.0)
(-90.0 90.0)
end
begin
id 19
name lradius
direction 1 -4.48958e-011 1.79638e-026
length 3.35554
axis 180 -30 -90 XYZ
dof rx
limits (-10.0 170.0)
end
begin
id 20
name lwrist
direction 1 -4.48952e-011 3.34345e-026
length 1.67777
axis -2.22354e-014 90 90 XYZ
dof ry
limits (-180.0 0.0)
end
begin
id 21
name lhand
direction 1 -4.49055e-011 6.6869e-026
length 0.661175
axis -4.26681e-014 90 90 XYZ
dof rx rz
limits (-90.0 90.0)
(-45.0 45.0)
end
begin
id 22
name lfingers
direction 1 -4.48731e-011 1.33738e-025
length 0.533057
axis -8.53362e-014 90 90 XYZ
dof rx
limits (0.0 90.0)
end
begin
id 23
name lthumb
direction 0.707107 -6.35005e-011 0.707107
length 0.765366
axis -90 45 2.85299e-015 XYZ
dof rx rz
limits (-45.0 45.0)
(-45.0 45.0)
end
begin
id 24
name rclavicle
direction -0.973174 0.211421 -0.0907389
length 3.59444
axis 0 0 0 XYZ
dof ry rz
limits (-10.0 20.0)
(-20.0 0.0)
end
begin
id 25
name rhumerus
direction -1 -4.48964e-011 1.56311e-027
length 5.02649
axis 180 30 90 XYZ
dof rx ry rz
limits (-90.0 60.0)
(-90.0 90.0)
(-90.0 90.0)
end
begin
id 26
name rradius
direction -1 -4.48948e-011 2.01724e-026
length 3.36431
axis 180 30 90 XYZ
dof rx
limits (-10.0 170.0)
end
begin
id 27
name rwrist
direction -1 -4.49008e-011 3.34345e-026
length 1.68216
axis -2.22354e-014 -90 -90 XYZ
dof ry
limits (-180.0 0.0)
end
begin
id 28
name rhand
direction -1 -4.49013e-011 6.6869e-026
length 0.730406
axis -4.26681e-014 -90 -90 XYZ
dof rx rz
limits (-90.0 90.0)
(-45.0 45.0)
end
begin
id 29
name rfingers
direction -1 -4.48867e-011 1.33738e-025
length 0.588872
axis -8.53362e-014 -90 -90 XYZ
dof rx
limits (0.0 90.0)
end
begin
id 30
name rthumb
direction -0.707107 -6.34907e-011 0.707107
length 0.845506
axis -90 -45 -2.85299e-015 XYZ
dof rx rz
limits (-45.0 45.0)
(-45.0 45.0)
end
:hierarchy
begin
root lhipjoint rhipjoint lowerback
lhipjoint lfemur
lfemur ltibia
ltibia lfoot
lfoot ltoes
rhipjoint rfemur
rfemur rtibia
rtibia rfoot
rfoot rtoes
lowerback upperback
upperback thorax
thorax lowerneck lclavicle rclavicle
lowerneck upperneck
upperneck head
lclavicle lhumerus
lhumerus lradius
lradius lwrist
lwrist lhand lthumb
lhand lfingers
rclavicle rhumerus
rhumerus rradius
rradius rwrist
rwrist rhand rthumb
rhand rfingers
end
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,3 @@
# CMU Dataset
* webpage (link to download the dataset): mocap.cs.cmu.edu/search.php
@@ -0,0 +1,15 @@
Subject #2 (various expressions and human behaviors)
02_01 02_01.tvd 02_01.c3d 02_01.amc 02_01.avi walk
02_02 02_02.tvd 02_02.c3d 02_02.amc 02_02.mpg 02_02.avi walk
02_03 02_03.tvd 02_03.c3d 02_03.amc 02_03.mpg 02_03.avi run/jog
02_04 02_04.tvd 02_04.c3d 02_04.amc 02_04.mpg 02_04.avi jump, balance
02_05 02_05.tvd 02_05.c3d 02_05.amc 02_05.mpg 02_05.avi punch/strike
02_06 02_06.tvd 02_06.c3d 02_06.amc 02_06.mpg 02_06.avi bend over, scoop up, rise, lift arm
02_07 02_07.tvd 02_07.c3d 02_07.amc 02_07.mpg 02_07.avi swordplay
02_08 02_08.tvd 02_08.c3d 02_08.amc 02_08.mpg 02_08.avi swordplay
02_09 02_09.tvd 02_09.c3d 02_09.amc 02_09.mpg 02_09.avi swordplay
02_10 02_10.tvd 02_10.c3d 02_10.amc 02_10.mpg 02_10.avi wash self
@@ -0,0 +1,24 @@
The skeleton joint order in UTD-MAD dataset:
1. head;
2. shoulder_center;
3. spine;
4. hip_center;
5. left_shoulder;
6. left_elbow;
7. left_wrist;
8. left_hand;
9. right_shoulder;
10. right_elbow;
11. right_wrist;
12. right_hand;
13. left_hip;
14. left_knee;
15. left_ankle;
16. left_foot;
17. right_hip;
18. right_knee;
19. right_ankle;
20. right_foot;
Each skeleton data is a 20 x 3 x num_frame matrix. Each row of a skeleton frame corresponds to three spatial coordinates of a joint.
@@ -0,0 +1,3 @@
# UTD-MHAD Dataset
* webpage (link to download the dataset): http://www.utdallas.edu/~kehtar/UTD-MHAD.html
Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

@@ -0,0 +1,230 @@
import numpy as np
from scipy.interpolate import CubicSpline
import matplotlib.pyplot as plt
class MocapParser(object):
def __init__(self, filename):
"""
Parser for motion capture. By default, if the data is described in Cartesian space, the x-axis should
be pointing in front of the human, the y-axis on his/her left, and z-axis upward.
:param filename:
"""
self.filename = filename
self.num_samples = 0
self.joint_names = []
self.link_names = []
self.marker_names = []
self.data = self.loadFile(filename)
def loadFile(self, filename):
raise NotImplementedError("loadFile is not implemented.")
def interpolate(self, data, method='cubic', axis=-1)
"""
Interpolate the Mocap data such that it is between 0 and 1, along the given axis.
:param data: mocap data
:param method: 'linear', 'cubic', 'hermite' interpolation
:param axis: The axis on which to interpolate. The length should be equal to the number of samples in the
mocap data
:return: Interpolator - function that given the time [0,1] will give the corresponding data
"""
self.num_samples = data.shape[axis]
x = np.linspace(0., 1., self.num_samples)
interpolator = CubicSpline(x, self.data, axis=axis)
return interpolator
def getMarkerName(self, marker_idx=None):
if marker_idx is None:
return self.getMarkerNames()
else:
return self.marker_names[marker_idx]
def getMarkerNames(self):
return self.marker_names
def getJointName(self, joint_idx=None):
if joint_idx is None:
return self.getJointNames()
else:
return self.joint_names[joint_idx]
def getJointNames(self):
return self.joint_names
def getLinkName(self, link_idx=None):
if link_idx is None:
return self.getLinkNames()
else:
return self.link_names[link_idx]
def getLinkNames(self):
return self.link_names
def getMarkerPosition(self, marker_idx=None):
if marker_idx is None:
return self.getMarkerPositions()
else:
pass
def getMarkerPositions(self):
pass
def getJointPosition(self, joint_idx=None):
if joint_idx is None:
return self.getJointPositions()
else:
pass
def getJointPositions(self):
pass
def getJointVelocity(self, joint_idx=None):
if joint_idx is None:
return self.getJointVelocities()
else:
pass
def getJointVelocities(self):
pass
def getLinkPosition(self, link_idx=None):
if link_idx is None:
return self.getLinkPositions()
else:
pass
def getLinkPositions(self):
pass
def getLinkVelocity(self, link_idx=None):
if link_idx is None:
return self.getLinkVelocities()
else:
pass
def getLinkVelocities(self):
pass
def getLinkOrientation(self, link_idx=None):
if link_idx is None:
return self.getLinkOrientations()
else:
pass
def getLinkOrientations(self):
pass
def getLinkAngularVelocity(self, link_idx=None):
if link_idx is None:
return self.getLinkAngularVelocities()
else:
pass
def getLinkAngularVelocities(self):
pass
## Plotting ##
def plot3d(self, ax=None):
pass
def plotJointProfile(self, ax=None, joint_idx=None, pos=True, vel=True, acc=True):
pass
def plotLinkProfile(self, ax=None, link_idx=None, pos=True, vel=True, acc=True, wrt='world'):
pass
def plotMarkerProfile(self, ax=None, link_idx=None, pos=True, vel=True, acc=True, wrt='world'):
pass
def animate3d(self, ax=None, title=None):
pass
from amcparser.skeleton import Skeleton
from amcparser.motion import SkelMotion
class CMUMocapParser(MocapParser):
def __init__(self, skeleton_filename, motion_filename, skeleton_scale=1.0):
super(CMUMocapParser, self).__init__(motion_filename)
self.joint_names = ['head', 'upperneck', 'lowerneck', 'upperback', 'thorax', 'lowerback', 'root', # Spine
'rclavicle', 'rhumerus', 'rradius', 'rwrist', 'rhand', 'rthumb', 'rfingers', # Right arm
'lclavicle', 'lhumerus', 'lradius', 'lwrist', 'lhand', 'lthumb', 'lfingers', # Left arm
'rhipjoint', 'rfemur', 'rtibia', 'rfoot', 'rtoes', # Right leg
'lhipjoint', 'lfemur', 'ltibia', 'lfoot', 'ltoes'] # Left leg
self.link_names = self.joint_names
self.marker_names = self.joint_names
self.base_name = 'root'
# Load skeleton
self.skeleton = Skeleton(skeleton_filename, scale=skeleton_scale)
def loadFile(self, filename, framerate=120.):
self.skeleton_motion = SkelMotion(self.skeleton, filename, (1./framerate))
# compute trajectories
#self.data = self.skeleton_motion.traverse(bone, start, end)
self.data = self.skeleton_motion.traverse(None, 0, -1)
# make sure that given axis
def animate3d(self, ax=None, title=None):
if ax is None:
fig = plt.figure()
ax = fig.gca(projection='3d')
# Rescaling such that the skeleton it is in the right proportion and at the middle
xmin, xmax = X[..., 2].min(), X[..., 2].max()
ymin, ymax = X[..., 0].min(), X[..., 0].max()
zmin, zmax = X[..., 1].min(), X[..., 1].max()
x_len, y_len, z_len = (xmax - xmin), (ymax - ymin), (zmax - zmin)
max_len = max([x_len, y_len, z_len])
xmin, xmax = xmin + (x_len - max_len) / 2., xmin + (x_len + max_len) / 2.
ymin, ymax = ymin + (y_len - max_len) / 2., ymin + (y_len + max_len) / 2.
zmin, zmax = zmin + (z_len - max_len) / 2., zmin + (z_len + max_len) / 2.
# Plot trajectories
x, y, z = skel.bones['rhand'].xyz_data.T
T = len(x)
def init():
ax.set_title('movement')
ax.set_xlabel('x')
ax.set_xlim(xmin, xmax)
ax.set_ylabel('y')
ax.set_ylim(ymin, ymax)
ax.set_zlabel('z')
ax.set_zlim(zmin, zmax)
# ax.scatter(x[0], y[0], z[0], marker='o')
return fig,
def animate(i):
# ax.view_init(elev=10., azim=i)
ax.scatter(x[i], y[i], z[i], marker='o')
return fig,
def animate_skeleton(i):
ax.clear()
init()
# ax.scatter(X[:,2,i], X[:,0,i], X[:,1,i], marker='o', c='b')
for d in [X_TO, X_RA, X_LA, X_RL, X_LL]:
ax.plot(d[:, i, 2], d[:, i, 0], d[:, i, 1], marker='o', c='b')
return [fig] # fig,
# Animate
# anim = animation.FuncAnimation(fig, animate, init_func=init,
# frames=T, interval=20, blit=True)
anim = animation.FuncAnimation(fig, animate_skeleton, init_func=init,
frames=T, interval=20, blit=False)
plt.show()
# Test
if __name__ == "__main__":
pass
@@ -0,0 +1,967 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### [UTD-MHAD: \"UTD-MHAD: A Multimodal Dataset for Human Action Recognition utilizing a Depth Camera and a Wearable Inertial Sensor\", 2015](http://www.utdallas.edu/~kehtar/UTD-MHAD.html)\n",
"\n",
"* nb of subjects: 8\n",
"* 27 different actions: (1) right arm swipe to the left, (2) right arm swipe to the right, (3) right hand wave, (4) two hand front clap, (5) right arm throw, (6) cross arms in the chest, (7) basketball shoot, (8) right hand draw x, (9) right hand draw circle (clockwise), (10) right hand draw circle (counter clockwise), (11) draw triangle, (12) bowling (right hand), (13) front boxing, (14) baseball swing from right, (15) tennis right hand forehand swing, (16) arm curl (two arms), (17) tennis serve, (18) two hand push, (19) right hand knock on door, (20) right hand catch an object, (21) right hand pick up and throw, (22) jogging in place, (23) walking in place, (24) sit to stand, (25) stand to sit, (26) forward lunge (left foot forward), (27) squat (two arms stretch out).\n",
"* labeled and segmented data: 861 data sequences, 3D skeleton joint positions"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import scipy.io as sio\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from mpl_toolkits.mplot3d import Axes3D\n",
"import matplotlib.animation as animation\n",
"import glob\n",
"import re\n",
"\n",
"from IPython.display import HTML\n",
"\n",
"#%matplotlib inline\n",
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"PATH = 'data/UTD/*.mat'"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Nb of demos: 861\n",
"Min T: 41\n",
"Max T: 125\n"
]
}
],
"source": [
"# Definition of some variables\n",
"id_to_jnt = ['head', 'shoulder_center', 'spine', 'hip_center', 'left_shoulder', 'left_elbow', 'left_wrist',\n",
" 'left_hand', 'right_shoulder', 'right_elbow', 'right_wrist', 'right_hand', 'left_hip', 'left_knee',\n",
" 'left_ankle', 'left_foot', 'right_hip', 'right_knee', 'right_ankle', 'right_foot']\n",
"jnt_to_id = {name: idx for idx,name in enumerate(id_to_jnt)}\n",
"id_to_action = ['Swipe left', 'Swipe right', 'Wave', 'Clap', 'Throw', 'Arm cross', 'Basketball shoot', \n",
" 'Draw X', 'Draw circle (clockwise)', 'Draw circle (counter clockwise)',\n",
" 'Draw triangle', 'Bowling', 'Boxing', 'Baseball swing', 'Tennis swing',\n",
" 'Arm curl', 'Tennis serve', 'Push', 'Knock', 'Catch', 'Pickup and throw',\n",
" 'Jog', 'Walk', 'Sit to stand', 'Stand to sit', 'Lunge', 'Squat']\n",
"action_to_id = {name: idx for idx,name in enumerate(id_to_action)}\n",
"Nj = len(id_to_jnt) # 20\n",
"\n",
"# Load all the data\n",
"files = glob.glob(PATH)\n",
"data = [sio.loadmat(f)['d_skel'] for f in files] # list of shape Njx3xT\n",
"N = len(data)\n",
"print(\"Nb of demos: %d\" % len(data))\n",
"Ts = np.array([d.shape[2] for d in data])\n",
"print(\"Min T: %d\" % np.min(Ts))\n",
"print(\"Max T: %d\" % np.max(Ts))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width);\n",
" canvas.attr('height', height);\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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 truncated
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Select a sequence\n",
"idx = np.random.randint(0, N)\n",
"X = np.copy(data[idx])\n",
"T = X.shape[2]\n",
"title_idx = int(re.findall(r'a[0-9]+', files[idx])[0][1:]) - 1\n",
"\n",
"# Get trajectory of one end-effector (x,y,z)\n",
"#x,y,z = X[jnt_to_id['right_wrist']] # left_arm\n",
"#x,y,z = z,x,y\n",
"#T = len(x)\n",
"\n",
"# Rescaling such that the skeleton it is in the right proportion and at the middle\n",
"xmin, xmax = X[:,2].min(), X[:,2].max()\n",
"ymin, ymax = X[:,0].min(), X[:,0].max()\n",
"zmin, zmax = X[:,1].min(), X[:,1].max()\n",
"x_len, y_len, z_len = (xmax - xmin), (ymax - ymin), (zmax - zmin)\n",
"max_len = max([x_len, y_len, z_len])\n",
"xmin, xmax = xmin + (x_len - max_len)/2., xmin + (x_len + max_len)/2.\n",
"ymin, ymax = ymin + (y_len - max_len)/2., ymin + (y_len + max_len)/2.\n",
"zmin, zmax = zmin + (z_len - max_len)/2., zmin + (z_len + max_len)/2.\n",
"\n",
"# Plot trajectory\n",
"fig = plt.figure()\n",
"ax = fig.gca(projection='3d')\n",
"\n",
"def init():\n",
" ax.set_title(id_to_action[title_idx])\n",
" ax.set_xlabel('x')\n",
" #ax.set_xlim(xmin, xmax)\n",
" ax.set_xlim(-xmax, -xmin)\n",
" ax.set_ylabel('y')\n",
" ax.set_ylim(ymin, ymax)\n",
" ax.set_zlabel('z')\n",
" ax.set_zlim(zmin, zmax)\n",
" #ax.scatter(x[0], y[0], z[0], marker='o')\n",
" return fig,\n",
"\n",
"def animate(i):\n",
" #ax.view_init(elev=10., azim=i)\n",
" ax.scatter(-x[i], y[i], z[i], marker='o')\n",
" return fig,\n",
" \n",
"def animate_skeleton(i):\n",
" ax.clear()\n",
" init()\n",
" #ax.scatter(X[:,2,i], X[:,0,i], X[:,1,i], marker='o', c='b')\n",
" for j in range(0,20,4):\n",
" ax.plot(-X[j:j+4,2,i], X[j:j+4,0,i], X[j:j+4,1,i], marker='o', c='b')\n",
" return fig,\n",
" \n",
"\n",
"# Animate\n",
"#anim = animation.FuncAnimation(fig, animate, init_func=init,\n",
"# frames=T, interval=20, blit=True)\n",
"anim = animation.FuncAnimation(fig, animate_skeleton, init_func=init,\n",
" frames=T, interval=20, blit=True)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# create video with HTML\n",
"#HTML(anim.to_html5_video())"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
@@ -0,0 +1,4 @@
# HWRT Database of Handwritten symbols
* webpage: www.martin-thoma.de/write-math/data/
* link to download the dataset: i13pc106.ira.uka.de/~mthoma/hwrt/2015-01-28-data.tar
@@ -0,0 +1,7 @@
# IAM Online Handwriting Database
* webpage: www.fki.inf.unibe.ch/databases/iam-on-line-handwriting-database
* link to download the dataset: http://www.fki.inf.unibe.ch/databases/iam-on-line-handwriting-database/download-the-iam-on-line-handwriting-database
Note that you need to register in order to download the datasets.
@@ -0,0 +1,5 @@
# ICDAR2013 - Handwriting Stroke Recovery from Offline Data (Kaggle)
* webpage: https://www.kaggle.com/c/icdar2013-stroke-recovery-from-offline-data
* link to download the dataset: https://www.kaggle.com/c/icdar2013-stroke-recovery-from-offline-data/data
@@ -0,0 +1,38 @@
## Online Handwritten Datasets
This repo contains the python code to load, parse and plot online handwritten characters.
In this folder, I focus on the following datasets:
1. Character Trajectories Data Set (2,858): https://archive.ics.uci.edu/ml/datasets/Character+Trajectories
2. UJI Pen Characters (V2) Data Set (11,640): archive.ics.uci.edu/ml/datasets/UJI+Pen+Characters+(Version+2)
3. HWRT Database of Handwritten symbols: www.martin-thoma.de/write-math/data/
4. ICDAR2013 - Handwriting Stroke Recovery from Offline Data (Kaggle): https://www.kaggle.com/c/icdar2013-stroke-recovery-from-offline-data
5. IAM Online Handwriting Database: www.fki.inf.unibe.ch/databases/iam-on-line-handwriting-database
There are of course other datasets (mostly offline) that could be used such as:
* MNIST dataset (Offline)
* NIST Handprinted Forms and Characters Database (Offline)
* The IRESTE On/Off Dual Handwriting Database (75€): www.irccyn.ec-nantes.fr/~viardgau/IRONOFF/ICDAR99.htm
* UCI online datasets:
* Online Handwritten Assamese Characters Dataset (8,235): archive.ics.uci.edu/ml/datasets/Online+Handwritten+Assamese+Characters+Dataset
* Pen-Based Recognition of Handwritten Digits Dataset (10,992): archive.ics.uci.edu/ml/datasets/Pen-Based+Recognition+of+Handwritten+Digits
* CASIA online and offline chinese handwriting Databases: www.nlpr.ia.ac.cn/databases/handwriting/Online_database.html
* CEDAR Handwriting (Offline)
## How to use it?
The whole python code to load and parse the different datasets is inside the jupyter notebook `handwritten-data.ipynb`. To open the jupyter notebook, you will first need to install jupyter. For each dataset, I plotted 25 random samples to give you a general feeling about the dataset. You will need to download the dataset that you which to use (and put it in the corresponding folder if you do not wish to modify the python code).
## FAQs
* What is the meaning of 'online'? Online in this case means that you also have the trajectories (x,y), while offline would mean that you only have pictures of handwritten characters/words/sentences.
* Do I need to cite the dataset that I am using? Yes, you should cite the corresponding paper which can usually be found on the website where you downloaded the dataset.
* For what can I use these datasets? Mostly for demonstration / supervised learning. You could, for instance, use one of the following models to learn the trajectories: Gaussian Processes, Gaussian Mixture Models, Hidden Markov Models, (Deep) Neural Networks, Dynamic Movement Primitives, etc.
@@ -0,0 +1,5 @@
# Character Trajectories Data Set
* webpage: https://archive.ics.uci.edu/ml/datasets/Character+Trajectories
* link to download the dataset: https://archive.ics.uci.edu/ml/machine-learning-databases/character-trajectories/
@@ -0,0 +1,4 @@
# UJI Pen Characters (V2) Data Set
* webpage: archive.ics.uci.edu/ml/datasets/UJI+Pen+Characters+(Version+2)
* link to download the dataset: http://archive.ics.uci.edu/ml/machine-learning-databases/uji-penchars/version2/
@@ -0,0 +1,388 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Online Handwritten Datasets\n",
"\n",
"### Table of Contents\n",
"\n",
"1. [UCI - Character Trajectories Data Set](#uci-character)\n",
"2. [UCI - UJI Pen Characters (V2) Data Set](#uci-ujipen)\n",
"3. [HWRT Database of Handwritten symbols](#hwrt)\n",
"4. [ICDAR2013 - Handwriting Stroke Recovery from Offline Data (Kaggle)](#kaggle)\n",
"5. [IAM Online Handwriting Database](#IAMonline)"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"import scipy.io\n",
"from scipy import misc\n",
"from ast import literal_eval\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [UCI - Character Trajectories Data Set](https://archive.ics.uci.edu/ml/datasets/Character+Trajectories ) <a id='uci-character'></a>\n",
"\n",
"* Size: 2,858\n",
"* Short description: single stroke trajectories sampled at 200Hz."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3bdecd590>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"uci_char_path = 'UCI-Character-Trajectories/mixoutALL_shifted.mat'\n",
"\n",
"# Load the data\n",
"uci_char = scipy.io.loadmat(uci_char_path)\n",
"#print(uci_char.keys()) # ['mixout', '__version__', '__header__', 'consts', '__globals__']\n",
"N = uci_char['mixout'].shape[1]\n",
"uci_char = uci_char['mixout'][0]\n",
"\n",
"# Get a list of (x,y) for each data\n",
"data = []\n",
"for ex in uci_char:\n",
" x = [ex[0,i] for i,force_value in enumerate(ex[2]) if force_value != 0.0]\n",
" y = [ex[1,i] for i,force_value in enumerate(ex[2]) if force_value != 0.0]\n",
" data.append(np.array([x,y]))\n",
"\n",
"# Choose randomly 25 characters and plot them\n",
"idx = np.random.choice(N, 25, replace=False)\n",
"data = [data[i] for i in idx]\n",
"plt.figure(figsize=(8,8))\n",
"for i,d in enumerate(data):\n",
" plt.subplot(5,5,i+1)\n",
" plt.axis('off')\n",
" plt.plot(d[0], d[1])\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [UCI - UJI Pen Characters (V2) Data Set](archive.ics.uci.edu/ml/datasets/UJI+Pen+Characters+(Version+2)) <a id='uci-ujipen'></a>\n",
"\n",
"* Size: 11,640 (Single stroke = 5,973)\n",
"* Short description: Single and multi-stroke characters and digits"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3bab85b90>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ujipen_path = 'UCI-Ujipen-Chars2/ujipenchars2.txt'\n",
"\n",
"# Load and parse the data\n",
"num_stroke = 0\n",
"data = []\n",
"with open(ujipen_path, 'rb') as f:\n",
" for line in f.readlines():\n",
" line = line.strip() # remove extra space before and after the sentence\n",
" if not line.startswith('//'): # Not a comment\n",
" if line.startswith('NUMSTROKES'): # check the nb of strokes\n",
" num_stroke = int(line[-1])\n",
" elif line.startswith('POINTS') and num_stroke == 1: # only keep single stroke characters\n",
" hash_idx = line.find('#')\n",
" coord = map(int, line[hash_idx+2:].split())\n",
" x = coord[::2]\n",
" y = coord[1::2]\n",
" data.append(np.array([x,y]))\n",
"\n",
"#print(len(data))\n",
"\n",
"# Choose randomly 25 characters and plot them\n",
"idx = np.random.choice(len(data), 25, replace=False)\n",
"data = [data[i] for i in idx]\n",
"plt.figure(figsize=(8,8))\n",
"for i,d in enumerate(data):\n",
" plt.subplot(5,5,i+1)\n",
" plt.axis('off')\n",
" plt.plot(d[0], d[1][::-1]) # note that the y coordinates goes from 'up' to 'bottom'\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [HWRT Database of Handwritten symbols](www.martin-thoma.de/write-math/data/) <a id='hwrt'></a>\n",
"\n",
"* Size: 151,160 (training data), 17,075 (test data)\n",
"* Short description: \"on-line data of handwritten symbols such as all alphanumeric characters, arrows, greek characters and mathematical symbols like the integral symbol\"\n",
"* Note: this dataset contains single and multiple strokes characters."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false,
"scrolled": true
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3bbd75f10>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"hwrt_path = 'HWRT/train-data.csv'\n",
"#hwrt_path = 'HWRT/test-data.csv'\n",
"\n",
"# Read the csv file. WARNING: do not load the whole file!\n",
"# Header: symbol_id; user_id; data; user_agent\n",
"data = pd.read_csv(hwrt_path, sep=';', quotechar=\"'\", index_col=False, skiprows=0, nrows=2000)\n",
"# transform the string '[[{},{}]]' into a list of list of dict\n",
"data.data = data.data.apply(literal_eval)\n",
"\n",
"# Get a list of (x,y) for each data\n",
"xy = []\n",
"for i,ex in enumerate(data['data']):\n",
" if len(ex) == 1: # single stroke\n",
" x = [dic['x'] for dic in ex[0]]\n",
" y = [dic['y'] for dic in ex[0]]\n",
" xy.append([x,y])\n",
"\n",
"# Choose randomly 25 characters and plot them\n",
"idx = np.random.choice(len(xy), 25, replace=False)\n",
"xy = [xy[i] for i in idx]\n",
"plt.figure(figsize=(8,8))\n",
"for i,d in enumerate(xy):\n",
" plt.subplot(5,5,i+1)\n",
" plt.axis('off')\n",
" plt.plot(d[0], d[1][::-1])\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [ICDAR2013 - Handwriting Stroke Recovery from Offline Data (Kaggle)](https://www.kaggle.com/c/icdar2013-stroke-recovery-from-offline-data) <a id='kaggle'></a>\n",
"\n",
"* Size: 1,081 (training: 605, test: 476)\n",
"* Short description: \"the data consists of 1,081 (arabic) signatures of 200 writers\""
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3bac78790>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3b2673d90>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"icdar_traj_path = 'ICDAR2013/train.csv' # normalized data (0,1)\n",
"#icdar_traj_path = 'ICDAR2013/unnormalized_data.csv' # unnormalized data\n",
"icdar_img_path = 'ICDAR2013/images-handwritten/'\n",
"\n",
"# Read the csv file. WARNING: do not load the whole file!\n",
"# Header: train_id, signature_id, writer_id, occurence_id, time, x, y\n",
"data = pd.read_csv(icdar_traj_path, sep=',') #, skiprows=0, nrows=2000)\n",
"#print(data.dtypes)\n",
"\n",
"# Get a list of (x,y) for each data\n",
"N = data['signature_id'].max()\n",
"xy = []\n",
"for i in range(N):\n",
" d = data.loc[data['signature_id'] == i+1]\n",
" xy.append(np.array([d['x'].values, d['y'].values]))\n",
"\n",
"# Choose randomly 25 characters and plot them\n",
"idx = np.random.choice(len(xy), 25, replace=False)\n",
"idx = np.array(range(25))\n",
"xy = [xy[i] for i in idx]\n",
"plt.figure(figsize=(8,8))\n",
"for i,d in enumerate(xy):\n",
" plt.subplot(5,5,i+1)\n",
" plt.axis('off')\n",
" plt.plot(d[0], 1.-d[1]) # note that we need to inverse the y\n",
"plt.show()\n",
"\n",
"# Plot the corresponding images\n",
"imgs = [misc.imread(icdar_img_path+'{:04d}.jpg'.format(i+1)) for i in idx]\n",
"plt.figure(figsize=(8,8))\n",
"for i,img in enumerate(imgs):\n",
" plt.subplot(5,5,i+1)\n",
" plt.axis('off')\n",
" plt.imshow(img)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## [IAM Online Handwriting Database](www.fki.inf.unibe.ch/databases/iam-on-line-handwriting-database) <a id='IAMonline'></a>\n",
"\n",
"* Size: 1,712 forms, 12,195 imgs/strokeset/sub-sentences/sequences.\n",
"* Short description: \" The IAM On-Line Handwriting Database (IAM-OnDB) contains forms of handwritten English text acquired on a whiteboard.\" It contains the images of the various forms and the corresponding trajectories/strokes. \n",
"* Note: You will need to register on the website in order to download the dataset. It is free!"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"image/png": "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 truncated
"text/plain": [
"<matplotlib.figure.Figure at 0x7ff3b260bc90>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import xml.etree.ElementTree as ET\n",
"from glob import glob\n",
"import os\n",
"\n",
"iam_imgs_dirpath = 'IAM-Online/lineImages/'\n",
"iam_strokes_dirpath = 'IAM-Online/lineStrokes/'\n",
"#iam_strokes_dirpath = 'IAM-Online/lineStrokes/a01/a01-000/a01-000u-01.xml'\n",
"\n",
"# Get all the paths\n",
"trajs = sorted(glob(iam_strokes_dirpath+'*/*/*.xml'))[:1000] # take only the first 1000\n",
"imgs = sorted(glob(iam_imgs_dirpath+'*/*/*.tif'))[:1000]\n",
"N = len(trajs)\n",
"\n",
"# Load all the xml files, and extract all the strokes\n",
"strokes = []\n",
"for i,traj in enumerate(trajs):\n",
" tree = ET.parse(traj)\n",
" # Get the data\n",
" xy = []\n",
" for stroke in tree.iter(tag='Stroke'):\n",
" x = [int(point.attrib['x']) for point in stroke]\n",
" y = [int(point.attrib['y']) for point in stroke]\n",
" xy.append(np.array([x,y]))\n",
" strokes.append(xy)\n",
"\n",
"\n",
"# Randomly choose a strokeset, and then randomly choose 25 strokes and plot them\n",
"idx = np.random.choice(N, 1)[0]\n",
"strokes = strokes[idx]\n",
"N_stroke = len(strokes)\n",
"size = N_stroke if N_stroke < 25 else 25\n",
"idx = np.random.choice(N_stroke, size, replace=False)\n",
"xy = [strokes[i] for i in idx]\n",
"plt.figure(figsize=(10,10))\n",
"for i,d in enumerate(xy):\n",
" if i==25: break\n",
" plt.subplot(5,5,i+1)\n",
" plt.plot(d[0], d[1].max()-d[1])\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}