class LightSourceTab(BaseWidget): """ Tab to select the lightsource device """ _lightsource = None _update_function = None def __init__(self, update_function=None): super().__init__("Light Source Tab") self._update_function = update_function self._device_select = ControlCombo(label="Light Source") self._custom = ControlEmptyWidget() self._device_select.changed_event = self._on_device_change self._device_select.add_item('None', None) for class_type in LightSource.__subclasses__(): self._device_select.add_item(class_type.__name__, class_type) def _on_device_change(self): device = self._device_select.value if callable(device): self._lightsource = device() self._custom.value = self._lightsource.get_custom_config() else: self._lightsource = None self._custom.value = None if callable(self._update_function): self._update_function({'lightsource': self._lightsource})
class NewAxisWindow(BaseWidget): """ Create a new Axis """ def __init__(self, done_function): super().__init__("New Axis") self._done_function = done_function self._axis_name = ControlText(label="Name") self._axis_hw_type = ControlCombo(label="HW Type", default=None) for class_type in ControlAxis.__subclasses__(): self._axis_hw_type.add_item(class_type.__name__, class_type) self._done_button = ControlButton(label="Done") self._done_button.value = self._done def _done(self): hw_type = self._axis_hw_type.value if issubclass(hw_type, ControlAxis): name = self._axis_name.value axis = hw_type(name) self._done_function(axis) self.close()
class DOE2py_Utility(BaseWidget): def __init__(self): super(DOE2py_Utility,self).__init__('DOE2py Utility') self._Input = ControlFile('Input file') self._Weather = ControlFile('Weather file') self._Library = ControlFile('User Library') self._Version = ControlCombo('DOE-2 Version') #self._Status_1 = ControlLabel('Simulation Status:') #self._Status_2 = ControlLabel('-') self._Run = ControlButton('Run Simulation') self._Close = ControlButton('Close') self._formset = ['',(' ','_Input',' '), ('', '_Weather', '' ), ('', '_Library', '' ), ('','_Version', '' ), ('', '_Run', '' ), ('','_Close',''),''] #('','_Status_1','','_Status_2', '' ) self._Run.value = self.__RunAction self._Close.value = self.__CloseAction with open('settings-gui.json') as data_file: data = json.load(data_file) self._Input.value = data["lastinput"] self._Weather.value = data["lastweather"] self._Library.value = data["lastlibrary"] for i in range(0,len(data["doe2versions"])): self._Version.add_item(data["doe2versions"][i]) def __RunAction(self): path = os.path.dirname(os.path.realpath(__file__)) if self._Library.value <> "": ImportLib(self._Version.value, self._Library.value, path) RunDOE2(self._Input.value[:-4], self._Weather.value, self._Version.value, path) #self._Status_2.value = "Completed!" def __CloseAction(self): with open('settings-gui.json') as data_file: data = json.load(data_file) data["lastinput"] = self._Input.value data["lastweather"] = self._Weather.value data["lastlibrary"] = self._Library.value with open('settings-gui.json','w') as data_file: json.dump(data,data_file) sys.exit()
class SimpleExample1(BaseWidget): def __init__(self): super(SimpleExample1, self).__init__('my_variant_api') #init clinvar self._clinvariants = ControlTextArea('rsvariants', 'rs12315123') self._clinbutton = ControlButton('Press this button') self._clinresult = ControlTextArea('result') self._clinbutton.value = self.__clinbuttonAction #init flanking site self._flancchrom = ControlText('chrom') self._flancpos = ControlText('pos') self._flancthree = ControlText('expand_3prime', 300) self._flancfive = ControlText('expand_5prime', 300) self._flancassembly = ControlCombo('assembly') self._flancassembly.add_item('GRCh37') self._flancassembly.add_item('GRCh38') self._flancbutton = ControlButton('Press this button') self._flancresult = ControlTextArea('result') self._flancbutton.value = self.__flancbuttonAction self.formset = [{ "Clinvar": ('_clinvariants', '_clinbutton', '_clinresult'), "Flanking Site": [('_flancchrom', '_flancpos', '_flancthree', '_flancfive', '_flancassembly'), '_flancbutton', '_flancresult'] }] def __clinbuttonAction(self): results = [] for rsid in self._clinvariants.value.split('\n'): clinsig = getClinicalSignificance(rsid) results.append(clinsig) self._clinresult.value = '\n'.join(results) def __flancbuttonAction(self): chrom = self._flancchrom.value pos = self._flancpos.value five = self._flancfive.value three = self._flancthree.value assembly = self._flancassembly.value uri = 'http://grch37.rest.ensembl.org/sequence/region/human/' + chrom + ':' + pos + '..' + pos + ':1?expand_3prime=' + three + '&expand_5prime=' + five + '&content-type=text/plain' site = getEnsemblResult(uri) fiveString = site[:int(five)] threeString = site[-int(three):] current = site[int(five):int(five) + 1] self._flancresult.value = fiveString + '\n' + current + '\n' + threeString
class OTModuleSelectComponent(OTModulePlugin, TypeBWVideoPipe): def __init__(self, name): icon_path = tools.getFileInSameDirectory(__file__, 'iconsubbg.jpg') TypeBWVideoPipe.__init__(self) OTModulePlugin.__init__(self, name, iconFile=icon_path) self._video = ModuleConnection("Video", connecting=TypeComponentsVideoPipe) self._player = ControlPlayer("Video player") self._colorComponent = ControlCombo("Component") self._colorComponent.add_item("A", 0) self._colorComponent.add_item("B", 1) self._colorComponent.add_item("C", 2) self._colorComponent.changed_event = self.refreshValue self._video.changed_event = self.newVideoInputChoosen self._formset = [ '_video', '_colorComponent', "_player", ] def refreshValue(self, value): self._player.refresh() def newVideoInputChoosen(self): ModuleConnection.changed_event(self._video) value = self._video.value if value: self.open(value) self._player.value = self print value def read(self): res, imgs = self._video.value.read() return res, imgs[self._colorComponent.value]
class OTModuleConvertColors(OTModulePlugin, TypeColorVideoPipe): def __init__(self, name): icon_path = tools.getFileInSameDirectory(__file__, 'iconsubbg.jpg') TypeColorVideoPipe.__init__(self) OTModulePlugin.__init__(self, name, iconFile=icon_path) self._video = ModuleConnection("Video", connecting=TypeColorVideo) self._player = ControlPlayer("Video player") self._colorDomain = ControlCombo("Color domain") self._colorDomain.add_item("XYZ", cv2.COLOR_BGR2XYZ) self._colorDomain.add_item("YCrCb", cv2.COLOR_BGR2YCR_CB) self._colorDomain.add_item("HSV", cv2.COLOR_BGR2HSV) self._colorDomain.add_item("HLS", cv2.COLOR_BGR2HLS) self._colorDomain.add_item("Lab", cv2.COLOR_BGR2LAB) self._colorDomain.add_item("Luv", cv2.COLOR_BGR2LUV) self._colorDomain.changed_event = self._player.refresh self._video.changed_event = self.newVideoInputChoosen self._player.process_frame_event = self.processFrame self._formset = [ '_video', '_colorDomain', "_player", ] def newVideoInputChoosen(self): ModuleConnection.changed_event(self._video) value = self._video.value if value: self.open(value) self._player.value = value def processFrame(self, frame): return cv2.cvtColor(frame, self._colorDomain.value)
class GenericCsvParserDialog(BaseWidget): def __init__(self, columns, parent=None): super(GenericCsvParserDialog, self).__init__('CSV Choose the columns', parent_win=parent) self._filename = None self._columns = columns self._columns_indexes = [] self._rownum = 0 # Definition of the forms fields self._filename = ControlFile('CSV File') self._separator = ControlCombo('Separator', default='auto') self._startingrow = ControlNumber('Starting row', default=0) for index, column in enumerate(columns): setattr( self, '_col_{0}'.format(index), ControlNumber(column, default=index, minimum=-1, maximum=1000)) self._filePreview = ControlList('Preview') self._loadButton = ControlButton('Load') form_row = ['_separator'] + [ '_col_{0}'.format(index) for index, column in enumerate(columns) ] + ['_loadButton'] self._formset = [('_filename', '_startingrow'), tuple(form_row), '_filePreview'] self._separator.changed_event = self.__refreshPreview self._filename.changed_event = self.__refreshPreview self._startingrow.changed_event = self.__refreshPreview self._loadButton.value = self.load self._load_event = None self._separator.add_item('auto', 'auto') self._separator.add_item(';', ';') self._separator.add_item(',', ',') self._separator.add_item('TAB', '\t') self._separator.add_item('Excel', csv.excel) self._separator.add_item('Excel TAB', csv.excel_tab) @property def load_file_event(self): return self._load_event @load_file_event.setter def load_file_event(self, value): self._load_event = value def __iter__(self): if self._filename.value != None and self._filename.value != '': csvfile = open(self._filename.value, 'U') if self.delimiter in ['auto', csv.excel, csv.excel_tab]: try: dialect = csv.Sniffer().sniff(csvfile.read(1024)) csvfile.seek(0) self._spamreader = csv.reader(csvfile, dialect) except: self._spamreader = None return self else: self._spamreader = csv.reader(csvfile, delimiter=self.delimiter) for i in range(int(self._startingrow.value)): next(self._spamreader, None) # skip the headers else: self._spamreader = None return self # For compatibility with python 3 def __next__(self): return self.next() def next(self): if self._spamreader != None: row = next(self._spamreader) res = [] for col in self._columns_indexes: if col == -1: res.append(self._rownum) else: if row[col].lower() == 'nan': res.append('None') else: res.append(row[col]) self._rownum += 1 return res else: raise StopIteration() def __refreshPreview(self): if self._filename.value != None and self._filename.value != '': with open(self._filename.value, 'U') as csvfile: if self.delimiter in ['auto', csv.excel, csv.excel_tab]: try: dialect = csv.Sniffer().sniff(csvfile.read(1024)) csvfile.seek(0) spamreader = csv.reader(csvfile, dialect) except: self.message('Error when reading the file.') return else: spamreader = csv.reader(csvfile, delimiter=self.delimiter) for i in range(int(self._startingrow.value)): next(spamreader, None) # skip the headers self._filePreview.value = [] self._filePreview.horizontalHeaders = map(str, range(1000)) for i, row in enumerate(spamreader): self._filePreview += row if i >= 10: break @property def delimiter(self): return self._separator.value def load(self): self.__refreshPreview() self._columns_indexes = [] for index, column in enumerate(self._columns): self._columns_indexes.append( int(getattr(self, '_col_{0}'.format(index)).value)) if self._load_event is not None: self._load_event()
class ImportWindow(BaseWidget): def __init__(self, timeline=None): super(ImportWindow, self).__init__('Import file', parent_win=timeline) self.setContentsMargins(10, 10, 10, 10) self._timeline = timeline # Definition of the forms fields self._filetype = ControlCombo('Please select the type of file you would like to import:') self._importButton = ControlButton('Import') self._panel = ControlEmptyWidget('Panel') self._file = ControlFile('File to import') self._panel.value = self._file self._filetype.add_item('Events file', 0) self._filetype.add_item('Graph file', 1) self._filetype.add_item('Bonsai events file', 2) self._formset = [ ('_filetype', ' '), '_panel', (' ', '_importButton'), ' '] self._filetype.changed_event = self.__fileTypeChanged self._importButton.value = self.__importData from pyforms.gui.dialogs.csv_parser import CsvParserDialog self._graphCsvParserDlg = CsvParserDialog() self._graphCsvParserDlg.xField.label = "Value column" self._graphCsvParserDlg.yField.hide() self._graphCsvParserDlg.zField.hide() self._graphCsvParserDlg.loadButton.hide() self._bonsaiImportDlg = BonsaiImportFileDlg() def __fileTypeChanged(self): if self._filetype.value == 0: self._panel.value = self._file elif self._filetype.value == 1: self._panel.value = self._graphCsvParserDlg elif self._filetype.value == 2: self._panel.value = self._bonsaiImportDlg def __importData(self): if self._filetype.value == 0: separator = ',' with open(self._file.value, 'rU') as csvfile: line = csvfile.readline() if ";" in line: separator = ';' with open(self._file.value, 'rU') as csvfile: csvfile = csv.reader(csvfile, delimiter=separator) self._timeline._time.import_csv(csvfile) elif self._filetype.value == 1: self._timeline._time.importchart_csv(self._graphCsvParserDlg) self._timeline.show_graphs_properties() elif self._filetype.value == 2: with open(self._bonsaiImportDlg._file.value, 'rU') as csvfile: values = [] pointEventValues = [] csvfile = csv.reader(csvfile, delimiter=' ') for row in csvfile: # strip Start/End word from all events names which are not PointEven try: timestr = row[1].rstrip('0') cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S.%f") except: timestr = row[1] cvttime = datetime.datetime.strptime(timestr, "%H:%M:%S") seconds = (cvttime - datetime.datetime(1900, 1, 1)).total_seconds() frame = int(round(self._bonsaiImportDlg._fps.value * seconds)) if row[2] == "PointEvent": eventtype = row[0] pointEventValues.append([eventtype, frame, row[2]]) else: if row[0].startswith('Start'): eventtype = row[0][len('Start'):] # strip Start word from the beginning else: eventtype = row[0][len('End'):] # strip End word from the beginning values.append([eventtype, frame, row[2]]) values = sorted(values, key=lambda x: (x[0].capitalize(), x[1])) pointEventValues = sorted(pointEventValues, key=lambda x: (x[0].capitalize(), x[1])) ntracks = len(set([x[0] for x in values])) + 1 # collapse events = [] eventsTypes = {} # Events names currentTrack = 0 for index in range(0, len(pointEventValues)): pointEventValue = pointEventValues[index] eventsTypes[pointEventValue[0]] = currentTrack self._timeline.addPeriod([pointEventValue[1], pointEventValue[1] + 50, pointEventValue[0]], track=currentTrack) currentTrack = 1 for index in range(0, len(values), 2): row0 = values[index] row1 = values[index + 1] if row0[0] not in eventsTypes: eventsTypes[row0[0]] = currentTrack track = currentTrack currentTrack += 1 else: track = eventsTypes[row0[0]] self._timeline.addPeriod([row0[1], row1[1], row0[0]], track=track) self._timeline.repaint() self._timeline._time.repaint() self.close() # pylint: disable=no-member def import_chart(self, filename, frame_col=0, val_col=1): self._filetype.value = 1 self._graphCsvParserDlg.filename = filename self._graphCsvParserDlg.frameColumn = frame_col self._graphCsvParserDlg.xColumn = val_col
class SensorTab(BaseWidget): """ Tab for sensors Shows a drop down with all subclasses of Sensor imported anywhere into this program When one is selected, it creates an instance of that sensor and shows the custom config GUI for that Sensor. """ _sensor = None _timer = QTimer() def __init__(self, update_function=None): super().__init__("Output Tab") # The update function will be called when the selected sensor changes # to fire the 'sensor' event self._update_function = update_function self._device_select = ControlCombo(label="Sensor") self._custom = ControlEmptyWidget() self._device_select.changed_event = self._on_device_change self._device_select.add_item('None', None) self._output = ControlList() self._live = ControlCheckBox(label="Live Output") self._live.changed_event = self._on_live for class_type in Sensor.__subclasses__(): self._device_select.add_item(class_type.__name__, class_type) def update_events(self, events): """ Updates the events """ if isinstance(self._sensor, Sensor): self._sensor.update_events(events) def _on_device_change(self): device = self._device_select.value if callable(device): self._sensor = device() self._custom.value = self._sensor.get_custom_config() else: self._sensor = None self._custom.value = None #print("Not Subclass") if callable(self._update_function): self._update_function({'sensor': self._sensor}) def _on_live(self): if self._live.value: if isinstance(self._sensor, Sensor): self._sensor.begin_live_data() self._output.horizontal_headers = self._sensor.get_live_headers( ) self._timer.timeout.connect(self._update_sensor) self._timer.start(100) else: self._timer.stop() if isinstance(self._sensor, Sensor): self._sensor.stop_live_data() def _update_sensor(self): if isinstance(self._sensor, Sensor): self._output += self._sensor.get_live_data() self._output.tableWidget.scrollToBottom()
class MultipleBlobDetection(BaseWidget): 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', 114, 0, 255) self._roi_x_min = ControlSlider('ROI x top', 0, 0, 1000) self._roi_x_max = ControlSlider('ROI x bottom', 1000, 0, 1000) self._roi_y_min = ControlSlider('ROI y left', 0, 0, 1000) self._roi_y_max = ControlSlider('ROI y right', 1000, 0, 1000) # 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', 3, 1, 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', 5, 1, 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', 19, 1, 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', 19, 1, 40) self._LoG = ControlCheckBox('LoG - Laplacian of Gaussian') self._LoG_size = ControlSlider('LoG Kernel Size', 30, 1, 60) self._progress_bar = ControlProgress('Progress Bar') # 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 # Define the event called before showing the image in the player self._player.process_frame_event = self.__processFrame # 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' ] def __videoFileSelectionEvent(self): """ When the videofile is selected instanciate the video in the player """ self._player.value = self._videofile.value def __color_channel(self, frame): """ Returns only one color channel of input frame. Output is in grayscale. """ frame = frame[:, :, self._color_list.value] return frame def __create_kernels(self): """ Creates kernels for morphological operations. Check cv2.getStructuringElement() doc for more info: http://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/ py_morphological_ops/py_morphological_ops.html Assumed that all kernels (except LoG kernel) are square. Example of use: open_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (19, 19)) erosion_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) dilate_kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) :return: _opening_kernel, _close_kernel, _erosion_kernel, \ _dilate_kernel, _LoG_kernel """ _opening_kernel = cv2.getStructuringElement(self._open_type.value, (self._open_size.value, self._open_size.value)) _close_kernel = cv2.getStructuringElement(self._close_type.value, (self._close_size.value, self._close_size.value)) _erosion_kernel = cv2.getStructuringElement(self._erode_type.value, (self._erode_size.value, self._erode_size.value)) _dilate_kernel = cv2.getStructuringElement(self._dilate_type.value, (self._dilate_size.value, self._dilate_size.value)) _LoG_kernel = get_log_kernel(self._LoG_size.value, int(self._LoG_size.value * 0.5)) return _opening_kernel, _close_kernel, _erosion_kernel, \ _dilate_kernel, _LoG_kernel def __morphological(self, frame): """ Apply morphological operations selected by the user. :param frame: input frame of selected video. :return: preprocessed frame. """ opening_kernel, close_kernel, erosion_kernel, \ dilate_kernel, log_kernel = self.__create_kernels() # prepare image - morphological operations if self._erode.value: frame = cv2.erode(frame, erosion_kernel, iterations=1) if self._open.value: frame = cv2.morphologyEx(frame, cv2.MORPH_OPEN, opening_kernel) if self._close.value: frame = cv2.morphologyEx(frame, cv2.MORPH_CLOSE, close_kernel) if self._dilate.value: frame = cv2.dilate(frame, dilate_kernel, iterations=1) # create LoG kernel for finding local maximas if self._LoG.value: frame = cv2.filter2D(frame, cv2.CV_32F, log_kernel) frame *= 255 # remove near 0 floats frame[frame < 0] = 0 return frame def __roi(self, frame): """ Define image region of interest. """ # ROI height, width = frame.shape self._roi_x_max.min = int(height / 2) self._roi_x_max.max = height self._roi_y_max.min = int(width / 2) self._roi_y_max.max = width self._roi_x_min.min = 0 self._roi_x_min.max = int(height / 2) self._roi_y_min.min = 0 self._roi_y_min.max = int(width / 2) # x axis frame[:int(self._roi_x_min.value)][::] = 255 frame[int(self._roi_x_max.value)::][::] = 255 # y axis for m in range(height): # height for n in range(width): # width if n > self._roi_y_max.value or n < self._roi_y_min.value: frame[m][n] = 255 # frame[0::][:int(self._roi_y_min.value)] = 255 # frame[0::][int(self._roi_y_max.value):] = 255 return frame def _kalman(self, max_points, stop_frame, vid_fragment): """ Kalman Filter function. Takes measurements from video analyse function and estimates positions of detected objects. Munkres algorithm is used for assignments between estimates (states) and measurements. :param max_points: measurements. :param stop_frame: number of frames to analise :param vid_fragment: video fragment for estimates displaying :return: x_est, y_est - estimates of x and y positions in the following format: x_est[index_of_object][frame] gives x position of object with index = [index_of_object] in the frame = [frame]. The same goes with y positions. """ # font for displaying info on the image font = cv2.FONT_HERSHEY_SIMPLEX index_error = 0 value_error = 0 # step of filter dt = 1. R_var = 1 # measurements variance between x-x and y-y # Q_var = 0.1 # model variance # state covariance matrix - no initial covariances, variances only # [10^2 px, 10^2 px, ..] - P = np.diag([100, 100, 10, 10, 1, 1]) # state transition matrix for 6 state variables # (position - velocity - acceleration, # x, y) F = np.array([[1, 0, dt, 0, 0.5 * pow(dt, 2), 0], [0, 1, 0, dt, 0, 0.5 * pow(dt, 2)], [0, 0, 1, 0, dt, 0], [0, 0, 0, 1, 0, dt], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]) # x and y coordinates only - measurements matrix H = np.array([[1., 0., 0., 0., 0., 0.], [0., 1., 0., 0., 0., 0.]]) # no initial corelation between x and y positions - variances only R = np.array( [[R_var, 0.], [0., R_var]]) # measurement covariance matrix # Q must be the same shape as P Q = np.diag([100, 100, 10, 10, 1, 1]) # model covariance matrix # create state vectors, max number of states - as much as frames x = np.zeros((stop_frame, 6)) # state initialization - initial state is equal to measurements m = 0 try: for i in range(len(max_points[0])): if max_points[0][i][0] > 0 and max_points[0][i][1] > 0: x[m] = [max_points[0][i][0], max_points[0][i][1], 0, 0, 0, 0] m += 1 # required for django runserver tests except IndexError: index_error = 1 est_number = 0 # number of estimates at the start try: for point in max_points[::][0]: if point[0] > 0 and point[1] > 0: est_number += 1 except IndexError: index_error = 1 # history of new objects appearance new_obj_hist = [[]] # difference between position of n-th object in m-1 frame and position # of the same object in m frame diff_2 = [[]] # for how many frames given object was detected frames_detected = [] # x and y posterior positions (estimates) for drawnings x_est = [[] for i in range(stop_frame)] y_est = [[] for i in range(stop_frame)] # variable for counting frames where object has no measurement striked_tracks = np.zeros(stop_frame) removed_states = [] new_detection = [] ff_nr = 0 # frame number self._progress_bar.label = '3/4: Generating position estimates..' self._progress_bar.value = 0 # kalman filter loop for frame in range(stop_frame): self._progress_bar.value = 100 * (ff_nr / stop_frame) # measurements in one frame try: frame_measurements = max_points[::][frame] except IndexError: index_error = 1 measurements = [] # make list of lists, not tuples; don't take zeros, # assuming it's image if not index_error: for meas in frame_measurements: if meas[0] > 0 and meas[1] > 0: measurements.append([meas[0], meas[1]]) # count prior for i in range(est_number): x[i][::] = dot(F, x[i][::]) P = dot(F, P).dot(F.T) + Q S = dot(H, P).dot(H.T) + R K = dot(P, H.T).dot(inv(S)) ################################################################## # prepare for update phase -> get (prior - measurement) assignment posterior_list = [] for i in range(est_number): if not np.isnan(x[i][0]) and not np.isnan(x[i][1]): posterior_list.append(i) # print(i) # print(posterior_list) # # print('state\n', x[0:est_number, 0:2]) # print('\n') # temp_matrix = np.array(x[0:est_number, 0:2]) try: temp_matrix = np.array(x[posterior_list, 0:2]) temp_matrix = np.append(temp_matrix, measurements, axis=0) except ValueError: value_error = 1 # print(temp_matrix) distance = pdist(temp_matrix, 'euclidean') # returns vector # make square matrix out of vector distance = squareform(distance) temp_distance = distance # remove elements that are repeated - (0-1), (1-0) etc. # distance = distance[est_number::, 0:est_number] distance = distance[0:len(posterior_list), len(posterior_list)::] # munkres row_index, column_index = linear_sum_assignment(distance) final_cost = distance[row_index, column_index].sum() unit_cost = [] index = [] for i in range(len(row_index)): # index(object, measurement) index.append([row_index[i], column_index[i]]) unit_cost.append(distance[row_index[i], column_index[i]]) ################################################################## # index correction - take past states into account removed_states.sort() for removed_index in removed_states: for i in range(len(index)): if index[i][0] >= removed_index: index[i][0] += 1 ################################################################## # find object to reject state_list = [index[i][0] for i in range(len(index))] reject = np.ones(len(posterior_list)) i = 0 for post_index in posterior_list: if post_index not in state_list: reject[i] = 0 i += 1 # check if distance (residual) isn't to high for assignment for i in range(len(unit_cost)): if unit_cost[i] > 20: print('cost to high, removing', i) reject[i] = 0 ################################################################## # update phase for i in range(len(index)): # find object that should get measurement next # count residual y: measurement - state if index[i][1] >= 0: y = np.array([measurements[index[i][1]] - dot(H, x[index[i][0], ::])]) # posterior x[index[i][0], ::] = x[index[i][0], ::] + dot(K, y.T).T # append new positions # if x[i][0] and x[i][1]: x_est[index[i][0]].append([x[index[i][0], 0]]) y_est[index[i][0]].append([x[index[i][0], 1]]) # posterior state covariance matrix P = dot(np.identity(6) - dot(K, H), P) print('posterior\n', x[0:est_number, 0:2]) ################################################################## # find new objects and create new states for them new_index = [] measurement_indexes = [] for i in range(len(index)): if index[i][1] >= 0.: # measurements that have assignment measurement_indexes.append(index[i][1]) for i in range(len(measurements)): if i not in measurement_indexes: # find measurements that don't have assignments new_index.append(i) new_detection.append([measurements[new_index[i]] for i in range(len(new_index))]) # for every detections in the last frame for i in range(len(new_detection[len(new_detection) - 1])): if new_detection[frame][i] and \ new_detection[frame][i][0] > 380: x[est_number, ::] = [new_detection[frame][i][0], new_detection[frame][i][1], 0, 0, 0, 0] est_number += 1 # print('state added', est_number) # print('new posterior\n', x[0:est_number, 0:2]) ################################################################## # find states without measurements and remove them no_track_list = [] for i in range(len(reject)): if not reject[i]: no_track_list.append(posterior_list[i]) # print('no_trk_list', no_track_list) for track in no_track_list: if track >= 0: striked_tracks[track] += 1 print('track/strikes', track, striked_tracks[track]) for i in range(len(striked_tracks)): if striked_tracks[i] >= 1: x[i, ::] = [None, None, None, None, None, None] if i not in removed_states: removed_states.append(i) print('state_removed', i) ff_nr += 1 # print(removed_states) # print(index) return x_est, y_est, est_number def _plot_points(self, vid_frag, max_points, x_est, y_est, est_number): self._progress_bar.label = '4/4: Plotting - measurements..' self._progress_bar.value = 0 # plot raw measurements for frame_positions in max_points: for pos in frame_positions: plt.plot(pos[0], pos[1], 'r.') # try: plt.axis([0, vid_frag[0].shape[1], vid_frag[0].shape[0], 0]) # except IndexError: # index_error = 1 plt.xlabel('width [px]') plt.ylabel('height [px]') plt.title('Objects raw measurements') ###################################################################### # image border - 10 px x_max = vid_frag[0].shape[1] - 10 y_max = vid_frag[0].shape[0] - 10 self._progress_bar.label = '4/4: Plotting - estimates..' self._progress_bar.value = 0 i = 0 # plot estimated trajectories for ind in range(est_number): self._progress_bar.value = 100 * (i / est_number) i += 1 # if estimate exists if len(x_est[ind]): for pos in range(len(x_est[ind])): # don't draw near 0 points and near max points if not np.isnan(x_est[ind][pos][0]) and \ x_est[ind][pos][0] > 10 and \ y_est[ind][pos][0] > 10 and \ x_est[ind][pos][0] < x_max - 10 and \ y_est[ind][pos][0] < y_max - 10: plt.plot(x_est[ind][pos][0], y_est[ind][pos][0], 'g.') # plt.plot(x_est[ind][::], y_est[ind][::], 'g-') # print(frame) # [xmin xmax ymin ymax] # try: plt.axis([0, vid_frag[0].shape[1], vid_frag[0].shape[0], 0]) # except IndexError: # index_error = 1 plt.xlabel('width [px]') plt.ylabel('height [px]') plt.title('Objects estimated trajectories') plt.grid() plt.show() def __processFrame(self, frame): """ Do some processing to the frame and return the result frame """ # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) frame = self.__color_channel(frame) if self._clahe.value: clahe = cv2.createCLAHE(clipLimit=8.0, tileGridSize=(8, 8)) frame = clahe.apply(frame) frame = self.__roi(frame) if self._threshold_box.value: ret, frame = cv2.threshold(frame, self._threshold.value, 255, cv2.THRESH_BINARY) frame = self.__morphological(frame) return frame def __runEvent(self): """ After setting the best parameters run the full algorithm """ if not self._start_frame.value or not self._stop_frame.value or \ self._start_frame.value >= self._stop_frame.value: raise ValueError('Wrong start or stop frame!') start_frame = int(self._start_frame.value) stop_frame = int(self._stop_frame.value) # pass cv2.VideoCapture object, not string # my_video = self._player.value video = self._player.value # self._load_bar.__init__('Processing..') vid_fragment = select_frames(video, start_frame, stop_frame) try: height = vid_fragment[0].shape[0] width = vid_fragment[0].shape[1] except IndexError: raise IndexError('No video loaded. Check video path.') i = 0 bin_frames = [] # preprocess image loop self._progress_bar.label = '1/4: Creating BW frames..' self._progress_bar.value = 0 for frame in vid_fragment: gray_frame = self.__color_channel(frame) # create a CLAHE object (Arguments are optional) if self._clahe.value: clahe = cv2.createCLAHE(clipLimit=8.0, tileGridSize=(8, 8)) gray_frame = clahe.apply(gray_frame) # ROI gray_frame = self.__roi(gray_frame) ret, th1 = cv2.threshold(gray_frame, self._threshold.value, 255, cv2.THRESH_BINARY) # frame_thresh1 = otsu_binary(cl1) bin_frames.append(th1) self._progress_bar.value = 100*(i/len(vid_fragment)) i += 1 ###################################################################### i = 0 maxima_points = [] # gather measurements loop self._progress_bar.label = '2/4: Finding local maximas..' self._progress_bar.value = 0 for frame in bin_frames: frame = self.__morphological(frame) # get local maximas of filtered image per frame maxima_points.append(local_maxima(frame)) self._progress_bar.value = 100 * (i / len(bin_frames)) i += 1 x_est, y_est, est_number = self._kalman(maxima_points, stop_frame, vid_fragment) print('\nFinal estimates number:', est_number) self._plot_points(vid_fragment, maxima_points, x_est, y_est, est_number) print('EOF - DONE')
class VehTrajAnalytics(BaseWidget): def __init__(self): super(VehTrajAnalytics, self).__init__('Vehicle Trajectory Analytics') #Definition of the forms fields self._firstname = ControlText('First name', 'Default value') self._middlename = ControlText('Middle name') self._lastname = ControlText('Lastname name') self._fullname = ControlText('Full name') self._button = ControlButton('Press this button') self._button2 = ControlButton('Press this button2') self._outputDir = ControlDir("Output Directory") self._inputFile = ControlFile("Input Trajectory File") self._load = ControlButton("Load") self._save = ControlButton("Save") self._vehicleId = ControlCombo("Vehicle id") self._time = ControlCombo("Time(sec)") self._positionX = ControlCombo("PositionX (feet)") self._positionY = ControlCombo("PositionY (feet)") # Instrumented vehicle trajectories self._radarRange = ControlCombo("Radar range (feet)") self._radarAngle = ControlCombo("Radar angle (degrees)") self._centerline = ControlFile("CenterlineFile") #all traffic stream self._lane = ControlCombo("Lane") self._vLength = ControlCombo("Vehicle Length") self._distanceAlong = ControlCombo("Distance Along Corridor") #Define the button action self._button.value = self.__buttonAction self.data = None self.outFolder = None self.formset = [[('_inputFile', '_load'), '_vehicleId', "_time", '_positionX', "_positionY", "_distanceAlong"], "=", { 'All Vehicle Trajectories': ['_lane', '_vLength'], 'Instrumented Vehicle Trajectories': ['_radarAngle', '_radarRange'] }, '=', ('_outputDir', '_save')] self._load.value = self.__loadAction self._save.value = self.__saveAction def __buttonAction(self): """Button action event""" self._fullname.value = self._firstname.value +" "+ self._middlename.value + \ " "+ self._lastname.value def __loadAction(self): fileName = self._inputFile.value if fileName.endswith("hdf"): self.data = pd.read_hdf(fileName, 'trajectories') self.vt = VTAnalytics.readModelData(fileName, start_time=start_time, end_time=end_time) else: #self.data = pd.read_csv(fileName) self.vt = VTAnalytics.readNGISIMData(fileName, start_time=start_time, end_time=end_time) self.data = self.vt.df columns = list(self.data.columns) self.__initializeBoxes2(columns) def __saveAction(self): print('done reading the data') writer = pd.ExcelWriter( os.path.join(self._outputDir.value, 'tables.xlsx')) PAGE_SIZE = (1000, 792.0) pdfReport = PdfReport( os.path.join(self._outputDir.value, 'report.pdf'), PAGE_SIZE) fig, ax = plt.subplots(figsize=(10, 8), dpi=100) self.vt.plotSpeedVsDensity(fig, ax, max_density=280) fig.savefig(os.path.join(self._outputDir.value, "SpeedVsDensity.png"), dpi=100) pdfReport.addChart2( os.path.join(self._outputDir.value, "SpeedVsDensity.png"), 'SpeedVsDensity') fig, ax = plt.subplots(figsize=(10, 8), dpi=100) self.vt.plotLCR(fig, laneChangeType='enter') fig.savefig(os.path.join(self._outputDir.value, "LCR.png"), dpi=100) pdfReport.addChart2(os.path.join(self._outputDir.value, "LCR.png"), "LaneChangeRate") fig, ax = plt.subplots(figsize=(10, 8), dpi=100) self.vt.plotSpeedVsDensityByLane(fig, plot_mean=True, dot_color='blue', alpha=0.4) out_fileName = os.path.join(self._outputDir.value, "SpeedVsDensityByLane.png") fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "SpeedVsDensityByLane") fig, ax = plt.subplots(figsize=(10, 8)) spdDist = self.vt.plotSpeedDistribution(ax) out_fileName = os.path.join(self._outputDir.value, "SpeedDistribution.png") fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "SpeedDistribution") spdDist.to_excel(writer, 'SpeedDistribution') fig, ax = plt.subplots(figsize=(10, 8)) accDist = self.vt.plotAccelerationDistribution(ax) out_fileName = os.path.join(self._outputDir.value, "AccelerationDistribution.png") fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "AccelerationDistribution") accDist.to_excel(writer, 'AcclerationDistribution') fig, ax = plt.subplots(figsize=(10, 8)) jerk = self.vt.getAccelerationJerk() jerkDist = self.vt.plotJerkDistribution(jerk, ax) out_fileName = os.path.join(self._outputDir.value, "AccelerationJerkDistribution.png") fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "AccelerationJerkDistribution") jerkDist.to_excel(writer, 'JerkDistribution') armsDist = self.vt.getARMSDistribution() fig, ax = plt.subplots(figsize=(10, 8)) self.vt.plotARMS(armsDist, ax) out_fileName = os.path.join(self._outputDir.value, "AccelerationRootMeanSquareError.png") fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "AccelerationRootMeanSquareError") armsDist.to_excel(writer, 'ARMS') writer.save() for i in range(1, 8): fig, ax = plt.subplots(figsize=(10, 8), dpi=100) self.vt.plotAllTrajectories(fig, ax, i, np.datetime64('2005-04-13 17:00:00'), np.datetime64('2005-04-13 17:10:00'), 0, 1000, point_size=0.5, title="All trajectories for lane %d" % i) out_fileName = os.path.join(self._outputDir.value, "All_trajectories_lane_%d.png" % i) fig.savefig(out_fileName, dpi=100) pdfReport.addChart2(out_fileName, "All trajectories for lane %d" % i) pdfReport.write() def __saveActionOLD(self): fig, ax = plt.subplots(figsize=(10, 8)) self.vt.plotSpeedVsDensity(fig, ax, max_density=280) fig.savefig(os.path.join(self._outputDir.value, "graph1.pdf"), dpi=100) fig, ax = plt.subplots(figsize=(10, 8)) self.vt.plotLCR(fig, laneChangeType='enter') fig.savefig(os.path.join(self._outputDir.value, "graph2.pdf"), dpi=100) fig, ax = plt.subplots(figsize=(10, 8)) self.vt.plotSpeedVsDensityByLane(fig, plot_mean=True, dot_color='blue', alpha=0.4) fig.savefig(os.path.join(self._outputDir.value, "graph3.pdf"), dpi=100) for i in range(1, 8): fig, ax = plt.subplots(figsize=(10, 8)) self.vt.plotAllTrajectories(fig, ax, i, np.datetime64('2005-04-13 17:00:00'), np.datetime64('2005-04-13 17:10:00'), 0, 1000, point_size=0.5) fig.savefig(os.path.join(self._outputDir.value, "graph%d.pdf" % (3 + i)), dpi=100) #file_list = [os.path.join(self._outputDir.value, "test.pdf"), # os.path.join(self._outputDir.value, "test2.pdf")] file_list = [ os.path.join(self._outputDir.value, "graph%d.pdf" % i) for i in range(1, 5) ] out_file = os.path.join(self._outputDir.value, "trajReport.pdf") combinePdfFiles(file_list, out_file) def __initializeBoxes2(self, columns): for i, col in enumerate(columns): self._vehicleId.add_item(col, i) self._time.add_item(col, i) self._positionX.add_item(col, i) self._positionY.add_item(col, i) self._lane.add_item(col, i) self._vLength.add_item(col, i) self._radarRange.add_item(col, i) self._radarAngle.add_item(col, i) self._distanceAlong.add_item(col, i) #self.__initializeBoxes() def __initializeBoxes(self): self._vehicleId.add_item("One", '1') self._vehicleId.add_item("Two", '2') self._vehicleId.add_item("Three", '3') self._time.add_item("One", '1') self._time.add_item("Two", '2') self._time.add_item("Three", '3') self._positionX.add_item("One", '1') self._positionX.add_item("Two", '2') self._positionX.add_item("Three", '3') self._positionY.add_item("One", '1') self._positionY.add_item("Two", '2') self._positionY.add_item("Three", '3') self._lane.add_item("One", '1') self._lane.add_item("Two", '2') self._lane.add_item("Three", '3') self._vLength.add_item("One", '1') self._vLength.add_item("Two", '2') self._vLength.add_item("Three", '3') def __saveResults(self): fig, ax = plt.subplots(figsize=(15, 10)) self.data.speed.hist(ax=ax, bins=np.arange(0, 71, 1), figsize=(15, 10), width=0.8, color='grey', alpha=0.5) ax.set_title("Distribution of instantaneous speeds", fontsize=18) ax.set_xlabel("speed (mph)", fontsize=16) fig.tight_layout() fig.savefig(os.path.join(self.outFolder, 'test.png'))
class ImportWindow(BaseWidget): def __init__(self, timeline=None): super(ImportWindow, self).__init__('Import file', parent_win=timeline) self.setContentsMargins(10, 10, 10, 10) self._timeline = timeline # Definition of the forms fields self._filetype = ControlCombo( 'Please select the type of file you would like to import:') self._importButton = ControlButton('Import') self._panel = ControlEmptyWidget('Panel') self._file = ControlFile('File to import') self._panel.value = self._file self._filetype.add_item('Events file', 0) self._filetype.add_item('Graph file', 1) self._filetype.add_item('Bonsai events file', 2) self._filetype.add_item('Bonsai events file (old format)', 3) self._formset = [('_filetype', ' '), '_panel', (' ', '_importButton'), ' '] self._filetype.changed_event = self.__fileTypeChanged self._importButton.value = self.__importData from pyforms.gui.dialogs.csv_parser import CsvParserDialog self._graphCsvParserDlg = CsvParserDialog() self._graphCsvParserDlg.xField.label = "Value column" self._graphCsvParserDlg.yField.hide() self._graphCsvParserDlg.zField.hide() self._graphCsvParserDlg.loadButton.hide() self._bonsai_import_dlg = BonsaiImportFileDlg() def __fileTypeChanged(self): if self._filetype.value == 0: self._panel.value = self._file elif self._filetype.value == 1: self._panel.value = self._graphCsvParserDlg elif self._filetype.value in [2, 3]: self._panel.value = self._bonsai_import_dlg def __importData(self): if self._filetype.value == 0: separator = ',' with open(self._file.value, 'rU') as csvfile: line = csvfile.readline() if ";" in line: separator = ';' with open(self._file.value, 'rU') as csvfile: csvfile = csv.reader(csvfile, delimiter=separator) self._timeline._time.import_csv(csvfile) elif self._filetype.value == 1: self._timeline._time.importchart_csv(self._graphCsvParserDlg) self._timeline.show_graphs_properties() elif self._filetype.value == 2: self.__import_bonsai_events() elif self._filetype.value == 3: self.__import_bonsai_events_oldformat() self._timeline.repaint() self._timeline._time.repaint() self.close() # pylint: disable=no-member def import_chart(self, filename, frame_col=0, val_col=1): self._filetype.value = 1 self._graphCsvParserDlg.filename = filename self._graphCsvParserDlg.frameColumn = frame_col self._graphCsvParserDlg.xColumn = val_col def __import_bonsai_events(self): with open(self._bonsai_import_dlg._file.value, 'rU') as csvfile: values = [] pointEventValues = [] csvfile = csv.reader(csvfile, delimiter=' ') for row in csvfile: # strip Start/End word from all events names which are not PointEven try: timestr = row[1].rstrip('0') cvttime = datetime.datetime.strptime( timestr, "%H:%M:%S.%f") except: timestr = row[1] try: print(timestr) cvttime = datetime.datetime.strptime( timestr, "%H:%M:%S") except: timestr = timestr.replace('T', ' ') print(timestr) cvttime = dateutil.parser.parse(timestr) seconds = (cvttime - datetime.datetime(1900, 1, 1)).total_seconds() frame = int(round(self._bonsai_import_dlg._fps.value * seconds)) if row[2] == "PointEvent": eventtype = row[0] pointEventValues.append([eventtype, frame, row[2]]) else: if row[0].startswith('Start'): eventtype = row[0][len( 'Start'):] # strip Start word from the beginning else: eventtype = row[0][len( 'End'):] # strip End word from the beginning values.append([eventtype, frame, row[2]]) values = sorted(values, key=lambda x: (x[0].capitalize(), x[1])) pointEventValues = sorted(pointEventValues, key=lambda x: (x[0].capitalize(), x[1])) ntracks = len(set([x[0] for x in values])) + 1 # collapse events = [] eventsTypes = {} # Events names currentTrack = 0 for index in range(0, len(pointEventValues)): pointEventValue = pointEventValues[index] eventsTypes[pointEventValue[0]] = currentTrack self._timeline.add_period([ pointEventValue[1], pointEventValue[1] + 50, pointEventValue[0] ], row=currentTrack) currentTrack = 1 for index in range(0, len(values), 2): row0 = values[index] row1 = values[index + 1] if row0[0] not in eventsTypes: eventsTypes[row0[0]] = currentTrack track = currentTrack currentTrack += 1 else: track = eventsTypes[row0[0]] self._timeline.add_period([row0[1], row1[1], row0[0]], row=track) def __import_bonsai_events_oldformat(self): with open(self._bonsai_import_dlg._file.value, 'rU') as csvfile: windows_events = [] points_events = [] first_date = None for row in csvfile: row = row[:-1] #remove the newline character if row.endswith('WindowClosing'): split = row.rfind(' ') #eventtype = row[-split:] eventtype = 'end' timestr = row[split - 33:split] eventname = row[4:split - 33] elif row.endswith('PointEvent'): split = row.rfind(' ') eventtype = row[split + 1:] timestr = row[split - 33:split] eventname = row[:split - 33] else: eventtype = 'start' timestr = row[-33:] eventname = row[6:-33] cvttime = dateutil.parser.parse(timestr.replace('T', ' ')) cvttime = cvttime.replace(tzinfo=None) if first_date is None: first_date = cvttime seconds = (cvttime - first_date).total_seconds() frame = int(round(self._bonsai_import_dlg._fps.value * seconds)) if eventtype == 'PointEvent': points_events.append([eventtype, frame, eventname]) else: if eventtype == 'start': windows_events.append([eventtype, frame, eventname]) elif eventtype == 'end': windows_events.append([eventtype, frame, eventname]) windows_events = sorted(windows_events, key=lambda x: (x[0][0].capitalize(), x[0][1])) points_events = sorted(points_events, key=lambda x: (x[0].capitalize(), x[1])) ntracks = len(set([x[0][1] for x in windows_events])) + 1 # collapse events = [] events_types = {} # Events names current_track = 0 for index in range(0, len(points_events)): eventtype, frame, eventname = points_events[index] events_types[eventname] = current_track self._timeline.add_period([frame, frame + 2, eventname], row=current_track) current_track = 1 for i in range(0, len(windows_events), 2): start = windows_events[i] end = windows_events[i + 1] eventtype, frame_begin, eventname = start _, frame_end, _ = end if eventname not in events_types: events_types[eventname] = current_track track = current_track current_track += 1 else: track = events_types[eventname] print('add', eventname, track, frame_begin, frame_end) self._timeline.add_period([frame_begin, frame_end, eventname], row=track)
def _update_shown_axis(self): index = self._axis_list.selected_row_index if not index is None: axis = self._axis[index] if not axis is None: assert isinstance(axis, ControlAxis) # Get the hardware type from the name of the class self._axis_hw_type.value = type(axis).__name__ # Update the minimum box if not self._min.visible: self._min.visible = True self._min.label = "Minimum ({})".format(axis.get_units()) self._events = False self._min.value = axis.get_min() self._events = True # Update the maximum box if not self._max.visible: self._max.visible = True self._max.label = "Maximum ({})".format(axis.get_units()) self._events = False self._max.value = axis.get_max() self._events = True # Update the norm_minimum box if not self._norm_min.visible: self._norm_min.visible = True self._norm_min.label = " 0% ({})".format(axis.get_units()) self._events = False self._norm_min.value = axis.get_norm_min() self._events = True # Update the norm_maximum box if not self._norm_max.visible: self._norm_max.visible = True self._norm_max.label = "100% ({})".format(axis.get_units()) self._events = False self._norm_max.value = axis.get_norm_max() self._events = True # Populate the special axis combo special_axis = ControlCombo(label="Special Axis") special_axis.add_item('', '') special_axis.add_item("X Axis", 'xaxis') special_axis.add_item("Y Axis", 'yaxis') if axis == self._xaxis: special_axis.value = 'xaxis' elif axis == self._yaxis: special_axis.value = 'yaxis' def axis_changed(_): """ Called when axis changed """ if special_axis.value == 'xaxis': self._xaxis = axis if self._yaxis == axis: self._yaxis = None elif special_axis.value == 'yaxis': self._yaxis = axis if self._xaxis == axis: self._xaxis = None else: if self._xaxis == axis: self._xaxis = None if self._yaxis == axis: self._yaxis = None self._send_events() print("Making Special Combo") special_axis.current_index_changed_event = axis_changed self._events = False self._special_axis.value = None self._special_axis.value = special_axis self._events = True # Update the custom config GUI self._axis_custom.value = axis.get_custom_config() self._save_button.visible = True else: self._axis_hw_type.value = '' self._min.visible = False self._max.visible = False self._norm_min.visible = False self._norm_max.visible = False self._special_axis.value = None self._axis_custom.value = None self._save_button.visible = False else: self._axis_hw_type.value = '' self._min.visible = False self._max.visible = False self._norm_min.visible = False self._norm_max.visible = False self._special_axis.value = None self._axis_custom.value = None self._save_button.visible = False