Skip to content

Commit eb60203

Browse files
committed
Initial commit.
0 parents  commit eb60203

66 files changed

Lines changed: 4584 additions & 0 deletions

Some content is hidden

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

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.pyc
2+
*.ini
3+
.project
4+
.pydevproject
5+
glitter/ffpyplayer
6+
glitter/libs

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CPL Lab, Cornell University
2+
Video tracking, scoring, and analysis software.
3+
LGPL3

glitter/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
__version__ = 2.0
3+
__description__ = 'CPL Video tracking/scoring and analysis software.'

glitter/exporter.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import operator
2+
import sys
3+
if getattr(sys, 'frozen', False):
4+
from collider import Collide2DPoly
5+
else:
6+
from kivy.garden.collider import Collide2DPoly
7+
import itertools
8+
9+
__all__ = ('DataList', )
10+
11+
class DataList(list):
12+
13+
def __init__(self, d, score_type, name, func='', previous=None, *largs, **kwargs):
14+
super(DataList, self).__init__(*largs, **kwargs)
15+
self.score_type = score_type
16+
''' Possible score_type are xyt, xy, t, pts '''
17+
self.previous = previous
18+
self.name = name
19+
self.func = func
20+
self.pts = []
21+
self.d = d
22+
23+
def compare_constant(self, value, op):
24+
if value.__class__ is not float and value.__class__ is not int:
25+
raise Exception('Invalid data type, %s, given to %s comparison operator.' %(type(value), op))
26+
if self.score_type != 'pts':
27+
raise Exception("You can use the %s comparison operator only on pts." %op)
28+
result = DataList(self.d, 't', self.name, '%s_%f_%s' % (op, float(value), self.name))
29+
result.pts = self.pts
30+
op = getattr(operator, op)
31+
result[:] = [op(t, value) for t in self.d['_pts']]
32+
return result
33+
def __lt__(self, val):
34+
return self.compare_constant(val, 'lt')
35+
def __le__(self, val):
36+
return self.compare_constant(val, 'le')
37+
def __gt__(self, val):
38+
return self.compare_constant(val, 'gt')
39+
def __ge__(self, val):
40+
return self.compare_constant(val, 'ge')
41+
42+
def within_dist(self, value):
43+
if value.__class__ is not float and value.__class__ is not int:
44+
raise Exception('Invalid data type, %s, used in within_dist.' %type(value))
45+
if self.score_type != 't':
46+
raise Exception("You can use the within_dist operator only on t score types.")
47+
result = DataList(self.d, 't', self.name, 'within_dist_%f_%s' % (float(value), self.name), self)
48+
result.pts = self.pts
49+
pts = self.d['_pts']
50+
result[:] = [False, ] * len(self)
51+
points = [pts[i] for i in range(len(self)) if self[i]]
52+
for i in range(len(result)):
53+
if value >= 0:
54+
result[i] = any([point <= pts[i] < point + value for point in points])
55+
else:
56+
result[i] = any([point + value < pts[i] <= point for point in points])
57+
return result
58+
59+
def __or__(self, other):
60+
if other.__class__ is not DataList:
61+
raise Exception('Invalid data type given to or (|).')
62+
score_types = (self.score_type, other.score_type)
63+
if 'pts' in score_types:
64+
raise Exception("You cannot 'or' pts type data.")
65+
if score_types[0] == score_types[1]:
66+
if score_types[0] != 't':
67+
raise Exception("You can only 'or' identical data types if they are both of type t.")
68+
if len(self) != len(other):
69+
raise Exception("You can only 'or' data types t if they are both of the same length.")
70+
result = DataList(self.d, self.score_type, self.name, 'or_'+other.name, self)
71+
result.pts = self.pts
72+
result.extend([self[i] or other[i] for i in range(len(self))])
73+
return result
74+
raise Exception("You cannot 'or' a "+score_types[0]+' type with a '+score_types[1]+' type.')
75+
76+
def __invert__(self):
77+
if self.score_type != 't':
78+
raise Exception("You can only 'invert' t type data.")
79+
result = DataList(self.d, self.score_type, self.name, 'invert_' + self.name, self)
80+
result.pts = self.pts
81+
result[:] = [not val for val in self]
82+
return result
83+
84+
def __and__(self, other):
85+
if other.__class__ is not DataList:
86+
raise Exception('Invalid data type given to and (&).')
87+
score_types = (self.score_type, other.score_type)
88+
if 'pts' in score_types:
89+
raise Exception("You cannot 'and' pts type data.")
90+
if score_types[0] == score_types[1]:
91+
if score_types[0] != 't':
92+
raise Exception("You can only 'and' identical data types if they are both of type t.")
93+
if len(self) != len(other):
94+
raise Exception("You can only 'and' data types t if they are both of the same length.")
95+
result = DataList(self.d, self.score_type, self.name, 'and_'+other.name, self)
96+
result.pts = self.pts
97+
result.extend([self[i] and other[i] for i in range(len(self))])
98+
return result
99+
if 't' in score_types:
100+
raise Exception("You cannot 'and' a "+score_types[0]+' type with a '+score_types[1]+' type.')
101+
a, b = self, other
102+
if score_types[0] == 'xyt':
103+
a, b = b, a
104+
collider = Collide2DPoly([p for p in itertools.chain.from_iterable(a)], cache=True)
105+
result = DataList(b.d, 't', b.name, 'and_'+a.name, b)
106+
result.pts = b.pts
107+
result.extend([b[i] in collider for i in range(len(b))])
108+
return result
109+
110+
# A scaler result from an operation on array
111+
class DataResult(float):
112+
113+
def __new__(cls, previous=None, *largs, **kwargs):
114+
obj = float.__new__(cls, *largs, **kwargs)
115+
obj.previous = previous
116+
return obj
117+
118+
def esum(data):
119+
return DataResult(data, sum(data))
120+
def emin(data):
121+
return DataResult(data, min(data))
122+
def emax(data):
123+
return DataResult(data, max(data))
124+
def elen(data):
125+
return DataResult(data, len(data))
126+
127+
def event(data):
128+
if data.__class__ is not DataList:
129+
raise Exception('Invalid data type given to event().')
130+
if data.score_type != 't':
131+
raise Exception('Only t type channels can be given to event().')
132+
pts = data.d['_pts']
133+
result = DataList(data.d, data.score_type, data.name, 'event', data)
134+
start = -1
135+
for i in range(len(data)):
136+
if data[i] and start == -1:
137+
start = i
138+
if start != -1 and (i + 1 == len(data) or not data[i + 1]):
139+
result.append(pts[i] - pts[start])
140+
result.pts.append(start)
141+
start = -1
142+
return result
143+
144+
def export_data(d, channels):
145+
result = [0, ] * len(channels)
146+
for i in range(len(channels)):
147+
lines = channels[i].split('\n')
148+
lines = [line for line in lines if line]
149+
exec('\n'.join(lines[:-1]))
150+
result[i] = eval(lines[-1])
151+
return result

glitter/help.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
3+
4+
5+
__all__ = ('HelpDoc')
6+
7+
8+
HelpDoc = '''
9+
[b]Browsing bar:[/b]
10+
11+
[b]Load video:[/b] Loads a video file. If set to load a default data file, it \
12+
also loads or create a data file with the same name as the video file. It closes\
13+
any previously opened video and data files. Current channels will not be deleted.
14+
15+
[b]Load data file:[/b] Loads or creates a data file. All the recorded data\
16+
is stored in the PyTables HDF5 format data file.
17+
18+
19+
[b]Exporter:[/b]
20+
The following file level variables are available in the exporter:
21+
_version (provides the version of the program which wrote the file).
22+
_filename (the filename of the video file associated with the data file).
23+
_vid_info (a dict with information about the video file, e.g. frame size...).
24+
_user (the user that created the file).
25+
_ID (the filename of the video file associated with the data file).
26+
_complete (whether all the frames in the video has been watched).
27+
_pts (the list of the timestamps of the video).
28+
29+
In addition, each channel's name defined in the data file is also available in \
30+
two flavors. For example, say you add a two channels, Head, and Tail in that \
31+
order. Then you can refer to them using either Head, Tail respectively, \
32+
or Head_0, Tail_1, respectively. That is, you can refer to each channel by \
33+
its name, or by appending _n, where n is the order number of the channel, \
34+
defined by the order in which the channels were created. This should resolve \
35+
naming conflicts.
36+
'''

0 commit comments

Comments
 (0)