예제 #1
0
    def __init__(self):
        super(Example1, self).__init__('dir examples')
        self.parent = None
        self._directory = ControlDir('Choose a directory')
        self._file = ControlFile('Choose a file')
        self._filetree = ControlFilesTree('Choose a file')
        self._image = ControlImage('Image')
        self._boundaries = ControlBoundingSlider('Bounding', horizontal=True)
        self._button = ControlButton('Click')

        self._button.value = self.onButtonClick
        # self._directory.value=self.onButtonClick

        self._checkbox = ControlCheckBox('Choose a directory')
        self._checkboxList = ControlCheckBoxList('Choose a file')
        self._player = ControlPlayer('Choose a file')
        self._slider = ControlSlider('Slider')
        self._player.show()
        self._checkboxList.value = [('Item 1', True), ('Item 2', False), ('Item 3', True)]

        self._combobox = ControlCombo('Choose a item')
        self._list = ControlList('List label')
        self._progress = ControlProgress('Progress bar')
        self._visvisVolume = ControlVisVisVolume('Visvis')
        self._timeline = ControlEventTimeline('Timeline')

        self._combobox.add_item('Item 1', 'Value 1')
        self._combobox.add_item('Item 2', 'Value 2')
        self._combobox.add_item('Item 3', 'Value 3')
        self._combobox.add_item('Item 4')

        self._list.value = [('Item1', 'Item2', 'Item3',), ('Item3', 'Item4', 'Item5',)]
        imageWithVolume = np.zeros((100, 100, 100), np.uint8)
        imageWithVolume[30:40, 30:50, :] = 255
        imageWithVolume[30:40, 70:72, :] = 255
        self._visvisVolume.value = imageWithVolume

        self._visvis = ControlVisVis('Visvis')
        values1 = [(i, random.random(), random.random()) for i in range(130)]
        values2 = [(i, random.random(), random.random()) for i in range(130)]
        self._visvis.value = [values1, values2]

        self.formset = [
            '_visvis'
            , '_directory'
            , '_button'
            , '_file'
            , '_boundaries'
            , '_filetree'
            , '_image'
            , '_slider'
            , ('_checkboxList', '_player')
            , ('_checkbox', ' ')
            , ('_combobox', ' ')
            , '_progress'
            , '='
            , ('_visvisVolume', '||', '_list')
            , '_timeline'
        ]
예제 #2
0
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)

        self.formset = ['_player']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._time.key_release_event = self.__timeline_key_release_event

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()
예제 #3
0
class BaseModule(BaseWidget):
    """Application form"""
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)

        self.formset = ['_player']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._time.key_release_event = self.__timeline_key_release_event

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

    ######################################################################################
    #### FUNCTIONS #######################################################################
    ######################################################################################

    def init_form(self):
        super(BaseModule, self).init_form()

        if conf.CHART_FILE_PATH: self._time.import_chart(*conf.CHART_FILE_PATH)
        if conf.PROJECT_PATH: self.load_project(conf.PROJECT_PATH)

    ######################################################################################
    #### IO FUNCTIONS ####################################################################
    ######################################################################################

    def save(self, data, project_path=None):
        self._project.save(data, project_path)
        return data

    def load(self, data, project_path=None):
        self._project.load(data, project_path)

    def save_project(self, project_path=None):
        try:
            if project_path is None:
                project_path = QFileDialog.getExistingDirectory(
                    self, "Select the project directory")

            if project_path is not None and str(project_path) != '':
                project_path = str(project_path)
                self.save({}, project_path)
        except Exception as e:
            QMessageBox.critical(self, "Error", str(e))

    def load_project(self, project_path=None):
        if project_path is None:
            project_path = QFileDialog.getExistingDirectory(
                self, "Select the project directory")
        if project_path is not None and str(project_path) != '':
            self.load({}, str(project_path))

    ######################################################################################
    #### EVENTS ##########################################################################
    ######################################################################################

    def on_player_click_event(self, event, x, y):
        """
		Code to select a blob with the mouse
		"""
        super(VideoAnnotationEditor, self).on_player_click_event(event, x, y)
        self._player.refresh()

    def process_frame_event(self, frame):
        """
		Function called before render each frame
		"""
        return frame

    def __open_project_event(self):
        self.load_project()

    def __save_project_event(self):
        self.save_project(self._project.directory)

    def __save_project_as_event(self):
        self.save_project()

    def __timeline_key_release_event(self, event):
        """
		Control video playback using the space bar to Play/Pause
		"""
        if event.key() == QtCore.Qt.Key_Space:
            self._player.stop(
            ) if self._player.is_playing else _player._video.play()

    ######################################################################################
    #### PROPERTIES ######################################################################
    ######################################################################################

    @property
    def timeline(self):
        return self._time

    @property
    def player(self):
        return self._player

    @property
    def video(self):
        return self._player.value

    @video.setter
    def video(self, value):
        self._player.value = value
        self._player.enabled = value is not None
        if value:
            self._time.max = self._player.max

    @property
    def project(self):
        return self._project
예제 #4
0
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super().__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)
        self._progress = ControlProgress('Progress', visible=False)

        # define the application toolbar
        self.toolbar = [
            ControlButton('Open',
                          icon=conf.ANNOTATOR_ICON_OPEN,
                          default=self.__open_project_event),
            ControlButton('Save',
                          icon=conf.ANNOTATOR_ICON_SAVE,
                          default=self.__save_project_event)
        ]

        self.formset = ['_player', '_progress']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._player.double_click_event = self.on_player_double_click_event
        self._player.drag_event = self.on_player_drag_event
        self._player.end_drag_event = self.on_player_end_drag_event

        # ignore these controls key release event
        self._time.key_release_event = lambda x: x
        self._player.key_release_event = lambda x: x

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                if float(new_version) > float(__version__):
                    response = self.question(
                        "<h2>New version <b>[{0}]</b> available</h2>"
                        "<p>Do you wish to update the software?</p>"
                        "<p>The software can be updated later by running the next command in the terminal:</p>"
                        "<i>pip install python-video-annotator --force-reinstall</i>"
                        .format(new_version),
                        'New version [{0}]'.format(new_version))

                    if response == 'yes':
                        subprocess.call([
                            sys.executable, "-m", "pip", "install",
                            'python-video-annotator', '--force-reinstall'
                        ])

                        self.message(
                            'The software was updated and this session will be closed. Please execute the software again.',
                            'Restart required')
                        exit()

            else:
                print('Unable to check new versions')

        except Exception as e:
            print('Unable to check new versions:')
예제 #5
0
class Base(BaseWidget):
    """Application form"""
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super().__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)
        self._progress = ControlProgress('Progress', visible=False)

        # define the application toolbar
        self.toolbar = [
            ControlButton('Open',
                          icon=conf.ANNOTATOR_ICON_OPEN,
                          default=self.__open_project_event),
            ControlButton('Save',
                          icon=conf.ANNOTATOR_ICON_SAVE,
                          default=self.__save_project_event)
        ]

        self.formset = ['_player', '_progress']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._player.double_click_event = self.on_player_double_click_event
        self._player.drag_event = self.on_player_drag_event
        self._player.end_drag_event = self.on_player_end_drag_event

        # ignore these controls key release event
        self._time.key_release_event = lambda x: x
        self._player.key_release_event = lambda x: x

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                if float(new_version) > float(__version__):
                    response = self.question(
                        "<h2>New version <b>[{0}]</b> available</h2>"
                        "<p>Do you wish to update the software?</p>"
                        "<p>The software can be updated later by running the next command in the terminal:</p>"
                        "<i>pip install python-video-annotator --force-reinstall</i>"
                        .format(new_version),
                        'New version [{0}]'.format(new_version))

                    if response == 'yes':
                        subprocess.call([
                            sys.executable, "-m", "pip", "install",
                            'python-video-annotator', '--force-reinstall'
                        ])

                        self.message(
                            'The software was updated and this session will be closed. Please execute the software again.',
                            'Restart required')
                        exit()

            else:
                print('Unable to check new versions')

        except Exception as e:
            print('Unable to check new versions:')

    ######################################################################################
    #### FUNCTIONS #######################################################################
    ######################################################################################

    def init_form(self):
        super().init_form()

        if conf.CHART_FILE_PATH:
            self._time.import_chart(*conf.CHART_FILE_PATH)
        if conf.VIDEOANNOTATOR_PROJECTPATH:
            self.load_project(conf.VIDEOANNOTATOR_PROJECTPATH)

        if len(sys.argv) > 1:
            QTimer.singleShot(1000, self.__load_project_from_argv)

    ######################################################################################
    #### EVENTS ##########################################################################
    ######################################################################################

    def on_player_drag_event(self, p1, p2):
        if self._project:
            self._project.player_on_drag(p1, p2)
        self._player.refresh()

    def on_player_end_drag_event(self, p1, p2):
        if self._project:
            self._project.player_on_end_drag(p1, p2)
        self._player.refresh()

    def on_player_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        if self._project:
            self._project.player_on_click(event, x, y)
        self._player.refresh()

    def on_player_double_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        if self._project:
            self._project.player_on_double_click(event, x, y)
        self._player.refresh()

    def process_frame_event(self, frame):
        """
        Function called before render each frame
        """
        return frame

    def add_dataset_event(self, dataset):
        pass

    def removed_dataset_event(self, dataset):
        pass

    def removed_object_event(self, obj):
        pass

    def __open_project_event(self):
        self.load_project()

    def __save_project_event(self):
        self.save_project(self._project.directory)

    def __save_project_as_event(self):
        self.save_project()

    def __load_project_from_argv(self):
        self.load_project(sys.argv[-1])

    ######################################################################################
    #### EVENT FUNCTIONS #################################################################
    ######################################################################################

    def select_next_path(self):

        selected = self.project.tree.selected_item

        if selected is not None:

            # If it's a video, try to select its first object and the object's first child
            if isinstance(selected.win, Video):

                if selected.childCount() > 0:
                    child_object = selected.child(0)

                    if child_object.childCount() > 0:
                        self.project.tree.selected_item = child_object.child(0)

            # If it's an object, try to select it's first child
            elif isinstance(selected.win, Object2D):
                if selected.childCount() > 0:
                    self.project.tree.selected_item = selected.child(0)

            # If it's a path try to select the first child of the next object of their parent video
            elif isinstance(selected.win, Path):

                parent_object = selected.parent()
                parent_video = parent_object.parent()

                parent_object_index = parent_video.indexOfChild(parent_object)

                if parent_object_index < parent_video.childCount() - 1:
                    next_object = parent_video.child(
                        parent_video.indexOfChild(parent_object) + 1)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)

                # If it's the last object of the video, go back to the path of the first one
                else:
                    next_object = parent_video.child(0)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)

    ######################################################################################
    ######################################################################################
    #### PROPERTIES ######################################################################
    ######################################################################################

    @property
    def progress_bar(self):
        return self._progress

    @property
    def timeline(self):
        return self._time

    @property
    def player(self):
        return self._player

    @property
    def video(self):
        return self._player.value

    @video.setter
    def video(self, value):
        self._player.value = value
        self._player.enabled = value is not None
        if value:
            self._time.max = self._player.max

    @property
    def project(self):
        return self._project
    def __init__(self):
        global conf;
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project  = Project(parent=self)
        Dialog.project = self._project

        self._player    = ControlPlayer("Player")
        self._time      = ControlEventTimeline('Time')
        self._dock      = ControlDockWidget("Timeline", side='bottom', order=1, margin=5)

        self.formset    = ['_player']

        self._dock.value                    = self._time
        self._player.process_frame_event    = self.process_frame_event
        self._player.click_event            = self.on_player_click_event
        self._time.key_release_event        = lambda x: x
        self._player.key_release_event      = lambda x: x

        self.load_order = []

        self.mainmenu.insert(0,
            {'File': [
                {'Open': self.__open_project_event, 'icon': conf.ANNOTATOR_ICON_OPEN},
                '-',
                {'Save': self.__save_project_event , 'icon': conf.ANNOTATOR_ICON_SAVE},
                {'Save as': self.__save_project_as_event, 'icon': conf.ANNOTATOR_ICON_SAVE},
                '-',
                {'Exit': QApplication.closeAllWindows, 'icon': conf.ANNOTATOR_ICON_EXIT}
            ] }
        )
        self.mainmenu.insert(1, {'Modules': []} )
        self.mainmenu.insert(2, {'Windows': []} )

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                if float(new_version) > float(__version__):
                    response = self.question(
                        "<h2>New version <b>[{0}]</b> available</h2>"
                        "<p>Do you wish to update the software?</p>"
                        "<p>The software can be updated later by running the next command in the terminal:</p>"
                        "<i>pip install python-video-annotator --force-reinstall</i>".format(new_version),
                        'New version [{0}]'.format(new_version)
                    )

                    if response == 'yes':
                        subprocess.call([sys.executable, "-m", "pip", "install", 'python-video-annotator', '--force-reinstall'])

                        self.message('The software was updated and this session will be closed. Please execute the software again.', 'Restart required')
                        exit()

            else:
                print('Enabled to check new versions')

        except Exception as e:
            print('Enabled to check new versions:')
class BaseModule(BaseWidget):
    """Application form"""

    def __init__(self):
        global conf;
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project  = Project(parent=self)
        Dialog.project = self._project

        self._player    = ControlPlayer("Player")
        self._time      = ControlEventTimeline('Time')
        self._dock      = ControlDockWidget("Timeline", side='bottom', order=1, margin=5)

        self.formset    = ['_player']

        self._dock.value                    = self._time
        self._player.process_frame_event    = self.process_frame_event
        self._player.click_event            = self.on_player_click_event
        self._time.key_release_event        = lambda x: x
        self._player.key_release_event      = lambda x: x

        self.load_order = []

        self.mainmenu.insert(0,
            {'File': [
                {'Open': self.__open_project_event, 'icon': conf.ANNOTATOR_ICON_OPEN},
                '-',
                {'Save': self.__save_project_event , 'icon': conf.ANNOTATOR_ICON_SAVE},
                {'Save as': self.__save_project_as_event, 'icon': conf.ANNOTATOR_ICON_SAVE},
                '-',
                {'Exit': QApplication.closeAllWindows, 'icon': conf.ANNOTATOR_ICON_EXIT}
            ] }
        )
        self.mainmenu.insert(1, {'Modules': []} )
        self.mainmenu.insert(2, {'Windows': []} )

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                if float(new_version) > float(__version__):
                    response = self.question(
                        "<h2>New version <b>[{0}]</b> available</h2>"
                        "<p>Do you wish to update the software?</p>"
                        "<p>The software can be updated later by running the next command in the terminal:</p>"
                        "<i>pip install python-video-annotator --force-reinstall</i>".format(new_version),
                        'New version [{0}]'.format(new_version)
                    )

                    if response == 'yes':
                        subprocess.call([sys.executable, "-m", "pip", "install", 'python-video-annotator', '--force-reinstall'])

                        self.message('The software was updated and this session will be closed. Please execute the software again.', 'Restart required')
                        exit()

            else:
                print('Enabled to check new versions')

        except Exception as e:
            print('Enabled to check new versions:')

    ######################################################################################
    #### FUNCTIONS #######################################################################
    ######################################################################################
        
    def init_form(self):
        super(BaseModule, self).init_form()

        if conf.CHART_FILE_PATH: self._time.import_chart(*conf.CHART_FILE_PATH)
        if conf.PROJECT_PATH:    self.load_project(conf.PROJECT_PATH)


    ######################################################################################
    #### IO FUNCTIONS ####################################################################
    ######################################################################################

    def save(self, data, project_path=None):
        self._project.save(data, project_path)
        return data


    def load(self, data, project_path=None):
        try:
            self._project.load(data, project_path)
        except FileNotFoundError as e:
            QMessageBox.critical(self, "Error", str(e))

    def save_project(self, project_path=None):
        try:
            if project_path is None:
                project_path = QFileDialog.getExistingDirectory(self, "Select the project directory")

            if project_path is not None and str(project_path)!='':
                project_path = str(project_path)
                self.save({}, project_path)
        except Exception as e:
            QMessageBox.critical(self, "Error", str(e))

    def load_project(self, project_path=None):
        if project_path is None:
            project_path = QFileDialog.getExistingDirectory(self, "Select the project directory")
        if project_path is not None and str(project_path)!='':
            self.load({}, str(project_path) )



    ######################################################################################
    #### EVENTS ##########################################################################
    ######################################################################################

    def on_player_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        super(VideoAnnotationEditor, self).on_player_click_event(event, x, y)
        self._player.refresh()

    def process_frame_event(self, frame):
        """
        Function called before render each frame
        """
        return frame


    def add_dataset_event(self, dataset):
        pass

    def removed_dataset_event(self, dataset):
        pass

    def removed_object_event(self, obj):
        pass


    def __open_project_event(self): self.load_project()

    def __save_project_event(self):
        print('Project saved')
        self.save_project(self._project.directory)

    def __save_project_as_event(self): self.save_project()

    def keyReleaseEvent(self, event):
        ######################################################################################
        #### SPECIFIC SHORTCUTS###############################################################
        ######################################################################################
        
        #Go to the next event and then click the mark the point button
        if event.key() == QtCore.Qt.Key_I:
            if self.timeline.timeline_widget.selected is not None and self.timeline.timeline_widget.selected != self.timeline.timeline_widget.pointer:
                self.move_to_next_event()
                self.mark_point()

        ######################################################################################
        #### DOCK SHORTCUTS ##################################################################
        ######################################################################################

        #Select the path of the next object
        if event.key() == QtCore.Qt.Key_U:
            self.select_next_path()

        #"Click" the Mark Point button in the current Path
        elif event.key() == QtCore.Qt.Key_O:
            self.mark_point()

        ######################################################################################
        #### TIMELINE SHORTCUTS ##############################################################
        ######################################################################################

        if self.timeline.timeline_widget.selected is not None:

            modifier = int(event.modifiers())

            if modifier == QtCore.Qt.ControlModifier and event.key() == QtCore.Qt.Key_Left:
                self.move_event_or_pointer_left(event)

            if modifier == QtCore.Qt.ControlModifier and event.key() == QtCore.Qt.Key_Right:
                self.move_event_or_pointer_right(event)

            if self.timeline.timeline_widget.selected != self.timeline.timeline_widget.pointer:

                # Delete the selected event
                if event.key() == QtCore.Qt.Key_Delete:
                    self.timeline.timeline_widget.remove_selected_event()

                # Lock or unlock an event
                if event.key() == QtCore.Qt.Key_L:
                    self.timeline.timeline_widget.toggle_selected_event_lock()

                if event.key() == QtCore.Qt.Key_E:
                    self.move_to_next_event()

                if event.key() == QtCore.Qt.Key_Q:
                    self.move_to_previous_event()

                if modifier == QtCore.Qt.ControlModifier and event.key() == QtCore.Qt.Key_Up:
                    self.move_event_up()

                if modifier == QtCore.Qt.ControlModifier and event.key() == QtCore.Qt.Key_Down:
                    self.move_event_down()

                if modifier == int(
                        QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and event.key() == QtCore.Qt.Key_Left:
                    self.move_event_end_left()

                if modifier == int(
                        QtCore.Qt.ShiftModifier | QtCore.Qt.ControlModifier) and event.key() == QtCore.Qt.Key_Right:
                    self.move_event_end_right()

                if modifier == QtCore.Qt.ShiftModifier and event.key() == QtCore.Qt.Key_Left:
                    self.move_event_begin_left()

                if modifier == QtCore.Qt.ShiftModifier and event.key() == QtCore.Qt.Key_Right:
                    self.move_event_begin_right()

        else:
            if event.key() == QtCore.Qt.Key_S:

                self.create_event_at_current_frame()

            # walk backwards 1 step
            elif event.key() == QtCore.Qt.Key_A:
                self.timeline.timeline_widget.position = self.timeline.timeline_widget.position - 1

            # forward 1 step
            elif event.key() == QtCore.Qt.Key_D:
                self.timeline.timeline_widget.position = self.timeline.timeline_widget.position + 1

            elif event.key() == QtCore.Qt.Key_E:
                self.move_to_first_event()

            elif event.key() == QtCore.Qt.Key_Q:
                self.move_to_last_event()

        ######################################################################################
        #### PLAYER SHORTCUTS ################################################################
        ######################################################################################

        # Control video playback using the space bar to Play/Pause
        if event.key() == QtCore.Qt.Key_Space:

            if self.player.video_widget.control.is_playing:
                self.player.video_widget.control.stop()
            else:
                self.player.video_widget.control.play()

        # Jumps 1 frame backwards
        elif event.key() == QtCore.Qt.Key_A:
            self.player.video_widget.control.video_index -= 2
            self.player.video_widget.control.call_next_frame()

        # Jumps 1 frame forward
        elif event.key() == QtCore.Qt.Key_D:
            self.player.video_widget.control.call_next_frame()

        # Jumps 20 seconds backwards
        elif event.key() == QtCore.Qt.Key_Z:
            self.player.video_widget.control.jump_backward()
            self.player.video_widget.control.call_next_frame()

        # Jumps 20 seconds forward
        elif event.key() == QtCore.Qt.Key_C:
            self.player.video_widget.control.jump_forward()
            self.player.video_widget.control.call_next_frame()

        elif event.key() == QtCore.Qt.Key_M:
            self._move_img = False

        elif event.key() == QtCore.Qt.Key_1:
            self.player.video_widget.control.next_frame_step = 1
            self.player.video_widget.show_tmp_msg('Speed: 1x')

        elif event.key() == QtCore.Qt.Key_2:
            self.player.video_widget.control.next_frame_step = 2
            self.player.video_widget.show_tmp_msg('Speed: 2x')

        elif event.key() == QtCore.Qt.Key_3:
            self.player.video_widget.control.next_frame_step = 3
            self.player.video_widget.show_tmp_msg('Speed: 3x')

        elif event.key() == QtCore.Qt.Key_4:
            self.player.video_widget.control.next_frame_step = 4
            self.player.video_widget.show_tmp_msg('Speed: 4x')

        elif event.key() == QtCore.Qt.Key_5:
            self.player.video_widget.control.next_frame_step = 5
            self.player.video_widget.show_tmp_msg('Speed: 5x')

        elif event.key() == QtCore.Qt.Key_6:
            self.player.video_widget.control.next_frame_step = 6
            self.player.video_widget.show_tmp_msg('Speed: 6x')

        elif event.key() == QtCore.Qt.Key_7:
            self.player.video_widget.control.next_frame_step = 7
            self.player.video_widget.show_tmp_msg('Speed: 7x')

        elif event.key() == QtCore.Qt.Key_8:
            self.player.video_widget.control.next_frame_step = 8
            self.player.video_widget.show_tmp_msg('Speed: 8x')

        elif event.key() == QtCore.Qt.Key_9:
            self.player.video_widget.control.next_frame_step = 9
            self.player.video_widget.show_tmp_msg('Speed: 9x')

    ######################################################################################
    #### EVENT FUNCTIONS #################################################################
    ######################################################################################

    def select_next_path(self):

        selected = self.project.tree.selected_item

        if selected is not None:

            #If it's a video, try to select its first object and the object's first child 
            if isinstance(selected.win, Video):

                if selected.childCount() > 0:
                    child_object = selected.child(0)

                    if child_object.childCount() > 0:
                        self.project.tree.selected_item = child_object.child(0)

            #If it's an object, try to select it's first child
            elif isinstance(selected.win, Object2D):
                if selected.childCount() > 0:
                    self.project.tree.selected_item = selected.child(0)

            #If it's a path try to select the first child of the next object of their parent video
            elif isinstance(selected.win, Path):

                parent_object = selected.parent()
                parent_video = parent_object.parent()

                parent_object_index = parent_video.indexOfChild(parent_object)

                if parent_object_index < parent_video.childCount() -1 :
                    next_object = parent_video.child(parent_video.indexOfChild(parent_object)+1)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)

                #If it's the last object of the video, go back to the path of the first one
                else:
                    next_object = parent_video.child(0)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)


    def mark_point(self):
        selected = self.project.tree.selected_item

        if selected is not None and isinstance(selected.win, Path):
            path = selected.win

            path.mark_point_button.click()


    def move_to_next_event(self):
        index = self.timeline.timeline_widget.selected_row.events.index(self.timeline.timeline_widget.selected)
        if index < len(self.timeline.timeline_widget.selected_row.events)-1:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[index+1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_previous_event(self):
        index = self.timeline.timeline_widget.selected_row.events.index(self.timeline.timeline_widget.selected)
        if index > 0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[index - 1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_first_event(self):
        if self.timeline.timeline_widget.selected_row is not None and len(self.timeline.timeline_widget.selected_row)>0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[0]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_last_event(self):
        if self.timeline.timeline_widget.selected_row is not None and len(self.timeline.timeline_widget.selected_row)>0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[len(self.timeline.timeline_widget.selected_row)-1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_event_or_pointer_left(self, event):
        modifier = int(event.modifiers())

        self.timeline.timeline_widget.selected.move(-1, 0)
        event.ignore()
        self.timeline.timeline_widget.repaint()

    def move_event_or_pointer_right(self, event):
        modifier = int(event.modifiers())

        self.timeline.timeline_widget.selected.move(1, 0)
        event.ignore()
        self.timeline.timeline_widget.repaint()

    def move_event_up(self):
        self.timeline.timeline_widget.selected.move(0, self.timeline.timeline_widget.selected.top_coordinate - self.timeline.timeline_widget.TRACK_HEIGHT)
        self.timeline.timeline_widget.repaint()

    def move_event_down(self):
        self.timeline.timeline_widget.selected.move(0, self.timeline.timeline_widget.selected.top_coordinate + self.timeline.timeline_widget.TRACK_HEIGHT)
        self.timeline.timeline_widget.repaint()

    def move_event_end_left(self):
        self.timeline.timeline_widget.selected.move_end(-1)
        self.timeline.timeline_widget.repaint()

    def move_event_end_right(self):
        self.timeline.timeline_widget.selected.move_end(1)
        self.timeline.timeline_widget.repaint()

    def move_event_begin_left(self):
        self.timeline.timeline_widget.selected.move_begin(-1)
        self.timeline.timeline_widget.repaint()

    def move_event_begin_right(self):
        self.timeline.timeline_widget.selected.move_begin(1)
        self.timeline.timeline_widget.repaint()

    def create_event_at_current_frame(self):
        if not self.timeline.timeline_widget.creating_event:
            # Start
            self.timeline.timeline_widget.creating_event_start = self.timeline.timeline_widget.pointer.frame
            self.timeline.timeline_widget.creating_event = True

            # TODO Add some indicator that an event is being recorded, like
            # using the track selector circle to become red

        else:
            # End, must be followed right after Start key and have no
            # effect otherwise
            self.timeline.timeline_widget.creating_event_end = self.timeline.timeline_widget.pointer.frame

            start = self.timeline.timeline_widget.creating_event_start
            end = self.timeline.timeline_widget.creating_event_end
            comment = ""

            if end > start:
                track = self.timeline.timeline_widget.selected_row
                if track is None and len(self.timeline.timeline_widget.tracks)>0:
                    track = self.timeline.timeline_widget.tracks[0]
                if track is None:
                    track = self.timeline.timeline_widget.add_track()

                self.timeline.timeline_widget.add_event(start, end, comment, track=track )
                self.timeline.timeline_widget.repaint()
                self.timeline.timeline_widget.creating_event = False
            else:
                self.timeline.timeline_widget.creating_event = False




    ######################################################################################
    #### PROPERTIES ######################################################################
    ######################################################################################

    @property
    def timeline(self): return self._time

    @property
    def player(self): return self._player
    
    @property
    def video(self): return self._player.value
    @video.setter
    def video(self, value): 
        self._player.value      = value
        self._player.enabled    = value is not None
        if value:
            self._time.max = self._player.max

    @property
    def project(self): return self._project
예제 #8
0
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)

        self.formset = ['_player']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._time.key_release_event = self.__timeline_key_release_event

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                new_version_numbers = [int(x) for x in new_version.split('.')]
                version_numbers = [int(x) for x in __version__.split('.')]
                for new_n, n in zip(new_version_numbers, version_numbers):
                    if new_n > n:
                        response = self.question(
                            "<h2>New version <b>[{0}]</b> available</h2>"
                            "<p>Do you wish to update the software?</p>"
                            "<p>The software can be updated later by running the next command in the terminal:</p>"
                            "<i>pip install python-video-annotator --force-reinstall</i>"
                            .format(new_version),
                            'New version [{0}]'.format(new_version))

                        if response == 'yes':
                            subprocess.call([
                                sys.executable, "-m", "pip", "install",
                                'python-video-annotator', '--force-reinstall'
                            ])

                            self.message(
                                'The software was updated and this session will be closed. Please execute the software again.',
                                'Restart required')
                            exit()
                        break
            else:
                print('Enabled to check new versions')

        except Exception as e:
            print('Enabled to check new versions:')
예제 #9
0
class BaseModule(BaseWidget):
    """Application form"""
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)

        self.formset = ['_player']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._time.key_release_event = self.__timeline_key_release_event

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                new_version_numbers = [int(x) for x in new_version.split('.')]
                version_numbers = [int(x) for x in __version__.split('.')]
                for new_n, n in zip(new_version_numbers, version_numbers):
                    if new_n > n:
                        response = self.question(
                            "<h2>New version <b>[{0}]</b> available</h2>"
                            "<p>Do you wish to update the software?</p>"
                            "<p>The software can be updated later by running the next command in the terminal:</p>"
                            "<i>pip install python-video-annotator --force-reinstall</i>"
                            .format(new_version),
                            'New version [{0}]'.format(new_version))

                        if response == 'yes':
                            subprocess.call([
                                sys.executable, "-m", "pip", "install",
                                'python-video-annotator', '--force-reinstall'
                            ])

                            self.message(
                                'The software was updated and this session will be closed. Please execute the software again.',
                                'Restart required')
                            exit()
                        break
            else:
                print('Enabled to check new versions')

        except Exception as e:
            print('Enabled to check new versions:')

    ######################################################################################
    #### FUNCTIONS #######################################################################
    ######################################################################################

    def init_form(self):
        super(BaseModule, self).init_form()

        if conf.CHART_FILE_PATH: self._time.import_chart(*conf.CHART_FILE_PATH)
        if conf.PROJECT_PATH: self.load_project(conf.PROJECT_PATH)

    ######################################################################################
    #### IO FUNCTIONS ####################################################################
    ######################################################################################

    def save(self, data, project_path=None):
        self._project.save(data, project_path)
        return data

    def load(self, data, project_path=None):
        try:
            self._project.load(data, project_path)
        except FileNotFoundError as e:
            QMessageBox.critical(self, "Error", str(e))

    def save_project(self, project_path=None):
        try:
            if project_path is None:
                project_path = QFileDialog.getExistingDirectory(
                    self, "Select the project directory")

            if project_path is not None and str(project_path) != '':
                project_path = str(project_path)
                self.save({}, project_path)
        except Exception as e:
            QMessageBox.critical(self, "Error", str(e))

    def load_project(self, project_path=None):
        if project_path is None:
            project_path = QFileDialog.getExistingDirectory(
                self, "Select the project directory")
        if project_path is not None and str(project_path) != '':
            self.load({}, str(project_path))

    ######################################################################################
    #### EVENTS ##########################################################################
    ######################################################################################

    def on_player_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        super(VideoAnnotationEditor, self).on_player_click_event(event, x, y)
        self._player.refresh()

    def process_frame_event(self, frame):
        """
        Function called before render each frame
        """
        return frame

    def add_dataset_event(self, dataset):
        pass

    def removed_dataset_event(self, dataset):
        pass

    def removed_object_event(self, obj):
        pass

    def __open_project_event(self):
        self.load_project()

    def __save_project_event(self):
        print('Project saved')
        self.save_project(self._project.directory)

    def __save_project_as_event(self):
        self.save_project()

    def __timeline_key_release_event(self, event):
        """
        Control video playback using the space bar to Play/Pause
        """
        if event.key() == QtCore.Qt.Key_Space:
            self._player.stop(
            ) if self._player.is_playing else _player._video.play()

    ######################################################################################
    #### PROPERTIES ######################################################################
    ######################################################################################

    @property
    def timeline(self):
        return self._time

    @property
    def player(self):
        return self._player

    @property
    def video(self):
        return self._player.value

    @video.setter
    def video(self, value):
        self._player.value = value
        self._player.enabled = value is not None
        if value:
            self._time.max = self._player.max

    @property
    def project(self):
        return self._project
예제 #10
0
class BaseModule(BaseWidget):
    """Application form"""
    def __init__(self):
        global conf
        conf += 'pythonvideoannotator.resources'  # Resources can only be loaded after pyqt is running

        super(BaseModule, self).__init__('Video annotation editor')

        self._project = Project(parent=self)
        Dialog.project = self._project

        self._player = ControlPlayer("Player")
        self._time = ControlEventTimeline('Time')
        self._dock = ControlDockWidget("Timeline",
                                       side='bottom',
                                       order=1,
                                       margin=5)
        self._progress = ControlProgress('Progress', visible=False)

        # define the application toolbar
        self.toolbar = [
            ControlButton('Open',
                          icon=conf.ANNOTATOR_ICON_OPEN,
                          default=self.__open_project_event),
            ControlButton('Save',
                          icon=conf.ANNOTATOR_ICON_SAVE,
                          default=self.__save_project_event)
        ]

        self.formset = ['_player', '_progress']

        self._dock.value = self._time
        self._player.process_frame_event = self.process_frame_event
        self._player.click_event = self.on_player_click_event
        self._player.double_click_event = self.on_player_double_click_event
        self._player.drag_event = self.on_player_drag_event
        self._player.end_drag_event = self.on_player_end_drag_event
        self._time.key_release_event = lambda x: x
        self._player.key_release_event = lambda x: x

        self.load_order = []

        self.mainmenu.insert(
            0, {
                'File': [{
                    'Open': self.__open_project_event,
                    'icon': conf.ANNOTATOR_ICON_OPEN
                }, '-', {
                    'Save': self.__save_project_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, {
                    'Save as': self.__save_project_as_event,
                    'icon': conf.ANNOTATOR_ICON_SAVE
                }, '-', {
                    'Exit': QApplication.closeAllWindows,
                    'icon': conf.ANNOTATOR_ICON_EXIT
                }]
            })
        self.mainmenu.insert(1, {'Modules': []})
        self.mainmenu.insert(2, {'Windows': []})

        track_user_stats()

        ########################################################################
        ###### CHECK NEW VERSIONS RELEASES #####################################
        ########################################################################
        try:
            versions = pypi_xmlrpc.package_releases('Python-video-annotator')

            if versions is not None:
                new_version = versions[0]
                if float(new_version) > float(__version__):
                    response = self.question(
                        "<h2>New version <b>[{0}]</b> available</h2>"
                        "<p>Do you wish to update the software?</p>"
                        "<p>The software can be updated later by running the next command in the terminal:</p>"
                        "<i>pip install python-video-annotator --force-reinstall</i>"
                        .format(new_version),
                        'New version [{0}]'.format(new_version))

                    if response == 'yes':
                        subprocess.call([
                            sys.executable, "-m", "pip", "install",
                            'python-video-annotator', '--force-reinstall'
                        ])

                        self.message(
                            'The software was updated and this session will be closed. Please execute the software again.',
                            'Restart required')
                        exit()

            else:
                print('Unable to check new versions')

        except Exception as e:
            print('Unable to check new versions:')

    ######################################################################################
    #### FUNCTIONS #######################################################################
    ######################################################################################

    def init_form(self):
        super(BaseModule, self).init_form()

        if conf.CHART_FILE_PATH:
            self._time.import_chart(*conf.CHART_FILE_PATH)
        if conf.VIDEOANNOTATOR_PROJECTPATH:
            self.load_project(conf.VIDEOANNOTATOR_PROJECTPATH)

        if len(sys.argv) > 1:
            QTimer.singleShot(1000, self.__load_project_from_argv)

    ######################################################################################
    #### IO FUNCTIONS ####################################################################
    ######################################################################################

    def save(self, data, project_path=None):
        self._project.save(data, project_path)
        return data

    def load(self, data, project_path=None):
        try:
            self._project.load(data, project_path)
        except FileNotFoundError as e:
            QMessageBox.critical(self, "Error", str(e))

    def save_project(self, project_path=None):
        try:
            if project_path is None:
                project_path = QFileDialog.getExistingDirectory(
                    self, "Select the project directory")

            if project_path is not None and str(project_path) != '':
                project_path = str(project_path)
                self.save({}, project_path)
        except Exception as e:
            traceback.print_exc()
            QMessageBox.critical(self, "Error", str(e))

    def load_project(self, project_path=None):
        if project_path is None:
            project_path = QFileDialog.getExistingDirectory(
                self, "Select the project directory")

        if project_path is not None and str(project_path) != '':
            self.load({}, str(project_path))

    ######################################################################################
    #### EVENTS ##########################################################################
    ######################################################################################

    def on_player_drag_event(self, p1, p2):
        if self._project:
            self._project.player_on_drag(p1, p2)
        self._player.refresh()

    def on_player_end_drag_event(self, p1, p2):
        if self._project:
            self._project.player_on_end_drag(p1, p2)
        self._player.refresh()

    def on_player_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        if self._project:
            self._project.player_on_click(event, x, y)
        self._player.refresh()

    def on_player_double_click_event(self, event, x, y):
        """
        Code to select a blob with the mouse
        """
        if self._project:
            self._project.player_on_double_click(event, x, y)
        self._player.refresh()

    def process_frame_event(self, frame):
        """
        Function called before render each frame
        """
        return frame

    def add_dataset_event(self, dataset):
        pass

    def removed_dataset_event(self, dataset):
        pass

    def removed_object_event(self, obj):
        pass

    def __open_project_event(self):
        self.load_project()

    def __save_project_event(self):
        self.save_project(self._project.directory)

    def __save_project_as_event(self):
        self.save_project()

    def keyReleaseEvent(self, event):
        ######################################################################################
        #### SPECIFIC SHORTCUTS###############################################################
        ######################################################################################

        #Go to the next event and then click the mark the point button
        if event.key() == QtCore.Qt.Key_I:
            if self.timeline.timeline_widget.selected is not None and self.timeline.timeline_widget.selected != self.timeline.timeline_widget.pointer:
                self.move_to_next_event()
                self.mark_point()

        #Select the path of the next object and click the mark the point button
        if event.key() == QtCore.Qt.Key_U:
            self.select_next_path()
            self.mark_point()

        #"Click" the Mark Point button in the current Path
        elif event.key() == QtCore.Qt.Key_O:
            self.mark_point()

        ######################################################################################
        #### TIMELINE SHORTCUTS ##############################################################
        ######################################################################################

        if self.timeline.timeline_widget.selected is not None:

            modifier = int(event.modifiers())

            if modifier == QtCore.Qt.ControlModifier and event.key(
            ) == QtCore.Qt.Key_Left:
                self.move_event_or_pointer_left(event)

            if modifier == QtCore.Qt.ControlModifier and event.key(
            ) == QtCore.Qt.Key_Right:
                self.move_event_or_pointer_right(event)

            if self.timeline.timeline_widget.selected != self.timeline.timeline_widget.pointer:

                # Delete the selected event
                if event.key() == QtCore.Qt.Key_Delete:
                    self.timeline.timeline_widget.remove_selected_event()

                # Lock or unlock an event
                if event.key() == QtCore.Qt.Key_L:
                    self.timeline.timeline_widget.toggle_selected_event_lock()

                if event.key() == QtCore.Qt.Key_E:
                    self.move_to_next_event()

                if event.key() == QtCore.Qt.Key_Q:
                    self.move_to_previous_event()

                if modifier == QtCore.Qt.ControlModifier and event.key(
                ) == QtCore.Qt.Key_Up:
                    self.move_event_up()

                if modifier == QtCore.Qt.ControlModifier and event.key(
                ) == QtCore.Qt.Key_Down:
                    self.move_event_down()

                if modifier == int(QtCore.Qt.ShiftModifier
                                   | QtCore.Qt.ControlModifier) and event.key(
                                   ) == QtCore.Qt.Key_Left:
                    self.move_event_end_left()

                if modifier == int(QtCore.Qt.ShiftModifier
                                   | QtCore.Qt.ControlModifier) and event.key(
                                   ) == QtCore.Qt.Key_Right:
                    self.move_event_end_right()

                if modifier == QtCore.Qt.ShiftModifier and event.key(
                ) == QtCore.Qt.Key_Left:
                    self.move_event_begin_left()

                if modifier == QtCore.Qt.ShiftModifier and event.key(
                ) == QtCore.Qt.Key_Right:
                    self.move_event_begin_right()

        else:
            if event.key() == QtCore.Qt.Key_S:

                self.create_event_at_current_frame()

            # walk backwards 1 step
            elif event.key() == QtCore.Qt.Key_A:
                self.timeline.timeline_widget.position = self.timeline.timeline_widget.position - 1

            # forward 1 step
            elif event.key() == QtCore.Qt.Key_D:
                self.timeline.timeline_widget.position = self.timeline.timeline_widget.position + 1

            elif event.key() == QtCore.Qt.Key_E:
                self.move_to_first_event()

            elif event.key() == QtCore.Qt.Key_Q:
                self.move_to_last_event()

        ######################################################################################
        #### PLAYER SHORTCUTS ################################################################
        ######################################################################################

        # Control video playback using the space bar to Play/Pause
        if event.key() == QtCore.Qt.Key_Space:
            if self.player.is_playing:
                self.player.stop()
            else:
                self.player.play()

        # Jumps 1 frame backwards
        elif event.key() == QtCore.Qt.Key_A:
            self.player.video_widget.control.video_index -= 2
            self.player.video_widget.control.call_next_frame()

        # Jumps 1 frame forward
        elif event.key() == QtCore.Qt.Key_D:
            self.player.video_widget.control.call_next_frame()

        # Jumps 20 seconds backwards
        elif event.key() == QtCore.Qt.Key_Z:
            self.player.video_widget.control.jump_backward()
            self.player.video_widget.control.call_next_frame()

        # Jumps 20 seconds forward
        elif event.key() == QtCore.Qt.Key_C:
            self.player.video_widget.control.jump_forward()
            self.player.video_widget.control.call_next_frame()

        elif event.key() == QtCore.Qt.Key_M:
            self._move_img = False

        elif event.key() == QtCore.Qt.Key_1:
            self.player.video_widget.control.next_frame_step = 1
            self.player.video_widget.show_tmp_msg('Speed: 1x')

        elif event.key() == QtCore.Qt.Key_2:
            self.player.video_widget.control.next_frame_step = 2
            self.player.video_widget.show_tmp_msg('Speed: 2x')

        elif event.key() == QtCore.Qt.Key_3:
            self.player.video_widget.control.next_frame_step = 3
            self.player.video_widget.show_tmp_msg('Speed: 3x')

        elif event.key() == QtCore.Qt.Key_4:
            self.player.video_widget.control.next_frame_step = 4
            self.player.video_widget.show_tmp_msg('Speed: 4x')

        elif event.key() == QtCore.Qt.Key_5:
            self.player.video_widget.control.next_frame_step = 5
            self.player.video_widget.show_tmp_msg('Speed: 5x')

        elif event.key() == QtCore.Qt.Key_6:
            self.player.video_widget.control.next_frame_step = 6
            self.player.video_widget.show_tmp_msg('Speed: 6x')

        elif event.key() == QtCore.Qt.Key_7:
            self.player.video_widget.control.next_frame_step = 7
            self.player.video_widget.show_tmp_msg('Speed: 7x')

        elif event.key() == QtCore.Qt.Key_8:
            self.player.video_widget.control.next_frame_step = 8
            self.player.video_widget.show_tmp_msg('Speed: 8x')

        elif event.key() == QtCore.Qt.Key_9:
            self.player.video_widget.control.next_frame_step = 9
            self.player.video_widget.show_tmp_msg('Speed: 9x')

    def __load_project_from_argv(self):
        self.load_project(sys.argv[-1])

    ######################################################################################
    #### EVENT FUNCTIONS #################################################################
    ######################################################################################

    def select_next_path(self):

        selected = self.project.tree.selected_item

        if selected is not None:

            #If it's a video, try to select its first object and the object's first child
            if isinstance(selected.win, Video):

                if selected.childCount() > 0:
                    child_object = selected.child(0)

                    if child_object.childCount() > 0:
                        self.project.tree.selected_item = child_object.child(0)

            #If it's an object, try to select it's first child
            elif isinstance(selected.win, Object2D):
                if selected.childCount() > 0:
                    self.project.tree.selected_item = selected.child(0)

            #If it's a path try to select the first child of the next object of their parent video
            elif isinstance(selected.win, Path):

                parent_object = selected.parent()
                parent_video = parent_object.parent()

                parent_object_index = parent_video.indexOfChild(parent_object)

                if parent_object_index < parent_video.childCount() - 1:
                    next_object = parent_video.child(
                        parent_video.indexOfChild(parent_object) + 1)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)

                #If it's the last object of the video, go back to the path of the first one
                else:
                    next_object = parent_video.child(0)

                    if next_object.childCount() > 0:
                        self.project.tree.selected_item = next_object.child(0)

    def mark_point(self):
        selected = self.project.tree.selected_item

        if selected is not None and isinstance(selected.win, Path):
            path = selected.win

            if not path.mark_point_button.checked:
                path.mark_point_button.click()

    def move_to_next_event(self):
        index = self.timeline.timeline_widget.selected_row.events.index(
            self.timeline.timeline_widget.selected)
        if index < len(self.timeline.timeline_widget.selected_row.events) - 1:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[
                index + 1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_previous_event(self):
        index = self.timeline.timeline_widget.selected_row.events.index(
            self.timeline.timeline_widget.selected)
        if index > 0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[
                index - 1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_first_event(self):
        if self.timeline.timeline_widget.selected_row is not None and len(
                self.timeline.timeline_widget.selected_row) > 0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[
                0]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_to_last_event(self):
        if self.timeline.timeline_widget.selected_row is not None and len(
                self.timeline.timeline_widget.selected_row) > 0:
            self.timeline.timeline_widget.selected = self.timeline.timeline_widget.selected_row.events[
                len(self.timeline.timeline_widget.selected_row) - 1]
            self.timeline.timeline_widget.position = self.timeline.timeline_widget.selected.begin

    def move_event_or_pointer_left(self, event):
        modifier = int(event.modifiers())

        self.timeline.timeline_widget.selected.move(-1, 0)
        event.ignore()
        self.timeline.timeline_widget.repaint()

    def move_event_or_pointer_right(self, event):
        modifier = int(event.modifiers())

        self.timeline.timeline_widget.selected.move(1, 0)
        event.ignore()
        self.timeline.timeline_widget.repaint()

    def move_event_up(self):
        self.timeline.timeline_widget.selected.move(
            0, self.timeline.timeline_widget.selected.top_coordinate -
            self.timeline.timeline_widget.TRACK_HEIGHT)
        self.timeline.timeline_widget.repaint()

    def move_event_down(self):
        self.timeline.timeline_widget.selected.move(
            0, self.timeline.timeline_widget.selected.top_coordinate +
            self.timeline.timeline_widget.TRACK_HEIGHT)
        self.timeline.timeline_widget.repaint()

    def move_event_end_left(self):
        self.timeline.timeline_widget.selected.move_end(-1)
        self.timeline.timeline_widget.repaint()

    def move_event_end_right(self):
        self.timeline.timeline_widget.selected.move_end(1)
        self.timeline.timeline_widget.repaint()

    def move_event_begin_left(self):
        self.timeline.timeline_widget.selected.move_begin(-1)
        self.timeline.timeline_widget.repaint()

    def move_event_begin_right(self):
        self.timeline.timeline_widget.selected.move_begin(1)
        self.timeline.timeline_widget.repaint()

    def create_event_at_current_frame(self):
        if not self.timeline.timeline_widget.creating_event:
            # Start
            self.timeline.timeline_widget.creating_event_start = self.timeline.timeline_widget.pointer.frame
            self.timeline.timeline_widget.creating_event = True

            # TODO Add some indicator that an event is being recorded, like
            # using the track selector circle to become red

        else:
            # End, must be followed right after Start key and have no
            # effect otherwise
            self.timeline.timeline_widget.creating_event_end = self.timeline.timeline_widget.pointer.frame

            start = self.timeline.timeline_widget.creating_event_start
            end = self.timeline.timeline_widget.creating_event_end
            comment = ""

            if end > start:
                track = self.timeline.timeline_widget.selected_row
                if track is None and len(
                        self.timeline.timeline_widget.tracks) > 0:
                    track = self.timeline.timeline_widget.tracks[0]
                if track is None:
                    track = self.timeline.timeline_widget.add_track()

                self.timeline.timeline_widget.add_event(start,
                                                        end,
                                                        comment,
                                                        track=track)
                self.timeline.timeline_widget.repaint()
                self.timeline.timeline_widget.creating_event = False
            else:
                self.timeline.timeline_widget.creating_event = False

    ######################################################################################
    ######################################################################################
    #### PROPERTIES ######################################################################
    ######################################################################################

    @property
    def progress_bar(self):
        return self._progress

    @property
    def timeline(self):
        return self._time

    @property
    def player(self):
        return self._player

    @property
    def video(self):
        return self._player.value

    @video.setter
    def video(self, value):
        self._player.value = value
        self._player.enabled = value is not None
        if value:
            self._time.max = self._player.max

    @property
    def project(self):
        return self._project
예제 #11
0
    def __init__(self, *args, **kwargs):
        super().__init__('Hazard Labelling')

        self._args = {  "filepath": FILEPATH,
                        "folder": FOLDER,
                        "dest": DEST
                        }

        self.set_margin(10)

        #Definition of the forms fields
        self._videofile = ControlFile('Video')
        self._hazardbutton = ControlButton('Hazard')
        self._next = ControlButton('Next Video')
        self._save_data = ControlButton('Save labels')
        self._player = ControlPlayer('Player')
        self._timeline = ControlEventTimeline('Timeline')
        self._panel = ControlDockWidget(label='Timeline', side='bottom', margin=10)
        self._status = ControlText('Status')
        self._file_list = []

        if self._args["folder"] is None:
            if self._args["filepath"] is not None:
                self._file_list = self._args["filepath"]
        elif self._args["folder"] is not None:
            if os.path.isdir(self._args["folder"]):
                self.__updateStatus("Source folder found at: {}".format(self._args["folder"]))
                print("Scanning folder and all subfolders... {}".format(self._args["folder"]))
                count = 0
                for (dirpath, dirnames, filenames) in os.walk(self._args["folder"]):
                    path = []
                    for f in filenames:
                        if f.rsplit('.')[-1] in ACCEPTABLE_EXT:
                            count += 1
                            path.append(dirpath + "/" + f)
                    self._file_list.extend(path)
                    if count % 100 == 0:
                        print("Found {} files...".format(count))
                print("Scan complete, found {} acceptable files".format(count))
        self._video_count = len(self._file_list)
        self._progress = ControlProgress(label="Video %p of " + str(self._video_count), defaultValue=1, min=1, max=self._video_count)

        self._hazard_counter = 0
        self._current_video = 0

        #Define function calls on button presses
        self._videofile.changed_event = self.__videoFileSelectionEvent
        self._hazardbutton.value = self.__labelHazard
        self._next.value = self.__nextVideo
        self._save_data.value = self.__saveData
        self._panel.value = self._timeline
        self._progress.value = self._current_video + 1

        #Define events
        self._player.process_frame_event = self.__processFrame
        self._player.click_event = self.__clickEvent
        self._player.key_release_event = self.__tagEvent

        #Define the organization of the Form Controls
        self._formset = [
            '_player',
            # '_hazardbutton',
            '_panel',
            ('_videofile', '_next'),
            ('_status', '_save_data'),
            '_progress'
            ]

        self._video_loaded = False

        try:
            self.__videoFileSelect(self._file_list[self._current_video])
        except Exception as e:
            self.__updateStatus("Select video...")

        self._hazard_default_duration = 0
예제 #12
0
class VideoWindow(BaseWidget):

    def __init__(self, *args, **kwargs):
        super().__init__('Hazard Labelling')

        self._args = {  "filepath": FILEPATH,
                        "folder": FOLDER,
                        "dest": DEST
                        }

        self.set_margin(10)

        #Definition of the forms fields
        self._videofile = ControlFile('Video')
        self._hazardbutton = ControlButton('Hazard')
        self._next = ControlButton('Next Video')
        self._save_data = ControlButton('Save labels')
        self._player = ControlPlayer('Player')
        self._timeline = ControlEventTimeline('Timeline')
        self._panel = ControlDockWidget(label='Timeline', side='bottom', margin=10)
        self._status = ControlText('Status')
        self._file_list = []

        if self._args["folder"] is None:
            if self._args["filepath"] is not None:
                self._file_list = self._args["filepath"]
        elif self._args["folder"] is not None:
            if os.path.isdir(self._args["folder"]):
                self.__updateStatus("Source folder found at: {}".format(self._args["folder"]))
                print("Scanning folder and all subfolders... {}".format(self._args["folder"]))
                count = 0
                for (dirpath, dirnames, filenames) in os.walk(self._args["folder"]):
                    path = []
                    for f in filenames:
                        if f.rsplit('.')[-1] in ACCEPTABLE_EXT:
                            count += 1
                            path.append(dirpath + "/" + f)
                    self._file_list.extend(path)
                    if count % 100 == 0:
                        print("Found {} files...".format(count))
                print("Scan complete, found {} acceptable files".format(count))
        self._video_count = len(self._file_list)
        self._progress = ControlProgress(label="Video %p of " + str(self._video_count), defaultValue=1, min=1, max=self._video_count)

        self._hazard_counter = 0
        self._current_video = 0

        #Define function calls on button presses
        self._videofile.changed_event = self.__videoFileSelectionEvent
        self._hazardbutton.value = self.__labelHazard
        self._next.value = self.__nextVideo
        self._save_data.value = self.__saveData
        self._panel.value = self._timeline
        self._progress.value = self._current_video + 1

        #Define events
        self._player.process_frame_event = self.__processFrame
        self._player.click_event = self.__clickEvent
        self._player.key_release_event = self.__tagEvent

        #Define the organization of the Form Controls
        self._formset = [
            '_player',
            # '_hazardbutton',
            '_panel',
            ('_videofile', '_next'),
            ('_status', '_save_data'),
            '_progress'
            ]

        self._video_loaded = False

        try:
            self.__videoFileSelect(self._file_list[self._current_video])
        except Exception as e:
            self.__updateStatus("Select video...")

        self._hazard_default_duration = 0

    def __videoFileSelect(self, filepath):
        try:
            self._videofile.value = str(filepath)
            self._player.value = self._videofile.value
            self._player.refresh()
            self._player.update_frame()
            # Hazard set to occur for 60 frames upon flagging
            self._hazard_default_duration = int(self._player.fps * 2)
            self._video_loaded = True
        except Exception as e:
            self.__updateStatus("Unable to select video")

    def __videoFileSelectionEvent(self):
        """
        When the videofile is selected instantiate the video in the player
        """
        try:
            self._player.value = self._videofile.value
            # Hazard set to occur for 60 frames upon flagging
            self._hazard_default_duration = int(self._player.fps * 2)
            self._video_loaded = True
        except Exception as e:
            self.__updateStatus("No video selected")

    def __nextVideo(self):
        if self._current_video >= (self._video_count - 1):
            self.__updateStatus("No more videos")
        else:
            self._current_video += 1
            self.__reset()
            self.__videoFileSelect(self._file_list[self._current_video])
            self._progress.value = self._current_video + 1

    def __reset(self):
        self._player.stop()
        self.__saveData()
        print("saving on reset")
        self._timeline.clean()
        self.__updateStatus("")

    def __processFrame(self, frame):
        """
        Do some processing to the frame and return the result frame
        """
        return frame

    def __clickEvent(self, click_event, x, y):
        self.__labelHazard()

    def __tagEvent(self, event):
        """
        Label hazard using Enter key
        """
        key = event.key()

        # QtCore.Qt.Key_Enter gives wrong value (at least on test PC) for Enter key
        # Desired == 16777221, actual == 16777220

        key_id = 16777220

        if event.key() == key_id:
            self.__labelHazard()

    def __addFlag(self, value):
        self._timeline.add_period(value)

    def __labelHazard(self):
        if self._video_loaded:
            if self._player.video_index > (self._player.max - self._hazard_default_duration):
                flag_duration = round(self._player.max - self._player.video_index)
            else:
                flag_duration = self._hazard_default_duration
            try:
                self._hazard_counter += 1
                self.__updateStatus("Hazard flagged! | Frame: {} Timestamp: {}".format(self._player.video_index,
                                round(self._player.video_index/self._player.fps, 3)))
                self.__addFlag((self._player.video_index, self._player.video_index + flag_duration, str(self._hazard_counter)))
            except Exception as e:
                try:
                    self._player.refresh()
                    self.__updateStatus("Hazard flagged! | Frame: {} Timestamp: {}".format(self._player.video_index,
                                    round(self._player.video_index/self._player.fps, 3)))
                except Exception as e:
                    self.__updateStatus("Unable to label, exiting...")
                    sys.exit(0)

    def __saveData(self):
        self._timeline.export_csv_file(self._videofile.value + "_hazard.csv")
        self.__updateStatus("Saving {} to {}".format(self._videofile.value + "_hazard.csv", self._args["dest"]))

    def __updateStatus(self, msg):
        self._status.value = str(msg)