def __init__(self, context): """ TestPlugin class to evaluate the image_recognition_msgs interfaces :param context: QT context, aka parent """ super(TestPlugin, self).__init__(context) # Widget setup self.setObjectName('Test Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback, clear_on_click=True) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._info = QLineEdit() self._info.setDisabled(True) self._info.setText("Draw a rectangle on the screen to perform recognition of that ROI") layout.addWidget(self._info) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber and service to None self._sub = None self._srv = None
def setup_ui(self): """Initialize widgets. """ self.file_name = QLabel() self.f_widget = self.setup_func_widget() self.f_2widget = self.setup_second_func_widget() self.label_w = LabelWidget(self) self.image_w = ImageWidget(self.label_w, self) self.filelist_w = FilelistWidget(self) self.l_layout = QVBoxLayout() self.l_layout.addWidget(self.file_name) self.l_layout.addWidget(self.image_w) self.l_layout.addWidget(self.f_widget) self.l_layout.addWidget(self.f_2widget) self.l_widget = QWidget() self.l_widget.setLayout(self.l_layout) self.r_layout = QVBoxLayout() self.r_layout.addWidget(self.label_w) self.r_layout.addWidget(self.filelist_w) self.r_widget = QWidget() self.r_widget.setLayout(self.r_layout) self.h_layout = QHBoxLayout() self.h_layout.addWidget(self.l_widget) self.h_layout.addWidget(self.r_widget) self.setLayout(self.h_layout)
def __init__(self, context): super(TestPlugin, self).__init__(context) # Widget setup self.setObjectName('Test Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._info = QLineEdit() self._info.setDisabled(True) self._info.setText( "Draw a rectangle on the screen to perform object recognition of that ROI" ) layout.addWidget(self._info) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber and service to None self._sub = None self._srv = None
def __init__(self, context): """ Annotation plugin to create data sets or test the Annotate.srv service :param context: Parent QT widget """ super(AnnotationPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback, clear_on_click=True) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._edit_path_button = QPushButton("Edit path") self._edit_path_button.clicked.connect(self._get_output_directory) grid_layout.addWidget(self._edit_path_button, 1, 1) self._output_path_edit = QLineEdit() self._output_path_edit.setDisabled(True) grid_layout.addWidget(self._output_path_edit, 1, 2) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._save_button = QPushButton("Annotate again!") self._save_button.clicked.connect(self.annotate_again_clicked) grid_layout.addWidget(self._save_button, 2, 3) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber to None self._sub = None self._srv = None self.labels = [] self.label = "" self.output_directory = ""
def __init__(self, context): super(LabelPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._edit_path_button = QPushButton("Edit path") self._edit_path_button.clicked.connect(self._get_output_directory) grid_layout.addWidget(self._edit_path_button, 1, 1) self._output_path_edit = QLineEdit() self._output_path_edit.setDisabled(True) grid_layout.addWidget(self._output_path_edit, 1, 2) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._save_button = QPushButton("Save another one") self._save_button.clicked.connect(self.store_image) grid_layout.addWidget(self._save_button, 2, 3) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber to None self._sub = None self.labels = [] self.roi_image = None self.label = "" self.output_directory = ""
def __init__(self): super().__init__() self.title = "Glorified Rectangle Creator" self.setWindowTitle(self.title) self.data_dir = "" self.left = 0 self.top = 0 self.width = 1024 self.height = 768 self.setGeometry(self.left, self.top, self.width, self.height) self.tab_panel = TableWidget(self) file_list = FileListWidget() self.tab_panel.tab1.layout.addWidget(file_list) class_list = ClassListWidget() self.tab_panel.tab1.layout.addWidget(class_list) self.image_panel = ImageWidget(self) self.image_panel_controls = ImageControlsWidget() self.tab_panel.tab2.layout.addWidget(self.image_panel) self.tab_panel.tab2.layout.addWidget(self.image_panel_controls) self.setCentralWidget(self.tab_panel) self.center() self.show()
def __init__(self, context): """ ManualPlugin class that performs a manual recognition based on a request :param context: QT context, aka parent """ super(ManualPlugin, self).__init__(context) # Widget setup self.setObjectName('Manual Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._done_recognizing_button = QPushButton("Done recognizing..") self._done_recognizing_button.clicked.connect(self._done_recognizing) self._done_recognizing_button.setDisabled(True) grid_layout.addWidget(self._done_recognizing_button, 3, 2) # Bridge for opencv conversion self.bridge = CvBridge() # Set service to None self._srv = None self._srv_name = None self._response = RecognizeResponse() self._recognizing = False
def setupUi(self, FormImageBboxEditor): FormImageBboxEditor.setObjectName("FormImageBboxEditor") FormImageBboxEditor.resize(684, 471) self.verticalLayout = QtWidgets.QVBoxLayout(FormImageBboxEditor) self.verticalLayout.setObjectName("verticalLayout") self.image = ImageWidget(FormImageBboxEditor) self.image.setObjectName("image") self.verticalLayout.addWidget(self.image) self.labelInfoPath = QtWidgets.QLabel(FormImageBboxEditor) self.labelInfoPath.setObjectName("labelInfoPath") self.verticalLayout.addWidget(self.labelInfoPath) self.labelInfoScale = QtWidgets.QLabel(FormImageBboxEditor) self.labelInfoScale.setObjectName("labelInfoScale") self.verticalLayout.addWidget(self.labelInfoScale) self.listView = QtWidgets.QListView(FormImageBboxEditor) self.listView.setObjectName("listView") self.verticalLayout.addWidget(self.listView) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.checkboxStayInside = QtWidgets.QCheckBox(FormImageBboxEditor) self.checkboxStayInside.setChecked(True) self.checkboxStayInside.setObjectName("checkboxStayInside") self.horizontalLayout.addWidget(self.checkboxStayInside) self.buttonSwitchInOutEditor = QtWidgets.QPushButton( FormImageBboxEditor) self.buttonSwitchInOutEditor.setObjectName("buttonSwitchInOutEditor") self.horizontalLayout.addWidget(self.buttonSwitchInOutEditor) self.buttonSwapInOutEditor = QtWidgets.QPushButton(FormImageBboxEditor) self.buttonSwapInOutEditor.setObjectName("buttonSwapInOutEditor") self.horizontalLayout.addWidget(self.buttonSwapInOutEditor) self.buttonImageNext = QtWidgets.QPushButton(FormImageBboxEditor) self.buttonImageNext.setObjectName("buttonImageNext") self.horizontalLayout.addWidget(self.buttonImageNext) self.buttonImagePrev = QtWidgets.QPushButton(FormImageBboxEditor) self.buttonImagePrev.setObjectName("buttonImagePrev") self.horizontalLayout.addWidget(self.buttonImagePrev) self.buttonDone = QtWidgets.QPushButton(FormImageBboxEditor) self.buttonDone.setObjectName("buttonDone") self.horizontalLayout.addWidget(self.buttonDone) self.verticalLayout.addLayout(self.horizontalLayout) self.verticalLayout.setStretch(0, 3) self.verticalLayout.setStretch(3, 1) self.retranslateUi(FormImageBboxEditor) QtCore.QMetaObject.connectSlotsByName(FormImageBboxEditor)
def initUI(self): vbox = QtGui.QVBoxLayout() # Create the widget that displays the video frame self.pic = ImageWidget() # A horizontal slider to scroll through the video self.sld = QtGui.QSlider(QtCore.Qt.Horizontal) # self.sld.setFocusPolicy(QtCore.Qt.NoFocus) self.sld.setRange(0, self.num_positions) self.sld.setValue(100) self.sld.valueChanged[int].connect(self.change_slider_value) # A special widget that displays the marked ranges and average frame colors # (Is also called slider, because it should later take over the role of the conventional slider) self.sld2 = SliderWidget() # The ranges class manages the marked video ranges and sends them to the widget when changed self.ranges = Ranges(update_function=self.sld2.setRanges) self.load_or_save_ranges(save=False) # A label with a quick introduction man_label = QtGui.QLabel() man_label.setText( "Use the slider to navigate (Mouse + keyboard).\n" + "Q = Start preview range, A = Start ad range, Z = Start ignore range\n" + "D = End current range, Bksp = remove last element.\n Auto-saves on close." ) man_label.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) # Put everything together and show it vbox.addWidget(self.pic) vbox.addWidget(self.sld) vbox.addWidget(self.sld2) vbox.addWidget(man_label) self.setLayout(vbox) self.setWindowTitle('Video Annotator') self.setAcceptDrops(True) self.show()
def __init__(self): QWidget.__init__(self) # loaind ui from xml uic.loadUi(os.path.join(DIRPATH, 'app.ui'), self) # button event handlers self.btnStartCaptureForVideoAnalysis.clicked.connect( self.start_capture_for_video_analysis) self.btnStopCaptureForVideoAnalysis.clicked.connect( self.stop_capture_for_video_analysis) self.btnChooseClassifierXML.clicked.connect( self.choose_classifier_file) self.btnChooseImage.clicked.connect(self.choose_image_for_analysis) self.setup_tray_menu() # add camera ids for i in range(0, 11): self.cboxCameraIds.addItem(str(i)) self.cboxCameraIds1.addItem(str(i)) # setting up handlers for menubar actions self.actionAbout.triggered.connect(self.about) self.actionExit.triggered.connect(qApp.quit) self.actionPreferences.triggered.connect(self.show_preferences) self.img_widget_vid_analysis = ImageWidget() self.hlayoutVideoAnalysis.addWidget(self.img_widget_vid_analysis) self.img_widget_img_analysis = ImageWidget() self.hlayoutImageAnalysis.addWidget(self.img_widget_img_analysis) self.vid_capture = VideoCapture() self.vid_capture.got_image_data_from_camera.connect( self.process_image_data_from_camera) self.highlight_faces = self.chkHighlightFaces.isChecked() self.chkHighlightFaces.stateChanged.connect( self.highlight_faces_checkbox_changed)
def add_log_row(self, log_content_array): # add row to the QTableWidget for logs row_count = self.logs_ui.logs_table.rowCount() self.logs_ui.logs_table.setRowCount(row_count + 1) event_sign_image_path = None # log levels: # debug # info # notice # warning # error if log_content_array["log_event_type"] == "info": info_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/info.png') event_sign_image_path = str(info_png_path) elif log_content_array["log_event_type"] == "warning": warning_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/warning.png') event_sign_image_path = str(warning_png_path) elif log_content_array["log_event_type"] == "notice": notice_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/notice.png') event_sign_image_path = str(notice_png_path) elif log_content_array["log_event_type"] == "debug": debug_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/debug.png') event_sign_image_path = str(debug_png_path) elif log_content_array["log_event_type"] == "success": debug_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/success.png') event_sign_image_path = str(debug_png_path) elif log_content_array["log_event_type"] == "error": error_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/error.png') event_sign_image_path = str(error_png_path) image = ImageWidget(event_sign_image_path, self) widget = QWidget() hbl = QHBoxLayout() hbl.setMargin(0) hbl.setSpacing(0) hbl.addWidget(image) widget.setLayout(hbl) self.logs_ui.logs_table.setCellWidget(row_count, 0, widget) self.logs_ui.logs_table.setItem( row_count, 1, QTableWidgetItem(log_content_array["log_event_type"])) titleitem = QTableWidgetItem(log_content_array["title"]) titleitem.setTextAlignment(QtCore.Qt.AlignCenter) self.logs_ui.logs_table.setItem(row_count, 2, titleitem) self.logs_ui.logs_table.setItem( row_count, 3, QTableWidgetItem(log_content_array["description"])) return 1
def show_start_screen(self, time_ms: int) -> None: """Show start-splashscreen for the given time. The regular UI is shown afterwards. Args: time_ms: Number of miliseconds to actually show the splash-screen """ image_widget = ImageWidget("images/splash_screen.png") v_layout = QVBoxLayout() h_layout = QHBoxLayout() h_layout.addWidget(image_widget) v_layout.addLayout(h_layout) widget = QWidget() widget.setLayout(v_layout) self.setCentralWidget(widget) timer = QTimer(self) timer.singleShot(time_ms, self.on_start_screen_end)
def __init__(self): # call super class super(MainWidget, self).__init__() # get widget self.imageWidget = ImageWidget() self.otherWidget = Profile() # create box layout self.boxLayout = QtGui.QVBoxLayout() # add widget to box self.boxLayout.addWidget(self.imageWidget) self.boxLayout.addStretch() self.boxLayout.addWidget(self.otherWidget) # set layout self.setLayout(self.boxLayout)
def add_log_row(self, log_content_array): # add row to the QTableWidget for logs row_count = self.logs_ui.logs_table.rowCount() self.logs_ui.logs_table.setRowCount(row_count + 1) event_sign_image_path = None if log_content_array['log_event_type'] == 'info': info_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/info.png') event_sign_image_path = str(info_png_path) elif log_content_array['log_event_type'] == 'warning': warning_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/warning.png') event_sign_image_path = str(warning_png_path) elif log_content_array['log_event_type'] == 'notice': notice_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/notice.png') event_sign_image_path = str(notice_png_path) elif log_content_array['log_event_type'] == 'debug': debug_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/debug.png') event_sign_image_path = str(debug_png_path) elif log_content_array['log_event_type'] == 'success': debug_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/success.png') event_sign_image_path = str(debug_png_path) elif log_content_array['log_event_type'] == 'error': error_png_path = os.path.join(os.path.dirname(__file__), 'resources/img/error.png') event_sign_image_path = str(error_png_path) image = ImageWidget(event_sign_image_path, self) widget = QWidget() hbl = QHBoxLayout() hbl.setMargin(0) hbl.setSpacing(0) hbl.addWidget(image) widget.setLayout(hbl) self.logs_ui.logs_table.setCellWidget(row_count, 0, widget) self.logs_ui.logs_table.setItem(row_count, 1, QTableWidgetItem(log_content_array['log_event_type'])) titleitem = QTableWidgetItem(log_content_array['title']) titleitem.setTextAlignment(QtCore.Qt.AlignCenter) self.logs_ui.logs_table.setItem(row_count, 2, titleitem) self.logs_ui.logs_table.setItem(row_count, 3, QTableWidgetItem(log_content_array['description'])) return 1
class AppWindow(QMainWindow): """ Main GUI class for application """ def __init__(self): QWidget.__init__(self) # loaind ui from xml uic.loadUi(os.path.join(DIRPATH, 'app.ui'), self) # FIXME - libpng warning: iCCP: known incorrect sRGB profile self.setWindowIcon(QIcon("./images/robot_icon.png")) # keep the window fixed sized self.setFixedSize(self.size()) # button event handlers self.btnStartCaptureForVideoAnalysis.clicked.connect( self.start_capture_for_video_analysis) self.btnStopCaptureForVideoAnalysis.clicked.connect( self.stop_capture_for_video_analysis) self.btnChooseClassifierXML.clicked.connect( self.choose_classifier_file) self.btnChooseImage.clicked.connect(self.choose_image_for_analysis) self.setup_tray_menu() # add camera ids for i in range(0, 11): self.cboxCameraIds.addItem(str(i)) self.cboxCameraIds1.addItem(str(i)) # setting up handlers for menubar actions self.actionAbout.triggered.connect(self.about) self.actionExit.triggered.connect(qApp.quit) self.actionPreferences.triggered.connect(self.show_preferences) # video analysis image widget self.img_widget_vid_analysis = ImageWidget() self.hlayoutVideoAnalysis.addWidget(self.img_widget_vid_analysis) # face training image widget self.img_widget_face_training = ImageWidget() self.hlayoutFaceTrainingImg.addWidget(self.img_widget_face_training) # face identification image widget self.img_widget_identify_face = ImageWidget() self.hlayoutIdentifyFace.addWidget(self.img_widget_identify_face) # image analysis image widget self.img_widget_img_analysis = ImageWidget() self.hlayoutImageAnalysis.addWidget(self.img_widget_img_analysis) img = cv2.imread("images/human.png") self.img_widget_img_analysis.handle_image_data(img) self.vid_capture = VideoCapture() self.vid_capture.got_image_data_from_camera.connect( self.process_image_data_from_camera) self.highlight_faces = self.chkHighlightFaces.isChecked() self.chkHighlightFaces.stateChanged.connect( self.highlight_faces_checkbox_changed) self.chckGrayscale.stateChanged.connect( self.grayscale_checkbox_changed) # face trainer dataset browser btn handler self.btnBrowseDatasetForFaceTrainer.clicked.connect( self.browse_dataset_for_face_trainer) self.btnBrowseClassifierForFaceTrainer.clicked.connect( self.browse_classifier_file_for_face_trainer) self.btnStartFaceTrainer.clicked.connect(self.start_face_trainer) self.btnBrowseIdentifyFace.clicked.connect(self.browse_identify_face) self.btnTalk.clicked.connect(self.lets_talk) # create and start robot self.robot = Robot(self.lblRobot) self.mouth = Mouth() # connect global signals to slots g_emitter().feed_mouth.connect(self.mouth.feed_text) g_emitter().set_speaking_state.connect(self.robot.set_speaking_state) g_emitter().set_idle_state.connect(self.robot.set_idle_state) self.robot.start() self.mouth.start() def lets_talk(self): text = self.teTalk.toPlainText() self.teTalk.setText("") g_emitter().emit_signal_to_feed_mouth(text) def browse_identify_face(self): fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') self.teIdentifyFace.setText(fname[0]) img = cv2.imread(fname[0]) self.img_widget_identify_face.handle_image_data(img) def start_face_trainer(self): dataset_dir = self.teFaceTrainerDataset.toPlainText() classifier_xml = self.teFaceTrainerClassifier.toPlainText() log.info( "starting face trainer with classifier '%s' and dataset '%s'" % (classifier_xml, dataset_dir)) ft = FaceTrainer(classifier_xml, dataset_dir) ft.processing_image.connect(self.processing_image_for_training) ft.face_training_finished.connect(self.face_training_finished) ft.start() self.lblFaceTrainingStatus.setText("FACE TRAINING UNDER PROGRESS") def face_training_finished(self): self.lblFaceTrainingStatus.setText("FACE TRAINING FINISHED") g_emitter().emit_signal_to_feed_mouth("face training finished") def processing_image_for_training(self, label, fname): log.info("processing image for training: '%s'" % label) self.lblFaceTrainerCurImg.setText("Learning face of: '%s' " % label) try: img = cv2.imread(fname) self.img_widget_face_training.handle_image_data(img) except Exception as exp: log.warning("failed while processing image '%s' while training" % fname) log.warning("Exception: %s" % str(exp)) def browse_dataset_for_face_trainer(self): dataset_dir = str( QFileDialog.getExistingDirectory(self, 'Select directory for dataset', '/home')) log.info("dataset dir file: %s" % dataset_dir) self.teFaceTrainerDataset.setText(dataset_dir) def browse_classifier_file_for_face_trainer(self): classifier_xml = QFileDialog.getOpenFileName(self, 'Open file', '/home') log.info("classifier xml file: %s" % classifier_xml[0]) self.teFaceTrainerClassifier.setText(classifier_xml[0]) def grayscale_checkbox_changed(self): fname = self.teImage.toPlainText() print(fname) img = cv2.imread(fname) if self.chckGrayscale.isChecked(): # convert image to grayscale pil_image = Image.open(fname).convert("L") # convery grayscale image to numpy array image_array = np.array(pil_image, "uint8") # FIXME - code crashes here !!! self.img_widget_img_analysis.handle_image_data(image_array) else: self.img_widget_img_analysis.handle_image_data(img) def highlight_faces_checkbox_changed(self): if self.chkHighlightFaces.isChecked(): print("yes") else: print("no") def choose_classifier_file(self): fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') log.info("chose classfier xml file: %s" % fname[0]) self.teClassifierXML.setText(fname[0]) def choose_image_for_analysis(self): fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') log.info("chose imagefile: %s, for analysis" % fname[0]) self.teImage.setText(fname[0]) img = cv2.imread(fname[0]) self.img_widget_img_analysis.handle_image_data(img) def start_capture_for_video_analysis(self): log.debug("start video capture") self.vid_capture.start() def stop_capture_for_video_analysis(self): log.debug("start video capture") self.vid_capture.stop() self.img_widget_vid_analysis.reset() def detect_face_in_image_data(self, image_data): """ function detects faces in image data, draws rectangle for faces in image data, and returns this updated image data with highlighted face/s """ self._red = (0, 0, 255) self._width = 2 self._min_size = (30, 30) # haarclassifiers work better in black and white gray_image = cv2.cvtColor(image_data, cv2.COLOR_BGR2GRAY) gray_image = cv2.equalizeHist(gray_image) # path to Haar face classfier's xml file face_cascade_xml = './cascades/haarcascades_cuda/haarcascade_frontalface_default.xml' self.classifier = cv2.CascadeClassifier(face_cascade_xml) faces = self.classifier.detectMultiScale(gray_image, scaleFactor=1.3, minNeighbors=4, flags=cv2.CASCADE_SCALE_IMAGE, minSize=self._min_size) for (x, y, w, h) in faces: cv2.rectangle(image_data, (x, y), (x + w, y + h), self._red, self._width) return image_data def process_image_data_from_camera(self, image_data): if self.chkHighlightFaces.isChecked(): image_data = self.detect_face_in_image_data(image_data) self.img_widget_vid_analysis.handle_image_data(image_data) def about(self): ad = AboutDialog() ad.display() def show_preferences(self): print("preferences") pd = PrefsDialog() pd.display() def setup_tray_menu(self): # setting up QSystemTrayIcon self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(QIcon("./images/robot_icon.png")) # tray actions show_action = QAction("Show", self) quit_action = QAction("Exit", self) hide_action = QAction("Hide", self) # action handlers show_action.triggered.connect(self.show) hide_action.triggered.connect(self.hide) quit_action.triggered.connect(qApp.quit) # tray menu tray_menu = QMenu() tray_menu.addAction(show_action) tray_menu.addAction(hide_action) tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.show() def closeEvent(self, event): try: event.ignore() self.hide() self.tray_icon.showMessage("RoboVision", "RoboVision was minimized to Tray", QSystemTrayIcon.Information, 2000) self.robot.stop() self.robot.join() except Exception as exp: log.warning("app close exp: %s" % str(exp)) def ok_pressed(self): log.debug("[AppWindow] :: ok") self.show_msgbox("AppWindow", "Its ok") def show_msgbox(self, title, text): """ Function for showing error/info message box """ msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(text) msg.setWindowTitle(title) msg.setStandardButtons(QMessageBox.Ok) retval = msg.exec_() print("[INFO] Value of pressed message box button:", retval)
#!./venv/bin/python3 import os from PySide2.QtWidgets import (QMainWindow, QApplication, QSizePolicy, QWidget) from PySide2.QtGui import QResizeEvent, QKeyEvent, QDesktopServices from PySide2.QtCore import QSize, Slot, QUrl import bad_practise_global as bpg import custom_log as l from PySide2.QtCore import Qt # from main_level_widget import MainWidget from image_widget import ImageWidget if __name__ == '__main__': # l.disable() import sys app = QApplication(sys.argv) image_widget = ImageWidget() image_widget.show() image_widget.resize(500, 500) # window.resize(bpg.screen_width, bpg.screen_height) sys.exit(app.exec_())
def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.buttonLoadKdenlive = QtWidgets.QPushButton(self.centralwidget) self.buttonLoadKdenlive.setObjectName("buttonLoadKdenlive") self.horizontalLayout_2.addWidget(self.buttonLoadKdenlive) self.buttonLoadImages = QtWidgets.QPushButton(self.centralwidget) self.buttonLoadImages.setObjectName("buttonLoadImages") self.horizontalLayout_2.addWidget(self.buttonLoadImages) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_2.addItem(spacerItem) self.buttonSaveKdenlive = QtWidgets.QPushButton(self.centralwidget) self.buttonSaveKdenlive.setObjectName("buttonSaveKdenlive") self.horizontalLayout_2.addWidget(self.buttonSaveKdenlive) self.buttonSaveBboxesJson = QtWidgets.QPushButton(self.centralwidget) self.buttonSaveBboxesJson.setObjectName("buttonSaveBboxesJson") self.horizontalLayout_2.addWidget(self.buttonSaveBboxesJson) self.verticalLayout.addLayout(self.horizontalLayout_2) self.gridLayout = QtWidgets.QGridLayout() self.gridLayout.setObjectName("gridLayout") self.lineeditTargetVideoResolution = QtWidgets.QLineEdit(self.centralwidget) self.lineeditTargetVideoResolution.setText("") self.lineeditTargetVideoResolution.setObjectName("lineeditTargetVideoResolution") self.gridLayout.addWidget(self.lineeditTargetVideoResolution, 0, 2, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout.addItem(spacerItem1, 0, 3, 1, 1) self.label = QtWidgets.QLabel(self.centralwidget) self.label.setObjectName("label") self.gridLayout.addWidget(self.label, 0, 1, 1, 1) self.verticalLayout.addLayout(self.gridLayout) self.image = ImageWidget(self.centralwidget) self.image.setObjectName("image") self.verticalLayout.addWidget(self.image) self.labelInfoPath = QtWidgets.QLabel(self.centralwidget) self.labelInfoPath.setObjectName("labelInfoPath") self.verticalLayout.addWidget(self.labelInfoPath) self.labelInfoScale = QtWidgets.QLabel(self.centralwidget) self.labelInfoScale.setObjectName("labelInfoScale") self.verticalLayout.addWidget(self.labelInfoScale) self.listView = QtWidgets.QListView(self.centralwidget) self.listView.setObjectName("listView") self.verticalLayout.addWidget(self.listView) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.checkboxStayInside = QtWidgets.QCheckBox(self.centralwidget) self.checkboxStayInside.setChecked(True) self.checkboxStayInside.setObjectName("checkboxStayInside") self.horizontalLayout.addWidget(self.checkboxStayInside) self.buttonSwitchInOutEditor = QtWidgets.QPushButton(self.centralwidget) self.buttonSwitchInOutEditor.setObjectName("buttonSwitchInOutEditor") self.horizontalLayout.addWidget(self.buttonSwitchInOutEditor) self.buttonSwapInOutEditor = QtWidgets.QPushButton(self.centralwidget) self.buttonSwapInOutEditor.setObjectName("buttonSwapInOutEditor") self.horizontalLayout.addWidget(self.buttonSwapInOutEditor) self.buttonImageNext = QtWidgets.QPushButton(self.centralwidget) self.buttonImageNext.setObjectName("buttonImageNext") self.horizontalLayout.addWidget(self.buttonImageNext) self.buttonImagePrev = QtWidgets.QPushButton(self.centralwidget) self.buttonImagePrev.setObjectName("buttonImagePrev") self.horizontalLayout.addWidget(self.buttonImagePrev) self.buttonDone = QtWidgets.QPushButton(self.centralwidget) self.buttonDone.setObjectName("buttonDone") self.horizontalLayout.addWidget(self.buttonDone) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_3 = QtWidgets.QHBoxLayout() self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setObjectName("label_2") self.horizontalLayout_3.addWidget(self.label_2) self.spinboxBboxRatioMultiplier = QtWidgets.QDoubleSpinBox(self.centralwidget) self.spinboxBboxRatioMultiplier.setObjectName("spinboxBboxRatioMultiplier") self.horizontalLayout_3.addWidget(self.spinboxBboxRatioMultiplier) self.buttonApplyBboxRatioMultiplier = QtWidgets.QPushButton(self.centralwidget) self.buttonApplyBboxRatioMultiplier.setObjectName("buttonApplyBboxRatioMultiplier") self.horizontalLayout_3.addWidget(self.buttonApplyBboxRatioMultiplier) spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_3.addItem(spacerItem2) self.verticalLayout.addLayout(self.horizontalLayout_3) self.verticalLayout.setStretch(2, 3) self.verticalLayout.setStretch(5, 1) MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
class ControlWidget(QWidget): def __init__(self, parent=None): super(ControlWidget, self).__init__(parent) self.set_init_settings() self.setup_ui() self.setup_labeling_func() self.setup_file_func() self.set_check() self.set_check_func() self.set_size() self.setFocusPolicy(QtCore.Qt.StrongFocus) def set_size(self): self.l_layout.setAlignment(QtCore.Qt.AlignTop) self.select_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.save_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.delete_button.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.image_w.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.label_w.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.filelist_w.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) self.f_widget.setFixedHeight(40) self.f_2widget.setFixedHeight(40) self.file_name.setFixedHeight(40) self.l_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.r_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) def set_init_settings(self): self.auto_load_next_data = False self.auto_save = True def setup_ui(self): """Initialize widgets. """ self.file_name = QLabel() self.f_widget = self.setup_func_widget() self.f_2widget = self.setup_second_func_widget() self.label_w = LabelWidget(self) self.image_w = ImageWidget(self.label_w, self) self.filelist_w = FilelistWidget(self) self.l_layout = QVBoxLayout() self.l_layout.addWidget(self.file_name) self.l_layout.addWidget(self.image_w) self.l_layout.addWidget(self.f_widget) self.l_layout.addWidget(self.f_2widget) self.l_widget = QWidget() self.l_widget.setLayout(self.l_layout) self.r_layout = QVBoxLayout() self.r_layout.addWidget(self.label_w) self.r_layout.addWidget(self.filelist_w) self.r_widget = QWidget() self.r_widget.setLayout(self.r_layout) self.h_layout = QHBoxLayout() self.h_layout.addWidget(self.l_widget) self.h_layout.addWidget(self.r_widget) self.setLayout(self.h_layout) def setup_func_widget(self): f_widget = QWidget() f_layout = QHBoxLayout() self.select_button = QPushButton("Open Dir") self.select_button.clicked.connect(self.select_dir) self.save_button = QPushButton("Save") self.save_button.clicked.connect(self.save_data) self.delete_button = QPushButton("Delete") self.delete_button.clicked.connect(self.delete_data) self.auto_load_next_data_box = QCheckBox("Auto Load Next") self.auto_save_box = QCheckBox("Auto Save") self.auto_take_over_last_data_box = QCheckBox("Auto Use Last label") f_layout.addWidget(self.select_button) f_layout.addWidget(self.save_button) f_layout.addWidget(self.delete_button) f_layout.addWidget(self.auto_load_next_data_box) f_layout.addWidget(self.auto_save_box) f_layout.addWidget(self.auto_take_over_last_data_box) f_widget.setLayout(f_layout) return f_widget def setup_second_func_widget(self): f_widget = QWidget() f_layout = QHBoxLayout() self.left_button = QPushButton("←") self.left_button.clicked.connect( lambda: self.open_data(self.filelist_w.select_filepath_back())) self.right_button = QPushButton("→") self.right_button.clicked.connect( lambda: self.open_data(self.filelist_w.select_filepath())) f_layout.addWidget(self.left_button) f_layout.addWidget(self.right_button) f_widget.setLayout(f_layout) return f_widget def set_check(self): self.auto_load_next_data_box.setChecked(self.auto_load_next_data) self.auto_save_box.setChecked(self.auto_save) self.auto_take_over_last_data_box.setChecked( self.image_w.auto_take_over_last_data) def set_check_func(self): self.auto_load_next_data_box.stateChanged.connect(self.change_check) self.auto_save_box.stateChanged.connect(self.change_check) self.auto_take_over_last_data_box.stateChanged.connect( self.change_check) def change_check(self): self.auto_load_next_data = self.auto_load_next_data_box.isChecked() self.auto_save = self.auto_save_box.isChecked() self.image_w.auto_take_over_last_data = self.auto_take_over_last_data_box.isChecked( ) def setup_labeling_func(self): for w in self.label_w.level_buttons: w.clicked.connect(self.labeling) def setup_file_func(self): for w in self.filelist_w.filelabel_list: w.clicked.connect(self.clicked_file) def labeling(self): lbutton = self.sender() return self.__f_labeling(int(lbutton.text()) - 1) def __f_labeling(self, level): self.image_w.update_labeling_data(level) if self.auto_load_next_data: if self.image_w.is_last_idx(): self.save_data() self.open_data(self.filelist_w.select_filepath()) return # self.image_w.update_selected_idx() img, level = self.image_w.get_selected_area_image() self.label_w.update_limage(img, level) def save_data(self): self.image_w.save_labeling_data(self.auto_save) def delete_data(self): self.image_w.delete_labeling_data() def select_dir(self): self.filelist_w.select_dir() self.setup_file_func() self.open_data(self.filelist_w.get_selected_path()) def open_data(self, file_path): if file_path: self.save_data() self.file_name.setText(file_path) self.image_w.load_image(file_path, self.filelist_w.selected_idx) img, level = self.image_w.get_selected_area_image() self.label_w.update_limage(img, level) def clicked_file(self): filelabel = self.sender() id = filelabel.id self.save_data() self.open_data(self.filelist_w.select_filepath(id)) def closeEvent(self, event): self.save_data() def keyPressEvent(self, event): if event.modifiers() == QtCore.Qt.ControlModifier: if event.key() == QtCore.Qt.Key_Up: self.image_w.move_selected_idx(v=-1, h=0) if event.key() == QtCore.Qt.Key_Down: self.image_w.move_selected_idx(v=1, h=0) if event.key() == QtCore.Qt.Key_Left: self.image_w.move_selected_idx(v=0, h=-1) if event.key() == QtCore.Qt.Key_Right: self.image_w.move_selected_idx(v=0, h=1) else: if event.key() == QtCore.Qt.Key_Up: self.open_data(self.filelist_w.select_filepath_back()) if event.key() == QtCore.Qt.Key_Down: self.open_data(self.filelist_w.select_filepath()) if event.key() == QtCore.Qt.Key_Left: self.open_data(self.filelist_w.select_filepath_back()) if event.key() == QtCore.Qt.Key_Right: self.open_data(self.filelist_w.select_filepath()) if event.key() == QtCore.Qt.Key_1: self.__f_labeling(0) if event.key() == QtCore.Qt.Key_2: self.__f_labeling(1) if event.key() == QtCore.Qt.Key_3: self.__f_labeling(2)
class AppWindow(QMainWindow): """ Main GUI class for application """ def __init__(self): QWidget.__init__(self) # loaind ui from xml uic.loadUi(os.path.join(DIRPATH, 'app.ui'), self) # button event handlers self.btnStartCaptureForVideoAnalysis.clicked.connect( self.start_capture_for_video_analysis) self.btnStopCaptureForVideoAnalysis.clicked.connect( self.stop_capture_for_video_analysis) self.btnChooseClassifierXML.clicked.connect( self.choose_classifier_file) self.btnChooseImage.clicked.connect(self.choose_image_for_analysis) self.setup_tray_menu() # add camera ids for i in range(0, 11): self.cboxCameraIds.addItem(str(i)) self.cboxCameraIds1.addItem(str(i)) # setting up handlers for menubar actions self.actionAbout.triggered.connect(self.about) self.actionExit.triggered.connect(qApp.quit) self.actionPreferences.triggered.connect(self.show_preferences) self.img_widget_vid_analysis = ImageWidget() self.hlayoutVideoAnalysis.addWidget(self.img_widget_vid_analysis) self.img_widget_img_analysis = ImageWidget() self.hlayoutImageAnalysis.addWidget(self.img_widget_img_analysis) self.vid_capture = VideoCapture() self.vid_capture.got_image_data_from_camera.connect( self.process_image_data_from_camera) self.highlight_faces = self.chkHighlightFaces.isChecked() self.chkHighlightFaces.stateChanged.connect( self.highlight_faces_checkbox_changed) def highlight_faces_checkbox_changed(self): if self.chkHighlightFaces.isChecked(): print("yes") else: print("no") def choose_classifier_file(self): fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') log.info("chose classfier xml file: %s" % fname[0]) self.teClassifierXML.setText(fname[0]) def choose_image_for_analysis(self): fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') log.info("chose imagefile: %s, for analysis" % fname[0]) self.teImage.setText(fname[0]) img = cv2.imread(fname[0]) print("type:", type(img)) #gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #self.img_widget_img_analysis.handle_image_data(image_data) self.img_widget_img_analysis.handle_image_data(img) def start_capture_for_video_analysis(self): log.debug("start video capture") self.vid_capture.start() def stop_capture_for_video_analysis(self): log.debug("start video capture") self.vid_capture.stop() self.img_widget_vid_analysis.reset() def detect_face_in_image_data(self, image_data): """ function detects faces in image data, draws rectangle for faces in image data, and returns this updated image data with highlighted face/s """ self._red = (0, 0, 255) self._width = 2 self._min_size = (30, 30) # haarclassifiers work better in black and white gray_image = cv2.cvtColor(image_data, cv2.COLOR_BGR2GRAY) gray_image = cv2.equalizeHist(gray_image) # path to Haar face classfier's xml file face_cascade_xml = './cascades/haarcascades_cuda/haarcascade_frontalface_default.xml' self.classifier = cv2.CascadeClassifier(face_cascade_xml) faces = self.classifier.detectMultiScale(gray_image, scaleFactor=1.3, minNeighbors=4, flags=cv2.CASCADE_SCALE_IMAGE, minSize=self._min_size) for (x, y, w, h) in faces: cv2.rectangle(image_data, (x, y), (x + w, y + h), self._red, self._width) return image_data def process_image_data_from_camera(self, image_data): if self.chkHighlightFaces.isChecked(): image_data = self.detect_face_in_image_data(image_data) self.img_widget_vid_analysis.handle_image_data(image_data) def about(self): ad = AboutDialog() ad.display() def show_preferences(self): print("preferences") pd = PrefsDialog() pd.display() def setup_tray_menu(self): # setting up QSystemTrayIcon self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(self.style().standardIcon( QStyle.SP_ComputerIcon)) # tray actions show_action = QAction("Show", self) quit_action = QAction("Exit", self) hide_action = QAction("Hide", self) # action handlers show_action.triggered.connect(self.show) hide_action.triggered.connect(self.hide) quit_action.triggered.connect(qApp.quit) # tray menu tray_menu = QMenu() tray_menu.addAction(show_action) tray_menu.addAction(hide_action) tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.show() def closeEvent(self, event): event.ignore() self.hide() self.tray_icon.showMessage("RoboVision", "RoboVision was minimized to Tray", QSystemTrayIcon.Information, 2000) def ok_pressed(self): log.debug("[AppWindow] :: ok") self.show_msgbox("AppWindow", "Its ok") def show_msgbox(self, title, text): """ Function for showing error/info message box """ msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(text) msg.setWindowTitle(title) msg.setStandardButtons(QMessageBox.Ok) retval = msg.exec_() print("[INFO] Value of pressed message box button:", retval)
class AnnotationPlugin(Plugin): def __init__(self, context): """ Annotation plugin to create and edit data sets either by manual annotation or automatically, e.g. using a tracker, and generating larger data sets with data augmentation. :param context: Parent QT widget """ super(AnnotationPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self.widget = QWidget() context.add_widget(self.widget) self.widget.resize(1800, 1000) """left side (current image, grab img button, ...)""" self.cur_im_widget = ImageWidget(self.widget, self.roi_callback, clear_on_click=False) self.cur_im_widget.setGeometry(QRect(20, 20, 640, 480)) self.grab_img_button = QPushButton(self.widget) self.grab_img_button.setText("Grab frame") self.grab_img_button.clicked.connect(self.grab_frame) self.grab_img_button.setGeometry(QRect(20, 600, 100, 50)) """right side (selected image, workspace...)""" self.sel_im_widget = ImageWidget(self.widget, self.roi_callback, clear_on_click=True) self.sel_im_widget.setGeometry(QRect(720, 20, 640, 480)) """list widgets for images and annotations""" self.annotation_list_widget = QListWidget(self.widget) self.annotation_list_widget.setGeometry(QRect(1400, 50, 150, 200)) self.annotation_list_widget.setObjectName("annotation_list_widget") self.annotation_list_widget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.annotation_list_widget.currentItemChanged.connect( self.select_annotation) self.image_list_widget = QListWidget(self.widget) self.image_list_widget.setGeometry(QRect(1550, 50, 250, 500)) self.image_list_widget.setObjectName("image_list_widget") self.image_list_widget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.image_list_widget.currentItemChanged.connect(self.select_image) self.output_path_edit = QLineEdit(self.widget) self.output_path_edit.setGeometry(QRect(1400, 20, 300, 30)) self.output_path_edit.setDisabled(True) self.edit_path_button = QPushButton(self.widget) self.edit_path_button.setText("set ws") self.edit_path_button.setGeometry(QRect(1700, 20, 100, 30)) self.edit_path_button.clicked.connect(self.get_workspace) """ buttons for adding or deleting annotations""" self.add_annotation_button = QPushButton(self.widget) self.add_annotation_button.setText("add") self.add_annotation_button.setGeometry(QRect(1400, 250, 75, 30)) self.add_annotation_button.clicked.connect(self.add_annotation) self.remove_annotation_button = QPushButton(self.widget) self.remove_annotation_button.setText("del") self.remove_annotation_button.setGeometry(QRect(1475, 250, 75, 30)) self.remove_annotation_button.clicked.connect( self.remove_current_annotation) """label combo box, line edit and button for adding labels""" self.option_selector = QComboBox(self.widget) self.option_selector.currentIndexChanged.connect(self.class_change) self.option_selector.setGeometry(1400, 280, 150, 30) self.label_edit = QLineEdit(self.widget) self.label_edit.setGeometry(QRect(1400, 310, 100, 30)) self.label_edit.setDisabled(False) self.edit_label_button = QPushButton(self.widget) self.edit_label_button.setText("add") self.edit_label_button.setGeometry(QRect(1500, 310, 50, 30)) self.edit_label_button.clicked.connect(self.add_label) """ button for image deletion""" self.remove_image_button = QPushButton(self.widget) self.remove_image_button.setText("delete image") self.remove_image_button.setGeometry(QRect(1550, 550, 150, 30)) self.remove_image_button.clicked.connect(self.remove_current_image) """ export data """ self.gen_data_label = QLabel(self.widget) self.gen_data_label.setText("Export workspace: ") self.gen_data_label.setGeometry(QRect(1550, 650, 250, 50)) self.export_ws_button = QPushButton(self.widget) self.export_ws_button.setText("Export") self.export_ws_button.setGeometry(QRect(1550, 700, 125, 50)) self.export_ws_button.clicked.connect(self.export_workspace_to_tf) self.conf_export_button = QPushButton(self.widget) self.conf_export_button.setText("Configure") self.conf_export_button.setGeometry(QRect(1675, 700, 125, 50)) self.conf_export_button.clicked.connect(self.set_export_parameters) """ generate augmented data """ self.gen_data_label = QLabel(self.widget) self.gen_data_label.setText("Generate augmented dataset:") self.gen_data_label.setGeometry(QRect(1550, 800, 250, 50)) self.gen_data_button = QPushButton(self.widget) self.gen_data_button.setText("Generate") self.gen_data_button.setGeometry(QRect(1550, 850, 125, 50)) self.gen_data_button.clicked.connect(self.generate_augmented_data) self.gen_data_button = QPushButton(self.widget) self.gen_data_button.setText("Configure") self.gen_data_button.setGeometry(QRect(1675, 850, 125, 50)) self.gen_data_button.clicked.connect( self.set_data_augmentation_parameters) """ functional stuff""" self.bridge = CvBridge() self.sub = None self.class_id = -1 self.label = "" self.changes_done = False self.workspace = None self.labels = [] self.images_with_annotations = [] self.cur_annotated_image = None self.cur_annotation_index = -1 self.class_change() # export parameters self.default_config_path = None self.pretrained_graph = None self.p_test = 0.2 self.batch_size = 12 # data augmentation parameters self.gen_dir = None self.num_illuminate = 1 self.num_scale = 1 self.num_blur = 1 def set_data_augmentation_parameters(self): self.gen_dir = QFileDialog.getExistingDirectory( self.widget, "Select output directory") num_illum, ok = QInputDialog.getText(self.widget, "Illumination changes per image", "1") if ok: try: self.num_illuminate = int(num_illum) except ValueError: pass num_scale, ok = QInputDialog.getText(self.widget, "Scaling changes per image", "1") if ok: try: self.num_scale = int(num_scale) except ValueError: pass num_blur, ok = QInputDialog.getText(self.widget, "Blurring changes per image", "1") if ok: try: self.num_blur = int(num_blur) except ValueError: pass def generate_augmented_data(self): if self.gen_dir is None: warning_dialog("Warning", "Set parameters first") return data_augmentation.multiply_dataset(self.workspace, self.gen_dir, None, 0, self.num_illuminate, self.num_scale, self.num_blur, 0) print("data augmentation done") def set_export_parameters(self): """ Set variables for export via QInputDialog and QFileDialog. """ # default config path config_path = QFileDialog.getOpenFileName(self.widget, "Select default config") config_path = str(config_path[0]) file, ext = os.path.splitext(config_path) if not ext == ".config": self.default_config_path = None warning_dialog("warning", "invalid file extension") return else: self.default_config_path = config_path # pretrained graph pretrained_graph_dir = QFileDialog.getExistingDirectory( self.widget, "Select pretrained graph directory") self.pretrained_graph = pretrained_graph_dir + "/model.ckpt" # batch size batch_size, ok = QInputDialog.getText(self.widget, "Set batch size", "12") if ok: try: self.batch_size = int(batch_size) except ValueError: pass # test percentage p_test, ok = QInputDialog.getText(self.widget, "Set test percentage", "0.2") if ok: try: self.p_test = float(p_test) except ValueError: pass def export_workspace_to_tf(self): """ Export workspace to training formats. """ if self.default_config_path is None or self.pretrained_graph is None: warning_dialog("Warning", "define default config and pretrained graph first") return tf_utils.export_data_to_tf(self.workspace, self.images_with_annotations, self.labels, self.p_test, self.default_config_path, self.batch_size, self.pretrained_graph, True) tf_utils.create_roi_images(self.workspace, self.images_with_annotations, self.labels) print("Export done") def add_label(self): """ If label doesn't exist yet, add to the list and combo box. """ new_label = str(self.label_edit.text()) if new_label is None or new_label == "": return for label in self.labels: if label[0] == new_label: warning_dialog("warning", "label\"" + label[0] + "\" already exists") return new_label = list((new_label, 0)) self.labels.append(new_label) self.option_selector.addItem(new_label[0]) label_file = self.workspace + "/labels.txt" utils.write_labels(label_file, self.labels) def add_annotation(self): """ Add annotation to current image. Bounding box is just a dummy. Use current label. """ if self.class_id == -1 or self.label == "": warning_dialog("Warning", "select label first") return if self.cur_annotated_image is None: warning_dialog("Warning", "select image first") return label = self.option_selector.currentText() annotation = utils.AnnotationWithBbox(self.class_id, 1.0, 0.5, 0.5, 1, 1) self.cur_annotated_image.annotation_list.append(annotation) index = len(self.cur_annotated_image.annotation_list) - 1 self.add_annotation_to_list_widget(index, label, True) self.changes_done = True def class_change(self): """ Called another label is selected in the combo box. Set current label and class id. """ self.label = self.option_selector.currentText() if self.labels is None or len(self.labels) == 0: return self.class_id = [i[0] for i in self.labels].index(self.label) # num_annotations = self.labels[self.class_id][1] def select_annotation(self): """ Called when an annotation is selected. The corresponding bounding box is drawn thicker, enables drawing on the image widget. """ item = self.annotation_list_widget.currentItem() if item is None: self.sel_im_widget.set_active(False) self.sel_im_widget.clear() return text = str(item.text()) index = text.split(":")[0] self.cur_annotation_index = int(index) self.show_image_from_workspace() self.sel_im_widget.set_active(True) def select_image(self): """ Called when an image from the list is selected. Save annotations, if changes were made. Then show selected image and its annotation list. """ if self.changes_done: utils.save_annotations(self.cur_annotated_image.image_file, self.cur_annotated_image.annotation_list) self.changes_done = False item = self.image_list_widget.currentItem() if item is None: return image_file = self.workspace + str(item.text()) self.cur_annotated_image = None for img in self.images_with_annotations: if img.image_file == image_file: self.cur_annotated_image = img if self.cur_annotated_image is not None: self.show_image_from_workspace() self.set_annotation_list() def set_annotation_list(self): """ Set list of annotations for the current image. """ self.annotation_list_widget.clear() self.cur_annotation_index = -1 for i in range(len(self.cur_annotated_image.annotation_list)): index = int(self.cur_annotated_image.annotation_list[i].label) num_labels = len(self.labels) if index < num_labels: self.add_annotation_to_list_widget(i, self.labels[index][0]) else: self.add_annotation_to_list_widget(i, "unknown") self.show_image_from_workspace() def add_annotation_to_list_widget(self, index, label, select=False): """ Add a QListWidgetItem to the annotation QListWidget :param index: index in annotation list :param label: label of annotation :param select: select new item or not """ item = QListWidgetItem() item.setText(str(index) + ":" + label) self.annotation_list_widget.addItem(item) if select: self.annotation_list_widget.setCurrentItem(item) self.select_annotation() def add_image_to_list_widget(self, file_name, select=False): """ Add a QListWidgetItem to the image QListWidget :param file_name: image file name :param select: select new item or not """ item = QListWidgetItem() item.setText(file_name) self.image_list_widget.addItem(item) if select: self.image_list_widget.setCurrentItem(item) self.select_image() def refresh_image_list_widget(self): """ Clear and fill image list widget """ self.image_list_widget.clear() for img in self.images_with_annotations: self.add_image_to_list_widget( img.image_file.replace(self.workspace, "")) def remove_current_annotation(self): """ Remove currently selected annotation """ if self.cur_annotation_index == -1: warning_dialog("Warning", "no annotation selected") return del (self.cur_annotated_image.annotation_list[ self.cur_annotation_index]) self.set_annotation_list() def remove_current_image(self): """ Remove currently selected image. Remove ItemWidget and delete files """ if self.cur_annotated_image is None: warning_dialog("Warning", "no image selected") return image_file = self.cur_annotated_image.image_file label_file = image_file.replace("images", "labels").replace("jpg", "txt") self.image_list_widget.removeItemWidget( self.image_list_widget.currentItem()) self.images_with_annotations.remove(self.cur_annotated_image) os.remove(image_file) if os.path.isfile(label_file): os.remove(label_file) self.refresh_image_list_widget() def get_workspace(self): """ Gets and sets the output directory via a QFileDialog. Save before, if changes were done. """ if self.changes_done: utils.save_annotations(self.cur_annotated_image.image_file, self.cur_annotated_image.annotation_list) self.changes_done = False self.load_workspace( QFileDialog.getExistingDirectory(self.widget, "Select output directory")) def load_workspace(self, path): """ Sets the workspace directory. Checks for missing directories and files, then loads all images, annotations & label list. :param path: The path of the directory """ if not path: path = "/tmp" self.workspace = path self.output_path_edit.setText(path) # clear all lists and references self.labels = [] self.cur_annotation_index = -1 self.cur_annotated_image = None self.images_with_annotations = [] self.changes_done = False self.class_id = -1 self.label = "" # clear combo box and listWidgets self.option_selector.clear() self.image_list_widget.clear() self.annotation_list_widget.clear() if utils.check_workspace(self.workspace): image_dir = self.workspace + "/images" label_file = self.workspace + "/labels.txt" self.labels = utils.read_labels(label_file) for label in self.labels: self.option_selector.addItem(label[0]) for dirname, dirnames, filenames in os.walk(image_dir): for filename in sorted(filenames): image_file = dirname + '/' + filename label_file = image_file.replace( "images", "labels").replace(".jpg", ".txt").replace(".png", ".txt") annotated_image = utils.read_annotated_image( image_file, label_file) self.images_with_annotations.append(annotated_image) self.add_image_to_list_widget("/images/" + filename) print("workspace loaded successfully") def grab_frame(self): """ Grab current frame, save to workspace and show it.""" if self.workspace is None or self.workspace == "": warning_dialog("Warning", "select workspace first") return cv_image = self.cur_im_widget.get_image() if cv_image is None: warning_dialog("warning", "no frame to grab") return file_name = "/images/{}.jpg".format( datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-%S_%f")) new_image = utils.AnnotatedImage(self.workspace + file_name, []) self.cur_annotated_image = new_image self.images_with_annotations.append(new_image) cv2.imwrite(self.workspace + file_name, cv_image) self.add_image_to_list_widget(file_name, True) self.select_image() # self.sel_im_widget.set_image(cv_image, None, None) def roi_callback(self): """ Called when a roi is drawn on an image_widget. Edit annotation if possible. """ if self.class_id == -1 or self.label == "": warning_dialog("Warning", "select label first") self.changes_done = True return if self.cur_annotation_index < 0: warning_dialog("Warning", "select annotation first") self.changes_done = True return # set bounding box x_center, y_center, width, height = self.sel_im_widget.get_normalized_roi( ) annotation = self.cur_annotated_image.annotation_list[ self.cur_annotation_index] annotation.bbox = utils.BoundingBox(x_center, y_center, width, height) # set selected label self.label = self.option_selector.currentText() if self.labels is None or len(self.labels) == 0: return self.class_id = [i[0] for i in self.labels].index(self.label) annotation.label = self.class_id self.set_annotation_list() self.show_image_from_workspace() self.sel_im_widget.clear() self.changes_done = True def show_image_from_workspace(self): """ Show current selected image and annotations """ if self.cur_annotated_image is None: return img = cv2.imread(self.cur_annotated_image.image_file) if img is not None: self.sel_im_widget.set_image( img, self.cur_annotated_image.annotation_list, self.cur_annotation_index) def image_callback(self, msg): """ Called when a new sensor_msgs/Image is coming in :param msg: The image message """ try: cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") except CvBridgeError as e: rospy.logerr(e) self.cur_im_widget.set_image(cv_image, None, None) def trigger_configuration(self): """ Callback when the configuration button is clicked """ topic_name, ok = QInputDialog.getItem( self.widget, "Select topic name", "Topic name", rostopic.find_by_type('sensor_msgs/Image')) if ok: self.create_subscriber(topic_name) def create_subscriber(self, topic_name): """ Method that creates a subscriber to a sensor_msgs/Image topic :param topic_name: The topic_name """ if self.sub: self.sub.unregister() self.sub = rospy.Subscriber(topic_name, Image, self.image_callback) rospy.loginfo("Listening to %s -- spinning .." % self.sub.name) self.widget.setWindowTitle("Label plugin, listening to (%s)" % self.sub.name) def shutdown_plugin(self): """ Callback function when shutdown is requested """ if self.changes_done: utils.save_annotations(self.cur_annotated_image.image_file, self.cur_annotated_image.annotation_list) def save_settings(self, plugin_settings, instance_settings): """ Callback function on shutdown to store the local plugin variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ instance_settings.set_value("workspace_dir", self.workspace) def restore_settings(self, plugin_settings, instance_settings): """ Callback function fired on load of the plugin that allows to restore saved variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ workspace = None try: workspace = instance_settings.value("workspace_dir") except: pass self.load_workspace(workspace) self.create_subscriber( str(instance_settings.value("topic_name", "/xtion/rgb/image_raw")))
def __init__(self, context): """ Annotation plugin to create and edit data sets either by manual annotation or automatically, e.g. using a tracker, and generating larger data sets with data augmentation. :param context: Parent QT widget """ super(AnnotationPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self.widget = QWidget() context.add_widget(self.widget) self.widget.resize(1800, 1000) """left side (current image, grab img button, ...)""" self.cur_im_widget = ImageWidget(self.widget, self.roi_callback, clear_on_click=False) self.cur_im_widget.setGeometry(QRect(20, 20, 640, 480)) self.grab_img_button = QPushButton(self.widget) self.grab_img_button.setText("Grab frame") self.grab_img_button.clicked.connect(self.grab_frame) self.grab_img_button.setGeometry(QRect(20, 600, 100, 50)) """right side (selected image, workspace...)""" self.sel_im_widget = ImageWidget(self.widget, self.roi_callback, clear_on_click=True) self.sel_im_widget.setGeometry(QRect(720, 20, 640, 480)) """list widgets for images and annotations""" self.annotation_list_widget = QListWidget(self.widget) self.annotation_list_widget.setGeometry(QRect(1400, 50, 150, 200)) self.annotation_list_widget.setObjectName("annotation_list_widget") self.annotation_list_widget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.annotation_list_widget.currentItemChanged.connect( self.select_annotation) self.image_list_widget = QListWidget(self.widget) self.image_list_widget.setGeometry(QRect(1550, 50, 250, 500)) self.image_list_widget.setObjectName("image_list_widget") self.image_list_widget.setSelectionMode( QAbstractItemView.ExtendedSelection) self.image_list_widget.currentItemChanged.connect(self.select_image) self.output_path_edit = QLineEdit(self.widget) self.output_path_edit.setGeometry(QRect(1400, 20, 300, 30)) self.output_path_edit.setDisabled(True) self.edit_path_button = QPushButton(self.widget) self.edit_path_button.setText("set ws") self.edit_path_button.setGeometry(QRect(1700, 20, 100, 30)) self.edit_path_button.clicked.connect(self.get_workspace) """ buttons for adding or deleting annotations""" self.add_annotation_button = QPushButton(self.widget) self.add_annotation_button.setText("add") self.add_annotation_button.setGeometry(QRect(1400, 250, 75, 30)) self.add_annotation_button.clicked.connect(self.add_annotation) self.remove_annotation_button = QPushButton(self.widget) self.remove_annotation_button.setText("del") self.remove_annotation_button.setGeometry(QRect(1475, 250, 75, 30)) self.remove_annotation_button.clicked.connect( self.remove_current_annotation) """label combo box, line edit and button for adding labels""" self.option_selector = QComboBox(self.widget) self.option_selector.currentIndexChanged.connect(self.class_change) self.option_selector.setGeometry(1400, 280, 150, 30) self.label_edit = QLineEdit(self.widget) self.label_edit.setGeometry(QRect(1400, 310, 100, 30)) self.label_edit.setDisabled(False) self.edit_label_button = QPushButton(self.widget) self.edit_label_button.setText("add") self.edit_label_button.setGeometry(QRect(1500, 310, 50, 30)) self.edit_label_button.clicked.connect(self.add_label) """ button for image deletion""" self.remove_image_button = QPushButton(self.widget) self.remove_image_button.setText("delete image") self.remove_image_button.setGeometry(QRect(1550, 550, 150, 30)) self.remove_image_button.clicked.connect(self.remove_current_image) """ export data """ self.gen_data_label = QLabel(self.widget) self.gen_data_label.setText("Export workspace: ") self.gen_data_label.setGeometry(QRect(1550, 650, 250, 50)) self.export_ws_button = QPushButton(self.widget) self.export_ws_button.setText("Export") self.export_ws_button.setGeometry(QRect(1550, 700, 125, 50)) self.export_ws_button.clicked.connect(self.export_workspace_to_tf) self.conf_export_button = QPushButton(self.widget) self.conf_export_button.setText("Configure") self.conf_export_button.setGeometry(QRect(1675, 700, 125, 50)) self.conf_export_button.clicked.connect(self.set_export_parameters) """ generate augmented data """ self.gen_data_label = QLabel(self.widget) self.gen_data_label.setText("Generate augmented dataset:") self.gen_data_label.setGeometry(QRect(1550, 800, 250, 50)) self.gen_data_button = QPushButton(self.widget) self.gen_data_button.setText("Generate") self.gen_data_button.setGeometry(QRect(1550, 850, 125, 50)) self.gen_data_button.clicked.connect(self.generate_augmented_data) self.gen_data_button = QPushButton(self.widget) self.gen_data_button.setText("Configure") self.gen_data_button.setGeometry(QRect(1675, 850, 125, 50)) self.gen_data_button.clicked.connect( self.set_data_augmentation_parameters) """ functional stuff""" self.bridge = CvBridge() self.sub = None self.class_id = -1 self.label = "" self.changes_done = False self.workspace = None self.labels = [] self.images_with_annotations = [] self.cur_annotated_image = None self.cur_annotation_index = -1 self.class_change() # export parameters self.default_config_path = None self.pretrained_graph = None self.p_test = 0.2 self.batch_size = 12 # data augmentation parameters self.gen_dir = None self.num_illuminate = 1 self.num_scale = 1 self.num_blur = 1
class AnnotationPlugin(Plugin): def __init__(self, context): """ Annotation plugin to create data sets or test the Annotate.srv service :param context: Parent QT widget """ super(AnnotationPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback, clear_on_click=True) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._edit_path_button = QPushButton("Edit path") self._edit_path_button.clicked.connect(self._get_output_directory) grid_layout.addWidget(self._edit_path_button, 1, 1) self._output_path_edit = QLineEdit() self._output_path_edit.setDisabled(True) grid_layout.addWidget(self._output_path_edit, 1, 2) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._save_button = QPushButton("Annotate again!") self._save_button.clicked.connect(self.annotate_again_clicked) grid_layout.addWidget(self._save_button, 2, 3) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber to None self._sub = None self._srv = None self.labels = [] self.label = "" self.output_directory = "" def image_roi_callback(self, roi_image): """ Callback from the image widget when the user has selected a ROI :param roi_image: The opencv image of the ROI """ if not self.labels: warning_dialog( "No labels specified!", "Please first specify some labels using the 'Edit labels' button" ) return height, width = roi_image.shape[:2] option = option_dialog("Label", self.labels) if option: self.label = option self._image_widget.add_detection(0, 0, width, height, option) self.annotate(roi_image) def annotate_again_clicked(self): """ Triggered when button clicked """ roi_image = self._image_widget.get_roi_image() if roi_image is not None: self.annotate(roi_image) def annotate(self, roi_image): """ Create an annotation :param roi_image: The image we want to annotate """ self.annotate_srv(roi_image) self.store_image(roi_image) def annotate_srv(self, roi_image): """ Call the selected Annotate.srv :param roi_image: The full opencv image we want to annotate """ if roi_image is not None and self.label is not None and self._srv is not None: height, width = roi_image.shape[:2] try: self._srv(image=self.bridge.cv2_to_imgmsg(roi_image, "bgr8"), annotations=[ Annotation(label=self.label, roi=RegionOfInterest(x_offset=0, y_offset=0, width=width, height=height)) ]) except Exception as e: warning_dialog("Service Exception", str(e)) def _create_service_client(self, srv_name): """ Create a service client proxy :param srv_name: Name of the service """ if self._srv: self._srv.close() if srv_name in rosservice.get_service_list(): rospy.loginfo("Creating proxy for service '%s'" % srv_name) self._srv = rospy.ServiceProxy( srv_name, rosservice.get_service_class_by_name(srv_name)) def store_image(self, roi_image): """ Store the image :param roi_image: Image we would like to store """ if roi_image is not None and self.label is not None and self.output_directory is not None: image_writer.write_annotated(self.output_directory, roi_image, self.label, True) def _get_output_directory(self): """ Gets and sets the output directory via a QFileDialog """ self._set_output_directory( QFileDialog.getExistingDirectory(self._widget, "Select output directory")) def _set_output_directory(self, path): """ Sets the output directory :param path: The path of the directory """ if not path: path = "/tmp" self.output_directory = path self._output_path_edit.setText("Saving images to %s" % path) def _get_labels(self): """ Gets and sets the labels """ text, ok = QInputDialog.getText( self._widget, 'Text Input Dialog', 'Type labels semicolon separated, e.g. banana;apple:', QLineEdit.Normal, ";".join(self.labels)) if ok: labels = set([ _sanitize(label) for label in str(text).split(";") if _sanitize(label) ]) # Sanitize to alphanumeric, exclude spaces self._set_labels(labels) def _set_labels(self, labels): """ Sets the labels :param labels: label string array """ if not labels: labels = [] self.labels = labels self._labels_edit.setText("%s" % labels) def _image_callback(self, msg): """ Called when a new sensor_msgs/Image is coming in :param msg: The image messaeg """ try: cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") except CvBridgeError as e: rospy.logerr(e) self._image_widget.set_image(cv_image) def trigger_configuration(self): """ Callback when the configuration button is clicked """ topic_name, ok = QInputDialog.getItem( self._widget, "Select topic name", "Topic name", rostopic.find_by_type('sensor_msgs/Image')) if ok: self._create_subscriber(topic_name) available_rosservices = [] for s in rosservice.get_service_list(): try: if rosservice.get_service_type(s) in _SUPPORTED_SERVICES: available_rosservices.append(s) except: pass srv_name, ok = QInputDialog.getItem(self._widget, "Select service name", "Service name", available_rosservices) if ok: self._create_service_client(srv_name) def _create_subscriber(self, topic_name): """ Method that creates a subscriber to a sensor_msgs/Image topic :param topic_name: The topic_name """ if self._sub: self._sub.unregister() self._sub = rospy.Subscriber(topic_name, Image, self._image_callback) rospy.loginfo("Listening to %s -- spinning .." % self._sub.name) self._widget.setWindowTitle("Label plugin, listening to (%s)" % self._sub.name) def shutdown_plugin(self): """ Callback function when shutdown is requested """ pass def save_settings(self, plugin_settings, instance_settings): """ Callback function on shutdown to store the local plugin variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ instance_settings.set_value("output_directory", self.output_directory) instance_settings.set_value("labels", self.labels) if self._sub: instance_settings.set_value("topic_name", self._sub.name) def restore_settings(self, plugin_settings, instance_settings): """ Callback function fired on load of the plugin that allows to restore saved variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ path = None try: path = instance_settings.value("output_directory") except: pass self._set_output_directory(path) labels = None try: labels = instance_settings.value("labels") except: pass self._set_labels(labels) self._create_subscriber( str(instance_settings.value("topic_name", "/usb_cam/image_raw"))) self._create_service_client( str( instance_settings.value("service_name", "/image_recognition/my_service")))
def __init__(self): QWidget.__init__(self) # loaind ui from xml uic.loadUi(os.path.join(DIRPATH, 'app.ui'), self) # FIXME - libpng warning: iCCP: known incorrect sRGB profile self.setWindowIcon(QIcon("./images/robot_icon.png")) # keep the window fixed sized self.setFixedSize(self.size()) # button event handlers self.btnStartCaptureForVideoAnalysis.clicked.connect( self.start_capture_for_video_analysis) self.btnStopCaptureForVideoAnalysis.clicked.connect( self.stop_capture_for_video_analysis) self.btnChooseClassifierXML.clicked.connect( self.choose_classifier_file) self.btnChooseImage.clicked.connect(self.choose_image_for_analysis) self.setup_tray_menu() # add camera ids for i in range(0, 11): self.cboxCameraIds.addItem(str(i)) self.cboxCameraIds1.addItem(str(i)) # setting up handlers for menubar actions self.actionAbout.triggered.connect(self.about) self.actionExit.triggered.connect(qApp.quit) self.actionPreferences.triggered.connect(self.show_preferences) # video analysis image widget self.img_widget_vid_analysis = ImageWidget() self.hlayoutVideoAnalysis.addWidget(self.img_widget_vid_analysis) # face training image widget self.img_widget_face_training = ImageWidget() self.hlayoutFaceTrainingImg.addWidget(self.img_widget_face_training) # face identification image widget self.img_widget_identify_face = ImageWidget() self.hlayoutIdentifyFace.addWidget(self.img_widget_identify_face) # image analysis image widget self.img_widget_img_analysis = ImageWidget() self.hlayoutImageAnalysis.addWidget(self.img_widget_img_analysis) img = cv2.imread("images/human.png") self.img_widget_img_analysis.handle_image_data(img) self.vid_capture = VideoCapture() self.vid_capture.got_image_data_from_camera.connect( self.process_image_data_from_camera) self.highlight_faces = self.chkHighlightFaces.isChecked() self.chkHighlightFaces.stateChanged.connect( self.highlight_faces_checkbox_changed) self.chckGrayscale.stateChanged.connect( self.grayscale_checkbox_changed) # face trainer dataset browser btn handler self.btnBrowseDatasetForFaceTrainer.clicked.connect( self.browse_dataset_for_face_trainer) self.btnBrowseClassifierForFaceTrainer.clicked.connect( self.browse_classifier_file_for_face_trainer) self.btnStartFaceTrainer.clicked.connect(self.start_face_trainer) self.btnBrowseIdentifyFace.clicked.connect(self.browse_identify_face) self.btnTalk.clicked.connect(self.lets_talk) # create and start robot self.robot = Robot(self.lblRobot) self.mouth = Mouth() # connect global signals to slots g_emitter().feed_mouth.connect(self.mouth.feed_text) g_emitter().set_speaking_state.connect(self.robot.set_speaking_state) g_emitter().set_idle_state.connect(self.robot.set_idle_state) self.robot.start() self.mouth.start()
class TestPlugin(Plugin): def __init__(self, context): super(TestPlugin, self).__init__(context) # Widget setup self.setObjectName('Test Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._info = QLineEdit() self._info.setDisabled(True) self._info.setText( "Draw a rectangle on the screen to perform object recognition of that ROI" ) layout.addWidget(self._info) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber and service to None self._sub = None self._srv = None def image_roi_callback(self, roi_image): if self._srv is None: warning_dialog( "No service specified!", "Please first specify a service via the options button (top-right gear wheel)" ) return try: result = self._srv( image=self.bridge.cv2_to_imgmsg(roi_image, "bgr8")) except Exception as e: warning_dialog("Service Exception", str(e)) return text_array = [ "%s: %.2f" % (r.label, r.probability) for r in result.recognitions ] if text_array: self._image_widget.set_text( text_array[0]) # Show first option in the image option_dialog("Classification results", text_array) # Show all results in a dropdown def _image_callback(self, msg): try: cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") except CvBridgeError as e: rospy.logerr(e) self._image_widget.set_image(cv_image) def trigger_configuration(self): topic_name, ok = QInputDialog.getItem( self._widget, "Select topic name", "Topic name", rostopic.find_by_type('sensor_msgs/Image')) if ok: self._create_subscriber(topic_name) available_rosservices = [] for s in rosservice.get_service_list(): try: if rosservice.get_service_type( s) == "object_recognition_srvs/Recognize": available_rosservices.append(s) except: pass srv_name, ok = QInputDialog.getItem(self._widget, "Select service name", "Service name", available_rosservices) if ok: self._create_service_client(srv_name) def _create_subscriber(self, topic_name): if self._sub: self._sub.unregister() self._sub = rospy.Subscriber(topic_name, Image, self._image_callback) rospy.loginfo("Listening to %s -- spinning .." % self._sub.name) self._widget.setWindowTitle("Test plugin, listening to (%s)" % self._sub.name) def _create_service_client(self, srv_name): if self._srv: self._srv.close() rospy.loginfo("Creating proxy for service '%s'" % srv_name) self._srv = rospy.ServiceProxy(srv_name, Recognize) def shutdown_plugin(self): pass def save_settings(self, plugin_settings, instance_settings): if self._sub: instance_settings.set_value("topic_name", self._sub.name) def restore_settings(self, plugin_settings, instance_settings): self._create_subscriber( str(instance_settings.value("topic_name", "/usb_cam/image_raw"))) self._create_service_client( str( instance_settings.value("service_name", "/object_recognition/blaat")))
class ManualPlugin(Plugin): def __init__(self, context): """ ManualPlugin class that performs a manual recognition based on a request :param context: QT context, aka parent """ super(ManualPlugin, self).__init__(context) # Widget setup self.setObjectName('Manual Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._done_recognizing_button = QPushButton("Done recognizing..") self._done_recognizing_button.clicked.connect(self._done_recognizing) self._done_recognizing_button.setDisabled(True) grid_layout.addWidget(self._done_recognizing_button, 3, 2) # Bridge for opencv conversion self.bridge = CvBridge() # Set service to None self._srv = None self._srv_name = None self._response = RecognizeResponse() self._recognizing = False def _get_labels(self): """ Gets and sets the labels """ text, ok = QInputDialog.getText(self._widget, 'Text Input Dialog', 'Type labels semicolon separated, e.g. banana;apple:', QLineEdit.Normal, ";".join(self.labels)) if ok: # Sanitize to alphanumeric, exclude spaces labels = set([_sanitize(label) for label in str(text).split(";") if _sanitize(label)]) self._set_labels(labels) def _set_labels(self, labels): """ Sets the labels :param labels: label string array """ if not labels: labels = [] self.labels = labels self._labels_edit.setText("%s" % labels) def _done_recognizing(self): self._image_widget.clear() self._recognizing = False def recognize_srv_callback(self, req): """ Method callback for the Recognize.srv :param req: The service request """ self._response.recognitions = [] self._recognizing = True try: cv_image = self.bridge.imgmsg_to_cv2(req.image, "bgr8") except CvBridgeError as e: rospy.logerr(e) self._image_widget.set_image(cv_image) self._done_recognizing_button.setDisabled(False) timeout = 60.0 # Maximum of 60 seconds future = rospy.Time.now() + rospy.Duration(timeout) rospy.loginfo("Waiting for manual recognition, maximum of %d seconds", timeout) while not rospy.is_shutdown() and self._recognizing: if rospy.Time.now() > future: raise rospy.ServiceException("Timeout of %d seconds exceeded .." % timeout) rospy.sleep(rospy.Duration(0.1)) self._done_recognizing_button.setDisabled(True) return self._response def image_roi_callback(self, roi_image): """ Callback triggered when the user has drawn an ROI on the image :param roi_image: The opencv image in the ROI """ if not self.labels: warning_dialog("No labels specified!", "Please first specify some labels using the 'Edit labels' button") return height, width = roi_image.shape[:2] option = option_dialog("Label", self.labels) if option: self._image_widget.add_detection(0, 0, width, height, option) self._stage_recognition(self._image_widget.get_roi(), option) def _stage_recognition(self, roi, label): """ Stage a manual recognition :param roi: ROI :param label: The label """ x, y, width, height = roi r = Recognition(roi=RegionOfInterest(x_offset=x, y_offset=y, width=width, height=height)) r.categorical_distribution.probabilities = [CategoryProbability(label=label, probability=1.0)] r.categorical_distribution.unknown_probability = 0.0 self._response.recognitions.append(r) def trigger_configuration(self): """ Callback when the configuration button is clicked """ srv_name, ok = QInputDialog.getText(self._widget, "Select service name", "Service name") if ok: self._create_service_server(srv_name) def _create_service_server(self, srv_name): """ Method that creates a service server for a Recognize.srv :param srv_name: """ if self._srv: self._srv.shutdown() if srv_name: rospy.loginfo("Creating service '%s'" % srv_name) self._srv_name = srv_name self._srv = rospy.Service(srv_name, Recognize, self.recognize_srv_callback) def shutdown_plugin(self): """ Callback function when shutdown is requested """ pass def save_settings(self, plugin_settings, instance_settings): """ Callback function on shutdown to store the local plugin variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ instance_settings.set_value("labels", self.labels) if self._srv: instance_settings.set_value("srv_name", self._srv_name) def restore_settings(self, plugin_settings, instance_settings): """ Callback function fired on load of the plugin that allows to restore saved variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ labels = None try: labels = instance_settings.value("labels") except: pass self._set_labels(labels) self._create_service_server(str(instance_settings.value("srv_name", "/my_recognition_service")))
class LabelPlugin(Plugin): def __init__(self, context): super(LabelPlugin, self).__init__(context) # Widget setup self.setObjectName('Label Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._edit_path_button = QPushButton("Edit path") self._edit_path_button.clicked.connect(self._get_output_directory) grid_layout.addWidget(self._edit_path_button, 1, 1) self._output_path_edit = QLineEdit() self._output_path_edit.setDisabled(True) grid_layout.addWidget(self._output_path_edit, 1, 2) self._labels_edit = QLineEdit() self._labels_edit.setDisabled(True) grid_layout.addWidget(self._labels_edit, 2, 2) self._edit_labels_button = QPushButton("Edit labels") self._edit_labels_button.clicked.connect(self._get_labels) grid_layout.addWidget(self._edit_labels_button, 2, 1) self._save_button = QPushButton("Save another one") self._save_button.clicked.connect(self.store_image) grid_layout.addWidget(self._save_button, 2, 3) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber to None self._sub = None self.labels = [] self.roi_image = None self.label = "" self.output_directory = "" def image_roi_callback(self, roi_image): if not self.labels: warning_dialog( "No labels specified!", "Please first specify some labels using the 'Edit labels' button" ) return self.roi_image = roi_image option = option_dialog("Label", self.labels) if option: self.label = option self._image_widget.set_text(option) self.store_image() def store_image(self): if not None in [self.roi_image, self.label, self.output_directory]: _write_image_to_file(self.output_directory, self.roi_image, self.label) def _get_output_directory(self): self._set_output_directory( QFileDialog.getExistingDirectory(self._widget, "Select output directory")) def _set_output_directory(self, path): if not path: path = "/tmp" self.output_directory = path self._output_path_edit.setText("Saving images to %s" % path) def _get_labels(self): text, ok = QInputDialog.getText( self._widget, 'Text Input Dialog', 'Type labels semicolon separated, e.g. banana;apple:', QLineEdit.Normal, ";".join(self.labels)) if ok: labels = set([ _sanitize(label) for label in str(text).split(";") if _sanitize(label) ]) # Sanitize to alphanumeric, exclude spaces self._set_labels(labels) def _set_labels(self, labels): if not labels: labels = [] self.labels = labels self._labels_edit.setText("%s" % labels) def _image_callback(self, msg): try: cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") except CvBridgeError as e: rospy.logerr(e) self._image_widget.set_image(cv_image) def trigger_configuration(self): topic_name, ok = QInputDialog.getItem( self._widget, "Select topic name", "Topic name", rostopic.find_by_type('sensor_msgs/Image')) if ok: self._create_subscriber(topic_name) def _create_subscriber(self, topic_name): if self._sub: self._sub.unregister() self._sub = rospy.Subscriber(topic_name, Image, self._image_callback) rospy.loginfo("Listening to %s -- spinning .." % self._sub.name) self._widget.setWindowTitle("Label plugin, listening to (%s)" % self._sub.name) def shutdown_plugin(self): pass def save_settings(self, plugin_settings, instance_settings): instance_settings.set_value("output_directory", self.output_directory) instance_settings.set_value("labels", self.labels) if self._sub: instance_settings.set_value("topic_name", self._sub.name) def restore_settings(self, plugin_settings, instance_settings): path = None try: path = instance_settings.value("output_directory") except: pass self._set_output_directory(path) labels = None try: labels = instance_settings.value("labels") except: pass self._set_labels(labels) self._create_subscriber( str(instance_settings.value("topic_name", "/usb_cam/image_raw")))
class TestPlugin(Plugin): def __init__(self, context): """ TestPlugin class to evaluate the image_recognition_msgs interfaces :param context: QT context, aka parent """ super(TestPlugin, self).__init__(context) # Widget setup self.setObjectName('Test Plugin') self._widget = QWidget() context.add_widget(self._widget) # Layout and attach to widget layout = QVBoxLayout() self._widget.setLayout(layout) self._image_widget = ImageWidget(self._widget, self.image_roi_callback, clear_on_click=True) layout.addWidget(self._image_widget) # Input field grid_layout = QGridLayout() layout.addLayout(grid_layout) self._info = QLineEdit() self._info.setDisabled(True) self._info.setText( "Draw a rectangle on the screen to perform recognition of that ROI" ) layout.addWidget(self._info) # Bridge for opencv conversion self.bridge = CvBridge() # Set subscriber and service to None self._sub = None self._srv = None def recognize_srv_call(self, roi_image): """ Method that calls the Recognize.srv :param roi_image: Selected roi_image by the user """ try: result = self._srv( image=self.bridge.cv2_to_imgmsg(roi_image, "bgr8")) except Exception as e: warning_dialog("Service Exception", str(e)) return print result for r in result.recognitions: text_array = [] best = CategoryProbability( label="unknown", probability=r.categorical_distribution.unknown_probability) for p in r.categorical_distribution.probabilities: text_array.append("%s: %.2f" % (p.label, p.probability)) if p.probability > best.probability: best = p self._image_widget.add_detection(r.roi.x_offset, r.roi.y_offset, r.roi.width, r.roi.height, best.label) if text_array: option_dialog( "Classification results (Unknown probability=%.2f)" % r.categorical_distribution.unknown_probability, text_array) # Show all results in a dropdown def get_face_properties_srv_call(self, roi_image): """ Method that calls the GetFaceProperties.srv :param roi_image: Selected roi_image by the user """ try: result = self._srv(face_image_array=[ self.bridge.cv2_to_imgmsg(roi_image, "bgr8") ]) except Exception as e: warning_dialog("Service Exception", str(e)) return msg = "" for properties in result.properties_array: msg += "- FaceProperties(gender=%s, age=%s, glasses=%s, mood=%s)" % \ ("male" if properties.gender == FaceProperties.MALE else "female", properties.age, "false" if properties.glasses == 0 else "true", properties.mood) info_dialog("Face Properties array", msg) def image_roi_callback(self, roi_image): """ Callback triggered when the user has drawn an ROI on the image :param roi_image: The opencv image in the ROI """ if self._srv is None: warning_dialog( "No service specified!", "Please first specify a service via the options button (top-right gear wheel)" ) return if self._srv.service_class == Recognize: self.recognize_srv_call(roi_image) elif self._srv.service_class == GetFaceProperties: self.get_face_properties_srv_call(roi_image) else: warning_dialog("Unknown service class", "Service class is unkown!") def _image_callback(self, msg): """ Sensor_msgs/Image callback :param msg: The image message """ try: cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8") except CvBridgeError as e: rospy.logerr(e) return self._image_widget.set_image(cv_image) def trigger_configuration(self): """ Callback when the configuration button is clicked """ topic_name, ok = QInputDialog.getItem( self._widget, "Select topic name", "Topic name", rostopic.find_by_type('sensor_msgs/Image')) if ok: self._create_subscriber(topic_name) available_rosservices = [] for s in rosservice.get_service_list(): try: if rosservice.get_service_type(s) in _SUPPORTED_SERVICES: available_rosservices.append(s) except: pass srv_name, ok = QInputDialog.getItem(self._widget, "Select service name", "Service name", available_rosservices) if ok: self._create_service_client(srv_name) def _create_subscriber(self, topic_name): """ Method that creates a subscriber to a sensor_msgs/Image topic :param topic_name: The topic_name """ if self._sub: self._sub.unregister() self._sub = rospy.Subscriber(topic_name, Image, self._image_callback) rospy.loginfo("Listening to %s -- spinning .." % self._sub.name) self._widget.setWindowTitle("Test plugin, listening to (%s)" % self._sub.name) def _create_service_client(self, srv_name): """ Method that creates a client service proxy to call either the GetFaceProperties.srv or the Recognize.srv :param srv_name: """ if self._srv: self._srv.close() if srv_name in rosservice.get_service_list(): rospy.loginfo("Creating proxy for service '%s'" % srv_name) self._srv = rospy.ServiceProxy( srv_name, rosservice.get_service_class_by_name(srv_name)) def shutdown_plugin(self): """ Callback function when shutdown is requested """ pass def save_settings(self, plugin_settings, instance_settings): """ Callback function on shutdown to store the local plugin variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ if self._sub: instance_settings.set_value("topic_name", self._sub.name) def restore_settings(self, plugin_settings, instance_settings): """ Callback function fired on load of the plugin that allows to restore saved variables :param plugin_settings: Plugin settings :param instance_settings: Settings of this instance """ self._create_subscriber( str(instance_settings.value("topic_name", "/usb_cam/image_raw"))) self._create_service_client( str( instance_settings.value("service_name", "/image_recognition/my_service")))
class VideoAnnotator(QtGui.QWidget): def __init__(self): super(VideoAnnotator, self).__init__() self.vid = None self.pic = None self.sld = None self.sld2 = None self.ranges = None # Number of distinct viewable video positions (slider granularity) self.num_positions = 50000 self.initUI() def initUI(self): vbox = QtGui.QVBoxLayout() # Create the widget that displays the video frame self.pic = ImageWidget() # A horizontal slider to scroll through the video self.sld = QtGui.QSlider(QtCore.Qt.Horizontal) # self.sld.setFocusPolicy(QtCore.Qt.NoFocus) self.sld.setRange(0, self.num_positions) self.sld.setValue(100) self.sld.valueChanged[int].connect(self.change_slider_value) # A special widget that displays the marked ranges and average frame colors # (Is also called slider, because it should later take over the role of the conventional slider) self.sld2 = SliderWidget() # The ranges class manages the marked video ranges and sends them to the widget when changed self.ranges = Ranges(update_function=self.sld2.setRanges) self.load_or_save_ranges(save=False) # A label with a quick introduction man_label = QtGui.QLabel() man_label.setText( "Use the slider to navigate (Mouse + keyboard).\n" + "Q = Start preview range, A = Start ad range, Z = Start ignore range\n" + "D = End current range, Bksp = remove last element.\n Auto-saves on close." ) man_label.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) # Put everything together and show it vbox.addWidget(self.pic) vbox.addWidget(self.sld) vbox.addWidget(self.sld2) vbox.addWidget(man_label) self.setLayout(vbox) self.setWindowTitle('Video Annotator') self.setAcceptDrops(True) self.show() def current_position(self, slider_value=None): if slider_value is None: return self.sld.value() / self.num_positions else: return slider_value / self.num_positions def change_slider_value(self, value): if self.vid is not None: self.pic.setImage(self.vid.get_frame(self.current_position(value))) def load_video(self, filename): self.vid = Video(filename) self.vid.compute_averages(50) #self.vid.compute_averages(1000) self.pic.setImage(self.vid.get_frame(0.0)) self.sld2.setAverages(self.vid.get_averages()) self.ranges = Ranges(update_function=self.sld2.setRanges) self.load_or_save_ranges(save=False) self.sld2.setRanges(self.ranges.get_ranges()) def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_Escape: self.close() elif e.key() == QtCore.Qt.Key_Backspace: self.ranges.remove_last_element() elif e.key() == QtCore.Qt.Key_A: self.ranges.add_range_start('ad', self.current_position()) elif e.key() == QtCore.Qt.Key_Q: self.ranges.add_range_start('preview', self.current_position()) elif e.key() == QtCore.Qt.Key_Z: self.ranges.add_range_start('ignore', self.current_position()) elif e.key() == QtCore.Qt.Key_D: self.ranges.add_range_end(self.current_position()) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): url = event.mimeData().urls()[0] path = str(url.toLocalFile()) if os.path.isfile(path): # Save old ranges self.load_or_save_ranges(save=True) # Open new video self.load_video(path) def load_or_save_ranges(self, save=False): if self.vid is not None: filename = os.path.splitext( self.vid.get_filename())[0] + '_annotation.txt' if save: with open(filename, 'w') as f: json.dump(self.ranges.get_ranges(), f) else: if os.path.isfile(filename): with open(filename, 'r') as f: range_data = json.load(f) self.ranges.set_ranges(range_data) def closeEvent(self, e): self.load_or_save_ranges(save=True)