def export(should_terminate, frames_to_export, current_frame, rec_dir, user_dir, start_frame=None, end_frame=None, plugin_initializers=[], out_file_path=None): logger = logging.getLogger(__name__ + ' with pid: ' + str(os.getpid())) #parse info.csv file with open(rec_dir + "/info.csv") as info: meta_info = dict( ((line.strip().split('\t')) for line in info.readlines())) rec_version = read_rec_version(meta_info) logger.debug("Exporting a video from recording with version: %s" % rec_version) if rec_version < VersionFormat('0.4'): video_path = rec_dir + "/world.avi" timestamps_path = rec_dir + "/timestamps.npy" else: video_path = rec_dir + "/world.mkv" timestamps_path = rec_dir + "/world_timestamps.npy" gaze_positions_path = rec_dir + "/gaze_positions.npy" #load gaze information gaze_list = np.load(gaze_positions_path) timestamps = np.load(timestamps_path) #correlate data if rec_version < VersionFormat('0.4'): gaze_positions_by_frame = correlate_gaze_legacy(gaze_list, timestamps) else: gaze_positions_by_frame = correlate_gaze(gaze_list, timestamps) cap = autoCreateCapture(video_path, timestamps=timestamps_path) width, height = cap.frame_size #Out file path verification, we do this before but if one uses a seperate tool, this will kick in. if out_file_path is None: out_file_path = os.path.join(rec_dir, "world_viz.mp4") else: file_name = os.path.basename(out_file_path) dir_name = os.path.dirname(out_file_path) if not dir_name: dir_name = rec_dir if not file_name: file_name = 'world_viz.mp4' out_file_path = os.path.expanduser(os.path.join(dir_name, file_name)) if os.path.isfile(out_file_path): logger.warning("Video out file already exsists. I will overwrite!") os.remove(out_file_path) logger.debug("Saving Video to %s" % out_file_path) #Trim mark verification #make sure the trim marks (start frame, endframe) make sense: We define them like python list slices,thus we can test them like such. trimmed_timestamps = timestamps[start_frame:end_frame] if len(trimmed_timestamps) == 0: logger.warn( "Start and end frames are set such that no video will be exported." ) return False if start_frame == None: start_frame = 0 #these two vars are shared with the lauching process and give a job length and progress report. frames_to_export.value = len(trimmed_timestamps) current_frame.value = 0 logger.debug( "Will export from frame %s to frame %s. This means I will export %s frames." % (start_frame, start_frame + frames_to_export.value, frames_to_export.value)) #setup of writer writer = AV_Writer(out_file_path) cap.seek_to_frame(start_frame) start_time = time() g = Global_Container() g.app = 'exporter' g.rec_dir = rec_dir g.user_dir = user_dir g.rec_version = rec_version g.timestamps = timestamps g.gaze_list = gaze_list g.gaze_positions_by_frame = gaze_positions_by_frame g.plugins = Plugin_List(g, plugin_by_name, plugin_initializers) while frames_to_export.value - current_frame.value > 0: if should_terminate.value: logger.warning("User aborted export. Exported %s frames to %s." % (current_frame.value, out_file_path)) #explicit release of VideoWriter writer.close() writer = None return False try: frame = cap.get_frame() except EndofVideoFileError: break events = {} #new positons and events events['gaze_positions'] = gaze_positions_by_frame[frame.index] # allow each Plugin to do its work. for p in g.plugins: p.update(frame, events) writer.write_video_frame(frame) current_frame.value += 1 writer.close() writer = None duration = time() - start_time effective_fps = float(current_frame.value) / duration logger.info( "Export done: Exported %s frames to %s. This took %s seconds. Exporter ran at %s frames per second" % (current_frame.value, out_file_path, duration, effective_fps)) return True
def export(should_terminate,frames_to_export,current_frame, rec_dir,start_frame=None,end_frame=None,plugin_initializers=[],out_file_path=None): logger = logging.getLogger(__name__+' with pid: '+str(os.getpid()) ) #parse info.csv file with open(rec_dir + "/info.csv") as info: meta_info = dict( ((line.strip().split('\t')) for line in info.readlines() ) ) rec_version = read_rec_version(meta_info) logger.debug("Exporting a video from recording with version: %s"%rec_version) if rec_version < VersionFormat('0.4'): video_path = rec_dir + "/world.avi" timestamps_path = rec_dir + "/timestamps.npy" else: video_path = rec_dir + "/world.mkv" timestamps_path = rec_dir + "/world_timestamps.npy" gaze_positions_path = rec_dir + "/gaze_positions.npy" #load gaze information gaze_list = np.load(gaze_positions_path) timestamps = np.load(timestamps_path) #correlate data if rec_version < VersionFormat('0.4'): positions_by_frame = correlate_gaze_legacy(gaze_list,timestamps) else: positions_by_frame = correlate_gaze(gaze_list,timestamps) cap = autoCreateCapture(video_path,timestamps=timestamps_path) width,height = cap.get_size() #Out file path verification, we do this before but if one uses a seperate tool, this will kick in. if out_file_path is None: out_file_path = os.path.join(rec_dir, "world_viz.mp4") else: file_name = os.path.basename(out_file_path) dir_name = os.path.dirname(out_file_path) if not dir_name: dir_name = rec_dir if not file_name: file_name = 'world_viz.mp4' out_file_path = os.path.expanduser(os.path.join(dir_name,file_name)) if os.path.isfile(out_file_path): logger.warning("Video out file already exsists. I will overwrite!") os.remove(out_file_path) logger.debug("Saving Video to %s"%out_file_path) #Trim mark verification #make sure the trim marks (start frame, endframe) make sense: We define them like python list slices,thus we can test them like such. trimmed_timestamps = timestamps[start_frame:end_frame] if len(trimmed_timestamps)==0: logger.warn("Start and end frames are set such that no video will be exported.") return False if start_frame == None: start_frame = 0 #these two vars are shared with the lauching process and give a job length and progress report. frames_to_export.value = len(trimmed_timestamps) current_frame.value = 0 logger.debug("Will export from frame %s to frame %s. This means I will export %s frames."%(start_frame,start_frame+frames_to_export.value,frames_to_export.value)) #setup of writer writer = AV_Writer(out_file_path) cap.seek_to_frame(start_frame) start_time = time() g = Global_Container() g.app = 'exporter' g.rec_dir = rec_dir g.rec_version = rec_version g.timestamps = timestamps g.gaze_list = gaze_list g.positions_by_frame = positions_by_frame g.plugins = Plugin_List(g,plugin_by_name,plugin_initializers) while frames_to_export.value - current_frame.value > 0: if should_terminate.value: logger.warning("User aborted export. Exported %s frames to %s."%(current_frame.value,out_file_path)) #explicit release of VideoWriter writer.close() writer = None return False try: frame = cap.get_frame() except EndofVideoFileError: break events = {} #new positons and events events['pupil_positions'] = positions_by_frame[frame.index] # allow each Plugin to do its work. for p in g.plugins: p.update(frame,events) writer.write_video_frame(frame) current_frame.value +=1 writer.close() writer = None duration = time()-start_time effective_fps = float(current_frame.value)/duration logger.info("Export done: Exported %s frames to %s. This took %s seconds. Exporter ran at %s frames per second"%(current_frame.value,out_file_path,duration,effective_fps)) return True
def main(): # Callback functions def on_resize(window,w, h): active_window = glfwGetCurrentContext() glfwMakeContextCurrent(window) hdpi_factor = glfwGetFramebufferSize(window)[0]/glfwGetWindowSize(window)[0] w,h = w*hdpi_factor, h*hdpi_factor g_pool.gui.update_window(w,h) g_pool.gui.collect_menus() graph.adjust_size(w,h) adjust_gl_view(w,h) glfwMakeContextCurrent(active_window) for p in g_pool.plugins: p.on_window_resize(window,w,h) def on_key(window, key, scancode, action, mods): g_pool.gui.update_key(key,scancode,action,mods) def on_char(window,char): g_pool.gui.update_char(char) def on_button(window,button, action, mods): g_pool.gui.update_button(button,action,mods) pos = glfwGetCursorPos(window) pos = normalize(pos,glfwGetWindowSize(main_window)) pos = denormalize(pos,(frame.img.shape[1],frame.img.shape[0]) ) # Position in img pixels for p in g_pool.plugins: p.on_click(pos,button,action) def on_pos(window,x, y): hdpi_factor = float(glfwGetFramebufferSize(window)[0]/glfwGetWindowSize(window)[0]) x,y = x*hdpi_factor,y*hdpi_factor g_pool.gui.update_mouse(x,y) def on_scroll(window,x,y): g_pool.gui.update_scroll(x,y*y_scroll_factor) def on_close(window): glfwSetWindowShouldClose(main_window,True) logger.debug('Process closing from window') try: rec_dir = sys.argv[1] except: #for dev, supply hardcoded dir: rec_dir = '/Users/mkassner/Desktop/Marker_Tracking_Demo_Recording/' if os.path.isdir(rec_dir): logger.debug("Dev option: Using hadcoded data dir.") else: if getattr(sys, 'frozen', False): logger.warning("You did not supply a data directory when you called this script! \ \nPlease drag a Pupil recoding directory onto the launch icon.") else: logger.warning("You did not supply a data directory when you called this script! \ \nPlease supply a Pupil recoding directory as first arg when calling Pupil Player.") return if not is_pupil_rec_dir(rec_dir): logger.error("You did not supply a dir with the required files inside.") return # load session persistent settings session_settings = Persistent_Dict(os.path.join(user_dir,"user_settings")) #backwards compatibility fn. patch_meta_info(rec_dir) #parse info.csv file meta_info_path = rec_dir + "/info.csv" with open(meta_info_path) as info: meta_info = dict( ((line.strip().split('\t')) for line in info.readlines() ) ) rec_version = read_rec_version(meta_info) if rec_version < VersionFormat('0.4'): video_path = rec_dir + "/world.avi" timestamps_path = rec_dir + "/timestamps.npy" else: video_path = rec_dir + "/world.mkv" timestamps_path = rec_dir + "/world_timestamps.npy" gaze_positions_path = rec_dir + "/gaze_positions.npy" #load gaze information gaze_list = np.load(gaze_positions_path) timestamps = np.load(timestamps_path) #correlate data if rec_version < VersionFormat('0.4'): positions_by_frame = correlate_gaze_legacy(gaze_list,timestamps) else: positions_by_frame = correlate_gaze(gaze_list,timestamps) # Initialize capture cap = autoCreateCapture(video_path,timestamps=timestamps_path) if isinstance(cap,FakeCapture): logger.error("could not start capture.") return width,height = session_settings.get('window_size',cap.get_size()) window_pos = session_settings.get('window_position',(0,0)) # not yet using this one. # Initialize glfw glfwInit() main_window = glfwCreateWindow(width, height, "Pupil Player: "+meta_info["Recording Name"]+" - "+ rec_dir.split(os.path.sep)[-1], None, None) glfwMakeContextCurrent(main_window) cygl.utils.init() # Register callbacks main_window glfwSetWindowSizeCallback(main_window,on_resize) glfwSetWindowCloseCallback(main_window,on_close) glfwSetKeyCallback(main_window,on_key) glfwSetCharCallback(main_window,on_char) glfwSetMouseButtonCallback(main_window,on_button) glfwSetCursorPosCallback(main_window,on_pos) glfwSetScrollCallback(main_window,on_scroll) # create container for globally scoped vars (within world) g_pool = Global_Container() g_pool.app = 'player' g_pool.version = get_version(version_file) g_pool.capture = cap g_pool.timestamps = timestamps g_pool.gaze_list = gaze_list g_pool.positions_by_frame = positions_by_frame g_pool.play = False g_pool.new_seek = True g_pool.user_dir = user_dir g_pool.rec_dir = rec_dir g_pool.rec_version = rec_version g_pool.meta_info = meta_info def next_frame(_): try: cap.seek_to_frame(cap.get_frame_index()) except FileSeekError: pass g_pool.new_seek = True def prev_frame(_): try: cap.seek_to_frame(cap.get_frame_index()-2) except FileSeekError: pass g_pool.new_seek = True def set_scale(new_scale): g_pool.gui.scale = new_scale g_pool.gui.collect_menus() def get_scale(): return g_pool.gui.scale def open_plugin(plugin): if plugin == "Select to load": return logger.debug('Open Plugin: %s'%plugin) new_plugin = plugin(g_pool) g_pool.plugins.add(new_plugin) def purge_plugins(): for p in g_pool.plugins: if p.__class__ in user_launchable_plugins: p.alive=False g_pool.plugins.clean() g_pool.gui = ui.UI() g_pool.gui.scale = session_settings.get('gui_scale',1) g_pool.main_menu = ui.Scrolling_Menu("Settings",pos=(-350,20),size=(300,300)) g_pool.main_menu.append(ui.Button("quit",lambda: on_close(None))) g_pool.main_menu.configuration = session_settings.get('main_menu_config',{}) g_pool.main_menu.append(ui.Slider('scale', setter=set_scale,getter=get_scale,step = .05,min=0.75,max=2.5,label='Interface Size')) g_pool.main_menu.append(ui.Info_Text('Player Version: %s'%g_pool.version)) g_pool.main_menu.append(ui.Info_Text('Recording Version: %s'%rec_version)) g_pool.main_menu.append(ui.Selector('Open plugin', selection = user_launchable_plugins, labels = [p.__name__.replace('_',' ') for p in user_launchable_plugins], setter= open_plugin, getter = lambda: "Select to load")) g_pool.main_menu.append(ui.Button('Close all plugins',purge_plugins)) g_pool.main_menu.append(ui.Button('Reset window size',lambda: glfwSetWindowSize(main_window,cap.get_size()[0],cap.get_size()[1])) ) g_pool.quickbar = ui.Stretching_Menu('Quick Bar',(0,100),(120,-100)) g_pool.play_button = ui.Thumb('play',g_pool,label='Play',hotkey=GLFW_KEY_SPACE) g_pool.play_button.on_color[:] = (0,1.,.0,.8) g_pool.forward_button = ui.Thumb('forward',getter = lambda: False,setter= next_frame, hotkey=GLFW_KEY_RIGHT) g_pool.backward_button = ui.Thumb('backward',getter = lambda: False, setter = prev_frame, hotkey=GLFW_KEY_LEFT) g_pool.quickbar.extend([g_pool.play_button,g_pool.forward_button,g_pool.backward_button]) g_pool.gui.append(g_pool.quickbar) g_pool.gui.append(g_pool.main_menu) #we always load these plugins system_plugins = [('Trim_Marks',{}),('Seek_Bar',{})] default_plugins = [('Scan_Path',{}),('Vis_Polyline',{}),('Vis_Circle',{}),('Export_Launcher',{})] previous_plugins = session_settings.get('loaded_plugins',default_plugins) g_pool.plugins = Plugin_List(g_pool,plugin_by_name,system_plugins+previous_plugins) for p in g_pool.plugins: if p.class_name == 'Trim_Marks': g_pool.trim_marks = p break #set the last saved window size on_resize(main_window, *glfwGetWindowSize(main_window)) glfwSetWindowPos(main_window,0,0) # gl_state settings basic_gl_setup() g_pool.image_tex = create_named_texture((height,width,3)) #set up performace graphs: pid = os.getpid() ps = psutil.Process(pid) ts = cap.get_now()-.03 cpu_graph = graph.Bar_Graph() cpu_graph.pos = (20,110) cpu_graph.update_fn = ps.get_cpu_percent cpu_graph.update_rate = 5 cpu_graph.label = 'CPU %0.1f' fps_graph = graph.Bar_Graph() fps_graph.pos = (140,110) fps_graph.update_rate = 5 fps_graph.label = "%0.0f REC FPS" pupil_graph = graph.Bar_Graph(max_val=1.0) pupil_graph.pos = (260,110) pupil_graph.update_rate = 5 pupil_graph.label = "Confidence: %0.2f" while not glfwWindowShouldClose(main_window): #grab new frame if g_pool.play or g_pool.new_seek: try: new_frame = cap.get_frame() except EndofVideoFileError: #end of video logic: pause at last frame. g_pool.play=False if g_pool.new_seek: display_time = new_frame.timestamp g_pool.new_seek = False update_graph = True else: update_graph = False frame = new_frame.copy() events = {} #new positons we make a deepcopy just like the image is a copy. events['pupil_positions'] = deepcopy(positions_by_frame[frame.index]) if update_graph: #update performace graphs for p in events['pupil_positions']: pupil_graph.add(p['confidence']) t = new_frame.timestamp if ts != t: dt,ts = t-ts,t fps_graph.add(1./dt) g_pool.play_button.status_text = str(frame.index) #always update the CPU graph cpu_graph.update() # allow each Plugin to do its work. for p in g_pool.plugins: p.update(frame,events) #check if a plugin need to be destroyed g_pool.plugins.clean() # render camera image glfwMakeContextCurrent(main_window) make_coord_system_norm_based() update_named_texture(g_pool.image_tex,frame.img) draw_named_texture(g_pool.image_tex) make_coord_system_pixel_based(frame.img.shape) # render visual feedback from loaded plugins for p in g_pool.plugins: p.gl_display() graph.push_view() fps_graph.draw() cpu_graph.draw() pupil_graph.draw() graph.pop_view() g_pool.gui.update() #present frames at appropriate speed wait_time = frame.timestamp - display_time display_time = frame.timestamp try: spent_time = time()-timestamp sleep(wait_time-spent_time) except: pass timestamp = time() glfwSwapBuffers(main_window) glfwPollEvents() session_settings['loaded_plugins'] = g_pool.plugins.get_initializers() session_settings['gui_scale'] = g_pool.gui.scale session_settings['main_menu_config'] = g_pool.main_menu.configuration session_settings['window_size'] = glfwGetWindowSize(main_window) session_settings['window_position'] = glfwGetWindowPos(main_window) session_settings.close() # de-init all running plugins for p in g_pool.plugins: p.alive = False g_pool.plugins.clean() cap.close() glfwDestroyWindow(main_window) glfwTerminate() logger.debug("Process done")
def main(): # Callback functions def on_resize(window, w, h): active_window = glfwGetCurrentContext() glfwMakeContextCurrent(window) hdpi_factor = glfwGetFramebufferSize(window)[0] / glfwGetWindowSize( window)[0] w, h = w * hdpi_factor, h * hdpi_factor g_pool.gui.update_window(w, h) g_pool.gui.collect_menus() graph.adjust_size(w, h) adjust_gl_view(w, h) glfwMakeContextCurrent(active_window) for p in g_pool.plugins: p.on_window_resize(window, w, h) def on_key(window, key, scancode, action, mods): g_pool.gui.update_key(key, scancode, action, mods) def on_char(window, char): g_pool.gui.update_char(char) def on_button(window, button, action, mods): g_pool.gui.update_button(button, action, mods) pos = glfwGetCursorPos(window) pos = normalize(pos, glfwGetWindowSize(window)) pos = denormalize( pos, (frame.img.shape[1], frame.img.shape[0])) # Position in img pixels for p in g_pool.plugins: p.on_click(pos, button, action) def on_pos(window, x, y): hdpi_factor = float( glfwGetFramebufferSize(window)[0] / glfwGetWindowSize(window)[0]) x, y = x * hdpi_factor, y * hdpi_factor g_pool.gui.update_mouse(x, y) def on_scroll(window, x, y): g_pool.gui.update_scroll(x, y * y_scroll_factor) def on_close(window): glfwSetWindowShouldClose(main_window, True) logger.debug('Process closing from window') try: rec_dir = sys.argv[1] except: #for dev, supply hardcoded dir: rec_dir = '/Users/mkassner/Desktop/Marker_Tracking_Demo_Recording/' if os.path.isdir(rec_dir): logger.debug("Dev option: Using hadcoded data dir.") else: if getattr(sys, 'frozen', False): logger.warning( "You did not supply a data directory when you called this script! \ \nPlease drag a Pupil recoding directory onto the launch icon." ) else: logger.warning( "You did not supply a data directory when you called this script! \ \nPlease supply a Pupil recoding directory as first arg when calling Pupil Player." ) return if not is_pupil_rec_dir(rec_dir): logger.error( "You did not supply a dir with the required files inside.") return # load session persistent settings session_settings = Persistent_Dict(os.path.join(user_dir, "user_settings")) #backwards compatibility fn. patch_meta_info(rec_dir) #parse info.csv file meta_info_path = rec_dir + "/info.csv" with open(meta_info_path) as info: meta_info = dict( ((line.strip().split('\t')) for line in info.readlines())) rec_version = read_rec_version(meta_info) if rec_version < VersionFormat('0.4'): video_path = rec_dir + "/world.avi" timestamps_path = rec_dir + "/timestamps.npy" else: video_path = rec_dir + "/world.mkv" timestamps_path = rec_dir + "/world_timestamps.npy" gaze_positions_path = rec_dir + "/gaze_positions.npy" #load gaze information gaze_list = np.load(gaze_positions_path) timestamps = np.load(timestamps_path) #correlate data if rec_version < VersionFormat('0.4'): positions_by_frame = correlate_gaze_legacy(gaze_list, timestamps) else: positions_by_frame = correlate_gaze(gaze_list, timestamps) # Initialize capture cap = autoCreateCapture(video_path, timestamps=timestamps_path) if isinstance(cap, FakeCapture): logger.error("could not start capture.") return width, height = session_settings.get('window_size', cap.frame_size) window_pos = session_settings.get('window_position', (0, 0)) # not yet using this one. # Initialize glfw glfwInit() main_window = glfwCreateWindow( width, height, "Pupil Player: " + meta_info["Recording Name"] + " - " + rec_dir.split(os.path.sep)[-1], None, None) glfwMakeContextCurrent(main_window) cygl.utils.init() # Register callbacks main_window glfwSetWindowSizeCallback(main_window, on_resize) glfwSetWindowCloseCallback(main_window, on_close) glfwSetKeyCallback(main_window, on_key) glfwSetCharCallback(main_window, on_char) glfwSetMouseButtonCallback(main_window, on_button) glfwSetCursorPosCallback(main_window, on_pos) glfwSetScrollCallback(main_window, on_scroll) # create container for globally scoped vars (within world) g_pool = Global_Container() g_pool.app = 'player' g_pool.version = get_version(version_file) g_pool.capture = cap g_pool.timestamps = timestamps g_pool.gaze_list = gaze_list g_pool.positions_by_frame = positions_by_frame g_pool.play = False g_pool.new_seek = True g_pool.user_dir = user_dir g_pool.rec_dir = rec_dir g_pool.rec_version = rec_version g_pool.meta_info = meta_info def next_frame(_): try: cap.seek_to_frame(cap.get_frame_index()) except FileSeekError: pass g_pool.new_seek = True def prev_frame(_): try: cap.seek_to_frame(cap.get_frame_index() - 2) except FileSeekError: pass g_pool.new_seek = True def set_scale(new_scale): g_pool.gui.scale = new_scale g_pool.gui.collect_menus() def get_scale(): return g_pool.gui.scale def open_plugin(plugin): if plugin == "Select to load": return logger.debug('Open Plugin: %s' % plugin) new_plugin = plugin(g_pool) g_pool.plugins.add(new_plugin) def purge_plugins(): for p in g_pool.plugins: if p.__class__ in user_launchable_plugins: p.alive = False g_pool.plugins.clean() g_pool.gui = ui.UI() g_pool.gui.scale = session_settings.get('gui_scale', 1) g_pool.main_menu = ui.Scrolling_Menu("Settings", pos=(-350, 20), size=(300, 300)) g_pool.main_menu.append(ui.Button("quit", lambda: on_close(None))) g_pool.main_menu.configuration = session_settings.get( 'main_menu_config', {}) g_pool.main_menu.append( ui.Slider('scale', setter=set_scale, getter=get_scale, step=.05, min=0.75, max=2.5, label='Interface Size')) g_pool.main_menu.append(ui.Info_Text('Player Version: %s' % g_pool.version)) g_pool.main_menu.append(ui.Info_Text('Recording Version: %s' % rec_version)) g_pool.main_menu.append( ui.Selector('Open plugin', selection=user_launchable_plugins, labels=[ p.__name__.replace('_', ' ') for p in user_launchable_plugins ], setter=open_plugin, getter=lambda: "Select to load")) g_pool.main_menu.append(ui.Button('Close all plugins', purge_plugins)) g_pool.main_menu.append( ui.Button( 'Reset window size', lambda: glfwSetWindowSize( main_window, cap.frame_size[0], cap.frame_size[1]))) g_pool.quickbar = ui.Stretching_Menu('Quick Bar', (0, 100), (120, -100)) g_pool.play_button = ui.Thumb('play', g_pool, label='Play', hotkey=GLFW_KEY_SPACE) g_pool.play_button.on_color[:] = (0, 1., .0, .8) g_pool.forward_button = ui.Thumb('forward', getter=lambda: False, setter=next_frame, hotkey=GLFW_KEY_RIGHT) g_pool.backward_button = ui.Thumb('backward', getter=lambda: False, setter=prev_frame, hotkey=GLFW_KEY_LEFT) g_pool.quickbar.extend( [g_pool.play_button, g_pool.forward_button, g_pool.backward_button]) g_pool.gui.append(g_pool.quickbar) g_pool.gui.append(g_pool.main_menu) #we always load these plugins system_plugins = [('Trim_Marks', {}), ('Seek_Bar', {})] default_plugins = [('Scan_Path', {}), ('Vis_Polyline', {}), ('Vis_Circle', {}), ('Export_Launcher', {})] previous_plugins = session_settings.get('loaded_plugins', default_plugins) g_pool.plugins = Plugin_List(g_pool, plugin_by_name, system_plugins + previous_plugins) for p in g_pool.plugins: if p.class_name == 'Trim_Marks': g_pool.trim_marks = p break #set the last saved window size on_resize(main_window, *glfwGetWindowSize(main_window)) glfwSetWindowPos(main_window, 0, 0) # gl_state settings basic_gl_setup() g_pool.image_tex = create_named_texture((height, width, 3)) #set up performace graphs: pid = os.getpid() ps = psutil.Process(pid) ts = cap.get_now() - .03 cpu_graph = graph.Bar_Graph() cpu_graph.pos = (20, 110) cpu_graph.update_fn = ps.get_cpu_percent cpu_graph.update_rate = 5 cpu_graph.label = 'CPU %0.1f' fps_graph = graph.Bar_Graph() fps_graph.pos = (140, 110) fps_graph.update_rate = 5 fps_graph.label = "%0.0f REC FPS" pupil_graph = graph.Bar_Graph(max_val=1.0) pupil_graph.pos = (260, 110) pupil_graph.update_rate = 5 pupil_graph.label = "Confidence: %0.2f" while not glfwWindowShouldClose(main_window): #grab new frame if g_pool.play or g_pool.new_seek: try: new_frame = cap.get_frame() except EndofVideoFileError: #end of video logic: pause at last frame. g_pool.play = False if g_pool.new_seek: display_time = new_frame.timestamp g_pool.new_seek = False update_graph = True else: update_graph = False frame = new_frame.copy() events = {} #new positons we make a deepcopy just like the image is a copy. events['pupil_positions'] = deepcopy(positions_by_frame[frame.index]) if update_graph: #update performace graphs for p in events['pupil_positions']: pupil_graph.add(p['confidence']) t = new_frame.timestamp if ts != t: dt, ts = t - ts, t fps_graph.add(1. / dt) g_pool.play_button.status_text = str(frame.index) #always update the CPU graph cpu_graph.update() # allow each Plugin to do its work. for p in g_pool.plugins: p.update(frame, events) #check if a plugin need to be destroyed g_pool.plugins.clean() # render camera image glfwMakeContextCurrent(main_window) make_coord_system_norm_based() update_named_texture(g_pool.image_tex, frame.img) draw_named_texture(g_pool.image_tex) make_coord_system_pixel_based(frame.img.shape) # render visual feedback from loaded plugins for p in g_pool.plugins: p.gl_display() graph.push_view() fps_graph.draw() cpu_graph.draw() pupil_graph.draw() graph.pop_view() g_pool.gui.update() #present frames at appropriate speed wait_time = frame.timestamp - display_time display_time = frame.timestamp try: spent_time = time() - timestamp sleep(wait_time - spent_time) except: pass timestamp = time() glfwSwapBuffers(main_window) glfwPollEvents() session_settings['loaded_plugins'] = g_pool.plugins.get_initializers() session_settings['gui_scale'] = g_pool.gui.scale session_settings['main_menu_config'] = g_pool.main_menu.configuration session_settings['window_size'] = glfwGetWindowSize(main_window) session_settings['window_position'] = glfwGetWindowPos(main_window) session_settings.close() # de-init all running plugins for p in g_pool.plugins: p.alive = False g_pool.plugins.clean() cap.close() glfwDestroyWindow(main_window) glfwTerminate() logger.debug("Process done")