Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
matham committed Dec 3, 2013
0 parents commit eb60203
Show file tree
Hide file tree
Showing 66 changed files with 4,584 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.pyc
*.ini
.project
.pydevproject
glitter/ffpyplayer
glitter/libs
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CPL Lab, Cornell University
Video tracking, scoring, and analysis software.
LGPL3
3 changes: 3 additions & 0 deletions glitter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

__version__ = 2.0
__description__ = 'CPL Video tracking/scoring and analysis software.'
151 changes: 151 additions & 0 deletions glitter/exporter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import operator
import sys
if getattr(sys, 'frozen', False):
from collider import Collide2DPoly
else:
from kivy.garden.collider import Collide2DPoly
import itertools

__all__ = ('DataList', )

class DataList(list):

def __init__(self, d, score_type, name, func='', previous=None, *largs, **kwargs):
super(DataList, self).__init__(*largs, **kwargs)
self.score_type = score_type
''' Possible score_type are xyt, xy, t, pts '''
self.previous = previous
self.name = name
self.func = func
self.pts = []
self.d = d

def compare_constant(self, value, op):
if value.__class__ is not float and value.__class__ is not int:
raise Exception('Invalid data type, %s, given to %s comparison operator.' %(type(value), op))
if self.score_type != 'pts':
raise Exception("You can use the %s comparison operator only on pts." %op)
result = DataList(self.d, 't', self.name, '%s_%f_%s' % (op, float(value), self.name))
result.pts = self.pts
op = getattr(operator, op)
result[:] = [op(t, value) for t in self.d['_pts']]
return result
def __lt__(self, val):
return self.compare_constant(val, 'lt')
def __le__(self, val):
return self.compare_constant(val, 'le')
def __gt__(self, val):
return self.compare_constant(val, 'gt')
def __ge__(self, val):
return self.compare_constant(val, 'ge')

def within_dist(self, value):
if value.__class__ is not float and value.__class__ is not int:
raise Exception('Invalid data type, %s, used in within_dist.' %type(value))
if self.score_type != 't':
raise Exception("You can use the within_dist operator only on t score types.")
result = DataList(self.d, 't', self.name, 'within_dist_%f_%s' % (float(value), self.name), self)
result.pts = self.pts
pts = self.d['_pts']
result[:] = [False, ] * len(self)
points = [pts[i] for i in range(len(self)) if self[i]]
for i in range(len(result)):
if value >= 0:
result[i] = any([point <= pts[i] < point + value for point in points])
else:
result[i] = any([point + value < pts[i] <= point for point in points])
return result

def __or__(self, other):
if other.__class__ is not DataList:
raise Exception('Invalid data type given to or (|).')
score_types = (self.score_type, other.score_type)
if 'pts' in score_types:
raise Exception("You cannot 'or' pts type data.")
if score_types[0] == score_types[1]:
if score_types[0] != 't':
raise Exception("You can only 'or' identical data types if they are both of type t.")
if len(self) != len(other):
raise Exception("You can only 'or' data types t if they are both of the same length.")
result = DataList(self.d, self.score_type, self.name, 'or_'+other.name, self)
result.pts = self.pts
result.extend([self[i] or other[i] for i in range(len(self))])
return result
raise Exception("You cannot 'or' a "+score_types[0]+' type with a '+score_types[1]+' type.')

def __invert__(self):
if self.score_type != 't':
raise Exception("You can only 'invert' t type data.")
result = DataList(self.d, self.score_type, self.name, 'invert_' + self.name, self)
result.pts = self.pts
result[:] = [not val for val in self]
return result

def __and__(self, other):
if other.__class__ is not DataList:
raise Exception('Invalid data type given to and (&).')
score_types = (self.score_type, other.score_type)
if 'pts' in score_types:
raise Exception("You cannot 'and' pts type data.")
if score_types[0] == score_types[1]:
if score_types[0] != 't':
raise Exception("You can only 'and' identical data types if they are both of type t.")
if len(self) != len(other):
raise Exception("You can only 'and' data types t if they are both of the same length.")
result = DataList(self.d, self.score_type, self.name, 'and_'+other.name, self)
result.pts = self.pts
result.extend([self[i] and other[i] for i in range(len(self))])
return result
if 't' in score_types:
raise Exception("You cannot 'and' a "+score_types[0]+' type with a '+score_types[1]+' type.')
a, b = self, other
if score_types[0] == 'xyt':
a, b = b, a
collider = Collide2DPoly([p for p in itertools.chain.from_iterable(a)], cache=True)
result = DataList(b.d, 't', b.name, 'and_'+a.name, b)
result.pts = b.pts
result.extend([b[i] in collider for i in range(len(b))])
return result

# A scaler result from an operation on array
class DataResult(float):

def __new__(cls, previous=None, *largs, **kwargs):
obj = float.__new__(cls, *largs, **kwargs)
obj.previous = previous
return obj

def esum(data):
return DataResult(data, sum(data))
def emin(data):
return DataResult(data, min(data))
def emax(data):
return DataResult(data, max(data))
def elen(data):
return DataResult(data, len(data))

def event(data):
if data.__class__ is not DataList:
raise Exception('Invalid data type given to event().')
if data.score_type != 't':
raise Exception('Only t type channels can be given to event().')
pts = data.d['_pts']
result = DataList(data.d, data.score_type, data.name, 'event', data)
start = -1
for i in range(len(data)):
if data[i] and start == -1:
start = i
if start != -1 and (i + 1 == len(data) or not data[i + 1]):
result.append(pts[i] - pts[start])
result.pts.append(start)
start = -1
return result

def export_data(d, channels):
result = [0, ] * len(channels)
for i in range(len(channels)):
lines = channels[i].split('\n')
lines = [line for line in lines if line]
exec('\n'.join(lines[:-1]))
result[i] = eval(lines[-1])
return result
36 changes: 36 additions & 0 deletions glitter/help.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@




__all__ = ('HelpDoc')


HelpDoc = '''
[b]Browsing bar:[/b]
[b]Load video:[/b] Loads a video file. If set to load a default data file, it \
also loads or create a data file with the same name as the video file. It closes\
any previously opened video and data files. Current channels will not be deleted.
[b]Load data file:[/b] Loads or creates a data file. All the recorded data\
is stored in the PyTables HDF5 format data file.
[b]Exporter:[/b]
The following file level variables are available in the exporter:
_version (provides the version of the program which wrote the file).
_filename (the filename of the video file associated with the data file).
_vid_info (a dict with information about the video file, e.g. frame size...).
_user (the user that created the file).
_ID (the filename of the video file associated with the data file).
_complete (whether all the frames in the video has been watched).
_pts (the list of the timestamps of the video).
In addition, each channel's name defined in the data file is also available in \
two flavors. For example, say you add a two channels, Head, and Tail in that \
order. Then you can refer to them using either Head, Tail respectively, \
or Head_0, Tail_1, respectively. That is, you can refer to each channel by \
its name, or by appending _n, where n is the order number of the channel, \
defined by the order in which the channels were created. This should resolve \
naming conflicts.
'''
Loading

0 comments on commit eb60203

Please sign in to comment.