Ejemplo n.º 1
0
    def add_slider(self,
                   label,
                   description,
                   minimum,
                   maximum,
                   value,
                   slider_moved_func,
                   parent,
                   tick_interval=1,
                   single_step=1,
                   slider_scale_factor=1,
                   int_values=False):
        # make layout to hold slider and textbox
        control_layout = QHBoxLayout()

        slider_label = label + "_slider"
        textbox_label = label + "_textbox"

        # make slider & add to layout
        slider = QSlider(Qt.Horizontal)
        slider.setObjectName(label)
        slider.setFocusPolicy(Qt.StrongFocus)
        slider.setTickPosition(QSlider.TicksBothSides)
        slider.setTickInterval(tick_interval)
        slider.setSingleStep(single_step)
        slider.setMinimum(minimum)
        slider.setMaximum(maximum)
        slider.setValue(value)
        control_layout.addWidget(slider)

        # make textbox & add to layout
        textbox = QLineEdit()
        textbox.setObjectName(label)
        textbox.setFixedWidth(40)
        textbox.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        textbox.returnPressed.connect(
            self.controller.update_crop_params_from_gui)
        self.update_textbox_from_slider(slider, textbox, slider_scale_factor,
                                        int_values)
        control_layout.addWidget(textbox)

        # connect slider to set textbox text & update params
        slider.sliderMoved.connect(lambda: self.update_textbox_from_slider(
            slider, textbox, slider_scale_factor, int_values))
        slider.sliderMoved.connect(slider_moved_func)
        slider.sliderPressed.connect(lambda: self.slider_pressed(slider))
        slider.sliderReleased.connect(lambda: self.slider_released(slider))

        # connect textbox to
        textbox.editingFinished.connect(
            lambda: self.update_slider_from_textbox(slider, textbox,
                                                    slider_scale_factor))
        textbox.editingFinished.connect(slider_moved_func)

        # add row to form layout
        parent.addRow(description, control_layout)

        # add to list of controls
        self.crop_param_controls[-1][slider_label] = slider
        self.crop_param_controls[-1][textbox_label] = textbox
Ejemplo n.º 2
0
 def _addSlider(self, v, cnt):
     control = QSlider(Qt.Horizontal)
     control.setMinimumWidth(172)
     control.setFocusPolicy(Qt.StrongFocus)
     control.setMaximum(v.max * 160)
     control.setMinimum(v.min * 160)
     control.setValue(v.value * 160)
     control.tag = cnt
     if self.styleName == "mac":
         control.setAttribute(Qt.WA_MacMiniSize, True)
     self.layout.addWidget(control, cnt, 1)
     self.connect(control, SIGNAL("valueChanged(int)"), self.numberChanged_)
Ejemplo n.º 3
0
 def _addSlider(self, v, cnt):
     control = QSlider(Qt.Horizontal)
     control.setMinimumWidth(172)
     control.setFocusPolicy(Qt.StrongFocus)
     control.setMaximum(v.max * 160)
     control.setMinimum(v.min * 160)
     control.setValue(v.value * 160)
     control.tag = cnt
     if self.styleName == "mac":
         control.setAttribute(Qt.WA_MacMiniSize, True)
     self.layout.addWidget(control, cnt, 1)
     self.connect(control, SIGNAL("valueChanged(int)"), self.numberChanged_)
Ejemplo n.º 4
0
 def add_slider(foo, col):
     sld = QSlider(Qt.Vertical, sliders)
     sld.setFocusPolicy(Qt.NoFocus)
     sld.valueChanged[int].connect(foo)
     sld.valueChanged.connect(self.plot)
     sliders_grid.addWidget(sld, 0, col)
class PreviewWindow(QMainWindow):
    """
    QMainWindow subclass used to show frames & tracking.
    """
    def __init__(self, controller):
        QMainWindow.__init__(self)

        # set controller
        self.controller = controller

        # set title
        self.setWindowTitle("Preview")

        # get parameter window position & size
        param_window_x = self.controller.param_window.x()
        param_window_y = self.controller.param_window.y()
        param_window_width = self.controller.param_window.width()

        # set position & size to be next to the parameter window
        self.setGeometry(param_window_x + param_window_width, param_window_y,
                         10, 10)

        # create main widget
        self.main_widget = QWidget(self)
        self.main_widget.setMinimumSize(QSize(500, 500))

        # create main layout
        self.main_layout = QGridLayout(self.main_widget)
        self.main_layout.setContentsMargins(0, 0, 0, 0)
        self.main_layout.setSpacing(0)

        # create label that shows frames
        self.image_widget = QWidget(self)
        self.image_layout = QVBoxLayout(self.image_widget)
        self.image_layout.setContentsMargins(0, 0, 0, 0)
        self.image_label = PreviewQLabel(self)
        self.image_label.setSizePolicy(QSizePolicy.MinimumExpanding,
                                       QSizePolicy.MinimumExpanding)
        self.image_label.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self.image_label.hide()
        self.image_layout.addWidget(self.image_label)
        self.main_layout.addWidget(self.image_widget, 0, 0)

        # self.image_label.setStyleSheet("border: 1px solid rgba(122, 127, 130, 0.5)")

        self.bottom_widget = QWidget(self)
        self.bottom_layout = QVBoxLayout(self.bottom_widget)
        self.bottom_layout.setContentsMargins(8, 0, 8, 8)
        self.bottom_widget.setMaximumHeight(40)
        self.main_layout.addWidget(self.bottom_widget, 1, 0)

        # create label that shows crop instructions
        self.instructions_label = QLabel("")
        self.instructions_label.setStyleSheet("font-size: 11px;")
        self.instructions_label.setAlignment(Qt.AlignCenter)
        self.bottom_layout.addWidget(self.instructions_label)

        # create image slider
        self.image_slider = QSlider(Qt.Horizontal)
        self.image_slider.setFocusPolicy(Qt.StrongFocus)
        self.image_slider.setTickPosition(QSlider.NoTicks)
        self.image_slider.setTickInterval(1)
        self.image_slider.setSingleStep(1)
        self.image_slider.setValue(0)
        self.image_slider.valueChanged.connect(self.controller.show_frame)
        self.image_slider.hide()
        self.bottom_layout.addWidget(self.image_slider)

        self.zoom = 1
        self.offset = [0, 0]
        self.center_y = 0
        self.center_x = 0

        # initialize variables
        self.image = None  # image to show
        self.tracking_data = None  # list of tracking data
        self.selecting_crop = False  # whether user is selecting a crop
        self.changing_heading_angle = False  # whether the user is changing the heading angle
        self.body_crop = None
        self.final_image = None

        # set main widget
        self.setCentralWidget(self.main_widget)

        # set window buttons
        if pyqt_version == 5:
            self.setWindowFlags(Qt.CustomizeWindowHint
                                | Qt.WindowMinimizeButtonHint
                                | Qt.WindowMaximizeButtonHint
                                | Qt.WindowFullscreenButtonHint)
        else:
            self.setWindowFlags(Qt.CustomizeWindowHint
                                | Qt.WindowMinimizeButtonHint
                                | Qt.WindowMaximizeButtonHint)

        self.show()

    def wheelEvent(self, event):
        old_zoom = self.zoom
        self.zoom = max(1, self.zoom + event.pixelDelta().y() / 100)

        self.zoom = int(self.zoom * 100) / 100.0

        self.update_image_label(self.final_image, zooming=True)

    def start_selecting_crop(self):
        # start selecting crop
        self.selecting_crop = True

        # add instruction text
        self.instructions_label.setText("Click & drag to select crop area.")

    def plot_image(self,
                   image,
                   params,
                   crop_params,
                   tracking_results,
                   new_load=False,
                   new_frame=False,
                   show_slider=True,
                   crop_around_body=False):
        if image is None:
            self.update_image_label(None)
            self.image_slider.hide()
            self.image_label.hide()
        else:
            if new_load:
                self.image_label.show()
                self.remove_tail_start()
                if show_slider:
                    if not self.image_slider.isVisible():
                        self.image_slider.setValue(0)
                        self.image_slider.setMaximum(self.controller.n_frames -
                                                     1)
                        self.image_slider.show()
                else:
                    self.image_slider.hide()

                max_inititial_size = 500
                if image.shape[0] > max_inititial_size:
                    min_height = max_inititial_size
                    min_width = max_inititial_size * image.shape[
                        1] / image.shape[0]
                elif image.shape[1] > max_inititial_size:
                    min_width = max_inititial_size
                    min_height = max_inititial_size * image.shape[
                        0] / image.shape[1]
                else:
                    min_height = image.shape[0]
                    min_width = image.shape[1]

                self.main_widget.setMinimumSize(
                    QSize(min_width, min_height + self.bottom_widget.height()))

            # convert to RGB
            if len(image.shape) == 2:
                image = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)

            # update image
            self.image = image.copy()

            try:
                body_crop = params['body_crop']
            except:
                body_crop = None

            try:
                tail_start_coords = params['tail_start_coords']

                # add tail start point to image
                cv2.circle(image, (int(
                    round(tail_start_coords[1] - crop_params['offset'][1])),
                                   int(
                                       round(tail_start_coords[0] -
                                             crop_params['offset'][0]))), 1,
                           (180, 180, 50), -1)
            except (KeyError, TypeError) as error:
                tail_start_coords = None

            if tracking_results is not None:
                body_position = tracking_results['body_position']
                heading_angle = tracking_results['heading_angle']

                # add tracking to image
                image = tracking.add_tracking_to_frame(image,
                                                       tracking_results,
                                                       cropped=True)

                if body_crop is not None and body_position is not None:
                    if not crop_around_body:
                        # copy image
                        overlay = image.copy()

                        # draw tail crop overlay
                        cv2.rectangle(overlay,
                                      (int(body_position[1] - body_crop[1]),
                                       int(body_position[0] - body_crop[0])),
                                      (int(body_position[1] + body_crop[1]),
                                       int(body_position[0] + body_crop[0])),
                                      (242, 242, 65), -1)

                        # overlay with the original image
                        cv2.addWeighted(overlay, 0.2, image, 0.8, 0, image)

                        self.body_crop = None
                    else:
                        self.body_crop = body_crop

            if crop_around_body:
                _, image = tracking.crop_frame_around_body(
                    image, body_position, params['body_crop'])

            self.final_image = image

            # update image label
            self.update_image_label(
                self.final_image,
                zoom=(not (crop_around_body and body_position is not None)),
                new_load=new_load)

    def draw_crop_selection(self, start_crop_coords, end_crop_coords):
        if self.selecting_crop and self.image is not None:
            # convert image to rgb
            if len(self.image.shape) < 3:
                image = np.repeat(self.image[:, :, np.newaxis], 3, axis=2)
            else:
                image = self.image.copy()

            # copy image
            overlay = image.copy()

            # draw crop selection overlay
            cv2.rectangle(overlay,
                          (start_crop_coords[1], start_crop_coords[0]),
                          (end_crop_coords[1], end_crop_coords[0]),
                          (255, 51, 0), -1)

            # overlay with the original image
            cv2.addWeighted(overlay, 0.5, image, 0.5, 0, image)

            # update image label
            self.update_image_label(image)

    def change_offset(self, prev_coords, new_coords):
        self.offset[0] -= new_coords[0] - prev_coords[0]
        self.offset[1] -= new_coords[1] - prev_coords[1]

        self.update_image_label(self.final_image)

    def draw_tail_start(self, rel_tail_start_coords):
        if self.controller.params['type'] == "headfixed":
            # send new tail start coordinates to controller
            self.controller.update_tail_start_coords(rel_tail_start_coords)

            # clear instructions text
            self.instructions_label.setText("")

        if self.image is not None:
            image = self.image.copy()

            cv2.circle(image, (int(round(rel_tail_start_coords[1])),
                               int(round(rel_tail_start_coords[0]))), 1,
                       (180, 180, 50), -1)

            # update image label
            self.update_image_label(image)

    def remove_tail_start(self):
        self.update_image_label(self.image)

    def add_angle_overlay(self, angle):
        image = self.image.copy()
        image_height = self.image.shape[0]
        image_width = self.image.shape[1]
        center_y = image_height / 2
        center_x = image_width / 2

        cv2.arrowedLine(
            image,
            (int(center_x -
                 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)),
             int(center_y -
                 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))),
            (int(center_x +
                 0.3 * image_height * np.sin((angle + 90) * np.pi / 180)),
             int(center_y +
                 0.3 * image_width * np.cos((angle + 90) * np.pi / 180))),
            (50, 255, 50), 2)

        self.update_image_label(image)

    def remove_angle_overlay(self):
        self.update_image_label(self.image)

    def update_image_label(self,
                           image,
                           zoom=True,
                           new_load=False,
                           zooming=False):
        if image is not None and self.zoom != 1 and zoom:
            if zooming:
                self.offset[0] = min(
                    max(
                        0, self.offset[0] + int(
                            (self.image_label.image.shape[0]) / 2.0) -
                        int(round((image.shape[0] / self.zoom) / 2.0))),
                    image.shape[0] - int(round(image.shape[0] / self.zoom)))
                self.offset[1] = min(
                    max(
                        0, self.offset[1] + int(
                            (self.image_label.image.shape[1]) / 2.0) -
                        int(round((image.shape[1] / self.zoom) / 2.0))),
                    image.shape[1] - int(round(image.shape[1] / self.zoom)))
            else:
                self.offset[0] = min(
                    max(0, self.offset[0]),
                    image.shape[0] - int(round(image.shape[0] / self.zoom)))
                self.offset[1] = min(
                    max(0, self.offset[1]),
                    image.shape[1] - int(round(image.shape[1] / self.zoom)))

            if self.center_y is None:
                self.center_y = int(round(image.shape[0] / 2.0))
            if self.center_x is None:
                self.center_x = int(round(image.shape[1] / 2.0))

            image = image[
                self.offset[0]:int(round(image.shape[0] / self.zoom)) +
                self.offset[0],
                self.offset[1]:int(round(image.shape[1] / self.zoom)) +
                self.offset[1], :].copy()

        if image is not None:
            if zoom:
                self.setWindowTitle("Preview - Zoom: {:.1f}x".format(
                    self.zoom))
            else:
                self.setWindowTitle("Preview - Zoom: 1x")
        else:
            self.setWindowTitle("Preview")

        self.image_label.update_pixmap(image, new_load=new_load)

    def crop_selection(self, start_crop_coord, end_crop_coord):
        if self.selecting_crop:
            # stop selecting the crop
            self.selecting_crop = False

            # clear instruction text
            self.instructions_label.setText("")

            # update crop parameters from the selection
            self.controller.update_crop_from_selection(start_crop_coord,
                                                       end_crop_coord)

    def closeEvent(self, ce):
        if not self.controller.closing:
            ce.ignore()
        else:
            ce.accept()
Ejemplo n.º 6
0
class OpencvCameraTestWidget(QWidget):
    available_resolutions = {
        "160x120": [160, 120],
        "176x144": [176, 144],
        "320x240": [320, 240],
        "352x288": [352, 288],
        "640x480": [640, 480],
        "960x720": [960, 720],
        "1280x960": [1280, 960]
    }

    def __init__(self, parent=None, capture=None, widget=None):
        super(OpencvCameraTestWidget, self).__init__(parent)
        self.main_layout = QVBoxLayout(self)
        self.main_layout.setSizeConstraint(QLayout.SetFixedSize)
        if capture is None:
            self.capture = cv2.VideoCapture(0)
        else:
            self.capture = capture

        if widget is None:
            self.camera_widget = QImageWidget()
            self.main_layout.addWidget(self.camera_widget)

            self.camera_ret = 0
            self.raw_camera_image = None
            # cv2.namedWindow("image")

            self.camera_timer = QTimer()
            self.camera_timer.timeout.connect(self.grab_video)
            self.camera_timer.start(1000 / 24)

        self.brightness_layout = QHBoxLayout()
        self.brightness_label = QLabel("Brightness: ")
        self.brightness_layout.addWidget(self.brightness_label)
        self.brightness_value_label = QLabel("")
        self.brightness_value_label.setMinimumWidth(30)

        self.brightness_slider = QSlider(Qt.Horizontal)
        self.brightness_slider.setFocusPolicy(Qt.StrongFocus)
        self.brightness_slider.setTickPosition(QSlider.TicksBothSides)
        self.brightness_slider.setMinimum(-10)
        self.brightness_slider.setMaximum(110)
        self.brightness_slider.setValue(20)
        self.brightness_slider.setTickPosition(QSlider.TicksBelow)
        self.brightness_slider.setTickInterval(10)
        self.brightness_slider.valueChanged.connect(self.set_brightness)
        self.brightness_layout.addWidget(self.brightness_slider)
        self.brightness_layout.addWidget(self.brightness_value_label)
        self.main_layout.addLayout(self.brightness_layout)

        self.contrast_layout = QHBoxLayout()
        self.contrast_label = QLabel("Contrast: ")
        self.contrast_layout.addWidget(self.contrast_label)
        self.contrast_value_label = QLabel("")
        self.contrast_value_label.setMinimumWidth(30)

        self.contrast_slider = QSlider(Qt.Horizontal)
        self.contrast_slider.setFocusPolicy(Qt.StrongFocus)
        self.contrast_slider.setTickPosition(QSlider.TicksBothSides)
        self.contrast_slider.setMinimum(-10)
        self.contrast_slider.setMaximum(110)
        self.contrast_slider.setValue(20)
        self.contrast_slider.setTickPosition(QSlider.TicksBelow)
        self.contrast_slider.setTickInterval(10)
        self.contrast_slider.valueChanged.connect(self.set_contrast)
        self.contrast_layout.addWidget(self.contrast_slider)
        self.contrast_layout.addWidget(self.contrast_value_label)
        self.main_layout.addLayout(self.contrast_layout)

        self.exposure_layout = QHBoxLayout()
        self.exposure_label = QLabel("Exposure: ")
        self.exposure_layout.addWidget(self.exposure_label)
        self.exposure_value_label = QLabel("")
        self.exposure_value_label.setMinimumWidth(30)

        self.exposure_slider = QSlider(Qt.Horizontal)
        self.exposure_slider.setFocusPolicy(Qt.StrongFocus)
        self.exposure_slider.setTickPosition(QSlider.TicksBothSides)
        self.exposure_slider.setMinimum(-10)
        self.exposure_slider.setMaximum(110)
        self.exposure_slider.setValue(20)
        self.exposure_slider.setTickPosition(QSlider.TicksBelow)
        self.exposure_slider.setTickInterval(10)
        self.exposure_slider.valueChanged.connect(self.set_exposure)
        self.exposure_layout.addWidget(self.exposure_slider)
        self.exposure_layout.addWidget(self.exposure_value_label)
        self.main_layout.addLayout(self.exposure_layout)

        self.iso_layout = QHBoxLayout()
        self.iso_label = QLabel("ISO: ")
        self.iso_layout.addWidget(self.iso_label)
        self.iso_value_label = QLabel("")
        self.iso_value_label.setMinimumWidth(30)

        self.iso_slider = QSlider(Qt.Horizontal)
        self.iso_slider.setFocusPolicy(Qt.StrongFocus)
        self.iso_slider.setTickPosition(QSlider.TicksBothSides)
        self.iso_slider.setMinimum(-10)
        self.iso_slider.setMaximum(110)
        self.iso_slider.setValue(20)
        self.iso_slider.setTickPosition(QSlider.TicksBelow)
        self.iso_slider.setTickInterval(10)
        self.iso_slider.valueChanged.connect(self.set_iso)
        self.iso_layout.addWidget(self.iso_slider)
        self.iso_layout.addWidget(self.iso_value_label)
        self.main_layout.addLayout(self.iso_layout)

        self.auto_exposure_label = QLabel("AutoExposure: ")
        self.auto_exposure_checkbox = QCheckBox("AutoExposure: ")
        self.exposure_layout.addWidget(self.auto_exposure_checkbox)
        self.auto_exposure_checkbox.stateChanged.connect(
            self.set_auto_exposure)

        self.resolutions_combo = QComboBox()
        self.resolutions_combo.addItems(self.available_resolutions.keys())
        self.main_layout.addWidget(self.resolutions_combo)
        self.resolutions_combo.currentIndexChanged[str].connect(
            self.set_resolution)

    def set_brightness(self, value):
        self.capture.set(cv2.CAP_PROP_BRIGHTNESS, value / 100.0)
        self.brightness_value_label.setText(str(value / 100.0))

    def set_contrast(self, value):
        self.capture.set(cv2.CAP_PROP_CONTRAST, value / 100.0)
        self.contrast_value_label.setText(str(value / 100.0))

    def set_exposure(self, value):

        self.capture.set(cv2.CAP_PROP_EXPOSURE, value / 100.0)
        self.exposure_value_label.setText(str(value / 100.0))

    def set_iso(self, value):

        self.capture.set(cv2.CAP_PROP_ISO_SPEED, value / 100.0)
        self.exposure_value_label.setText(str(value / 100.0))

    def set_auto_exposure(self, value):
        if value > 0:
            self.capture.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)
        else:
            self.capture.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0.25)

    def set_resolution(self, string):
        if str(string) in self.available_resolutions:
            height = self.available_resolutions[str(string)][0]
            width = self.available_resolutions[str(string)][1]
            self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
            self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, width)

    def grab_video(self):
        # print "grab video"
        self.camera_ret, self.raw_camera_image = self.capture.read()
        if self.camera_ret:
            self.raw_camera_image = cv2.cvtColor(self.raw_camera_image,
                                                 cv2.COLOR_BGR2RGB)
            self.camera_widget.set_opencv_image(self.raw_camera_image)