def __init__(self, parent=None): super(DistancesWindow, self).__init__('Distances', parent_win=parent) self.mainwindow = parent self.set_margin(5) #self.layout().setMargin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._datasets_panel = ControlEmptyWidget('Paths') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._formset = ['_datasets_panel', '_apply', '_progress'] self.load_order = ['_datasets_panel'] self.datasets_dialog = DatasetsDialog(self) self._datasets_panel.value = self.datasets_dialog self.datasets_dialog.datasets_filter = lambda x: isinstance( x, (Path, Contours)) self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide()
def __init__(self, parent=None): super(BackgroundFinderWindow, self).__init__('Background finder', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(400) self._panel = ControlEmptyWidget('Videos') self._image = ControlImage('Image') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._matrixSize = ControlSlider('Gaussian blur matrix size', default=5, minimum=1, maximum=11) self._sigmaX = ControlSlider('Gaussian blur sigma X', default=5, minimum=1, maximum=11) self._jump_2_frame = ControlSlider('Jump n frames', default=100, minimum=1, maximum=10000) self._cmp_jump = ControlSlider('Compare with frame in front', default=100, minimum=1, maximum=10000) self._threshold = ControlSlider('Threshold', default=5, minimum=0, maximum=255) self._formset = [[ '_panel', '||', [ ('_matrixSize', '_sigmaX'), ('_jump_2_frame', '_cmp_jump', '_threshold'), '_image', ], ], '_apply', '_progress'] self.videos_dialog = VideosDialog(self) self._panel.value = self.videos_dialog self.videos_dialog.interval_visible = False self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide()
def __init__(self, parent=None): BaseWidget.__init__(self, 'Motion counter', parent_win=parent) self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(500) self._player = ControlPlayer('Player') self._datasets = ControlEmptyWidget('Paths', default=DatasetsDialog()) self._backgrounds = ControlEmptyWidget('Backgrounds', default=ObjectsDialog()) self._show_diff = ControlCheckBox('Show diffs boxes') self._threshold = ControlSlider('Threshold', default=5, minimum=1, maximum=255) self._radius = ControlSlider('Radius', default=30, minimum=1, maximum=200) self._apply = ControlButton('Apply', checkable=True) self._compare = ControlCombo('Compare with') self._progress = ControlProgress('Progress') self._formset = [ '_datasets', '=', '_compare', '_backgrounds', ('_threshold', '_radius', '_show_diff'), '_player', '_apply', '_progress' ] self._compare.add_item('Last frame', 1) self._compare.add_item('First frame', 2) self._compare.add_item('Background image', 3) self.load_order = ['_threshold', '_radius', '_show_diff'] self._backgrounds.value.datasets_filter = lambda x: isinstance( x, Image) self._datasets.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) self._player.process_frame_event = self.__process_frame_event self._datasets.value.video_selection_changed_event = self.__video_selection_changed_event self._compare.changed_event = self.__compare_changed_event self._apply.value = self.__apply_btn_event self._apply.icon = conf.ANNOTATOR_ICON_MOTION self._progress.hide() self._backgrounds.hide()
def __init__(self): super().__init__('Student Info') self.set_margin(10) self.formset = [] leftside = [] leftside.append('Target GPA') self.slider = ControlSlider('', 2.5, 1.0, 4.0) leftside.append('slider') leftside.append('Current Enrollment: ') leftside.append(str(len(university.students))) leftside.append('Max Enrollment: ') leftside.append(str(university.capacity())) self.pbar = ControlProgress() self.pbar.min = 0 self.pbar.max = university.capacity() self.pbar.value = len(university.students) leftside.append('pbar') leftside.append('Average GPA: ') # need to add grad_rate leftside.append('2.3') leftside.append('Graduation Rate: ') leftside.append(str(university.grad_rate)) leftside.append('Average Morale: ') # need to add morale leftside.append('78%') # need to add morale to value self.morale_pbar = ControlProgress() self.morale_pbar.min = 0 self.morale_pbar.max = 100 self.morale_pbar.value = 78 leftside.append('morale_pbar') self.mylist = ControlList('Students') self.mylist.horizontal_headers = ['Name', 'GPA', 'Morale'] for student in university.students: self.mylist += (student.name, student.gpa, student.morale) self.formset.append((leftside, ' ', 'mylist'))
def __init__(self, parent=None): BaseWidget.__init__(self, 'Export data', parent_win=parent) self.set_margin(5) self.setMinimumHeight(600) self.setMinimumWidth(800) self._tree = ControlTree('Data') self._apply = ControlButton('Apply', checkable=True) self._progress = ControlProgress('Progress') self._add = ControlButton('Add') self._remove = ControlButton('Remove') self._export_list = ControlList('Columns to export') self._outdir = ControlDir('Output directory') self._outfile = ControlText('Output file name') self._toggleevts = ControlCheckBox('Split files by events') self._splitevents = ControlCheckBoxList('Events') self._evtsreload = ControlButton('Reload events') self._formset = [[['_add', '_tree'], '||', ['_remove', '_export_list']], '_toggleevts', '_evtsreload', '_splitevents', '_outdir', '_outfile', '_apply', '_progress'] self._add.value = self.__add_column_event self._remove.value = self.__remove_column_event self._apply.value = self.__apply_btn_event self._evtsreload.value = self.__reload_events self._outdir.changed_event = self.__update_outfile_name_event self._outfile.changed_event = self.__update_outfile_name_event self._toggleevts.changed_event = self.__toggleevents_visibility self._splitevents.changed_event = self.__update_outfile_name_event self._splitevents.selection_changed_event = self.__update_outfile_name_event self._tree.show_header = False self._apply.icon = conf.ANNOTATOR_ICON_MOTION self._evtsreload.icon = conf.ANNOTATOR_ICON_REFRESH self._add.icon = conf.ANNOTATOR_ICON_ADD self._remove.icon = conf.ANNOTATOR_ICON_REMOVE self._progress.hide() self._splitevents.hide() self._evtsreload.hide() self._apply.enabled = False self._properties = []
def __init__(self): super(MainWindow, self).__init__('PABLOPOLY') print() # Setting defaults settings self._board = ControlList(label='Tabuleiro') self._playDice = ControlButton('Jogar Dado') self.mylabel = ControlLabel('One') self._teste = ControlWeb() self._teste.value = 'https://github.com/UmSenhorQualquer/pyforms' self._myMoney = ControlProgress(label='Your Money is on %p%', default=15, min=0, max=100) self._informations = ControlLabel( 'Inital Money: $ 1500,00 | Max Money: $ 10000,00') self._board.value = returnBoad() self.formset = [ (('_teste', '=', '_myMoney'), '_playDice'), '_informations', ] print(self.formset) self._playDice.value = self.__playDices
def __init__(self, title=''): super(BaseApp, self).__init__(title) self._progress = ControlProgress('Processing') self._boundings = ControlBoundingSlider('Ranges', horizontal=True) #Only creates the variable if didn't exists yet. if not hasattr(self, '_modules_tabs'): self._modules_tabs = {} self.formset = [(' ', 'Frames bounding', ' '), '_boundings', self._modules_tabs, '_progress'] #Controls organization definition self.mainmenu = [{ 'File': [{ 'Open csv file': self.__open_tracking_file }, '-', { 'Export data': self.export_tracking_file }, '-', { 'Exit': exit }] }] self._data = None #Events definition self._csvParser = CsvParserDialog() self._csvParser.load_file_event = self.load_tracking_file self._boundings.changed = self.frames_boundings_changed
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' ]
def __init__(self, *args, **kwargs): #settings.PYFORMS_STYLESHEET = "style.css" super().__init__("EKOHEX Loader GUI v1.0 - Maciej Nachtygal") # Definition of the forms fields self._uC = ControlCombo("Mikrokontroler: ") items = ["Wybierz...", "Attiny 10", "Attiny 13", "Attiny 24"] for item in items: self._uC.add_item(item) self._clock = ControlCombo("Ust. zegara: ") self._upload = ControlCombo("Częst. wgrywania: ") items = [ "2 kHz", "4 kHz", "8 kHz", "16 kHz", "32 kHz", "93.75 kHz", "187 kHz", "375 kHz", "750 kHz", "1500 kHz" ] for item in items: self._upload.add_item(item) self._hexfile = ControlFile("Wybierz plik .hex : ") self._reapeat = ControlCheckBox("produkcja") self._reapeatInput = ControlText("Ilość: ") self._reapeatInput.enabled = False self.repeatStatus = self._reapeatInput.enabled self._progress = ControlProgress() self._progress.min = 0 self._progress.max = 100 self.progressStatus = 0 self._startButton = ControlButton("Start") self._stopButton = ControlButton("Stop") self.stop = False self._logBox = ControlTextArea("Log:") self._logBox.readonly = True self._logBox.autoscroll = True self._logBox.value = "Program gotowy do działania!\n" self.avrdudeInfo = "" # Define the function that will be called when a file is selected self._hexfile.changed_event = self.__hexFileSelectionEvent self._uC.changed_event = self.__uCSelectionEvent self._clock.changed_event = self.__clockSelectionEvent self._upload.changed_event = self.__uploadSelectionEvent self._reapeat.changed_event = self.__reapeatSelectionEvent self._reapeatInput.changed_event = self.__valueUpdateSelectionEvent self._startButton.value = self.__startSelectionEvent self._stopButton.value = self.__stopSelectionEvent # Define the organization of the Form Controls self._formset = [("_hexfile"), ("_uC", "_clock"), ("_upload", "_reapeat", "_reapeatInput"), ("_progress"), ("_startButton", "_stopButton"), "_logBox"]
def __init__(self, parent=None): BaseWidget.__init__(self, 'Regions filter', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(500) self._paths = [] self._pathspanel = ControlEmptyWidget('Path to process') self._geomspanel = ControlEmptyWidget('Geometries') self._apply = ControlButton('Apply', checkable=True) self._progress = ControlProgress('Progress') self._formset = [ '_pathspanel', '_geomspanel', '_apply', '_progress' ] self.load_order = ['_start', '_end', '_panel'] self.paths_dialog = DatasetsDialog(self) self.paths_dialog.objects_filter = lambda x: isinstance(x, Object2D) self.paths_dialog.datasets_filter = lambda x: isinstance(x, (Contours,Path) ) self._pathspanel.value = self.paths_dialog self.geoms_dialog = ObjectsDialog(self) self.geoms_dialog.objects_filter = lambda x: isinstance(x, Geometry) self._geomspanel.value = self.geoms_dialog self._apply.value = self.__apply_btn_event self._apply.icon = conf.ANNOTATOR_ICON_REGIONS self._progress.hide()
def __init__(self, parent=None): super(SmoothPathsWindow, self).__init__('Smooth paths', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._datasets_panel = ControlEmptyWidget('Paths') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._winsize = ControlSlider('Window size', minimum=3, default=3, maximum=100) self._order = ControlSlider('Order', minimum=0, default=0, maximum=10) self._deriv = ControlSlider('Derivative', minimum=0, default=0, maximum=10) self._rate = ControlSlider('Rate', minimum=0, default=0, maximum=10) self._formset = [ '_datasets_panel', '=', '_winsize', '_order', '_deriv', '_rate', ' ', '_apply', '_progress' ] self.load_order = ['_datasets_panel'] self.datasets_dialog = DatasetsDialog(self) self._datasets_panel.value = self.datasets_dialog self.datasets_dialog.datasets_filter = lambda x: isinstance( x, (Path, Value)) self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide()
def __init__(self, parent=None): super(FindOrientationWindow, self).__init__('Estimate countour orientation', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(300) self._panel = ControlEmptyWidget('Videos') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._debug = ControlCheckBox('Create all the intermediate values') self._min_steps = ControlSlider('Minimum steps', default=20, minimum=1, maximum=1000) self._min_dist = ControlSlider('Minimum distance', default=30, minimum=1, maximum=1000) self._panel.value = self.contours_dialog = DatasetsDialog(self) self.contours_dialog.datasets_filter = lambda x: isinstance( x, Contours) self._formset = [ '_panel', ('_min_steps', '_min_dist'), '_debug', '_apply', '_progress' ] self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide()
def __init__(self, parent=None, parent_win=None): BaseWidget.__init__(self, 'Events stats', parent_win=parent_win) self._parent = parent self._bounds = ControlBoundingSlider('Frames range', 1, 100, horizontal=True) self._nframes = ControlNumber('Merge in a group of', 1800) self._videofsp = ControlNumber('FPS', 30.0) self._analyseButton = ControlButton('Calculate graphs') self._events = ControlCheckBoxList() self._graph = ControlVisVis('Graph') self._showTotalCounts = ControlCheckBox('Show total events counting') self._showEvtsCounts = ControlCheckBox('Show events counting', True) self._progress = ControlProgress() self._exportDurations = ControlButton('Export durations') self._exportTotals = ControlButton('Export totals') self._formset = [(' ', '_showEvtsCounts', '|', '_showTotalCounts', '|', '_nframes', '_videofsp', '_analyseButton', '_exportDurations', '_exportTotals'), '_bounds', { 'a:Graph': ['_graph'], 'c:Events selection': ['_events'] }, '_progress'] self._analyseButton.value = self.__generate_graph self._exportDurations.value = self.__export_durations self._exportTotals.value = self.__export_totals self._progress.hide() self.__load_events() self.set_margin(5) self.setMinimumWidth(800) self.setMinimumHeight(600)
def __init__(self, *args, **kwargs): super().__init__('Youtube Downloader') self._url = ControlText('Link') self._runbutton = ControlButton('Download') self._progress = ControlProgress(max=100) self._actualLabel = ControlLabel("Progess:") self._status = ControlLabel("Idle") self._eta = ControlLabel("") self.pattern = re.compile( r"^(https?\:\/\/)?(www\.)?(youtube\.com|youtu\.?be)\/.+$") # self._thumbnail = ControlImage() self._formset = [('_url', '_runbutton'), ('_actualLabel', '_status'), ('_progress', '_eta'), ' '] # self._url.finishEditing = self.__downloadImage self._runbutton.value = self.__buttonAction self.disabled = False
def __init__(self, *args, **kwargs): super().__init__('Computer vision algorithm example') self.set_margin(10) #Definition of the forms fields self._indir = ControlText(label="Choose Dir:", value=self.INDIR) self._indir.value = self.INDIR self._outdir = ControlText(label="Choose Output Dir:", value=self.OUTDIR) self._outdir.value = self.OUTDIR self._infiles = [] self._filescount = ControlLabel("Total Files Selected: ") self._selectfiles = ControlButton('Select Files') self._selectfiles.value = self.__loadFiles # self._videofile = ControlFile('Video') # self._outputfile = ControlText('Results output file') # self._threshold = ControlSlider('Threshold', default=114, minimum=0, maximum=255) # self._blobsize = ControlSlider('Minimum blob size', default=110, minimum=100, maximum=2000) # self._player = ControlPlayer('Player') self._runbutton = ControlButton('Run') # #Define the function that will be called when a file is selected # self._videofile.changed_event = self.__videoFileSelectionEvent # #Define the event that will be called when the run button is processed self._runbutton.value = self.__runEvent self._progress_label = ControlLabel("Progress:") self._progress = ControlProgress("%") # #Define the event called before showing the image in the player # self._player.process_frame_event = self.__process_frame self._image_tbls = controls.ControlList() #Define the organization of the Form Controls self._formset = [('_indir', '_outdir'), ('_filescount', '_selectfiles'), '_image_tbls', '_runbutton', ('_progress_label', '_progress'), '']
class Stats(BaseWidget): def __init__(self, parent=None, parent_win=None): BaseWidget.__init__(self, 'Events stats', parent_win=parent_win) self._parent = parent self._bounds = ControlBoundingSlider('Frames range', 1, 100, horizontal=True) self._nframes = ControlNumber('Merge in a group of', 1800) self._videofsp = ControlNumber('FPS', 30.0) self._analyseButton = ControlButton('Calculate graphs') self._events = ControlCheckBoxList() self._graph = ControlVisVis('Graph') self._showTotalCounts = ControlCheckBox('Show total events counting') self._showEvtsCounts = ControlCheckBox('Show events counting', True) self._progress = ControlProgress() self._exportDurations = ControlButton('Export durations') self._exportTotals = ControlButton('Export totals') self._formset = [(' ', '_showEvtsCounts', '|', '_showTotalCounts', '|', '_nframes', '_videofsp', '_analyseButton', '_exportDurations', '_exportTotals'), '_bounds', { 'a:Graph': ['_graph'], 'c:Events selection': ['_events'] }, '_progress'] self._analyseButton.value = self.__generate_graph self._exportDurations.value = self.__export_durations self._exportTotals.value = self.__export_totals self._progress.hide() self.__load_events() self.set_margin(5) self.setMinimumWidth(800) self.setMinimumHeight(600) def __load_events(self): """ This function load the events present in the main window """ self._events_list = [] event_types = [] start = None end = None for track in self._parent.tracks: for delta in track.events: if delta.title not in event_types: self._events += (delta.title, True) event_types.append(delta.title) if start == None or start > delta._begin: start = delta._begin if end == None or end < delta._end: end = delta._end self._events_list.append( (delta._begin, delta._end, delta.title)) if len(self._events_list) == 0: return self._events_list = sorted(self._events_list, key=lambda x: (x[1], x[0])) # Set the bounding bar for the frames selection self._bounds.min = start - 10 self._bounds.max = end + 10 self._bounds.value = (start, end) self._nframes.min = 1 self._nframes.max = end self.__generate_graph() def __do_the_calculations(self): self._values2display = [] self._legends = [] self._duration = {} events_to_include = self._events.value # If no events are selected, clean the graph and exit the function if len(events_to_include) == 0 or \ (not self._showTotalCounts.value and not self._showEvtsCounts.value): return self._progress.min = 0 self._progress.max = self._bounds.value[1] self._progress.value = 0 self._progress.show() framesBin = self._nframes.value totalFrames = int(self._bounds.value[1] + 1) # Stores the counting related to a all the events totalcounts = np.array([0 for x in range(totalFrames)]) # Stores the counting related each event counts = {} for label in events_to_include: counts[label] = np.array([0 for x in range(totalFrames)]) self._duration[label] = np.array([0 for x in range(totalFrames)]) for i in range(0, totalFrames): # events_counted - this variable is used to # avoid repeating the same event in the current BIN counting if (i % framesBin) == 0: events_counted = [] self._progress.value = i for j, (start, end, event) in enumerate(self._events_list): if start <= i and end >= i and \ (event in events_to_include) and \ (j not in events_counted): # Do not count again a event that was already counted for this BIN lowerBound = i - (i % framesBin) upperBound = lowerBound + framesBin totalcounts[lowerBound:upperBound] += 1 counts[event][lowerBound:upperBound] += 1 events_counted.append(j) if start <= i and end >= i and (event in events_to_include): self._duration[event][i] += 1 if self._showTotalCounts.value: self._values2display.append(totalcounts) self._legends.append('All selected events') if self._showEvtsCounts.value: for label, values in counts.items(): self._legends.append(label) self._values2display.append(values) self._progress.hide() def __export_durations(self): directory = str( QtGui.QFileDialog.getExistingDirectory( self, "Select directory to save the data")) if directory != '': self.__do_the_calculations() events_to_include = self._events.value self._progress.min = 0 self._progress.max = self._bounds.value[1] * len(events_to_include) self._progress.value = 0 self._progress.show() framesBin = self._nframes.value totalFrames = int(self._bounds.value[1] + 1) for j, label in enumerate(events_to_include): with open(os.path.join(directory, '{0}.csv'.format(label)), 'wb') as csvfile: spamwriter = csv.writer(csvfile, delimiter=' ', quoting=csv.QUOTE_MINIMAL) spamwriter.writerow([ 'Period', 'event', 'start frame', 'end frame', 'duration in frames', 'duration in seconds' ]) for k, i in enumerate(range(0, totalFrames, framesBin)): count = sum(self._duration[label][i:i + framesBin]) time = float(count) / float(self._videofsp.value) if count > 0: spamwriter.writerow( [k, label, i, i + framesBin, count, time]) self._progress.value = i + self._bounds.value[1] * j def __export_totals(self): directory = str( QtGui.QFileDialog.getExistingDirectory( self, "Select directory to save the data")) if directory != '': self.__do_the_calculations() events_to_include = self._events.value all_events_ordered_by_time = sorted(self._get_all_events(), key=lambda x: x._begin) # these are special point events to mark experiment start and end experiment_start_frame_idx = int( all_events_ordered_by_time[0].begin) experiment_end_frame_idx = int( all_events_ordered_by_time[-1].begin) try: # these are special point events to mark experiment start and end events_to_include.remove(all_events_ordered_by_time[0]._title) events_to_include.remove(all_events_ordered_by_time[-1].title) except Exception as err: print("Warning: {0}".format(str(err))) self._progress.min = 0 self._progress.max = self._bounds.value[1] * len(events_to_include) self._progress.value = 0 self._progress.show() framesBin = self._nframes.value # e.g. 1800 if we want separation in minutes and have 30fps totalFrames = int(self._bounds.value[1] + 1) # totalFrames = int((experiment_end_time - experiment_start_time) + 1) with open(os.path.join(directory, 'totals.csv'), 'wb') as csvfile: spamwriter = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_MINIMAL) for j, label in enumerate(events_to_include): spamwriter.writerow([label]) spamwriter.writerow( ['Period', ' Duration (s)', ' Total', ' Occurrences']) events_occur = self._find_occurrences( self._duration[label]) for k, frame_idx in enumerate( range(experiment_start_frame_idx, experiment_end_frame_idx, int(framesBin))): groups = self.__event_groups_in_frames_threshold( events_occur, frame_idx, frame_idx + framesBin) groups_count = len(groups) frames_count = sum( self._duration[label][frame_idx:frame_idx + framesBin]) groups_start_times_str = " ".join([ format(((group[0] - experiment_start_frame_idx) / float(framesBin)), ".2f") for group in groups ]) # frames_count = sum(list(len(group) for group in groups)) time = float(frames_count) / float( self._videofsp.value) if frames_count > 0: # spamwriter.writerow([k, label, i, i + framesBin, frames_count, "{0:.2f}".format(time), groups_count]) # spamwriter.writerow(["{period:6}".format(period=k), "{start_second:11}".format(start_second=groups_start_times), "{start_second:15}".format(start_second=i), "{0:13.2f}".format(time), "{count:12}".format(count=groups_count)]) spamwriter.writerow([ "{period:6}".format(period=k), "{0:13.2f}".format(time), "{count:6}".format(count=groups_count), "{occur:15}".format( occur=groups_start_times_str) ]) else: # spamwriter.writerow([k, label, i, i + framesBin, 0, 0, 0]) # spamwriter.writerow(["{period:6}".format(period=k), "{start_second:11}".format(start_second=groups_start_times), "{start_second:15}".format(start_second=i), "{dur:13.2f}".format(dur=0), "{count:12}".format(count=0)]) spamwriter.writerow([ "{period:6}".format(period=k), "{dur:13.2f}".format(dur=0), "{count:6}".format(count=0), "{:15}".format("--") ]) self._progress.value = frame_idx + self._bounds.value[ 1] * j spamwriter.writerow([]) spamwriter.writerow([]) def _find_occurrences(self, events): """ Returns list with indexes of where value is equal to 1 In other words, indexes represent frames that correspond to event occurrences :param events: all durations occurrences list e.g. [0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0] returns [1, 2, 4, 5, 6, 8, 11, 12, 13, 14, 15, 16, 17, 18] """ return list(k for k, i in enumerate(events) if i) # all indexes of 1 def __event_groups_in_frames_threshold(self, events_occur, frames_threshold_first_index, frames_threshold_last_index): """ Returns list with events occurrences (groups) starting at frames_threshold_first_index, and before frames_threshold_last_index e.g. events_occur = [1, 2, 4, 5, 6, 8, 11, 12, 13, 14, 15, 16] frames_threshold_first_index = 5 frames_threshold_last_index = 15 returns [[8], [11, 12, 13, 14, 15, 16] """ prev = events_occur[0] last = 0 final = [] for k, i in enumerate(events_occur): if (i - prev) > 1: final.append(events_occur[last:k]) last = k prev = i final.append(events_occur[last:]) return list(occur for occur in final if occur[0] >= frames_threshold_first_index and occur[0] < frames_threshold_last_index) def __generate_graph(self): self.__do_the_calculations() self._graph.value = self._values2display self._graph.legends = self._legends def _get_all_events(self): self._time = self._parent res = [] for track in self._time.tracks: for delta in track._events: res.append(delta) return res
class MotionCounter(BaseWidget): def __init__(self, parent=None): BaseWidget.__init__(self, 'Motion counter', parent_win=parent) self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(500) self._player = ControlPlayer('Player') self._datasets = ControlEmptyWidget('Paths', default=DatasetsDialog()) self._backgrounds = ControlEmptyWidget('Backgrounds', default=ObjectsDialog()) self._show_diff = ControlCheckBox('Show diffs boxes') self._threshold = ControlSlider('Threshold', default=5, minimum=1, maximum=255) self._radius = ControlSlider('Radius', default=30, minimum=1, maximum=200) self._apply = ControlButton('Apply', checkable=True) self._compare = ControlCombo('Compare with') self._progress = ControlProgress('Progress') self._formset = [ '_datasets', '=', '_compare', '_backgrounds', ('_threshold', '_radius', '_show_diff'), '_player', '_apply', '_progress' ] self._compare.add_item('Last frame', 1) self._compare.add_item('First frame', 2) self._compare.add_item('Background image', 3) self.load_order = ['_threshold', '_radius', '_show_diff'] self._backgrounds.value.datasets_filter = lambda x: isinstance( x, Image) self._datasets.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) self._player.process_frame_event = self.__process_frame_event self._datasets.value.video_selection_changed_event = self.__video_selection_changed_event self._compare.changed_event = self.__compare_changed_event self._apply.value = self.__apply_btn_event self._apply.icon = conf.ANNOTATOR_ICON_MOTION self._progress.hide() self._backgrounds.hide() ########################################################################### ### EVENTS ################################################################ ########################################################################### def __compare_changed_event(self): if self._compare.value == 1: self._backgrounds.hide() elif self._compare.value == 2: self._backgrounds.hide() elif self._compare.value == 3: self._backgrounds.show() self._lastframe = None def __video_selection_changed_event(self): video = self._datasets.value.selected_video if video is not None: self._player.value = video.video_capture def __process_frame_event(self, frame): index = self._player.video_index - 1 selected_video = self._datasets.value.selected_video radius = self._radius.value threshold = self._threshold.value show_diff = self._show_diff.value compare_with = self._compare.value if compare_with == 3 and len(self._backgrounds.value.objects): background_img = self._backgrounds.value.objects[0].image background_img = cv2.cvtColor(background_img, cv2.COLOR_BGR2GRAY) else: background_img = None for video, (begin, end), datasets in self._datasets.value.selected_data: if video != selected_video: continue for dataset in datasets: pos = dataset.get_position(index) if pos is None: continue if show_diff: # calculate the cut x, y = pos cutx = int(round(x - radius)) cuty = int(round(y - radius)) cutxx = int(round(x + radius)) cutyy = int(round(y + radius)) if cutx < 0: cutx = 0 if cutxx > frame.shape[1]: cutxx = frame.shape[1] if cuty < 0: cuty = 0 if cutyy > frame.shape[0]: cutyy = frame.shape[0] gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) small = gray[cuty:cutyy, cutx:cutxx].copy() circular_mask = np.zeros((cutyy - cuty, cutxx - cutx), dtype=np.uint8) cv2.circle(circular_mask, (cutyy - cuty, cutxx - cutx), radius, 255, -1) small_masked = cv2.bitwise_and(circular_mask, small) if not hasattr(self, '_lastframe') or type( self._lastframe) is not np.ndarray: if self._compare.value == 1 or self._compare.value == 2: self._lastframe = gray elif self._compare.value == 3: self._lastframe = background_img if type(self._lastframe) is np.ndarray: last_masked = cv2.bitwise_and( circular_mask, self._lastframe[cuty:cutyy, cutx:cutxx]) diff = cv2.absdiff(small_masked, last_masked) cv2.circle(frame, pos, radius, (0, 0, 0), -1) frame[cuty:cutyy, cutx:cutxx] += cv2.merge( (diff, diff, diff)) if self._compare.value == 1: self._lastframe = gray else: cv2.circle(frame, pos, radius, (0, 0, 255), 2) return frame def __apply_btn_event(self): if self._apply.checked: self._datasets.enabled = False self._show_diff.enabled = False self._threshold.enabled = False self._player.enabled = False self._radius.enabled = False self._player.stop() self._apply.label = 'Cancel' total_2_analyse = 0 for video, (begin, end), datasets in self._datasets.value.selected_data: total_2_analyse += end - begin + 1 self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() radius = self._radius.value threshold = self._threshold.value count = 0 for video, (begin, end), datasets in self._datasets.value.selected_data: begin = int(begin) end = int(end) + 1 capture = cv2.VideoCapture(video.filepath) capture.set(cv2.CAP_PROP_POS_FRAMES, begin) last_image = [None for x in datasets] compare_with = self._compare.value if compare_with == 3: if len(self._backgrounds.value.objects): background_img = self._backgrounds.value.objects[ 0].image background_img = cv2.cvtColor(background_img, cv2.COLOR_BGR2GRAY) else: self.critical('No background selected') break else: background_img = None for index in range(begin, end): res, frame = capture.read() if not res: break if not self._apply.checked: break for dataset_index, dataset in enumerate(datasets): pos = dataset.get_position(index) if pos is None: continue x, y = pos cutx = int(round(x - radius)) cuty = int(round(y - radius)) cutxx = int(round(x + radius)) cutyy = int(round(y + radius)) if cutx < 0: cutx = 0 if cutxx > frame.shape[1]: cutxx = frame.shape[1] if cuty < 0: cuty = 0 if cutyy > frame.shape[0]: cutyy = frame.shape[0] gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) small = gray[cuty:cutyy, cutx:cutxx].copy() circular_mask = np.zeros((cutyy - cuty, cutxx - cutx), dtype=np.uint8) cv2.circle(circular_mask, (cutyy - cuty, cutxx - cutx), radius, 255, -1) small_masked = cv2.bitwise_and(small, small, circular_mask) if type(last_image[dataset_index]) is not np.ndarray: last_image[dataset_index] = small_masked if compare_with == 1 or compare_with == 2: last_image[dataset_index] = gray elif compare_with == 3: last_image[dataset_index] = background_img segment = last_image[dataset_index] last_masked = cv2.bitwise_and( circular_mask, segment[cuty:cutyy, cutx:cutxx]) diff = cv2.absdiff(small_masked, last_masked) diff[diff < threshold] = 0 diff[diff >= threshold] = 1 motion = np.sum(diff) dataset.set_motion(index, motion) if compare_with == 1: last_image[dataset_index] = gray self._progress.value = count count += 1 self._datasets.enabled = True self._show_diff.enabled = True self._threshold.enabled = True self._player.enabled = True self._radius.enabled = True self._apply.label = 'Apply' self._apply.checked = False self._progress.hide()
class DistancesWindow(BaseWidget): def __init__(self, parent=None): super(DistancesWindow, self).__init__('Distances', parent_win=parent) self.mainwindow = parent self.set_margin(5) #self.layout().setMargin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._datasets_panel = ControlEmptyWidget('Paths') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._formset = ['_datasets_panel', '_apply', '_progress'] self.load_order = ['_datasets_panel'] self.datasets_dialog = DatasetsDialog(self) self._datasets_panel.value = self.datasets_dialog self.datasets_dialog.datasets_filter = lambda x: isinstance( x, (Path, Contours)) self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide() ########################################################################### ### EVENTS ################################################################ ########################################################################### ########################################################################### ### PROPERTIES ############################################################ ########################################################################### @property def datasets(self): return self.datasets_dialog.datasets def __apply_event(self): if self._apply.checked: self._datasets_panel.enabled = False self._apply.label = 'Cancel' total_2_analyse = 0 for video, (begin, end), datasets in self.datasets_dialog.selected_data: total_2_analyse += (end - begin + 1) * len(datasets) * len(datasets) self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() count = 0 for video, (begin, end), datasets in self.datasets_dialog.selected_data: begin = int(begin) end = int(end) + 1 if len(datasets) < 2: continue for d1_index in range(len(datasets)): for d2_index in range(len(datasets)): if d1_index == d2_index: break if not self._apply.checked: break set1 = datasets[d1_index] set2 = datasets[d2_index] val = set1.object2d.create_value() val.name = "distance-between ({0}) and ({1})".format( set1.name, set2.name) for index in range(begin, end): if not self._apply.checked: break pos1 = set1.get_position(index) if pos1 is None: continue pos2 = set2.get_position(index) if pos2 is None: continue dist = pts_utils.lin_dist(pos1, pos2) val.set_value(index, dist) self._progress.value = count count += 1 count = d1_index * d2_index * (end - begin + 1) self._datasets_panel.enabled = True self._apply.label = 'Apply' self._apply.checked = False self._progress.hide()
class BackgroundFinderWindow(BaseWidget): def __init__(self, parent=None): super(BackgroundFinderWindow, self).__init__('Background finder', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(400) self._panel = ControlEmptyWidget('Videos') self._image = ControlImage('Image') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._matrixSize = ControlSlider('Gaussian blur matrix size', default=5, minimum=1, maximum=11) self._sigmaX = ControlSlider('Gaussian blur sigma X', default=5, minimum=1, maximum=11) self._jump_2_frame = ControlSlider('Jump n frames', default=100, minimum=1, maximum=10000) self._cmp_jump = ControlSlider('Compare with frame in front', default=100, minimum=1, maximum=10000) self._threshold = ControlSlider('Threshold', default=5, minimum=0, maximum=255) self._formset = [[ '_panel', '||', [ ('_matrixSize', '_sigmaX'), ('_jump_2_frame', '_cmp_jump', '_threshold'), '_image', ], ], '_apply', '_progress'] self.videos_dialog = VideosDialog(self) self._panel.value = self.videos_dialog self.videos_dialog.interval_visible = False self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide() def init_form(self): super(BackgroundFinderWindow, self).init_form() self.videos_dialog.project = self.mainwindow.project ########################################################################### ### EVENTS ################################################################ ########################################################################### ########################################################################### ### PROPERTIES ############################################################ ########################################################################### def __update_image_event(self, frame, frame_count): self._image.value = frame self._progress.value = self._base_nframes + frame_count def __apply_event(self): if self._apply.checked and self._apply.label == 'Apply': self._panel.enabled = False self._image.enabled = False self._matrixSize.enabled = False self._sigmaX.enabled = False self._jump_2_frame.enabled = False self._cmp_jump.enabled = False self._threshold.enabled = False self._apply.label = 'Cancel' total_steps = 0 for video, _ in self.videos_dialog.selected_data: total_steps += video.total_frames self._progress.min = 0 self._progress.max = total_steps self._progress.show() self._base_nframes = 0 exit = True for video, _ in self.videos_dialog.selected_data: if not self._apply.checked: break bg = BackgroundDetector( capture=video.video_capture, gaussianBlurMatrixSize=self._matrixSize.value, gaussianBlursigmaX=self._sigmaX.value, update_function=self.__update_image_event) bg.detect(self._jump_2_frame.value, self._cmp_jump.value, self._threshold.value) image = video.create_image() image.name = 'background-{0}'.format(len(list(video.images))) image.image = bg.background_color self._base_nframes += video.total_frames self._panel.enabled = True self._image.enabled = True self._matrixSize.enabled = True self._sigmaX.enabled = True self._jump_2_frame.enabled = True self._cmp_jump.enabled = True self._threshold.enabled = True self._apply.label = 'Apply' exit = self._apply.checked self._apply.checked = False self._progress.hide()
class RegionsFilter(BaseWidget): def __init__(self, parent=None): BaseWidget.__init__(self, 'Regions filter', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(500) self._paths = [] self._pathspanel = ControlEmptyWidget('Path to process') self._geomspanel = ControlEmptyWidget('Geometries') self._apply = ControlButton('Apply', checkable=True) self._progress = ControlProgress('Progress') self._formset = [ '_pathspanel', '_geomspanel', '_apply', '_progress' ] self.load_order = ['_start', '_end', '_panel'] self.paths_dialog = DatasetsDialog(self) self.paths_dialog.objects_filter = lambda x: isinstance(x, Object2D) self.paths_dialog.datasets_filter = lambda x: isinstance(x, (Contours,Path) ) self._pathspanel.value = self.paths_dialog self.geoms_dialog = ObjectsDialog(self) self.geoms_dialog.objects_filter = lambda x: isinstance(x, Geometry) self._geomspanel.value = self.geoms_dialog self._apply.value = self.__apply_btn_event self._apply.icon = conf.ANNOTATOR_ICON_REGIONS self._progress.hide() def __reload_tracks_event(self): self._tracks.clearItems() for track in self.mainwindow._time.tracks: self._tracks.addItem(str(track.title), track) def __apply_btn_event(self): if self._apply.checked: self._pathspanel.enabled = False self._geomspanel.enabled = False self._apply.label = 'Cancel' # calculate the total number of frames to analyse total_2_analyse = 0 for video, (begin, end), datasets_list in self.paths_dialog.selected_data: total_2_analyse += end-begin+1 self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() contours = [] for video, geometries in self.geoms_dialog.selected_data: for geometry_object in geometries: for contour in geometry_object.geometry: contours.append(np.int32(contour[1])) count = 0 for video, (begin, end), datasets_list in self.paths_dialog.selected_data: begin, end = int(begin), int(end)+1 for path_dataset in datasets_list: object2d = path_dataset.object2d value_obj = object2d.create_value() value_obj.name = 'regions-filter ({0})'.format(len(object2d)) for index in range(begin, end+1): pt = path_dataset.get_position(index) for contour in contours: dist = cv2.pointPolygonTest(contour, pt, True) value_obj.set_value(index, dist) count += 1 self._progress.value = count self._pathspanel.enabled = True self._geomspanel.enabled = True self._apply.label = 'Apply' self._progress.hide() def add_event_2_timeline(self, track, evt_name, begin, end): self.mainwindow.add_event_2_timeline(track, evt_name, begin, end) def add_dataset_event(self, dataset): if isinstance(dataset, Path): self._paths += [dataset, True] def removed_dataset_event(self, dataset): if isinstance(dataset, Path): self._paths -= dataset def removed_object_event(self, obj): items2remove = [] for i, (item, checked) in enumerate(self._paths.items): if item.object2d==obj: items2remove.append(i) for i in sorted(items2remove,reverse=True): self._paths -= i ########################################################################### ### PROPERTIES ############################################################ ########################################################################### @property def video_filename(self): return None @video_filename.setter def video_filename(self, value): self._panel.value.video_filename = value self._start.max = self._panel.value.total_n_frames self._end.max = self._panel.value.total_n_frames @property def paths(self): return self._paths.value @paths.setter def paths(self, value): self._paths.value = value def save(self, data): return data def load(self, data): pass
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:')
class VideosExporterGui(BaseWidget, VideosExporterPreview, VideosExporterProcess): def __init__(self, parent=None): super(VideosExporterGui, self).__init__('Videos exporter', parent_win=parent) self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(400) self._toolbox = ControlToolBox('Tool') self._panel_area = ControlEmptyWidget('Set the object area', default=DatasetsDialog(self)) self._panel_colors = ControlEmptyWidget('Set the object color', default=DatasetsDialog(self)) self._panel_imgs = ControlEmptyWidget('Set the video background', default=ImagesDialog(self)) #### path panel ################################################ self._panel_path = ControlEmptyWidget('Set the object path', default=DatasetsDialog(self)) self._drawpath = ControlCheckBox('Draw paths') ################################################################ #### draw events ############################################### self._drawevents = ControlCheckBoxList('Events') self._eventstitles = ControlCheckBox('Draw titles') self._evtsreload1 = ControlButton('Reload events') ################################################################ #### split by events ########################################### self._splitevents = ControlCheckBoxList('Events') self._evtsreload2 = ControlButton('Reload events') ################################################################ self._codec = ControlCheckBox('Force AVI') self._outdir = ControlDir('Output directory') self._outfile = ControlText('Output file name') self._player = ControlPlayer('Player') self._progress = ControlProgress('Progress') self._apply = ControlButton('Export video(s)', checkable=True) self._apply.icon = conf.ANNOTATOR_ICON_PATH self._apply.enabled = False self._usefixedsize = ControlCheckBox('Use a fixed size') self._usefixedcolor = ControlCheckBox('Use a fixed color') self._radius = ControlSlider('Circle radius', default=10, minimum=1, maximum=300) self._color = ControlText('BGR color', default='255,255,255') self.formset = [('_toolbox', '||', '_player'), '=', '_outdir', ('_outfile', '_codec'), '_apply', '_progress'] self._toolbox.value = [ ('Path', [self._panel_path, self._drawpath]), ('Circle (optional)', [self._panel_area, (self._usefixedsize, self._radius)]), ('Circle color (optional)', [self._panel_colors, (self._usefixedcolor, self._color)]), ('Background (optional)', [self._panel_imgs]), ('Draw events (optional)', [self._evtsreload1, self._drawevents, self._eventstitles]), ('Split files by events (optional)', [self._evtsreload2, self._splitevents]), ] self._panel_path.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) #self._panel_area.value.datasets_filter = lambda x: isinstance(x, Value ) self._panel_colors.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) and hasattr(x, 'has_colors_avg' ) and x.has_colors_avg ### Set the controls events ############################################# self._evtsreload1.value = self.__reload_events self._evtsreload2.value = self.__reload_events self._outfile.changed_event = self.outputfile_changed_event self._usefixedsize.changed_event = self.__usefixedsize_changed_event self._usefixedcolor.changed_event = self.__usefixedcolor_changed_event self._splitevents.selection_changed_event = self.outputfile_changed_event self._panel_path.value.video_selection_changed_event = self.__video_selection_changed_event self._codec.changed_event = self.__video_selection_changed_event ## function from VideosExporterProcess class self._apply.value = self.apply_event ## function from VideosExporterPreview class self._player.process_frame_event = self.player_processframe_event self._evtsreload1.icon = conf.ANNOTATOR_ICON_REFRESH self._evtsreload2.icon = conf.ANNOTATOR_ICON_REFRESH self._progress.hide() self._radius.hide() self._color.hide() self.__check_areatab_event() ########################################################################### ### UTILS ################################################################# ########################################################################### def __reload_events(self): """ Find all the events available on the timeline """ timeline = self.parent().timeline rows = timeline.rows events = {} for row in rows: for event in row.events: events[event.title] = True events = sorted(events.keys()) loaded_events = dict(self._drawevents.items) self._drawevents.value = [(e, loaded_events.get(e, False)) for e in events] loaded_events = dict(self._splitevents.items) self._splitevents.value = [(e, loaded_events.get(e, False)) for e in events] ########################################################################### ### EVENTS ################################################################ ########################################################################### def show(self): """ Load the events when the window is oppened """ super(VideosExporterGui, self).show() self.__reload_events() def __check_areatab_event(self): """ Activate or deactivate the color tab """ if len(list(self._panel_area.value.datasets) ) > 0 or self._usefixedsize.value: self._toolbox.set_item_enabled(2, True) else: self._toolbox.set_item_enabled(2, False) def __usefixedcolor_changed_event(self): if self._usefixedcolor.value: self._color.show() self._panel_colors.hide() else: self._color.hide() self._panel_colors.show() def __usefixedsize_changed_event(self): self.__check_areatab_event() if self._usefixedsize.value: self._radius.show() self._panel_area.hide() else: self._radius.hide() self._panel_area.show() def outputfile_changed_event(self): """ Update the output filename """ filename = self._outfile.value video = self._panel_path.value.selected_video if video is not None: filename = filename if len(filename) > 0 else video.filename videofilepath, video_extension = os.path.splitext(video.filename) outfilepath, outfile_extension = os.path.splitext(filename) names = [outfilepath] if len(outfilepath) > 0 else [] if '{videoindex}' not in outfilepath: names.append('{videoindex}') if len(list(self._splitevents.value)) > 0: if '{event}' not in outfilepath: names.append('{event}') if '{start}' not in outfilepath: names.append('{start}') if '{end}' not in outfilepath: names.append('{end}') self._outfile.value = ('-'.join(names) + video_extension) self._apply.enabled = True else: self._apply.enabled = False def __video_selection_changed_event(self): """ Activate the video preview """ video = self._panel_path.value.selected_video if video is not None: self._player.value = video.video_capture def get_object_area(self, path, areas, index): try: if self._usefixedsize.value: area = (self._radius.value**2 * math.pi) elif len(areas) > 0: a = areas[0] if isinstance(a, Value): area = a.get_value(index) else: area = a.get_area_value(index) else: area = path.get_area_value(index) return area except: return None def get_object_color(self, path, colors, index): try: if self._usefixedcolor.value: color = tuple(eval(self._color.value)) elif len(colors) > 0: color = colors[0].get_color_avg(index) else: color = path.get_color_avg(index) if color is None: raise Exception() except: color = 255, 255, 255 return color
class ContoursImagesWindow(BaseWidget): def __init__(self, parent=None): super(ContoursImagesWindow, self).__init__('Contour images', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._contourspanel = ControlEmptyWidget('Contours datasets') self._progress = ControlProgress('Progress', visible=False) self._apply = ControlButton('Apply', checkable=True) self._toolbox = ControlToolBox('Toolbox') self._exportdir = ControlDir('Export images to folder', default='images-from-contour') #### mask ###################################################### self._usemaskimg = ControlCheckBox('Apply a mask to the image') self._usemaskdilate = ControlCheckBox('Dilate the mask and apply it to the image') self._maskdilatesize = ControlSlider('Dilate size', default=0, minimum=0, maximum=100) self._usemaskellipse = ControlCheckBox('Apply the min. ellipse as a mask to the image') self._usemaskcircular = ControlCheckBox('Apply a circular mask to the image') self._maskcircularsize = ControlSlider('Circular radius', default=0, minimum=0, maximum=100) self._usemaskrect = ControlCheckBox('Apply the min. rect as a mask to the image') ################################################################ #### margin #################################################### self._margin = ControlSlider('Margin size', default=0, minimum=0, maximum=100) ################################################################ #### imagesize ################################################# self._imagesize = ControlSlider('Image size', default=0, minimum=0, maximum=400) ################################################################ #### cut ####################################################### self._usecut = ControlCheckBox('Cut image') self._cutx = ControlBoundingSlider('X cut', default=(10,30), minimum=0, maximum=1000) self._cuty = ControlBoundingSlider('Y cut', default=(10,30), minimum=0, maximum=1000) ################################################################ #### use stretch ############################################### self._usestretch = ControlCheckBox('Stretch image') ################################################################ #### filter per events ######################################### self._eventslst = ControlCheckBoxList('Events', enabled=True) self._reloadevts = ControlButton('Reload events', enabled=True, default=self.__reload_events_btn_evt) ################################################################ #### rotation ################################################## self._userotup = ControlCheckBox('Turn the contour always up') self._userotdown = ControlCheckBox('Turn the contour always down') self._usefixedangle = ControlCheckBox('Use a fixed orientation') self._fixedangle = ControlSlider('Rotate the images using a fixed angle', enabled=True, default=0, minimum=0, maximum=360) self._usedatasetangle = ControlCheckBox('Use the orientation of other contour') self._datasetanglepanel = ControlEmptyWidget('Datasets for the orientation', enabled=True) ################################################################ #### image position ############################################ self._useposdataset = ControlCheckBox('Use a dataset to center the image') self._datasetpospanel = ControlEmptyWidget('Datasets for the image position', enabled=True) ################################################################ self.formset = [ '_toolbox', '_exportdir', '_apply', '_progress' ] self.load_order = [ '_contourspanel','_userotup', '_userotdown', '_exportdir','_usemaskimg','_usemaskdilate','_usemaskellipse','_usemaskellipse', '_usemaskcircular', '_maskcircularsize', '_usemaskrect', '_margin', '_imagesize', '_usestretch', '_eventslst', '_usefixedangle', '_fixedangle', '_usedatasetangle', '_datasetanglepanel', '_useposdataset', '_datasetpospanel', '_usecut', '_cuty', '_cutx' ] #datasets painel self.datasets_dialog = DatasetsDialog(self) self.datasets_dialog.datasets_filter = lambda x: isinstance(x, Contours ) self._contourspanel.value = self.datasets_dialog self.posdatasets_dialog = DatasetsDialog(self) self.posdatasets_dialog.datasets_filter = lambda x: isinstance(x, (Contours,Path) ) self._datasetpospanel.value = self.posdatasets_dialog self.orientdatasets_dialog = DatasetsDialog(self) self.orientdatasets_dialog.datasets_filter = lambda x: isinstance(x, Contours ) self.orientdatasets_dialog.interval_visible = False self._datasetanglepanel.value = self.orientdatasets_dialog self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._imagesize.changed_event = self.__image_size_changed_evt self._toolbox.value = [ ('Extract from contours',( self.datasets_dialog, )), ('Mask',( self._usemaskimg, (self._usemaskdilate,self._maskdilatesize), (self._usemaskcircular,self._maskcircularsize), (self._usemaskellipse,self._usemaskrect), )), ('Margin, image size and stretch image',( self._usestretch, self._margin, self._imagesize, self._usecut, self._cutx, self._cuty )), ('Rotate images',( (self._userotup, self._userotdown), (self._usefixedangle, self._fixedangle), self._usedatasetangle, self._datasetanglepanel )), ('Center images',( self._useposdataset, self._datasetpospanel, )), ('Export images per events',( self._reloadevts, self._eventslst, )), ] self.__reload_events_btn_evt() self.__image_size_changed_evt() ########################################################################### ### EVENTS ################################################################ ########################################################################### def __image_size_changed_evt(self): if self._imagesize.value>0: self._usecut.enabled = True self._cutx.enabled = True self._cuty.enabled = True self._cuty.max = self._imagesize.value self._cutx.max = self._imagesize.value else: self._usecut.enabled = False self._cutx.enabled = False self._cuty.enabled = False def __reload_events_btn_evt(self): """ Find all the events available on the timeline """ timeline = self.mainwindow.timeline rows = timeline.rows events = {} for row in rows: for event in row.events: events[event.title] = True events = sorted(events.keys()) loaded_events = dict(self._eventslst.items) self._eventslst.value = [(e, loaded_events.get(e, False)) for e in events] ########################################################################### ### PROPERTIES ############################################################ ########################################################################### @property def datasets(self): return self.datasets_dialog.datasets @property def player(self): return self._filter._player def __get_events_cuts(self, begin, end): ### calculate the video cuts ############################# selected_events = self._eventslst.value videocuts = [] if len(selected_events): # use the events to cut the video totalframes = 0 timeline = self.mainwindow.timeline for row in timeline.rows: for event in row.events: if event.end<=begin: continue if event.begin>=end: continue if event.title not in selected_events: continue b = int(event.begin if event.begin>=begin else begin) e = int(event.end if event.end<=end else end) totalframes += e-b videocuts.append( (b, e, event.title) ) videocuts = sorted(videocuts, key = lambda x: x[0]) else: # no events were selected totalframes = end-begin videocuts = [(int(begin), int(end), None)] ########################################################## return videocuts def __get_export_map(self, begin_frame, end_frame, eventscuts): """ Create a map of folders to export the images to """ exportmap = [] for begin, end, title in eventscuts: if title is None: continue for i in range(begin, end): # fill the map with empty values if len(exportmap)<=i: while len(exportmap)<=i: exportmap.append(None) if exportmap[i] is None: exportmap[i]=[] exportmap[i].append(title) for i in range(begin_frame, end_frame): # fill the map with empty values if len(exportmap)<=i: while len(exportmap)<=i: exportmap.append(None) if exportmap[i] is None: exportmap[i]=[] if len(exportmap[i])==0: exportmap[i].append('untagged') return exportmap def __apply_event(self): if self._apply.checked: if self._usecut.value and self._imagesize.value>0: x, xx = self._cutx.value y, yy = self._cuty.value if int(yy)==int(y) or int(xx)==int(x): self.message("The second cut value has to be bigger than the first", "Error", "error") self._apply.checked=False return self._toolbox.enabled = False self._exportdir.enabled = False self._progress.value = 0 self._apply.label = 'Cancel' # setup the progress bar total_2_analyse = 0 for video, (begin, end), datasets in self.datasets_dialog.selected_data: total_2_analyse += end-begin self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() ###################################################################### # create a directory to export the images if the option was selected EXPORT_DIRECTORY = self._exportdir.value if len(EXPORT_DIRECTORY)==0: EXPORT_DIRECTORY = 'contour-images' if not os.path.exists(EXPORT_DIRECTORY): os.makedirs(EXPORT_DIRECTORY) ###################################################################### ############ CONFIGURE IMAGE CUT PARAMETERS ########################## params = {} params['mask'] = self._usemaskimg.value params['ellipse_mask'] = self._usemaskellipse.value params['rect_mask'] = self._usemaskrect.value params['margin'] = self._margin.value params['stretch'] = self._usestretch.value if self._usemaskdilate.value: params['mask'] = int(self._maskdilatesize.value) if self._usemaskcircular.value: params['circular_mask'] = int(self._maskcircularsize.value) if self._usefixedangle.value: params['angle'] = math.radians(self._fixedangle.value) if self._userotup.value: params['angle'] = 'up' if self._userotdown.value: params['angle'] = 'down' if self._imagesize.value>0: params['size'] = (self._imagesize.value, self._imagesize.value) ###################################################################### ###################################################################### # check if should use the angle from other datasets if self._usedatasetangle.value: objects_angles = {} for _, _, datasets in self.datasets_dialog.selected_data: for dataset in datasets: for _, _, d in self._datasetanglepanel.value.selected_data: objects_angles[dataset.object2d] = d[0] ###################################################################### ###################################################################### # check if should use position from other datasets if self._useposdataset.value: objects_pos = {} for _, _, datasets in self.datasets_dialog.selected_data: for dataset in datasets: for _, _, d in self._datasetpospanel.value.selected_data: objects_pos[dataset.object2d] = d[0] ###################################################################### for video, (begin, end), datasets in self.datasets_dialog.selected_data: if not self._apply.checked: break if len(datasets)==0: continue begin, end = int(begin), int(end) capture = cv2.VideoCapture(video.filepath) capture.set(cv2.CAP_PROP_POS_FRAMES, begin); eventscuts = self.__get_events_cuts(begin, end) exportmap = self.__get_export_map(begin, end, eventscuts) ###################################################################### # create the directories to export the images per video and events videofolder = os.path.join(EXPORT_DIRECTORY, video.name) if not os.path.exists(videofolder): os.makedirs(videofolder) for dataset in datasets: objectfolder = os.path.join(videofolder, dataset.object2d.name) if not os.path.exists(objectfolder): os.makedirs(objectfolder) datasetfolder = os.path.join(objectfolder, dataset.name) if not os.path.exists(datasetfolder): os.makedirs(datasetfolder) ###################################################################### for i in range(begin,end): if not self._apply.checked: break res, frame = capture.read() #exit in the case the frame was not read. if not res: self._apply.label = 'Apply' self._toolbox.enabled = True self._exportdir.enabled = True self._apply.checked = False self._progress.hide() return False, None for foldername in exportmap[i]: if not self._apply.checked: break for dataset in datasets: parameters = dict(params) parameters['frame'] = frame.copy() # in the case we are using another dataset angle to rotate the image if self._usedatasetangle.value: dtangle = objects_angles.get(dataset.object2d, None) if dtangle is not None: parameters['angle'] = dtangle.get_angle(i) else: continue if self._useposdataset.value: dpos = objects_pos.get(dataset.object2d, None) if dpos is not None: parameters['image_center'] = dpos.get_position(i) else: continue ok, img = dataset.get_image(i, **parameters) if ok: folder = os.path.join(videofolder, dataset.object2d.name, dataset.name, foldername) imgpath = os.path.join(folder, '{0}.png'.format(i) ) if not os.path.exists(folder): os.makedirs(folder) if self._usecut.value and self._imagesize.value>0: x, xx = self._cutx.value y, yy = self._cuty.value img = img[int(y):int(yy), int(x):int(xx)] cv2.imwrite(imgpath, img) self._progress.value += 1 self._apply.label = 'Apply' self._toolbox.enabled = True self._exportdir.enabled = True self._apply.checked = False self._progress.hide()
def __init__(self, parent=None): super(ContoursImagesWindow, self).__init__('Contour images', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._contourspanel = ControlEmptyWidget('Contours datasets') self._progress = ControlProgress('Progress', visible=False) self._apply = ControlButton('Apply', checkable=True) self._toolbox = ControlToolBox('Toolbox') self._exportdir = ControlDir('Export images to folder', default='images-from-contour') #### mask ###################################################### self._usemaskimg = ControlCheckBox('Apply a mask to the image') self._usemaskdilate = ControlCheckBox('Dilate the mask and apply it to the image') self._maskdilatesize = ControlSlider('Dilate size', default=0, minimum=0, maximum=100) self._usemaskellipse = ControlCheckBox('Apply the min. ellipse as a mask to the image') self._usemaskcircular = ControlCheckBox('Apply a circular mask to the image') self._maskcircularsize = ControlSlider('Circular radius', default=0, minimum=0, maximum=100) self._usemaskrect = ControlCheckBox('Apply the min. rect as a mask to the image') ################################################################ #### margin #################################################### self._margin = ControlSlider('Margin size', default=0, minimum=0, maximum=100) ################################################################ #### imagesize ################################################# self._imagesize = ControlSlider('Image size', default=0, minimum=0, maximum=400) ################################################################ #### cut ####################################################### self._usecut = ControlCheckBox('Cut image') self._cutx = ControlBoundingSlider('X cut', default=(10,30), minimum=0, maximum=1000) self._cuty = ControlBoundingSlider('Y cut', default=(10,30), minimum=0, maximum=1000) ################################################################ #### use stretch ############################################### self._usestretch = ControlCheckBox('Stretch image') ################################################################ #### filter per events ######################################### self._eventslst = ControlCheckBoxList('Events', enabled=True) self._reloadevts = ControlButton('Reload events', enabled=True, default=self.__reload_events_btn_evt) ################################################################ #### rotation ################################################## self._userotup = ControlCheckBox('Turn the contour always up') self._userotdown = ControlCheckBox('Turn the contour always down') self._usefixedangle = ControlCheckBox('Use a fixed orientation') self._fixedangle = ControlSlider('Rotate the images using a fixed angle', enabled=True, default=0, minimum=0, maximum=360) self._usedatasetangle = ControlCheckBox('Use the orientation of other contour') self._datasetanglepanel = ControlEmptyWidget('Datasets for the orientation', enabled=True) ################################################################ #### image position ############################################ self._useposdataset = ControlCheckBox('Use a dataset to center the image') self._datasetpospanel = ControlEmptyWidget('Datasets for the image position', enabled=True) ################################################################ self.formset = [ '_toolbox', '_exportdir', '_apply', '_progress' ] self.load_order = [ '_contourspanel','_userotup', '_userotdown', '_exportdir','_usemaskimg','_usemaskdilate','_usemaskellipse','_usemaskellipse', '_usemaskcircular', '_maskcircularsize', '_usemaskrect', '_margin', '_imagesize', '_usestretch', '_eventslst', '_usefixedangle', '_fixedangle', '_usedatasetangle', '_datasetanglepanel', '_useposdataset', '_datasetpospanel', '_usecut', '_cuty', '_cutx' ] #datasets painel self.datasets_dialog = DatasetsDialog(self) self.datasets_dialog.datasets_filter = lambda x: isinstance(x, Contours ) self._contourspanel.value = self.datasets_dialog self.posdatasets_dialog = DatasetsDialog(self) self.posdatasets_dialog.datasets_filter = lambda x: isinstance(x, (Contours,Path) ) self._datasetpospanel.value = self.posdatasets_dialog self.orientdatasets_dialog = DatasetsDialog(self) self.orientdatasets_dialog.datasets_filter = lambda x: isinstance(x, Contours ) self.orientdatasets_dialog.interval_visible = False self._datasetanglepanel.value = self.orientdatasets_dialog self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._imagesize.changed_event = self.__image_size_changed_evt self._toolbox.value = [ ('Extract from contours',( self.datasets_dialog, )), ('Mask',( self._usemaskimg, (self._usemaskdilate,self._maskdilatesize), (self._usemaskcircular,self._maskcircularsize), (self._usemaskellipse,self._usemaskrect), )), ('Margin, image size and stretch image',( self._usestretch, self._margin, self._imagesize, self._usecut, self._cutx, self._cuty )), ('Rotate images',( (self._userotup, self._userotdown), (self._usefixedangle, self._fixedangle), self._usedatasetangle, self._datasetanglepanel )), ('Center images',( self._useposdataset, self._datasetpospanel, )), ('Export images per events',( self._reloadevts, self._eventslst, )), ] self.__reload_events_btn_evt() self.__image_size_changed_evt()
def __init__(self, parent=None): super(VideosExporterGui, self).__init__('Videos exporter', parent_win=parent) self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(400) self._toolbox = ControlToolBox('Tool') self._panel_area = ControlEmptyWidget('Set the object area', default=DatasetsDialog(self)) self._panel_colors = ControlEmptyWidget('Set the object color', default=DatasetsDialog(self)) self._panel_imgs = ControlEmptyWidget('Set the video background', default=ImagesDialog(self)) #### path panel ################################################ self._panel_path = ControlEmptyWidget('Set the object path', default=DatasetsDialog(self)) self._drawpath = ControlCheckBox('Draw paths') ################################################################ #### draw events ############################################### self._drawevents = ControlCheckBoxList('Events') self._eventstitles = ControlCheckBox('Draw titles') self._evtsreload1 = ControlButton('Reload events') ################################################################ #### split by events ########################################### self._splitevents = ControlCheckBoxList('Events') self._evtsreload2 = ControlButton('Reload events') ################################################################ self._codec = ControlCheckBox('Force AVI') self._outdir = ControlDir('Output directory') self._outfile = ControlText('Output file name') self._player = ControlPlayer('Player') self._progress = ControlProgress('Progress') self._apply = ControlButton('Export video(s)', checkable=True) self._apply.icon = conf.ANNOTATOR_ICON_PATH self._apply.enabled = False self._usefixedsize = ControlCheckBox('Use a fixed size') self._usefixedcolor = ControlCheckBox('Use a fixed color') self._radius = ControlSlider('Circle radius', default=10, minimum=1, maximum=300) self._color = ControlText('BGR color', default='255,255,255') self.formset = [('_toolbox', '||', '_player'), '=', '_outdir', ('_outfile', '_codec'), '_apply', '_progress'] self._toolbox.value = [ ('Path', [self._panel_path, self._drawpath]), ('Circle (optional)', [self._panel_area, (self._usefixedsize, self._radius)]), ('Circle color (optional)', [self._panel_colors, (self._usefixedcolor, self._color)]), ('Background (optional)', [self._panel_imgs]), ('Draw events (optional)', [self._evtsreload1, self._drawevents, self._eventstitles]), ('Split files by events (optional)', [self._evtsreload2, self._splitevents]), ] self._panel_path.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) #self._panel_area.value.datasets_filter = lambda x: isinstance(x, Value ) self._panel_colors.value.datasets_filter = lambda x: isinstance( x, (Contours, Path)) and hasattr(x, 'has_colors_avg' ) and x.has_colors_avg ### Set the controls events ############################################# self._evtsreload1.value = self.__reload_events self._evtsreload2.value = self.__reload_events self._outfile.changed_event = self.outputfile_changed_event self._usefixedsize.changed_event = self.__usefixedsize_changed_event self._usefixedcolor.changed_event = self.__usefixedcolor_changed_event self._splitevents.selection_changed_event = self.outputfile_changed_event self._panel_path.value.video_selection_changed_event = self.__video_selection_changed_event self._codec.changed_event = self.__video_selection_changed_event ## function from VideosExporterProcess class self._apply.value = self.apply_event ## function from VideosExporterPreview class self._player.process_frame_event = self.player_processframe_event self._evtsreload1.icon = conf.ANNOTATOR_ICON_REFRESH self._evtsreload2.icon = conf.ANNOTATOR_ICON_REFRESH self._progress.hide() self._radius.hide() self._color.hide() self.__check_areatab_event()
class SmoothPathsWindow(BaseWidget): def __init__(self, parent=None): super(SmoothPathsWindow, self).__init__('Smooth paths', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(400) self.setMinimumWidth(800) self._datasets_panel = ControlEmptyWidget('Paths') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._winsize = ControlSlider('Window size', minimum=3, default=3, maximum=100) self._order = ControlSlider('Order', minimum=0, default=0, maximum=10) self._deriv = ControlSlider('Derivative', minimum=0, default=0, maximum=10) self._rate = ControlSlider('Rate', minimum=0, default=0, maximum=10) self._formset = [ '_datasets_panel', '=', '_winsize', '_order', '_deriv', '_rate', ' ', '_apply', '_progress' ] self.load_order = ['_datasets_panel'] self.datasets_dialog = DatasetsDialog(self) self._datasets_panel.value = self.datasets_dialog self.datasets_dialog.datasets_filter = lambda x: isinstance( x, (Path, Value)) self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide() def init_form(self): super(SmoothPathsWindow, self).init_form() self.datasets_dialog.project = self.mainwindow.project ########################################################################### ### EVENTS ################################################################ ########################################################################### ########################################################################### ### PROPERTIES ############################################################ ########################################################################### @property def datasets(self): return self.datasets_dialog.datasets def __apply_event(self): if self._apply.checked: if self._winsize.value < self._order.value + 2: self.message( 'The Window size has to be bigger than the Order + 2 ', 'Error', 'error') self._apply.checked = False return if self._order.value < self._deriv.value: self.message( 'The Derivative has to be less than or equal to the Order', 'Error', 'error') self._apply.checked = False return if len(self.datasets_dialog.datasets) == 0: self.message('You have to select at least one dataset', 'Error', 'error') self._apply.checked = False return self._datasets_panel.enabled = False self._apply.label = 'Cancel' total_2_analyse = 0 for video, (begin, end), datasets in self.datasets_dialog.selected_data: total_2_analyse += (end - begin + 1) * 2 self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() count = 0 for video, (begin, end), datasets in self.datasets_dialog.selected_data: begin = int(begin) end = int(end) + 1 for dataset in datasets: if isinstance(dataset, Path): values = [ dataset.get_position(index) for index in range(begin, end) ] elif isinstance(dataset, Value): values = [ dataset.get_value(index) for index in range(begin, end) ] #remove the None positions for curr_idx in range(len(values)): if values[curr_idx] is None: #Search for a not None position on the past new_vals = None for prev_idx in range(curr_idx, 0, -1): new_vals = values[prev_idx] if new_vals is not None: break #Search for a not None position on the future if new_vals is None: for nex_idx in range(curr_idx, end): new_vals = values[nex_idx] if new_vals is not None: break #No positions were found, assume 0,0 position if new_vals is None: if isinstance(dataset, Path): new_vals = (0, 0) elif isinstance(dataset, Value): new_vals = 0 values[curr_idx] = new_vals self._progress.value = count count += 1 winsize = self._winsize.value winsize = winsize + 1 if (winsize % 2) == 0 else winsize if isinstance(dataset, Path): xs = np.array([x for x, y in values]) ys = np.array([y for x, y in values]) xs = savitzky_golay(xs, winsize, self._order.value, self._deriv.value, self._rate.value) ys = savitzky_golay(ys, winsize, self._order.value, self._deriv.value, self._rate.value) for index in range(begin, end): pos = dataset.get_position(index) if pos is not None: dataset.set_position(index, xs[index], ys[index]) self._progress.value = count count += 1 elif isinstance(dataset, Value): xs = np.array(values) xs = savitzky_golay(xs, winsize, self._order.value, self._deriv.value, self._rate.value) for index in range(begin, end): val = dataset.get_value(index) if val is not None: dataset.set_value(index, xs[index]) self._progress.value = count count += 1 self._datasets_panel.enabled = True self._apply.label = 'Apply' self._apply.checked = False self._progress.hide()
class ExportWindow(BaseWidget): def __init__(self, parent=None): BaseWidget.__init__(self, 'Export data', parent_win=parent) self.set_margin(5) self.setMinimumHeight(600) self.setMinimumWidth(800) self._tree = ControlTree('Data') self._apply = ControlButton('Apply', checkable=True) self._progress = ControlProgress('Progress') self._add = ControlButton('Add') self._remove = ControlButton('Remove') self._export_list = ControlList('Columns to export') self._outdir = ControlDir('Output directory') self._outfile = ControlText('Output file name') self._toggleevts = ControlCheckBox('Split files by events') self._splitevents = ControlCheckBoxList('Events') self._evtsreload = ControlButton('Reload events') self._formset = [[['_add', '_tree'], '||', ['_remove', '_export_list']], '_toggleevts', '_evtsreload', '_splitevents', '_outdir', '_outfile', '_apply', '_progress'] self._add.value = self.__add_column_event self._remove.value = self.__remove_column_event self._apply.value = self.__apply_btn_event self._evtsreload.value = self.__reload_events self._outdir.changed_event = self.__update_outfile_name_event self._outfile.changed_event = self.__update_outfile_name_event self._toggleevts.changed_event = self.__toggleevents_visibility self._splitevents.changed_event = self.__update_outfile_name_event self._splitevents.selection_changed_event = self.__update_outfile_name_event self._tree.show_header = False self._apply.icon = conf.ANNOTATOR_ICON_MOTION self._evtsreload.icon = conf.ANNOTATOR_ICON_REFRESH self._add.icon = conf.ANNOTATOR_ICON_ADD self._remove.icon = conf.ANNOTATOR_ICON_REMOVE self._progress.hide() self._splitevents.hide() self._evtsreload.hide() self._apply.enabled = False self._properties = [] ########################################################################### ### EVENTS ################################################################ ########################################################################### def __toggleevents_visibility(self): if self._toggleevts.value: self._splitevents.show() self._evtsreload.show() else: self._splitevents.hide() self._evtsreload.hide() def __field_full_name(self, tree_item): name = tree_item.text(0) while True: tree_item = tree_item.parent() if tree_item is None: break name = "{0} > {1}".format(tree_item.text(0), name) return name def __add_column_event(self): self.__update_outfile_name_event() item = self._tree.selected_item if item is None: return if hasattr(item, 'data_function'): self._export_list += [self.__field_full_name(item)] self._properties.append((len(item.win), item.data_function)) elif isinstance(item.win, Value): self._export_list += [self.__field_full_name(item)] self._properties.append((len(item.win), item.win.get_value)) def __remove_column_event(self): self.__update_outfile_name_event() if self._export_list.selected_row_index is None: return elif self._export_list.selected_row_index >= 0: self._properties.pop(self._export_list.selected_row_index) self._export_list -= -1 def __update_outfile_name_event(self): """ Update the output filename """ filename = self._outfile.value if len(filename.strip()) == 0: return outfilepath, outfile_extension = os.path.splitext(filename) names = [outfilepath] if len(outfilepath) > 0 else [] if len(list(self._splitevents.value)) > 0: if '{event}' not in outfilepath: names.append('{event}') if '{start}' not in outfilepath: names.append('{start}') if '{end}' not in outfilepath: names.append('{end}') self._outfile.value = ('-'.join(names) + '.csv') self._apply.enabled = True def __apply_btn_event(self): if self._apply.checked: if len(self._properties) == 0: QMessageBox.about( self, "Error", "You need to select at least one value to export.") self._apply.checked = False return if self._outfile.value is None or len( self._outfile.value.strip()) == 0: QMessageBox.about( self, "Error", "You need to select the name of the output file.") self._apply.checked = False return if self._outdir.value is None or len(self._outdir.value) == 0: QMessageBox.about( self, "Error", "You need to select the name of the output directory.") self._apply.checked = False return self.__update_outfile_name_event() self._export_list.enabled = False self._tree.enabled = False self._add.enabled = False self._remove.enabled = False self._outdir.enabled = False self._outfile.enabled = False self._apply.label = 'Cancel' ### calculate the video cuts ############################# timeline = self.parent().timeline selected_events = self._splitevents.value videocuts = [] if len(selected_events): # use the events to cut the video totalframes = 0 for row in timeline.rows: for event in row.events: if event.title not in selected_events: continue b = event.begin e = event.end totalframes += e - b videocuts.append((int(b), int(e), event.title)) videocuts = sorted(videocuts, key=lambda x: x[0]) else: # no events were selected end = max([size for size, func in self._properties]) totalframes = end videocuts = [(0, int(end), None)] ########################################################## self._progress.min = 0 self._progress.max = totalframes self._progress.show() for b, e, eventname in videocuts: filename = self._outfile.value filename = filename.format(event=eventname, start=b, end=e) filename = os.path.join(self._outdir.value, filename) with open(filename, 'w') as out: ## write the csv columns headers out.write('frame;') for values in self._export_list.value: out.write(('{0};'.format(values[0]))) out.write('\n') ## write the values for index in range(b, e): out.write('{0};'.format(index)) for _, func in self._properties: out.write('{0};'.format(func(index))) out.write('\n') self._progress += 1 self._export_list.enabled = True self._tree.enabled = True self._add.enabled = True self._remove.enabled = True self._outdir.enabled = True self._outfile.enabled = True self._apply.label = 'Apply' self._apply.checked = False self._progress.hide() def __copy_tree_node(self, item, new_item): new_item.win = item.win if hasattr(item, 'data_function'): new_item.data_function = item.data_function def __reload_events(self): """ Find all the events available on the timeline """ timeline = self.parent().timeline rows = timeline.rows events = {} for row in rows: for event in row.events: events[event.title] = True events = sorted(events.keys()) loaded_events = dict(self._splitevents.items) self._splitevents.value = [(e, loaded_events.get(e, False)) for e in events] @property def project(self): return self._project @project.setter def project(self, value): self._project = value self._tree.clear() self._tree.clone_tree(value.tree, copy_function=self.__copy_tree_node) self.__reload_events()
def __init__(self): super(MultipleBlobDetection, self).__init__('Multiple Blob Detection') # Definition of the forms fields self._videofile = ControlFile('Video') self._outputfile = ControlText('Results output file') self._threshold_box = ControlCheckBox('Threshold') self._threshold = ControlSlider('Binary Threshold') self._threshold.value = 114 self._threshold.min = 1 self._threshold.max = 255 self._roi_x_min = ControlSlider('ROI x top') self._roi_x_max = ControlSlider('ROI x bottom') self._roi_y_min = ControlSlider('ROI y left') self._roi_y_max = ControlSlider('ROI y right') # self._blobsize = ControlSlider('Minimum blob size', 100, 100, 2000) self._player = ControlPlayer('Player') self._runbutton = ControlButton('Run') self._start_frame = ControlText('Start Frame') self._stop_frame = ControlText('Stop Frame') self._color_list = ControlCombo('Color channels') self._color_list.add_item('Red Image Channel', 2) self._color_list.add_item('Green Image Channel', 1) self._color_list.add_item('Blue Image Channel', 0) self._clahe = ControlCheckBox('CLAHE ') self._dilate = ControlCheckBox('Morphological Dilation') self._dilate_type = ControlCombo('Dilation Kernel Type') self._dilate_type.add_item('RECTANGLE', cv2.MORPH_RECT) self._dilate_type.add_item('ELLIPSE', cv2.MORPH_ELLIPSE) self._dilate_type.add_item('CROSS', cv2.MORPH_CROSS) self._dilate_size = ControlSlider('Dilation Kernel Size', default=3, min=1, max=10) self._dilate_size.value = 5 self._dilate_size.min = 1 self._dilate_size.max = 10 self._erode = ControlCheckBox('Morphological Erosion') self._erode_type = ControlCombo('Erode Kernel Type') self._erode_type.add_item('RECTANGLE', cv2.MORPH_RECT) self._erode_type.add_item('ELLIPSE', cv2.MORPH_ELLIPSE) self._erode_type.add_item('CROSS', cv2.MORPH_CROSS) self._erode_size = ControlSlider('Erode Kernel Size') self._erode_size.value = 5 self._erode_size.min = 1 self._erode_size.max = 10 self._open = ControlCheckBox('Morphological Opening') self._open_type = ControlCombo('Open Kernel Type') self._open_type.add_item('RECTANGLE', cv2.MORPH_RECT) self._open_type.add_item('ELLIPSE', cv2.MORPH_ELLIPSE) self._open_type.add_item('CROSS', cv2.MORPH_CROSS) self._open_size = ControlSlider('Open Kernel Size') self._open_size.value = 20 self._open_size.min = 1 self._open_size.max = 40 self._close = ControlCheckBox('Morphological Closing') self._close_type = ControlCombo('Close Kernel Type') self._close_type.add_item('RECTANGLE', cv2.MORPH_RECT) self._close_type.add_item('ELLIPSE', cv2.MORPH_ELLIPSE) self._close_type.add_item('CROSS', cv2.MORPH_CROSS) self._close_size = ControlSlider('Close Kernel Size', default=19, min=1, max=40) self._close_size.value = 20 self._close_size.min = 1 self._close_size.max = 40 self._LoG = ControlCheckBox('LoG - Laplacian of Gaussian') self._LoG_size = ControlSlider('LoG Kernel Size') self._LoG_size.value = 20 self._LoG_size.min = 1 self._LoG_size.max = 60 self._progress_bar = ControlProgress('Progress Bar') # Define the function that will be called when a file is selected self._videofile.changed_event = self.__video_file_selection_event # Define the event that will be called when the run button is processed self._runbutton.value = self.__run_event # Define the event called before showing the image in the player self._player.process_frame_event = self.__process_frame self._error_massages = {} # Define the organization of the Form Controls self.formset = [ ('_videofile', '_outputfile'), ('_start_frame', '_stop_frame'), ('_color_list', '_clahe', '_roi_x_min', '_roi_y_min'), ('_threshold_box', '_threshold', '_roi_x_max', '_roi_y_max'), ('_dilate', '_erode', '_open', '_close'), ('_dilate_type', '_erode_type', '_open_type', '_close_type'), ('_dilate_size', '_erode_size', '_open_size', '_close_size'), ('_LoG', '_LoG_size'), ('_runbutton', '_progress_bar'), '_player' ] self.is_roi_set = False
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
class FindOrientationWindow(BaseWidget): def __init__(self, parent=None): super(FindOrientationWindow, self).__init__('Estimate countour orientation', parent_win=parent) self.mainwindow = parent self.set_margin(5) self.setMinimumHeight(300) self.setMinimumWidth(300) self._panel = ControlEmptyWidget('Videos') self._progress = ControlProgress('Progress') self._apply = ControlButton('Apply', checkable=True) self._debug = ControlCheckBox('Create all the intermediate values') self._min_steps = ControlSlider('Minimum steps', default=20, minimum=1, maximum=1000) self._min_dist = ControlSlider('Minimum distance', default=30, minimum=1, maximum=1000) self._panel.value = self.contours_dialog = DatasetsDialog(self) self.contours_dialog.datasets_filter = lambda x: isinstance( x, Contours) self._formset = [ '_panel', ('_min_steps', '_min_dist'), '_debug', '_apply', '_progress' ] self._apply.value = self.__apply_event self._apply.icon = conf.ANNOTATOR_ICON_PATH self._progress.hide() def init_form(self): super(FindOrientationWindow, self).init_form() ########################################################################### ### EVENTS ################################################################ ########################################################################### ########################################################################### ### PROPERTIES ############################################################ ########################################################################### def __apply_event(self): IMAGE_SIZE = 150 if self._apply.checked and self._apply.label == 'Apply': self._panel.enabled = False self._apply.label = 'Cancel' self._min_dist.enabled = False self._min_steps.enabled = False total_2_analyse = 0 for video, (begin, end), datasets in self.contours_dialog.selected_data: capture = video.video_capture total_2_analyse += (end - begin) #*len(datasets)*1 self._progress.min = 0 self._progress.max = total_2_analyse self._progress.show() debug_mode = self._debug.value count = 0 for video, (begin, end), datasets in self.contours_dialog.selected_data: if len(datasets) == 0: continue begin, end = int(begin), int(end) back_frames = [] front_frames = [] for dataset in datasets: for i in range(begin, end): self._progress.value = count count += 1 ok, img = dataset.get_image(i, mask=True, angle='up', size=(IMAGE_SIZE, IMAGE_SIZE)) if ok: cv2.normalize(img, img, 0, 255, cv2.NORM_MINMAX) v1 = img[:int(img.shape[0] / 2)].sum() / np.count_nonzero( img[:int(img.shape[0] / 2)]) v2 = img[int(img.shape[0] / 2):].sum() / np.count_nonzero( img[int(img.shape[0] / 2):]) if v1 < v2: dataset.flip(i) """ window = 30 min_walked = 50 savitzky_golay_window_size = (window+1 if (window % 2 )==0 else window) if debug_mode: # create the values for debug ########################################## v1 = dataset.object2d.create_value() v1.name = 'Est. orient. - step1 - smoothed walked distance (prev {0} frames)'.format(window) v2 = dataset.object2d.create_value() v2.name = 'Est. orient. - step1 - smoothed walked distance with direction (prev {0} frames)'.format(window) vflipped = dataset.object2d.create_value() vflipped.name = 'Est. orient. - step1 - flipped images' ######################################################################## _, walked_distance = dataset.calc_walked_distance(window) _, dir_walked_distance = dataset.calc_walked_distance_with_direction(window) walked_distance = savitzky_golay(np.array(walked_distance), window_size=savitzky_golay_window_size) dir_walked_distance = savitzky_golay(np.array(dir_walked_distance), window_size=savitzky_golay_window_size) for i in range(begin, end): self._progress.value = count; count+=1 if i>=len(walked_distance): continue vflipped.set_value(i, 0) ### Debug ############################################################## if debug_mode: v1.set_value(i, walked_distance[i]) v2.set_value(i, dir_walked_distance[i]) ######################################################################## if walked_distance[i]>min_walked and dir_walked_distance[i]<-min_walked: dataset.flip(i) if debug_mode: vflipped.set_value(i, 1) if debug_mode: # create the values for debug ########################################## v1 = dataset.object2d.create_value() v1.name = 'Est. orient. - step2 - smoothed walked distance (prev {0} frames)'.format(window) v2 = dataset.object2d.create_value() v2.name = 'Est. orient. - step2 - smoothed walked distance with direction (prev {0} frames)'.format(window) vtrainning = dataset.object2d.create_value() vtrainning.name = 'Est. orient. - step2 - good images for trainning' ######################################################################## _, walked_distance = dataset.calc_walked_distance(window) _, dir_walked_distance = dataset.calc_walked_distance_with_direction(window) trainning_frames = [] IMAGE_SIZE = 150 MAX_TRAINNING_SET = 400 model = cv2.ml.ANN_MLP_create() layer_sizes = np.int32([IMAGE_SIZE**2, IMAGE_SIZE, IMAGE_SIZE, 2]) model.setLayerSizes(layer_sizes) model.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP) model.setBackpropMomentumScale(0.0) model.setBackpropWeightScale(0.001) model.setTermCriteria((cv2.TERM_CRITERIA_COUNT, 20, 0.01)) model.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 2, 1) train = [] answers = [] for i in range(begin, end): self._progress.value = count; count+=1 if i>=len(walked_distance): continue trainning_frames.append(False) if debug_mode: vtrainning.set_value(i, 0) ### Debug ############################################################## if debug_mode: #v1.set_value(i, walked_distance[i]) #v2.set_value(i, dir_walked_distance[i]) pass ######################################################################## triangle_angle = dataset.get_minimumenclosingtriangle_angle(i) if triangle_angle is None: continue dataset_angle = dataset.get_angle(i) if dataset_angle is None: continue if walked_distance[i]>min_walked and dir_walked_distance[i]>min_walked and \ min_dist_angles(dataset_angle, triangle_angle)<(np.pi/2): trainning_frames[i] = True if MAX_TRAINNING_SET is None or len(train)<MAX_TRAINNING_SET: ok1, img_up = dataset.get_image(i, mask=True, angle='up', size=(IMAGE_SIZE,IMAGE_SIZE) ) ok2, img_down = dataset.get_image(i, mask=True, angle='down', size=(IMAGE_SIZE,IMAGE_SIZE) ) print(ok1) if ok1 and ok2: cv2.normalize(img_up, img_up, 0, 255, cv2.NORM_MINMAX) cv2.normalize(img_down, img_down, 0, 255, cv2.NORM_MINMAX) train.append(img_up[:,:,0].flatten()) train.append(img_down[:,:,0].flatten()) answers.append([1,0]) answers.append([0,1]) v1.set_value(i, img_up[:int(img_up.shape[0]/2)].sum() / np.count_nonzero(img_up[:int(img_up.shape[0]/2)]) ) v2.set_value(i, img_up[int(img_up.shape[0]/2):].sum() / np.count_nonzero(img_up[int(img_up.shape[0]/2):]) ) cv2.imwrite('/home/manuel/Desktop/test/{0}.png'.format(i), img_up) if debug_mode: vtrainning.set_value(i, 1) print("1") train = np.float32(train) answers = np.float32(answers) model.train(train, cv2.ml.ROW_SAMPLE, answers) if debug_mode: # create the values for debug ########################################## v1 = dataset.object2d.create_value() v1.name = 'Est. orient. - step3 - prediction front' v2 = dataset.object2d.create_value() v2.name = 'Est. orient. - step3 - prediction back' v3 = dataset.object2d.create_value() v3.name = 'Est. orient. - step3 - binary prediction' print("2") for i in range(begin, end): self._progress.value = count; count+=1 if i>=len(trainning_frames): continue if debug_mode: v1.set_value(i,0) if not trainning_frames[i]: ok, img = dataset.get_image(i, mask=True, angle='up', size=(IMAGE_SIZE,IMAGE_SIZE) ) if ok: cv2.normalize(img, img) _ret, resp = model.predict(np.float32([img[:,:,0].flatten()])) if resp.argmax()==1: dataset.flip(i) if debug_mode: v1.set_value(i,resp[0][0]) v2.set_value(i,resp[0][1]) v3.set_value(i,resp.argmax()) """ self._min_dist.enabled = True self._min_steps.enabled = True self._panel.enabled = True self._apply.label = 'Apply' self._apply.checked = False self._progress.hide()