Skip to content

Commit

Permalink
Merge branch 'offline_marker_tracker'
Browse files Browse the repository at this point in the history
  • Loading branch information
mkassner committed May 21, 2014
2 parents bc20957 + b78b0e0 commit c8f9654
Show file tree
Hide file tree
Showing 25 changed files with 1,473 additions and 318 deletions.
4 changes: 2 additions & 2 deletions pupil_src/capture/eye.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import os
from time import time, sleep
import shelve
from file_methods import Persistent_Dict
import logging
from ctypes import c_int,c_bool,c_float
import numpy as np
Expand Down Expand Up @@ -119,7 +119,7 @@ def get_from_data(data):


# load session persistent settings
session_settings = shelve.open(os.path.join(g_pool.user_dir,'user_settings_eye'),protocol=2)
session_settings = Persistent_Dict(os.path.join(g_pool.user_dir,'user_settings_eye') )
def load(var_name,default):
return session_settings.get(var_name,default)
def save(var_name,var):
Expand Down
4 changes: 2 additions & 2 deletions pupil_src/capture/pupil_detectors/canny_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import cv2
from time import sleep
import shelve
from file_methods import Persistent_Dict
import numpy as np
from methods import *
import atb
Expand Down Expand Up @@ -47,7 +47,7 @@ def __init__(self,g_pool):
super(Canny_Detector, self).__init__()

# load session persistent settings
self.session_settings = shelve.open(os.path.join(g_pool.user_dir,'user_settings_detector'),protocol=2)
self.session_settings =Persistent_Dict(os.path.join(g_pool.user_dir,'user_settings_detector') )

# coase pupil filter params
self.coarse_detection = c_bool(self.load('coarse_detection',True))
Expand Down
20 changes: 8 additions & 12 deletions pupil_src/capture/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ def get_rec_time_str(self):
return strftime("%H:%M:%S", rec_time)

def update(self,frame,recent_pupil_positons,events):
self.frame_count += 1
# cv2.putText(frame.img, "Frame %s"%self.frame_count,(200,200), cv2.FONT_HERSHEY_SIMPLEX,1,(255,100,100))
for p in recent_pupil_positons:
if p['norm_pupil'] is not None:
gaze_pt = p['norm_gaze'][0],p['norm_gaze'][1],p['norm_pupil'][0],p['norm_pupil'][1],p['timestamp'],p['confidence']
self.gaze_list.append(gaze_pt)
self.timestamps.append(frame.timestamp)
self.writer.write(frame.img)
self.frame_count += 1


def stop_and_destruct(self):
#explicit release of VideoWriter
Expand All @@ -109,32 +111,26 @@ def stop_and_destruct(self):
self.eye_tx.send(None)
except:
logger.warning("Could not stop eye-recording. Please report this bug!")

gaze_list_path = os.path.join(self.rec_path, "gaze_positions.npy")
np.save(gaze_list_path,np.asarray(self.gaze_list))

timestamps_path = os.path.join(self.rec_path, "timestamps.npy")
np.save(timestamps_path,np.array(self.timestamps))

try:
surface_definitions_file = glob(os.path.join(self.g_pool.user_dir,"surface_definitions*"))[0].rsplit(os.path.sep,1)[-1]
copy2(os.path.join(self.g_pool.user_dir,surface_definitions_file),os.path.join(self.rec_path,surface_definitions_file))
copy2(os.path.join(self.g_pool.user_dir,"surface_definitions"),os.path.join(self.rec_path,"surface_definitions"))
except:
logger.info("No surface_definitions data found. You may want this if you do marker tracking.")

try:
cal_pt_cloud = np.load(os.path.join(self.g_pool.user_dir,"cal_pt_cloud.npy"))
cal_pt_cloud_path = os.path.join(self.rec_path, "cal_pt_cloud.npy")
np.save(cal_pt_cloud_path, cal_pt_cloud)
copy2(os.path.join(self.g_pool.user_dir,"cal_pt_cloud.npy"),os.path.join(self.rec_path,"cal_pt_cloud.npy"))
except:
logger.warning("No calibration data found. Please calibrate first.")

try:
camera_matrix = np.load(os.path.join(self.g_pool.user_dir,"camera_matrix.npy"))
dist_coefs = np.load(os.path.join(self.g_pool.user_dir,"dist_coefs.npy"))
cam_path = os.path.join(self.rec_path, "camera_matrix.npy")
dist_path = os.path.join(self.rec_path, "dist_coefs.npy")
np.save(cam_path, camera_matrix)
np.save(dist_path, dist_coefs)
copy2(os.path.join(self.g_pool.user_dir,"camera_matrix.npy"),os.path.join(self.rec_path,"camera_matrix.npy"))
copy2(os.path.join(self.g_pool.user_dir,"dist_coefs.npy"),os.path.join(self.rec_path,"dist_coefs.npy"))
except:
logger.info("No camera intrinsics found.")

Expand Down
48 changes: 25 additions & 23 deletions pupil_src/capture/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import os, sys
from time import time
import shelve
from file_methods import Persistent_Dict
import logging
from ctypes import c_int,c_bool,c_float,create_string_buffer
import numpy as np
Expand Down Expand Up @@ -64,6 +64,8 @@ def on_resize(window,w, h):
atb.TwWindowSize(*map(int,fb_size))
adjust_gl_view(w,h,window)
glfwMakeContextCurrent(active_window)
for p in g_pool.plugins:
p.on_window_resize(window,w,h)

def on_iconify(window,iconfied):
if not isinstance(cap,FakeCapture):
Expand Down Expand Up @@ -104,48 +106,49 @@ def on_close(window):


# load session persistent settings
session_settings = shelve.open(os.path.join(g_pool.user_dir,'user_settings_world'),protocol=2)
session_settings = Persistent_Dict(os.path.join(g_pool.user_dir,'user_settings_world'))
def load(var_name,default):
return session_settings.get(var_name,default)
def save(var_name,var):
session_settings[var_name] = var


# load last calibration data
try:
pt_cloud = np.load(os.path.join(g_pool.user_dir,'cal_pt_cloud.npy'))
logger.info("Using calibration found in %s" %g_pool.user_dir)
map_pupil = calibrate.get_map_from_cloud(pt_cloud,(width,height))
except:
logger.info("No calibration found.")
def map_pupil(vector):
""" 1 to 1 mapping
"""
return vector

# any object we attach to the g_pool object now will only be visible to this process!
# vars should be declared here to make them visible to the reader.
g_pool.plugins = []
g_pool.map_pupil = map_pupil
g_pool.update_textures = c_bool(1)

# Initialize capture
cap = autoCreateCapture(cap_src, cap_size, 24, timebase=g_pool.timebase)

if isinstance(cap,FakeCapture):
g_pool.update_textures.value = False

# Get an image from the grabber
try:
frame = cap.get_frame()
except CameraCaptureError:
logger.error("Could not retrieve image from capture")
cap.close()
return

height,width = frame.img.shape[:2]

# load last calibration data
try:
pt_cloud = np.load(os.path.join(g_pool.user_dir,'cal_pt_cloud.npy'))
logger.debug("Using calibration found in %s" %g_pool.user_dir)
map_pupil = calibrate.get_map_from_cloud(pt_cloud,(width,height))
except :
logger.debug("No calibration found.")
def map_pupil(vector):
""" 1 to 1 mapping """
return vector


# any object we attach to the g_pool object *from now on* will only be visible to this process!
# vars should be declared here to make them visible to the code reader.
g_pool.plugins = []
g_pool.map_pupil = map_pupil
g_pool.update_textures = c_bool(1)
if isinstance(cap,FakeCapture):
g_pool.update_textures.value = False
g_pool.capture = cap


# helpers called by the main atb bar
def update_fps():
old_time, bar.timestamp = bar.timestamp, time()
Expand Down Expand Up @@ -336,7 +339,6 @@ def reset_timebase():
#check if a plugin need to be destroyed
g_pool.plugins = [p for p in g_pool.plugins if p.alive]


# render camera image
glfwMakeContextCurrent(world_window)

Expand Down
10 changes: 4 additions & 6 deletions pupil_src/player/export_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,6 @@ def __init__(self, g_pool,data_dir,frame_count):
default_path = "world_viz.avi"

self.rec_name = create_string_buffer(default_path,512)
self.start_frame = c_int(0)
self.end_frame = c_int(frame_count)


def init_gui(self):
Expand All @@ -96,8 +94,8 @@ def update_bar(self):
self._bar.clear()

self._bar.add_var('export name',self.rec_name, help="Supply export video recording name. The export will be in the recording dir. If you give a path the export will end up there instead.")
self._bar.add_var('start frame',self.start_frame,help="Supply start frame no. Negative numbers will count from the end. The behaves like python list indexing")
self._bar.add_var('end frame',self.end_frame,help="Supply end frame no. Negative numbers will count from the end. The behaves like python list indexing")
self._bar.add_var('start frame',vtype=c_int,getter=self.g_pool.trim_marks.atb_get_in_mark,setter= self.g_pool.trim_marks.atb_set_in_mark, help="Supply start frame no. Negative numbers will count from the end. The behaves like python list indexing")
self._bar.add_var('end frame',vtype=c_int,getter=self.g_pool.trim_marks.atb_get_out_mark,setter= self.g_pool.trim_marks.atb_set_out_mark,help="Supply end frame no. Negative numbers will count from the end. The behaves like python list indexing")
self._bar.add_button('new export',self.add_export)

for job,i in zip(self.exports,range(len(self.exports)))[::-1]:
Expand Down Expand Up @@ -134,8 +132,8 @@ def add_export(self):
current_frame = RawValue(c_int,0)

data_dir = self.data_dir
start_frame= self.start_frame.value
end_frame= self.end_frame.value
start_frame= self.g_pool.trim_marks.in_mark
end_frame= self.g_pool.trim_marks.out_mark+1 #end_frame is exclusive
plugins = []

# Here we make clones of every plugin that supports it.
Expand Down
2 changes: 1 addition & 1 deletion pupil_src/player/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ def export(should_terminate,frames_to_export,current_frame, data_dir,start_frame
p = plugin_by_name[name](g,**args)
plugins.append(p)
except:
logger.warning("Plugin '%s' failed to load." %name)
logger.warning("Plugin '%s' could not be loaded in exporter." %name)


while frames_to_export.value - current_frame.value > 0:
Expand Down
42 changes: 27 additions & 15 deletions pupil_src/player/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
import logging
#set up root logger before other imports
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logger.setLevel(logging.WARNING)
#since we are not using OS.fork on MacOS we need to do a few extra things to log our exports correctly.
if platform.system() == 'Darwin':
if __name__ == '__main__': #clear log if main
Expand All @@ -72,7 +72,7 @@
logging.getLogger("OpenGL").addHandler(logging.NullHandler())
logger = logging.getLogger(__name__)

import shelve
from file_methods import Persistent_Dict
from time import time,sleep
from ctypes import c_int,c_bool,c_float,create_string_buffer
import numpy as np
Expand All @@ -81,7 +81,7 @@
from glfw import *
import atb

from uvc_capture import autoCreateCapture,EndofVideoFileError,FakeCapture
from uvc_capture import autoCreateCapture,EndofVideoFileError,FileSeekError,FakeCapture

# helpers/utils
from methods import normalize, denormalize,Temp
Expand All @@ -105,14 +105,15 @@
from display_gaze import Display_Gaze
from vis_light_points import Vis_Light_Points
from seek_bar import Seek_Bar
from trim_marks import Trim_Marks
from export_launcher import Export_Launcher
from scan_path import Scan_Path
from marker_detector import Marker_Detector
from offline_marker_detector import Offline_Marker_Detector
from pupil_server import Pupil_Server
from filter_fixations import Filter_Fixations
from manual_gaze_correction import Manual_Gaze_Correction

plugin_by_index = (Vis_Circle,Vis_Cross, Vis_Polyline, Vis_Light_Points,Scan_Path,Filter_Fixations,Manual_Gaze_Correction,Marker_Detector,Pupil_Server)
plugin_by_index = (Vis_Circle,Vis_Cross, Vis_Polyline, Vis_Light_Points,Scan_Path,Filter_Fixations,Manual_Gaze_Correction,Offline_Marker_Detector,Pupil_Server)
name_by_index = [p.__name__ for p in plugin_by_index]
index_by_name = dict(zip(name_by_index,range(len(name_by_index))))
plugin_by_name = dict(zip(name_by_index,plugin_by_index))
Expand All @@ -130,6 +131,8 @@ def on_resize(window,w, h):
fb_size = denormalize(norm_size,glfwGetFramebufferSize(window))
atb.TwWindowSize(*map(int,fb_size))
glfwMakeContextCurrent(active_window)
for p in g.plugins:
p.on_window_resize(window,w,h)

def on_key(window, key, scancode, action, mods):
if not atb.TwEventKeyboardGLFW(key,action):
Expand Down Expand Up @@ -160,14 +163,14 @@ def on_scroll(window,x,y):

def on_close(window):
glfwSetWindowShouldClose(main_window,True)
logger.info('Process closing from window')
logger.debug('Process closing from window')


try:
rec_dir = sys.argv[1]
except:
#for dev, supply hardcoded dir:
rec_dir = "/Users/mkassner/Downloads/1-4/000/"
rec_dir = '/home/mkassner/Desktop/003'
if os.path.isdir(rec_dir):
logger.debug("Dev option: Using hadcoded data dir.")
else:
Expand Down Expand Up @@ -210,7 +213,7 @@ def on_close(window):


# load session persistent settings
session_settings = shelve.open(os.path.join(user_dir,"user_settings"),protocol=2)
session_settings = Persistent_Dict(os.path.join(user_dir,"user_settings"))
def load(var_name,default):
return session_settings.get(var_name,default)
def save(var_name,var):
Expand Down Expand Up @@ -242,14 +245,16 @@ def save(var_name,var):
glfwSetScrollCallback(main_window,on_scroll)


# create container for globally scoped vars (within world)
# create container for globally scoped varfs (within world)
g = Temp()
g.plugins = []
g.play = False
g.new_seek = True
g.user_dir = user_dir
g.rec_dir = rec_dir
g.app = 'player'
g.timestamps = timestamps
g.positions_by_frame = positions_by_frame



Expand Down Expand Up @@ -280,11 +285,17 @@ def set_play(value):
g.play = value

def next_frame():
cap.seek_to_frame(cap.get_frame_index())
try:
cap.seek_to_frame(cap.get_frame_index())
except FileSeekError:
pass
g.new_seek = True

def prev_frame():
cap.seek_to_frame(cap.get_frame_index()-2)
try:
cap.seek_to_frame(cap.get_frame_index()-2)
except FileSeekError:
pass
g.new_seek = True


Expand Down Expand Up @@ -331,7 +342,7 @@ def get_from_data(data):
bar.add_var("play",vtype=c_bool,getter=get_play,setter=set_play,key="space")
bar.add_button('step next',next_frame,key='right')
bar.add_button('step prev',prev_frame,key='left')
bar.add_var("frame index",getter=lambda:cap.get_frame_index()-1 )
bar.add_var("frame index",vtype=c_int,getter=lambda:cap.get_frame_index()-1 )

bar.plugin_to_load = c_int(0)
plugin_type_enum = atb.enum("Plug In",index_by_name)
Expand All @@ -349,6 +360,8 @@ def get_from_data(data):
#we always load these plugins
g.plugins.append(Export_Launcher(g,data_dir=rec_dir,frame_count=len(timestamps)))
g.plugins.append(Seek_Bar(g,capture=cap))
g.trim_marks = Trim_Marks(g,capture=cap)
g.plugins.append(g.trim_marks)

#these are loaded based on user settings
for initializer in load('plugins',[]):
Expand Down Expand Up @@ -397,8 +410,7 @@ def get_from_data(data):
g.new_seek = False

frame = new_frame.copy()

#new positons and events we make a deepcopy just like the image should be a copy.
#new positons and events we make a deepcopy just like the image is a copy.
current_pupil_positions = deepcopy(positions_by_frame[frame.index])
events = []

Expand Down Expand Up @@ -462,7 +474,7 @@ def get_from_data(data):

if __name__ == '__main__':
freeze_support()
if 1:
if 0:
main()
else:
import cProfile,subprocess,os
Expand Down
Loading

0 comments on commit c8f9654

Please sign in to comment.