def set_calfactor(self): """ Measure filament width, set spinbox to value, then call by clicking calibrate button. """ prev_cal = self.ui.cal_factor.value() user_w_pxl = self.ui.vline_right.value() - self.ui.vline_left.value() width_pxl = np_ave( self.cal_width_history) # self.areas['width'].width_value new_cal = round(self.ui.filament_width.value() / float(width_pxl), 4) #mm/pxl self.ui.cal_factor.setValue(new_cal) append_texteditor( self.ui.text_pipe_out, 'Calibrate: user_W: {} vs detected: {:.4f} pxl'.format( user_w_pxl, width_pxl)) append_texteditor( self.ui.text_pipe_out, 'Calibrate: prev cal_factor: {:.4f} mm/pxl'.format(prev_cal)) #update vals self.set_cal_values() #set cal date date_time = QtCore.QDateTime.currentDateTime() self.ui.cal_date.setDateTime(date_time) #return to main tab self.ui.tabWidget.setCurrentIndex(0)
def save_config(self, config_filename=None): """ """ self.update_config() #write config_filename = config_filename or self.config_filename with open(config_filename, 'w') as configfile: self.config.write(configfile) # append_texteditor(self.ui.text_pipe_out, 'Config updated: {}'.format(config_filename))
def set_cal_values(self): """ """ self.convert_width = self.ui.cal_factor.value() self.convert_speed = self.convert_width * self.stream_fps self.ui.calfactor_inv.setValue(1 / self.convert_width) self.frame_result['cal_factor'] = self.convert_width #done append_texteditor( self.ui.text_pipe_out, 'Calibrate: set cal_factor: {:.4f} mm/pxl'.format( self.ui.cal_factor.value())) append_texteditor( self.ui.text_pipe_out, 'Calibrate: set convert_speed: {:.4f} mm/pxl frame/s'.format( self.convert_speed))
def record_video_save(self): """ stop and save """ self.recording = False self.ui.record_video.setChecked(False) if self.record_file is not None: #release video file - save self.record_file.release() self.ui.record_state.setText('Saved') self.ui.record_start_new.setEnabled(False) self.record_file = None append_texteditor(self.ui.text_pipe_out, 'Video saved: {}'.format(self.record_filename)) #save config with the same namve configname = self.record_filename.split('.avi')[0] configname += '.cfg' self.save_config(configname)
def load_video_from_file(self, video_fullname=None): """ Called by pb clicked: disconnect current camera if connected enalbe controls setup frame numbers and slider. Once video is running, camera view cannot be restored. Only through restarting app. """ self.main_timer.stop() if self.stream is not None: self.stream.stop() #stop thread, release capture self.stream.new_frame.disconnect() if video_fullname is None: video_fullname = load_file_name(self, type_filter='Video File (*.AVI)') if video_fullname is not None: append_texteditor(self.ui.text_pipe_out, 'load video: {}'.format(video_fullname)) self.ui.frame_next.setEnabled(True) self.ui.frame_prev.setEnabled(True) self.ui.frame_number.setEnabled(True) self.ui.play_video.setEnabled(True) if self.video_capture is not None: self.video_capture.release() self.video_capture = None self.video_capture = cv2.VideoCapture(video_fullname) retval, frame = self.video_capture.read() self.frame_extruder = frame filename = os.path.split(video_fullname)[-1] self.video_filename = os.path.splitext(filename)[0] if retval: self.ui.fps.setValue(self.video_capture.get(cv2.CAP_PROP_FPS)) self.stream_fps = self.ui.fps.value() self.time_passed_ms = (1 / self.ui.fps.value()) * 1000 self.num_frames = int( self.video_capture.get(cv2.CAP_PROP_FRAME_COUNT)) append_texteditor( self.ui.text_pipe_out, 'next_video shape: {}, num frames {}'.format( frame.shape, self.num_frames)) self.ui.frame_number.setMaximum(self.num_frames) #try get config file_search = os.path.splitext(video_fullname)[0] video_config_filename = get_files_like( folder=None, filename_contains=file_search, ext='cfg') try: video_config_filename = video_config_filename[0] append_texteditor( self.ui.text_pipe_out, 'load video config: {}'.format(video_config_filename)) append_texteditor( self.ui.text_pipe_out, 'video config: {}'.format(video_config_filename)) self.load_configs(video_config_filename) self.areas_setup() self.set_cal_values() except IndexError: append_texteditor(self.ui.text_pipe_out, 'no config file found: {}'.format( video_config_filename)) # else: append_texteditor(self.ui.text_pipe_out, 'frame is None: {}'.format(video_fullname)) #---- end if video_filename is not None self.main_timer.start(self.main_timer_rate)
def __init__(self, main_app, pipe_in=None, pipe_out=None, **kwargs): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.app_settings = kwargs self.pipe_in = pipe_in self.pipe_out = pipe_out self.close_attempts = 0 #complicated exit process self.measure_active = False #when active, do not display cv dwg to increase speed self.process_active = True #run realtime in-processing self.new_frame_processed = False #update display on True self.update_areas = False #True, new/update areas and frame self.frame_id = 0 # id used in ROIA for update of points, # also the current video frame number self.prev_frame = -1 self.convert_speed = 1.0 #cal factor/fps self.convert_width = 1.0 #cal factor self.time_passed_ms = (1 / 30.) * 1000 # self.missed_frames = 0 #collect a few filament width estimations over time self.cal_collect_width = False #control self.cal_width_history = [] #collected data self.cal_w_len = 60 #number to collect #result reporting -send dict via pipe self.frame_result = {} self.frame_result['name'] = 'frame_result' self.frame_result['time_stamp'] = '' self.frame_result['gear_speed'] = 0 #pxl/frame self.frame_result['filament_speed'] = 0 #pxl/frame self.frame_result['filament_width'] = 0 #pxl self.frame_result['time_elasped'] = 0 #sec self.frame_result['cal_factor'] = 1.0 #mm/pxl self.frame_result['frame_id'] = 1.0 # #setup reporting -send dict via pipe self.setup_details = {} self.setup_details['name'] = 'setup_details' self.setup_details['user_filament_width'] = 2.85 #mm self.setup_details['config'] = {} #video recording reporting self.video_details = {} self.video_details['name'] = 'video_filename' self.video_details['video_filename'] = None self.data_folder = 'data' #load *.cfg self.load_configs() #timers self.current_time = QtCore.QTime() self.main_timer_rate = 50 #ms self.main_timer = QtCore.QTimer(self) self.main_timer.timeout.connect(self.main_task_loop) #source self.video_capture = None #from a video file self.stream = None #from camera self.frame_extruder = None #threading self.__workers_done = True self.__threads = [] if kwargs.get('load_video_def', False): self.video_mode = True self.load_video_from_file( video_fullname='data\Test_2017_02_17__08_45_46.avi') self.ui.load_video.setEnabled(True) else: self.video_mode = False self.init_threads(main_app) #video recording settings self.recording = False #busy recording self.record_file = None self.record_filename_prev = '' self.record_fps = self.stream_fps # fps for video file #UI camera display self.microscope_display = CameraLabel(self.ui.groupBox_video) self.microscope_display.setMaximumSize(QtCore.QSize(640, 480)) self.microscope_display.setFrameShape(QtWidgets.QFrame.WinPanel) self.microscope_display.setFrameShadow(QtWidgets.QFrame.Sunken) self.microscope_display.setLineWidth(2) self.microscope_display.setScaledContents(True) self.microscope_display.setAlignment(QtCore.Qt.AlignCenter) self.microscope_display.setObjectName("microscope_display") self.ui.verticalLayout_2.addWidget(self.microscope_display) if self.frame_extruder is not None: self.microscope_display.pixmap = converter(self.frame_extruder) #init configs self.areas_setup() self.set_cal_values() #CONNECTIONS #UI ROI setup self.ui.img_rotation.valueChanged.connect(self.set_update_areas) self.ui.vline_left.valueChanged.connect(self.set_update_areas) self.ui.vline_right.valueChanged.connect(self.set_update_areas) self.ui.w_y2.valueChanged.connect(self.set_update_areas) self.ui.w_vline_left_border.valueChanged.connect(self.set_update_areas) self.ui.w_vline_right_border.valueChanged.connect( self.set_update_areas) self.ui.fil_roi_x.valueChanged.connect(self.set_update_areas) self.ui.fil_roi_y.valueChanged.connect(self.set_update_areas) self.ui.fil_roi_size.valueChanged.connect(self.set_update_areas) self.ui.gear_roi_x.valueChanged.connect(self.set_update_areas) self.ui.gear_roi_y.valueChanged.connect(self.set_update_areas) self.ui.gear_roi_size.valueChanged.connect(self.set_update_areas) self.ui.mat_colour.currentIndexChanged.connect(self.set_update_areas) self.ui.save_config.clicked.connect(self.save_config) #calibration # self.ui.filament_width.valueChanged.connect(self.updated_std_width) self.ui.calibrate.clicked.connect(self.start_cal) #video playback self.ui.load_video.clicked.connect(self.load_video_from_file) self.ui.frame_number.valueChanged.connect(self.new_frame_trackbar) self.ui.frame_next.clicked.connect(self.new_frame_next) self.ui.frame_prev.clicked.connect(self.new_frame_prev) #video recording self.ui.record_video.clicked.connect(self.record_video_start_stop) self.ui.record_save.clicked.connect(self.record_video_save) self.ui.record_start_new.clicked.connect(self.record_start_new) #--- qr = self.frameGeometry() self.move(qr.topLeft()) self.setWindowTitle('Vision') self.ui.report_results.setChecked(False) if self.video_mode: self.ui.tabWidget.setCurrentIndex(4) #DEBUG #profile self.busy_profile = kwargs.get('do_profiling', 0) #0 or number of frames to profile self.ping_count = 0 #START current_time_str = self.current_time.currentTime().toString( 'hh:mm:ss.zzz') append_texteditor(self.ui.text_pipe_out, 'start time_stamp: {}'.format(current_time_str)) #start threads if any for thread, worker in self.__threads: thread.start( ) # this will emit 'started' and start thread's event loop self.main_timer.start(self.main_timer_rate) self.pipe_out.send('vision started') self.updated_std_width(self.ui.filament_width.value())
def load_configs(self, add_config_filename=None): """ """ self.expected_speed = 2 #mm/s default_config_filename = 'config_vision.cfg' self.set_config_name = 'vision' self.config = configparser.RawConfigParser() self.config.optionxform = str self.config_filename = default_config_filename read_result = self.config.read(self.config_filename) append_texteditor(self.ui.text_pipe_out, 'config loaded: {}'.format(read_result)) if add_config_filename is not None: self.config_filename = add_config_filename read_result = self.config.read(self.config_filename) append_texteditor(self.ui.text_pipe_out, 'add config loaded: {}'.format(read_result)) #image processing self.ui.width_thresh_inv.setChecked( self.config.getboolean(self.set_config_name, 'width_thresh_inv')) #vertical alingment line - user sets it to filament left and right edge self.ui.vline_left.setValue( self.config.getint(self.set_config_name, 'vline_left')) self.ui.vline_right.setValue( self.config.getint(self.set_config_name, 'vline_right')) #whole image rotation self.ui.img_rotation.setValue( self.config.getfloat(self.set_config_name, 'img_rotation')) #ROI - filament width estimation self.ui.w_y2.setValue(self.config.getint(self.set_config_name, 'w_y2')) self.ui.w_vline_left_border.setValue( self.config.getint(self.set_config_name, 'w_vline_left_border')) self.ui.w_vline_right_border.setValue( self.config.getint(self.set_config_name, 'w_vline_right_border')) #ROI - filament speed estimation self.ui.fil_roi_x.setValue( self.config.getint(self.set_config_name, 'fil_roi_x')) self.ui.fil_roi_y.setValue( self.config.getint(self.set_config_name, 'fil_roi_y')) self.ui.fil_roi_size.setValue( self.config.getint(self.set_config_name, 'fil_roi_size')) #ROI GEAR self.ui.gear_roi_x.setValue( self.config.getint(self.set_config_name, 'gear_roi_x')) self.ui.gear_roi_y.setValue( self.config.getint(self.set_config_name, 'gear_roi_y')) self.ui.gear_roi_size.setValue( self.config.getint(self.set_config_name, 'gear_roi_size')) #CAL self.ui.filament_width.setValue( self.config.getfloat(self.set_config_name, 'filament_width')) self.ui.cal_factor.setValue( self.config.getfloat(self.set_config_name, 'cal_factor')) self.ui.calfactor_inv.setValue( 1 / self.config.getfloat(self.set_config_name, 'cal_factor')) date_time = self.config.get(self.set_config_name, 'cal_date') self.ui.cal_date.setDateTime(QtCore.QDateTime.fromString(date_time)) #material set_combo_index(self.ui.mat_colour, self.config.get(self.set_config_name, 'mat_colour')) set_combo_index(self.ui.mat_type, self.config.get(self.set_config_name, 'mat_colour')) self.ui.mat_date_id.setText( self.config.get(self.set_config_name, 'mat_date_id')) self.ui.mat_manufacturer.setText( self.config.get(self.set_config_name, 'mat_manufacturer')) #pre-process self.rot_apply_flag = round(self.ui.img_rotation.value(), 1) != 0 #camera self.ui.cam_model.setText(self.config.get('camera', 'cam_model')) self.ui.cam_number.setValue(self.config.getint('camera', 'cam_number')) self.ui.cam_fps.setValue(self.config.getint('camera', 'cam_fps')) self.ui.fps.setValue(self.config.getint('camera', 'cam_fps')) #for writing to configs to results file self.setup_details['config'] = make_config_dict(self.config)
def main_task_loop(self): """ """ #replay recorded video if self.video_mode: if self.video_new_frame(): self.process_new_frame(0, self.frame_id, self.time_passed_ms, self.frame_extruder) #update display if self.new_frame_processed: self.new_frame_processed = False self.post_process() elif not (self.video_mode): self.ping_count += 1 if self.ping_count > 30: self.pipe_out.send('ping {}'.format(self.ping_count)) self.ping_count = 0 date_time = QtCore.QDateTime.currentDateTime() msg = date_time.toString() self.pipe_out.send(msg) self.new_frame_processed = True #poll comms if self.pipe_in.poll(): new_task = self.pipe_in.recv() append_texteditor(self.ui.text_pipe_in, 'New task {}'.format(new_task)) if isinstance(new_task, dict): #process video if new_task.get('process_video', False): self.ui.report_results.setChecked(True) self.ui.play_video.setChecked(True) #process camera else: measure = new_task.get('measure', False) if measure: self.updated_std_width() if new_task.get('record_video', False): self.ui.record_video.setChecked(True) self.record_video_start_stop(new_state=True) if new_task.get('save_video', False): self.record_video_save() self.ui.report_results.setChecked(measure) self.measure_active = measure and not (self.video_mode) self.process_active = not ( self.recording and not (self.ui.report_results.isChecked())) else: #string command or something else if new_task == 'exit': self.close() elif new_task == 'init_dino_cam': #try re-init cam # self.init_dino_cam() pass #only execute for limeted number of frames if self.busy_profile > 0: self.busy_profile -= 1 if self.busy_profile <= 0: self.close()