Esempio n. 1
0
def get_recording_dirs(data_dir):
    """
    You can supply a data folder or any folder
    - all folders within will be checked for necessary files
    - in order to make a visualization
    """
    if is_pupil_rec_dir(data_dir):
        yield data_dir
    for root, dirs, files in os.walk(data_dir):
        for d in dirs:
            joined = os.path.join(root, d)
            if not d.startswith(".") and is_pupil_rec_dir(joined):
                yield joined
Esempio n. 2
0
def get_recording_dirs(data_dir):
    """
        You can supply a data folder or any folder
        - all folders within will be checked for necessary files
        - in order to make a visualization
    """
    if is_pupil_rec_dir(data_dir):
        yield data_dir
    for root, dirs, files in os.walk(data_dir):
        for d in dirs:
            joined = os.path.join(root, d)
            if not d.startswith(".") and is_pupil_rec_dir(joined):
                yield joined
Esempio n. 3
0
def get_recording_dirs(data_dir):
    '''
        You can supply a data folder or any folder
        - all folders within will be checked for necessary files
        - in order to make a visualization
    '''
    filtered_recording_dirs = []
    if is_pupil_rec_dir(data_dir):
        filtered_recording_dirs.append(data_dir)
    for root, dirs, files in os.walk(data_dir):
        filtered_recording_dirs += [os.path.join(root, d) for d in dirs
                                    if not d.startswith(".") and is_pupil_rec_dir(os.path.join(root, d))]
    logger.debug("Filtered Recording Dirs: {}".format(filtered_recording_dirs))
    return filtered_recording_dirs
Esempio n. 4
0
def get_recording_dirs(data_dir):
    '''
        You can supply a data folder or any folder
        - all folders within will be checked for necessary files
        - in order to make a visualization
    '''
    filtered_recording_dirs = []
    if is_pupil_rec_dir(data_dir):
        filtered_recording_dirs.append(data_dir)
    for root, dirs, files in os.walk(data_dir):
        filtered_recording_dirs += [os.path.join(root, d) for d in dirs
                                    if not d.startswith(".") and is_pupil_rec_dir(os.path.join(root, d))]
    logger.debug("Filtered Recording Dirs: {}".format(filtered_recording_dirs))
    return filtered_recording_dirs
Esempio n. 5
0
 def on_drop(window, count, paths):
     paths = [paths[x].decode("utf-8") for x in range(count)]
     for path in paths:
         if pm.is_pupil_rec_dir(path):
             _restart_with_recording(path)
             return
     # call `on_drop` callbacks until a plugin indicates
     # that it has consumed the event (by returning True)
     any(p.on_drop(paths) for p in g_pool.plugins)
Esempio n. 6
0
 def on_drop(window, count, paths):
     paths = [paths[x].decode("utf-8") for x in range(count)]
     for path in paths:
         if pm.is_pupil_rec_dir(path):
             _restart_with_recording(path)
             return
     for plugin in g_pool.plugins:
         if plugin.on_drop(paths):
             break
Esempio n. 7
0
 def on_drop(window, count, paths):
     paths = [paths[x].decode("utf-8") for x in range(count)]
     for path in paths:
         if pm.is_pupil_rec_dir(path):
             _restart_with_recording(path)
             return
     # call `on_drop` callbacks until a plugin indicates
     # that it has consumed the event (by returning True)
     any(p.on_drop(paths) for p in g_pool.plugins)
Esempio n. 8
0
 def on_drop(window, count, paths):
     for x in range(count):
         new_rec_dir = paths[x].decode('utf-8')
         if is_pupil_rec_dir(new_rec_dir):
             logger.debug("Starting new session with '{}'".format(new_rec_dir))
             ipc_pub.notify({"subject": "player_drop_process.should_start", "rec_dir": new_rec_dir})
             glfw.glfwSetWindowShouldClose(window, True)
         else:
             logger.error("'{}' is not a valid pupil recording".format(new_rec_dir))
Esempio n. 9
0
 def on_drop(window, count, paths):
     for x in range(count):
         new_rec_dir = paths[x].decode('utf-8')
         if is_pupil_rec_dir(new_rec_dir):
             logger.debug("Starting new session with '{}'".format(new_rec_dir))
             ipc_pub.notify({"subject": "player_drop_process.should_start", "rec_dir": new_rec_dir})
             glfw.glfwSetWindowShouldClose(window, True)
         else:
             logger.error("'{}' is not a valid pupil recording".format(new_rec_dir))
Esempio n. 10
0
 def on_drop(window,count,paths):
     for x in range(count):
         new_rec_dir =  paths[x]
         if is_pupil_rec_dir(new_rec_dir):
             logger.debug("Starting new session with '%s'"%new_rec_dir)
             global rec_dir
             rec_dir = new_rec_dir
             glfwSetWindowShouldClose(window,True)
         else:
             logger.error("'%s' is not a valid pupil recording"%new_rec_dir)
Esempio n. 11
0
 def on_drop(window, count, paths):
     for x in range(count):
         new_rec_dir = paths[x].decode('utf-8')
         if is_pupil_rec_dir(new_rec_dir):
             logger.debug("Starting new session with '{}'".format(new_rec_dir))
             global rec_dir
             rec_dir = new_rec_dir
             glfwSetWindowShouldClose(window, True)
         else:
             logger.error("'{}' is not a valid pupil recording".format(new_rec_dir))
Esempio n. 12
0

if __name__ == '__main__':
    freeze_support()
    try:
        rec_dir = os.path.expanduser(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 hardcoded data dir.")
        else:
            logger.warning("You did not supply a data directory when you called this script!")
    glfwInit()
    while rec_dir is not None:
        if not is_pupil_rec_dir(rec_dir):
            rec_dir = None
            show_no_rec_window()
        else:
            this_session_dir = rec_dir
            rec_dir = None
            session(this_session_dir)
    glfwTerminate()

    # import cProfile,subprocess,os
    # cProfile.runctx("main()",{},locals(),"player.pstats")
    # loc = os.path.abspath(__file__).rsplit('pupil_src', 1)
    # gprof2dot_loc = os.path.join(loc[0], 'pupil_src', 'shared_modules','gprof2dot.py')
    # subprocess.call("python "+gprof2dot_loc+" -f pstats player.pstats | dot -Tpng -o player_cpu_time.png", shell=True)
    # print "created cpu time graph for pupil player . Please check out the png next to the main.py file"
Esempio n. 13
0
def main():

    # Callback functions
    def on_resize(window, w, h):
        active_window = glfwGetCurrentContext()
        glfwMakeContextCurrent(window)
        adjust_gl_view(w, h, window)
        norm_size = normalize((w, h), glfwGetWindowSize(window))
        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):
            if action == GLFW_PRESS:
                pass

    def on_char(window, char):
        if not atb.TwEventCharGLFW(char, 1):
            pass

    def on_button(window, button, action, mods):
        if not atb.TwEventMouseButtonGLFW(button, action):
            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.plugins:
                p.on_click(pos, button, action)

    def on_pos(window, x, y):
        norm_pos = normalize((x, y), glfwGetWindowSize(window))
        fb_x, fb_y = denormalize(norm_pos, glfwGetFramebufferSize(window))
        if atb.TwMouseMotion(int(fb_x), int(fb_y)):
            pass

    def on_scroll(window, x, y):
        if not atb.TwMouseWheel(int(x)):
            pass

    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

    #backwards compatibility fn.
    patch_meta_info(rec_dir)

    #parse and load data folder info
    video_path = rec_dir + "/world.avi"
    timestamps_path = rec_dir + "/timestamps.npy"
    gaze_positions_path = rec_dir + "/gaze_positions.npy"
    meta_info_path = rec_dir + "/info.csv"

    #parse info.csv file
    with open(meta_info_path) as info:
        meta_info = dict(
            ((line.strip().split('\t')) for line in info.readlines()))
    rec_version = meta_info["Capture Software Version"]
    rec_version_float = int(
        filter(type(rec_version).isdigit,
               rec_version)[:3]) / 100.  #(get major,minor,fix of version)
    logger.debug("Recording version: %s , %s" %
                 (rec_version, rec_version_float))

    #load gaze information
    gaze_list = np.load(gaze_positions_path)
    timestamps = np.load(timestamps_path)

    #correlate data
    positions_by_frame = correlate_gaze(gaze_list, timestamps)

    # load session persistent settings
    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):
        session_settings[var_name] = var

    # Initialize capture
    cap = autoCreateCapture(video_path, timestamps=timestamps_path)

    if isinstance(cap, FakeCapture):
        logger.error("could not start capture.")
        return

    width, height = cap.get_size()

    # 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)

    # 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 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

    # helpers called by the main atb bar
    def update_fps():
        old_time, bar.timestamp = bar.timestamp, time()
        dt = bar.timestamp - old_time
        if dt:
            bar.fps.value += .1 * (1. / dt - bar.fps.value)

    def set_window_size(mode, data):
        width, height = cap.get_size()
        ratio = (1, .75, .5, .25)[mode]
        w, h = int(width * ratio), int(height * ratio)
        glfwSetWindowSize(main_window, w, h)
        data.value = mode  # update the bar.value

    def get_from_data(data):
        """
        helper for atb getter and setter use
        """
        return data.value

    def get_play():
        return g.play

    def set_play(value):
        g.play = value

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

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

    def open_plugin(selection, data):
        if plugin_by_index[selection] not in additive_plugins:
            for p in g.plugins:
                if isinstance(p, plugin_by_index[selection]):
                    return

        g.plugins = [p for p in g.plugins if p.alive]
        logger.debug('Open Plugin: %s' % name_by_index[selection])
        new_plugin = plugin_by_index[selection](g)
        g.plugins.append(new_plugin)
        g.plugins.sort(key=lambda p: p.order)

        if hasattr(new_plugin, 'init_gui'):
            new_plugin.init_gui()
        # save the value for atb bar
        data.value = selection

    def get_from_data(data):
        """
        helper for atb getter and setter use
        """
        return data.value

    atb.init()
    # add main controls ATB bar
    bar = atb.Bar(name="Controls",
                  label="Controls",
                  help="Scene controls",
                  color=(50, 50, 50),
                  alpha=100,
                  valueswidth=150,
                  text='light',
                  position=(10, 10),
                  refresh=.1,
                  size=(300, 160))
    bar.next_atb_pos = (10, 220)
    bar.fps = c_float(0.0)
    bar.timestamp = time()
    bar.window_size = c_int(load("window_size", 0))
    window_size_enum = atb.enum("Display Size", {
        "Full": 0,
        "Medium": 1,
        "Half": 2,
        "Mini": 3
    })
    bar.version = create_string_buffer(version, 512)
    bar.recording_version = create_string_buffer(rec_version, 512)
    bar.add_var("fps", bar.fps, step=1., readonly=True)
    bar._fps = c_float(cap.get_fps())
    bar.add_var("recoding fps", bar._fps, readonly=True)
    bar.add_var("display size",
                vtype=window_size_enum,
                setter=set_window_size,
                getter=get_from_data,
                data=bar.window_size)
    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",
                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)
    bar.add_var("plugin",
                setter=open_plugin,
                getter=get_from_data,
                data=bar.plugin_to_load,
                vtype=plugin_type_enum)
    bar.add_var(
        "version of recording",
        bar.recording_version,
        readonly=True,
        help="version of the capture software used to make this recording")
    bar.add_var("version of player",
                bar.version,
                readonly=True,
                help="version of the Pupil Player")
    bar.add_button("exit", on_close, data=main_window, key="esc")

    #set the last saved window size
    set_window_size(bar.window_size.value, bar.window_size)
    on_resize(main_window, *glfwGetWindowSize(main_window))
    glfwSetWindowPos(main_window, 0, 0)

    #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', []):
        name, args = initializer
        logger.debug("Loading plugin: %s with settings %s" % (name, args))
        try:
            p = plugin_by_name[name](g, **args)
            g.plugins.append(p)
        except:
            logger.warning("Plugin '%s' failed to load from settings file." %
                           name)

    if load('plugins', "_") == "_":
        #lets load some default if we dont have presets
        g.plugins.append(Scan_Path(g))
        g.plugins.append(Vis_Polyline(g))
        g.plugins.append(Vis_Circle(g))
        # g.plugins.append(Vis_Light_Points(g))

    #sort by exec order
    g.plugins.sort(key=lambda p: p.order)

    #init gui
    for p in g.plugins:
        if hasattr(p, 'init_gui'):
            p.init_gui()

    # gl_state settings
    basic_gl_setup()
    g.image_tex = create_named_texture((height, width, 3))

    while not glfwWindowShouldClose(main_window):

        update_fps()

        #grab new frame
        if g.play or g.new_seek:
            try:
                new_frame = cap.get_frame()
            except EndofVideoFileError:
                #end of video logic: pause at last frame.
                g.play = False

            if g.new_seek:
                display_time = new_frame.timestamp
                g.new_seek = False

        frame = new_frame.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 = []

        # allow each Plugin to do its work.
        for p in g.plugins:
            p.update(frame, current_pupil_positions, events)

        #check if a plugin need to be destroyed
        g.plugins = [p for p in g.plugins if p.alive]

        # render camera image
        glfwMakeContextCurrent(main_window)
        make_coord_system_norm_based()
        draw_named_texture(g.image_tex, frame.img)
        make_coord_system_pixel_based(frame.img.shape)
        # render visual feedback from loaded plugins
        for p in g.plugins:
            p.gl_display()

        #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()

        atb.draw()
        glfwSwapBuffers(main_window)
        glfwPollEvents()

    plugin_save = []
    for p in g.plugins:
        try:
            p_initializer = p.get_class_name(), p.get_init_dict()
            plugin_save.append(p_initializer)
        except AttributeError:
            #not all plugins need to be savable, they will not have the init dict.
            # any object without a get_init_dict method will throw this exception.
            pass

    # de-init all running plugins
    for p in g.plugins:
        p.alive = False
        #reading p.alive actually runs plug-in cleanup
        _ = p.alive

    save('plugins', plugin_save)
    save('window_size', bar.window_size.value)
    session_settings.close()

    cap.close()
    bar.destroy()
    glfwDestroyWindow(main_window)
    glfwTerminate()
    logger.debug("Process done")
Esempio n. 14
0
def player_drop(rec_dir, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir,
                app_version):
    # general imports
    import logging
    # networking
    import zmq
    import zmq_tools
    from time import sleep

    # zmq ipc setup
    zmq_ctx = zmq.Context()
    ipc_pub = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url)

    # log setup
    logging.getLogger("OpenGL").setLevel(logging.ERROR)
    logger = logging.getLogger()
    logger.handlers = []
    logger.setLevel(logging.INFO)
    logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url))
    # create logger for the context of this function
    logger = logging.getLogger(__name__)

    try:

        import glfw
        import gl_utils
        from OpenGL.GL import glClearColor
        from version_utils import VersionFormat
        from file_methods import Persistent_Dict
        from pyglui.pyfontstash import fontstash
        from pyglui.ui import get_roboto_font_path
        from player_methods import is_pupil_rec_dir, update_recording_to_recent

        def on_drop(window, count, paths):
            nonlocal rec_dir
            rec_dir = paths[0].decode('utf-8')

        if rec_dir:
            if not is_pupil_rec_dir(rec_dir):
                rec_dir = None
        # load session persistent settings
        session_settings = Persistent_Dict(
            os.path.join(user_dir, "user_settings_player"))
        if VersionFormat(session_settings.get("version",
                                              '0.0')) != app_version:
            logger.info(
                "Session setting are from a  different version of this app. I will not use those."
            )
            session_settings.clear()
        w, h = session_settings.get('window_size', (1280, 720))
        window_pos = session_settings.get('window_position',
                                          window_position_default)

        glfw.glfwInit()
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, 0)
        window = glfw.glfwCreateWindow(w, h, 'Pupil Player')
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, 1)

        glfw.glfwMakeContextCurrent(window)
        glfw.glfwSetWindowPos(window, window_pos[0], window_pos[1])
        glfw.glfwSetDropCallback(window, on_drop)

        glfont = fontstash.Context()
        glfont.add_font('roboto', get_roboto_font_path())
        glfont.set_align_string(v_align="center", h_align="middle")
        glfont.set_color_float((0.2, 0.2, 0.2, 0.9))
        gl_utils.basic_gl_setup()
        glClearColor(0.5, .5, 0.5, 0.0)
        text = 'Drop a recording directory onto this window.'
        tip = '(Tip: You can drop a recording directory onto the app icon.)'
        # text = "Please supply a Pupil recording directory as first arg when calling Pupil Player."
        while not glfw.glfwWindowShouldClose(window):

            fb_size = glfw.glfwGetFramebufferSize(window)
            hdpi_factor = float(fb_size[0] / glfw.glfwGetWindowSize(window)[0])
            gl_utils.adjust_gl_view(*fb_size)

            if rec_dir:
                if is_pupil_rec_dir(rec_dir):
                    logger.info(
                        "Starting new session with '{}'".format(rec_dir))
                    text = "Updating recording format."
                    tip = "This may take a while!"
                else:
                    logger.error(
                        "'{}' is not a valid pupil recording".format(rec_dir))
                    tip = "Oops! That was not a valid recording."
                    rec_dir = None

            gl_utils.clear_gl_screen()
            glfont.set_blur(10.5)
            glfont.set_color_float((0.0, 0.0, 0.0, 1.))
            glfont.set_size(w / 25. * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, .3 * h * hdpi_factor, text)
            glfont.set_size(w / 30. * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, .4 * h * hdpi_factor, tip)
            glfont.set_blur(0.96)
            glfont.set_color_float((1., 1., 1., 1.))
            glfont.set_size(w / 25. * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, .3 * h * hdpi_factor, text)
            glfont.set_size(w / 30. * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, .4 * h * hdpi_factor, tip)

            glfw.glfwSwapBuffers(window)

            if rec_dir:
                update_recording_to_recent(rec_dir)
                glfw.glfwSetWindowShouldClose(window, True)

            glfw.glfwPollEvents()

        session_settings['window_position'] = glfw.glfwGetWindowPos(window)
        session_settings.close()
        glfw.glfwDestroyWindow(window)
        if rec_dir:
            ipc_pub.notify({
                "subject": "player_process.should_start",
                "rec_dir": rec_dir
            })

    except:
        import traceback
        trace = traceback.format_exc()
        logger.error(
            'Process player_drop crashed with trace:\n{}'.format(trace))

    finally:
        sleep(1.0)
Esempio n. 15
0
def show_no_rec_window():
    from pyglui.pyfontstash import fontstash
    from pyglui.ui import get_roboto_font_path
    global rec_dir
    def on_drop(window, count, paths):
        global rec_dir
        rec_dir = paths[0].decode('utf-8')

    # load session persistent settings
    session_settings = Persistent_Dict(os.path.join(user_dir, "user_settings"))
    if VersionFormat(session_settings.get("version", '0.0')) != get_version(version_file):
        logger.info("Session setting are from a  different version of this app. I will not use those.")
        session_settings.clear()
    w, h = session_settings.get('window_size', (1280, 720))
    window_pos = session_settings.get('window_position', window_position_default)

    glfwWindowHint(GLFW_RESIZABLE, 0)
    window = glfwCreateWindow(w, h, 'Pupil Player')
    glfwWindowHint(GLFW_RESIZABLE, 1)

    glfwMakeContextCurrent(window)
    glfwSetWindowPos(window, window_pos[0], window_pos[1])
    glfwSetDropCallback(window, on_drop)

    glfont = fontstash.Context()
    glfont.add_font('roboto', get_roboto_font_path())
    glfont.set_align_string(v_align="center", h_align="middle")
    glfont.set_color_float((0.2, 0.2, 0.2, 0.9))
    gl_utils.basic_gl_setup()
    glClearColor(0.5, .5, 0.5, 0.0)
    text = 'Drop a recording directory onto this window.'
    tip = '(Tip: You can drop a recording directory onto the app icon.)'
    # text = "Please supply a Pupil recording directory as first arg when calling Pupil Player."
    while not glfwWindowShouldClose(window):

        fb_size = glfwGetFramebufferSize(window)
        hdpi_factor = float(fb_size[0] / glfwGetWindowSize(window)[0])
        gl_utils.adjust_gl_view(*fb_size)

        if rec_dir:
            if is_pupil_rec_dir(rec_dir):
                logger.info("Starting new session with '{}'".format(rec_dir))
                text = "Updating recording format."
                tip = "This may take a while!"
            else:
                logger.error("'{}' is not a valid pupil recording".format(rec_dir))
                tip = "Oops! That was not a valid recording."
                rec_dir = None

        gl_utils.clear_gl_screen()
        glfont.set_blur(10.5)
        glfont.set_color_float((0.0, 0.0, 0.0, 1.))
        glfont.set_size(w/25.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .3*h*hdpi_factor, text)
        glfont.set_size(w/30.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .4*h*hdpi_factor, tip)
        glfont.set_blur(0.96)
        glfont.set_color_float((1., 1., 1., 1.))
        glfont.set_size(w/25.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .3*h*hdpi_factor, text)
        glfont.set_size(w/30.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .4*h*hdpi_factor, tip)

        glfwSwapBuffers(window)

        if rec_dir:
            update_recording_to_recent(rec_dir)
            glfwSetWindowShouldClose(window, True)

        glfwPollEvents()

    session_settings['window_position'] = glfwGetWindowPos(window)
    session_settings['version'] = str(get_version(version_file))
    session_settings.close()
    del glfont
    glfwDestroyWindow(window)
Esempio n. 16
0
File: main.py Progetto: elmorg/pupil
if __name__ == '__main__':
    freeze_support()
    try:
        rec_dir = os.path.expanduser(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 hardcoded data dir.")
        else:
            logger.warning(
                "You did not supply a data directory when you called this script!"
            )
    glfwInit()
    while rec_dir is not None:
        if not is_pupil_rec_dir(rec_dir):
            rec_dir = None
            show_no_rec_window()
        else:
            this_session_dir = rec_dir
            rec_dir = None
            session(this_session_dir)
    glfwTerminate()

    # import cProfile,subprocess,os
    # cProfile.runctx("main()",{},locals(),"player.pstats")
    # loc = os.path.abspath(__file__).rsplit('pupil_src', 1)
    # gprof2dot_loc = os.path.join(loc[0], 'pupil_src', 'shared_modules','gprof2dot.py')
    # subprocess.call("python "+gprof2dot_loc+" -f pstats player.pstats | dot -Tpng -o player_cpu_time.png", shell=True)
    # print "created cpu time graph for pupil player . Please check out the png next to the main.py file"
Esempio n. 17
0
def show_no_rec_window():
    from pyglui.pyfontstash import fontstash
    from pyglui.ui import get_roboto_font_path
    global rec_dir
    def on_drop(window, count, paths):
        global rec_dir
        rec_dir = paths[0].decode('utf-8')

    # load session persistent settings
    session_settings = Persistent_Dict(os.path.join(user_dir, "user_settings"))
    if VersionFormat(session_settings.get("version", '0.0')) != get_version(version_file):
        logger.info("Session setting are from a  different version of this app. I will not use those.")
        session_settings.clear()
    w, h = session_settings.get('window_size', (1280, 720))
    window_pos = session_settings.get('window_position', window_position_default)

    glfwWindowHint(GLFW_RESIZABLE, 0)
    window = glfwCreateWindow(w, h, 'Pupil Player')
    glfwWindowHint(GLFW_RESIZABLE, 1)

    glfwMakeContextCurrent(window)
    glfwSetWindowPos(window, window_pos[0], window_pos[1])
    glfwSetDropCallback(window, on_drop)

    glfont = fontstash.Context()
    glfont.add_font('roboto', get_roboto_font_path())
    glfont.set_align_string(v_align="center", h_align="middle")
    glfont.set_color_float((0.2, 0.2, 0.2, 0.9))
    gl_utils.basic_gl_setup()
    glClearColor(0.5, .5, 0.5, 0.0)
    text = 'Drop a recording directory onto this window.'
    tip = '(Tip: You can drop a recording directory onto the app icon.)'
    # text = "Please supply a Pupil recording directory as first arg when calling Pupil Player."
    while not glfwWindowShouldClose(window):

        fb_size = glfwGetFramebufferSize(window)
        hdpi_factor = float(fb_size[0] / glfwGetWindowSize(window)[0])
        gl_utils.adjust_gl_view(*fb_size)

        if rec_dir:
            if is_pupil_rec_dir(rec_dir):
                logger.info("Starting new session with '{}'".format(rec_dir))
                text = "Updating recording format."
                tip = "This may take a while!"
            else:
                logger.error("'{}' is not a valid pupil recording".format(rec_dir))
                tip = "Oops! That was not a valid recording."
                rec_dir = None

        gl_utils.clear_gl_screen()
        glfont.set_blur(10.5)
        glfont.set_color_float((0.0, 0.0, 0.0, 1.))
        glfont.set_size(w/25.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .3*h*hdpi_factor, text)
        glfont.set_size(w/30.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .4*h*hdpi_factor, tip)
        glfont.set_blur(0.96)
        glfont.set_color_float((1., 1., 1., 1.))
        glfont.set_size(w/25.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .3*h*hdpi_factor, text)
        glfont.set_size(w/30.*hdpi_factor)
        glfont.draw_text(w/2*hdpi_factor, .4*h*hdpi_factor, tip)

        glfwSwapBuffers(window)

        if rec_dir:
            update_recording_to_recent(rec_dir)
            glfwSetWindowShouldClose(window, True)

        glfwPollEvents()

    session_settings['window_position'] = glfwGetWindowPos(window)
    session_settings['version'] = str(get_version(version_file))
    session_settings.close()
    del glfont
    glfwDestroyWindow(window)
Esempio n. 18
0
def main():

    # Callback functions
    def on_resize(window,w, h):
        active_window = glfwGetCurrentContext()
        glfwMakeContextCurrent(window)
        adjust_gl_view(w,h,window)
        norm_size = normalize((w,h),glfwGetWindowSize(window))
        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):
            if action == GLFW_PRESS:
                pass

    def on_char(window,char):
        if not atb.TwEventCharGLFW(char,1):
            pass

    def on_button(window,button, action, mods):
        if not atb.TwEventMouseButtonGLFW(button,action):
            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.plugins:
                p.on_click(pos,button,action)

    def on_pos(window,x, y):
        norm_pos = normalize((x,y),glfwGetWindowSize(window))
        fb_x,fb_y = denormalize(norm_pos,glfwGetFramebufferSize(window))
        if atb.TwMouseMotion(int(fb_x),int(fb_y)):
            pass

    def on_scroll(window,x,y):
        if not atb.TwMouseWheel(int(x)):
            pass

    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

    #backwards compatibility fn.
    patch_meta_info(rec_dir)

    #parse and load data folder info
    video_path = rec_dir + "/world.avi"
    timestamps_path = rec_dir + "/timestamps.npy"
    gaze_positions_path = rec_dir + "/gaze_positions.npy"
    meta_info_path = rec_dir + "/info.csv"


    #parse info.csv file
    with open(meta_info_path) as info:
        meta_info = dict( ((line.strip().split('\t')) for line in info.readlines() ) )
    rec_version = meta_info["Capture Software Version"]
    rec_version_float = int(filter(type(rec_version).isdigit, rec_version)[:3])/100. #(get major,minor,fix of version)
    logger.debug("Recording version: %s , %s"%(rec_version,rec_version_float))


    #load gaze information
    gaze_list = np.load(gaze_positions_path)
    timestamps = np.load(timestamps_path)

    #correlate data
    positions_by_frame = correlate_gaze(gaze_list,timestamps)


    # load session persistent settings
    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):
        session_settings[var_name] = var


    # Initialize capture
    cap = autoCreateCapture(video_path,timestamps=timestamps_path)

    if isinstance(cap,FakeCapture):
        logger.error("could not start capture.")
        return

    width,height = cap.get_size()


    # 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)

    # 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 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



    # helpers called by the main atb bar
    def update_fps():
        old_time, bar.timestamp = bar.timestamp, time()
        dt = bar.timestamp - old_time
        if dt:
            bar.fps.value += .1 * (1. / dt - bar.fps.value)

    def set_window_size(mode,data):
        width,height = cap.get_size()
        ratio = (1,.75,.5,.25)[mode]
        w,h = int(width*ratio),int(height*ratio)
        glfwSetWindowSize(main_window,w,h)
        data.value=mode # update the bar.value

    def get_from_data(data):
        """
        helper for atb getter and setter use
        """
        return data.value

    def get_play():
        return g.play

    def set_play(value):
        g.play = value

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

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



    def open_plugin(selection,data):
        if plugin_by_index[selection] not in additive_plugins:
            for p in g.plugins:
                if isinstance(p,plugin_by_index[selection]):
                    return

        g.plugins = [p for p in g.plugins if p.alive]
        logger.debug('Open Plugin: %s'%name_by_index[selection])
        new_plugin = plugin_by_index[selection](g)
        g.plugins.append(new_plugin)
        g.plugins.sort(key=lambda p: p.order)

        if hasattr(new_plugin,'init_gui'):
            new_plugin.init_gui()
        # save the value for atb bar
        data.value=selection

    def get_from_data(data):
        """
        helper for atb getter and setter use
        """
        return data.value

    atb.init()
    # add main controls ATB bar
    bar = atb.Bar(name = "Controls", label="Controls",
            help="Scene controls", color=(50, 50, 50), alpha=100,valueswidth=150,
            text='light', position=(10, 10),refresh=.1, size=(300, 160))
    bar.next_atb_pos = (10,220)
    bar.fps = c_float(0.0)
    bar.timestamp = time()
    bar.window_size = c_int(load("window_size",0))
    window_size_enum = atb.enum("Display Size",{"Full":0, "Medium":1,"Half":2,"Mini":3})
    bar.version = create_string_buffer(version,512)
    bar.recording_version = create_string_buffer(rec_version,512)
    bar.add_var("fps", bar.fps, step=1., readonly=True)
    bar._fps = c_float(cap.get_fps())
    bar.add_var("recoding fps",bar._fps,readonly=True)
    bar.add_var("display size", vtype=window_size_enum,setter=set_window_size,getter=get_from_data,data=bar.window_size)
    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",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)
    bar.add_var("plugin",setter=open_plugin,getter=get_from_data,data=bar.plugin_to_load, vtype=plugin_type_enum)
    bar.add_var("version of recording",bar.recording_version, readonly=True, help="version of the capture software used to make this recording")
    bar.add_var("version of player",bar.version, readonly=True, help="version of the Pupil Player")
    bar.add_button("exit", on_close,data=main_window,key="esc")

    #set the last saved window size
    set_window_size(bar.window_size.value,bar.window_size)
    on_resize(main_window, *glfwGetWindowSize(main_window))
    glfwSetWindowPos(main_window,0,0)


    #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',[]):
        name, args = initializer
        logger.debug("Loading plugin: %s with settings %s"%(name, args))
        try:
            p = plugin_by_name[name](g,**args)
            g.plugins.append(p)
        except:
            logger.warning("Plugin '%s' failed to load from settings file." %name)

    if load('plugins',"_") == "_":
        #lets load some default if we dont have presets
        g.plugins.append(Scan_Path(g))
        g.plugins.append(Vis_Polyline(g))
        g.plugins.append(Vis_Circle(g))
        # g.plugins.append(Vis_Light_Points(g))

    #sort by exec order
    g.plugins.sort(key=lambda p: p.order)

    #init gui
    for p in g.plugins:
        if hasattr(p,'init_gui'):
            p.init_gui()

    # gl_state settings
    basic_gl_setup()
    g.image_tex = create_named_texture((height,width,3))


    while not glfwWindowShouldClose(main_window):

        update_fps()

        #grab new frame
        if g.play or g.new_seek:
            try:
                new_frame = cap.get_frame()
            except EndofVideoFileError:
                #end of video logic: pause at last frame.
                g.play=False

            if g.new_seek:
                display_time = new_frame.timestamp
                g.new_seek = False

        frame = new_frame.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 = []

        # allow each Plugin to do its work.
        for p in g.plugins:
            p.update(frame,current_pupil_positions,events)

        #check if a plugin need to be destroyed
        g.plugins = [p for p in g.plugins if p.alive]

        # render camera image
        glfwMakeContextCurrent(main_window)
        make_coord_system_norm_based()
        draw_named_texture(g.image_tex,frame.img)
        make_coord_system_pixel_based(frame.img.shape)
        # render visual feedback from loaded plugins
        for p in g.plugins:
            p.gl_display()

        #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()


        atb.draw()
        glfwSwapBuffers(main_window)
        glfwPollEvents()

    plugin_save = []
    for p in g.plugins:
        try:
            p_initializer = p.get_class_name(),p.get_init_dict()
            plugin_save.append(p_initializer)
        except AttributeError:
            #not all plugins need to be savable, they will not have the init dict.
            # any object without a get_init_dict method will throw this exception.
            pass

    # de-init all running plugins
    for p in g.plugins:
        p.alive = False
        #reading p.alive actually runs plug-in cleanup
        _ = p.alive

    save('plugins',plugin_save)
    save('window_size',bar.window_size.value)
    session_settings.close()

    cap.close()
    bar.destroy()
    glfwDestroyWindow(main_window)
    glfwTerminate()
    logger.debug("Process done")
Esempio n. 19
0
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")
Esempio n. 20
0
def player_drop(rec_dir, ipc_pub_url, ipc_sub_url, ipc_push_url, user_dir, app_version):
    # general imports
    import logging

    # networking
    import zmq
    import zmq_tools
    from time import sleep

    # zmq ipc setup
    zmq_ctx = zmq.Context()
    ipc_pub = zmq_tools.Msg_Dispatcher(zmq_ctx, ipc_push_url)

    # log setup
    logging.getLogger("OpenGL").setLevel(logging.ERROR)
    logger = logging.getLogger()
    logger.handlers = []
    logger.setLevel(logging.INFO)
    logger.addHandler(zmq_tools.ZMQ_handler(zmq_ctx, ipc_push_url))
    # create logger for the context of this function
    logger = logging.getLogger(__name__)

    try:

        import glfw
        import gl_utils
        from OpenGL.GL import glClearColor
        from version_utils import VersionFormat
        from file_methods import Persistent_Dict
        from pyglui.pyfontstash import fontstash
        from pyglui.ui import get_roboto_font_path
        import player_methods as pm
        import update_methods as um

        def on_drop(window, count, paths):
            nonlocal rec_dir
            rec_dir = paths[0].decode("utf-8")

        if rec_dir:
            if not pm.is_pupil_rec_dir(rec_dir):
                rec_dir = None
        # load session persistent settings
        session_settings = Persistent_Dict(
            os.path.join(user_dir, "user_settings_player")
        )
        if VersionFormat(session_settings.get("version", "0.0")) != app_version:
            logger.info(
                "Session setting are from a  different version of this app. I will not use those."
            )
            session_settings.clear()
        w, h = session_settings.get("window_size", (1280, 720))
        window_pos = session_settings.get("window_position", window_position_default)

        glfw.glfwInit()
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, 0)
        window = glfw.glfwCreateWindow(w, h, "Pupil Player")
        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, 1)

        glfw.glfwMakeContextCurrent(window)
        glfw.glfwSetWindowPos(window, window_pos[0], window_pos[1])
        glfw.glfwSetDropCallback(window, on_drop)

        glfont = fontstash.Context()
        glfont.add_font("roboto", get_roboto_font_path())
        glfont.set_align_string(v_align="center", h_align="middle")
        glfont.set_color_float((0.2, 0.2, 0.2, 0.9))
        gl_utils.basic_gl_setup()
        glClearColor(0.5, 0.5, 0.5, 0.0)
        text = "Drop a recording directory onto this window."
        tip = "(Tip: You can drop a recording directory onto the app icon.)"
        # text = "Please supply a Pupil recording directory as first arg when calling Pupil Player."
        while not glfw.glfwWindowShouldClose(window):

            fb_size = glfw.glfwGetFramebufferSize(window)
            hdpi_factor = glfw.getHDPIFactor(window)
            gl_utils.adjust_gl_view(*fb_size)

            if rec_dir:
                if pm.is_pupil_rec_dir(rec_dir):
                    logger.info("Starting new session with '{}'".format(rec_dir))
                    text = "Updating recording format."
                    tip = "This may take a while!"
                else:
                    logger.error("'{}' is not a valid pupil recording".format(rec_dir))
                    tip = "Oops! That was not a valid recording."
                    rec_dir = None

            gl_utils.clear_gl_screen()
            glfont.set_blur(10.5)
            glfont.set_color_float((0.0, 0.0, 0.0, 1.0))
            glfont.set_size(w / 25.0 * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, 0.3 * h * hdpi_factor, text)
            glfont.set_size(w / 30.0 * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, 0.4 * h * hdpi_factor, tip)
            glfont.set_blur(0.96)
            glfont.set_color_float((1.0, 1.0, 1.0, 1.0))
            glfont.set_size(w / 25.0 * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, 0.3 * h * hdpi_factor, text)
            glfont.set_size(w / 30.0 * hdpi_factor)
            glfont.draw_text(w / 2 * hdpi_factor, 0.4 * h * hdpi_factor, tip)

            glfw.glfwSwapBuffers(window)

            if rec_dir:
                try:
                    um.update_recording_to_recent(rec_dir)
                except AssertionError as err:
                    logger.error(str(err))
                    rec_dir = None
                else:
                    glfw.glfwSetWindowShouldClose(window, True)

            glfw.glfwPollEvents()

        session_settings["window_position"] = glfw.glfwGetWindowPos(window)
        session_settings.close()
        glfw.glfwDestroyWindow(window)
        if rec_dir:
            ipc_pub.notify(
                {"subject": "player_process.should_start", "rec_dir": rec_dir}
            )

    except:
        import traceback

        trace = traceback.format_exc()
        logger.error("Process player_drop crashed with trace:\n{}".format(trace))

    finally:
        sleep(1.0)
Esempio n. 21
0
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")