Пример #1
0
class VispyUI(object):
    _CUSTOM_LAYERS = {'CircleLayer': CircleLayer, 'LineLayer': LineLayer}

    # Variables possible for kwargs, use these defaults if missing from kwargs
    _DEFAULTS = {
        'n_cores': 0,
        'epochs_per_cycle': 10,
        'display_multiplier': 3,
        'border': 1.0
    }

    def __init__(self,
                 state_file=None,
                 image=None,
                 suffix=None,
                 out_dir="output",
                 **kwargs):
        # epochs_per_cycle=None, n_cores=None, display_multiplier=None, border=None):

        if int(image is None) + int(state_file is None) != 1:
            raise Exception("Need input image, or state to restore.")
        # state
        self._tempdir = tempfile.mkdtemp(prefix="imageStretch_")

        if state_file is not None:
            self._load_state(state_file)
        else:
            self._suffix = "" if suffix is None else "_%s" % (suffix, )
            self._out_dir = out_dir
            self._image = image
            n_cores = kwargs[
                'n_cores'] if 'n_cores' in kwargs else self._DEFAULTS['n_cores']
            self._sim = ScaleInvariantImage(image, n_cores=n_cores, state=None)
            self._index = 0
            self._increment_run_number()

        # let these be overridden by command line if they're still none
        for arg in self._DEFAULTS:
            if arg in kwargs and kwargs[arg] is not None:
                setattr(self, privatize(arg), kwargs[arg])
            elif not hasattr(self, privatize(arg)):
                setattr(self, privatize(arg), self._DEFAULTS[arg])

        logging.info("Using args:")
        for arg in self._DEFAULTS:
            logging.info("\t%s: %s" % (arg, getattr(self, privatize(arg))))

        self._interactive = not kwargs['just_image']
        if kwargs['just_image']:
            self._write_image()
            return

        # set up VISPY display
        self._canvas = vispy.scene.SceneCanvas(
            keys='interactive', show=True, title="Route editor -- H for help")
        self._viewbox = self._canvas.central_widget.add_view()
        self._viewbox.camera = vispy.scene.cameras.PanZoomCamera(
            parent=self._viewbox.scene, aspect=1)
        self._add_graphics_elements()
        self.set_text_box_state(False)
        self._canvas.events.key_press.connect(self._on_key_press)
        self._canvas.events.close.connect(self._on_close)
        self._closing = False
        self._set_image(self._image / 255.0)
        self._worker = Thread(target=self._train_thread)

        self._worker.start()
        logging.info("Started worker thread.")

    def is_interactive(self):
        return self._interactive

    def _on_close(self, event):
        self._closing = True
        logging.info("Shutting down...")

    def _increment_run_number(self):
        if not os.path.exists(self._out_dir):
            os.mkdir(self._out_dir)
        files = [
            f for f in os.listdir(self._out_dir)
            if f.startswith('output') and f.endswith('.png')
        ]
        numbers = [
            int(re.search('^output_([0-9]+)_.+.png', f).groups()[0])
            for f in files
        ]
        self._run = np.max(numbers) + 1 if len(numbers) > 0 else 0

    def _save_state(self):
        logging.info("Saving state...")
        model_filename = "model_%i%s.tf" % (self._run, self._suffix)
        model_filepath = os.path.join(self._out_dir, model_filename)
        temp_filepath = os.path.join(self._tempdir, model_filename)
        self._sim.get_model().save(temp_filepath)
        with open(temp_filepath, 'r') as infile:
            model_bin = infile.read()
        model = {
            'model_bin': model_bin,
            'epc': self._epochs_per_cycle,
            'dm': self._display_multiplier,
            'suffix': self._suffix,
            'out_dir': self._out_dir,
            'image': self._image,
            'border': self._border,
            'index': self._index,
            'run': self._run
        }

        with open(model_filepath, 'w') as outfile:
            cp.dump(model, outfile)
        logging.info("Wrote:  %s" % (model_filepath, ))

    def _load_state(self, model_filepath):
        logging.info("loading state...")
        with open(model_filepath, 'r') as infile:
            state = cp.load(infile)
        self._epochs_per_cycle = state['epc']
        self._display_multiplier = state['dm']
        self._suffix = state['suffix']
        self._out_dir = state['out_dir']
        self._image = state['image']
        self._index = state['index'] + 1
        self._run = state['run']
        self._border = state['border']
        model_filename = "model_%i%s.tf" % (self._run, self._suffix)
        model_filepath = os.path.join(self._tempdir, model_filename)
        with open(model_filepath, 'w') as outfile:
            outfile.write(state['model_bin'])
        state['model'] = keras.models.load_model(
            model_filepath, custom_objects=self._CUSTOM_LAYERS)
        self._sim = ScaleInvariantImage(state=state)

    def _train_thread(self):
        tf_session, tf_graph = self._sim.get_session_and_graph()
        with tf_session.as_default():
            with tf_graph.as_default():

                while not self._closing:
                    for ep in range(self._epochs_per_cycle):
                        if self._closing:
                            break
                        self._sim.train_epochs(1)
                    self._save_state()
                    if self._closing:
                        break
                    img = self._write_image()
                    self._set_image(img)
                    self._index += 1
                    if self._closing:
                        break
        self._save_state()
        logging.info("Close detected, shutting down worker thread.")
        logging.info("Deleting work dir:  %s" % (self._tempdir, ))
        shutil.rmtree(self._tempdir)

    def _write_image(self):

        img = self._sim.get_display_image(
            np.array(self._sim.get_image().shape) * self._display_multiplier,
            margin=self._border)

        out_filename = "output_%i%s_%.8i.png" % (self._run, self._suffix,
                                                 self._index)
        out_path = os.path.join(self._out_dir, out_filename)
        while os.path.exists(out_path):
            self._index += 1
            out_filename = "output_%i%s_%.8i.png" % (self._run, self._suffix,
                                                     self._index)
            out_path = os.path.join(self._out_dir, out_filename)

        cv2.imwrite(out_path, np.uint8(255 * img[:, :, ::-1]))
        logging.info("Wrote:  %s" % (out_path, ))
        return img

    def _add_graphics_elements(self):
        """
        Create the VISPY graphics objects
        """

        # Image
        self._image_object = Image(self._image, parent=self._viewbox.scene)
        self._image_object.set_gl_state('translucent', depth_test=False)
        self._image_object.order = 1
        self._image_object.visible = True

        self._text_box_width = 150
        self._text_box_height = 40
        self._text_box_offset = 10
        # Text background box in upper-left corner
        self._text_bkg_rect = vispy.scene.visuals.Rectangle(
            [
                self._text_box_width / 2 + self._text_box_offset,
                self._text_box_height / 2 + self._text_box_offset
            ],
            color=[0.1, 0.0, 0.0, .8],
            border_color=[0.1, 0.0, 0.0],
            border_width=2,
            height=self._text_box_height,
            width=self._text_box_width,
            radius=10.0,
            parent=self._canvas.scene)
        self._text_bkg_rect.set_gl_state('translucent', depth_test=False)
        self._text_bkg_rect.visible = True
        self._text_bkg_rect.order = 2

        # Text
        self._text = "?"
        self._text_pos = [
            self._text_box_offset + 10, self._text_box_offset + 10
        ]
        self._text_obj = vispy.scene.visuals.Text(self._text,
                                                  parent=self._canvas.scene,
                                                  color=[0.9, 0.8, 0.8],
                                                  anchor_x='left',
                                                  anchor_y='top')
        self._text_obj.pos = self._text_pos
        self._text_obj.font_size = 18
        self._text_obj.visible = True
        self._text_obj.order = 3

    def set_text_box_state(self, state):
        self._text_bkg_rect.visible = state
        self._text_obj.visible = state

    def _change_text(self, new_text):
        if new_text is not None:
            self._text = new_text
        else:
            self._text = ""
        self._text_obj.text = self._text

    def _set_image(self, image=None):
        xmin, ymin = 0, 0
        xmax, ymax = image.shape[1], image.shape[0]
        self._viewbox.camera.set_range(x=(xmin, xmax), y=(ymin, ymax), z=None)
        self._image_object.set_data(flip(image))
        self._image_object.visible = True

    def _on_key_press(self, ev):
        if ev.key.name == 'Escape':
            self._canvas.close()
        else:
            self._change_text(ev.key.name)
            logging.info("Unknown keypress:  %s" % (ev.key.name, ))
Пример #2
0
class VispyUI(object):
    """
    Display an image, rectangle, text, enable pan/tilt, keyboard
    """
    def __init__(self):
        self._make_new_random_image()
        # state
        self._last_mouse_pos = np.array([0.0, 0.0])
        self._load_data()  # Load data in after the view has been setup
        self._canvas = vispy.scene.SceneCanvas(
            keys='interactive', show=True, title="Route editor -- H for help")
        self._viewbox = self._canvas.central_widget.add_view()
        self._viewbox.camera = vispy.scene.cameras.PanZoomCamera(
            parent=self._viewbox.scene, aspect=1)
        self._add_graphics_elements()

        self._canvas.events.key_press.connect(self._on_key_press)
        self._canvas.events.mouse_move.connect(self._on_mouse_move)
        self._canvas.events.mouse_press.connect(self._on_mouse_press)
        self._canvas.events.mouse_release.connect(self._on_mouse_release)

        self._set_map_image(self._image)

    def _make_new_random_image(self):
        self._h, self._w = 100 + int(np.random.rand(1) * 100), 100 + int(
            np.random.rand(1) * 100)
        self._image = np.uint8(
            np.zeros((self._h, self._w, 3)) +
            255 * np.random.rand(self._h * self._w * 3).reshape(
                (self._h, self._w, 3)))

    def _add_graphics_elements(self):
        """
        Create all the graphics objects (VISPY objects), put them on the canvas.
        """

        # Image
        self._image_object = Image(self._image, parent=self._viewbox.scene)
        self._image_object.set_gl_state('translucent', depth_test=False)
        self._image_object.order = 1
        self._image_object.visible = True

        self._text_box_width = 150
        self._text_box_height = 40
        self._text_box_offset = 10
        # Text background box in upper-left corner
        self._text_bkg_rect = vispy.scene.visuals.Rectangle(
            [
                self._text_box_width / 2 + self._text_box_offset,
                self._text_box_height / 2 + self._text_box_offset
            ],
            color=[0.1, 0.0, 0.0, .8],
            border_color=[0.1, 0.0, 0.0],
            border_width=2,
            height=self._text_box_height,
            width=self._text_box_width,
            radius=10.0,
            parent=self._canvas.scene)
        self._text_bkg_rect.set_gl_state('translucent', depth_test=False)
        self._text_bkg_rect.visible = True
        self._text_bkg_rect.order = 2

        # Text
        self._text = "?"
        self._text_pos = [
            self._text_box_offset + 10, self._text_box_offset + 10
        ]
        self._text_obj = vispy.scene.visuals.Text(self._text,
                                                  parent=self._canvas.scene,
                                                  color=[0.9, 0.8, 0.8],
                                                  anchor_x='left',
                                                  anchor_y='top')
        self._text_obj.pos = self._text_pos
        self._text_obj.font_size = 18
        self._text_obj.visible = True
        self._text_obj.order = 3

    def _change_text(self, new_text):
        if new_text is not None:
            self._text = new_text
        else:
            self._text = ""
        self._text_obj.text = self._text

    def _load_data(self):
        """
        Downlaod (if necessary) and load into memory the costmap, route and scrubber deck state controls.
        """
        self._images = []

    def _set_map_image(self, disp_image=None):
        """
        Extract an image to display from the current cost map.
        """
        if disp_image is not None:
            self._image = disp_image
        xmin, ymin = 0, 0
        xmax, ymax = self._image.shape[1], self._image.shape[0]
        self._viewbox.camera.set_range(x=(xmin, xmax), y=(ymin, ymax), z=None)
        self._image_object.set_data(self._image)
        self._image_object.visible = True

    def _on_key_press(self, ev):
        """
        vispy keyboard callback
        """

        if not ev or not ev.key:
            # on Mac sometimes this callback is triggered with
            # NoneType key when clicking between desktops or full screen apps
            return

        control_pressed = 'Control' in [e.name for e in ev.modifiers]
        shift_pressed = 'Shift' in [e.name for e in ev.modifiers]
        print "Shift:  %s\nControl:%s" % (shift_pressed, control_pressed)
        if ev.key.name == "Space":

            self._make_new_random_image()
            self._set_map_image()

        elif ev.key.name == "Z":
            print "Z"
        elif ev.key.name == "M":
            print "M"

        else:
            self._change_text(ev.key.name)
            logging.info("Unknown keypress:  %s" % (ev.key.name, ))

    def _on_mouse_move(self, event):
        """
        vispy mouse motion callback
        All mouse events are in map coordinate frame
        """
        self._last_mouse_pos = event.pos

    def _on_mouse_press(self, event):
        '''
        Vispy mouse button press callback.
        All mouse events are in map coordinate frame
        '''
        self._last_mouse_pos = event.pos

    def _on_mouse_release(self, event):
        """
        Vispy mouse button release callback.
        All mouse events are in map coordinate frame
        """

        self._last_mouse_pos = event.pos
Пример #3
0
class ImageSorter(object):
    """
    Display an image, rectangle, text, enable pan/tilt, keyboard
    """
    def __init__(self, image_dir, out_file=None, max_load=10):
        self._in_dir = os.path.abspath(os.path.expanduser(image_dir))
        self._out_file = out_file if out_file is not None else os.path.join(
            self._in_dir, "results.json")
        self._images = LabeledImageSet(image_dir, self._out_file,
                                       self._out_file)
        self._current_filename, self._current_index = self._images.get_unlabeled(
        )

        # state
        self._last_mouse_pos = np.array([0.0, 0.0])
        self._canvas = vispy.scene.SceneCanvas(
            keys='interactive', show=True, title="Route editor -- H for help")
        self._viewbox = self._canvas.central_widget.add_view()
        self._viewbox.camera = vispy.scene.cameras.PanZoomCamera(
            parent=self._viewbox.scene, aspect=1)
        self._add_graphics_elements()
        self._canvas.events.key_press.connect(self._on_key_press)
        self._canvas.events.mouse_move.connect(self._on_mouse_move)
        self._canvas.events.mouse_press.connect(self._on_mouse_press)
        self._canvas.events.mouse_release.connect(self._on_mouse_release)
        self._canvas.events.resize.connect(self._on_resize)
        self._update_image()

    def _save_results(self):
        self._images.save()

    def _add_graphics_elements(self):
        """
        Create all the graphics objects (VISPY objects), put them on the canvas.
        """

        # Image
        self._image_object = Image(None, parent=self._viewbox.scene)
        self._image_object.set_gl_state('translucent', depth_test=False)
        self._image_object.order = 1
        self._image_object.visible = True

        self._text_box_width = 150
        self._text_box_height = 60
        self._text_box_offset = 10
        # Text background box in upper-left corner
        self._text_bkg_rect = vispy.scene.visuals.Rectangle(
            [
                self._text_box_width / 2 + self._text_box_offset,
                self._text_box_height / 2 + self._text_box_offset
            ],
            color=[0.1, 0.0, 0.0, .8],
            border_color=[0.1, 0.0, 0.0],
            border_width=2,
            height=self._text_box_height,
            width=self._text_box_width,
            radius=10.0,
            parent=self._canvas.scene)
        self._text_bkg_rect.set_gl_state('translucent', depth_test=False)
        self._text_bkg_rect.visible = True
        self._text_bkg_rect.order = 2
        self._resize_text_bkg_box()

        # Text
        self._font1_size = 10
        self._font2_size = 18
        self._vspace = self._font1_size * 2.2
        self._text_pos = [
            self._text_box_offset + 10, self._text_box_offset + 10
        ]
        self._text_obj = vispy.scene.visuals.Text("",
                                                  parent=self._canvas.scene,
                                                  color=[0.9, 0.8, 0.8],
                                                  anchor_x='left',
                                                  anchor_y='top')
        self._text_obj.pos = self._text_pos
        self._text_obj.font_size = self._font1_size
        self._text_obj.visible = True
        self._text_obj.order = 3

        self._text2_pos = [self._text_pos[0], self._vspace + self._text_pos[1]]
        self._text2_obj = vispy.scene.visuals.Text("",
                                                   parent=self._canvas.scene,
                                                   color=[0.9, 0.8, 0.8],
                                                   anchor_x='left',
                                                   anchor_y='top')
        self._text2_obj.pos = self._text2_pos
        self._text2_obj.font_size = self._font2_size
        self._text2_obj.visible = True
        self._text2_obj.order = 3

    def _resize_text_bkg_box(self):
        logging.info('resize')
        self._text_bkg_rect.center = np.array([
            self._canvas.size[0] / 2,
            self._text_box_height / 2 + self._text_box_offset
        ])
        self._text_bkg_rect.width = self._canvas.size[
            0] - 2 * self._text_box_offset

    def _on_resize(self, event):
        self._resize_text_bkg_box()

    def _update_image(self):
        """
        Extract an image to display from the current cost map.
        """
        self._current_filename = self._images.get_i(self._current_index)
        self._current_image = self._images.get_image(self._current_filename)

        logging.info("Got new image:  %s, %s" %
                     (self._current_image.shape, self._current_filename))
        xmin, ymin = 0, 0
        xmax, ymax = self._current_image.shape[1], self._current_image.shape[0]
        self._viewbox.camera.set_range(x=(xmin, xmax), y=(ymin, ymax), z=None)
        self._image_object.set_data(self._current_image)
        self._image_object.visible = True
        self._update_text()

    def _update_text(self):
        result = self._images.get_label(self._current_filename)
        result_str = "%i" % (result, ) if result is not None else "(unlabeled)"

        text1 = self._current_filename
        text2 = "%i / %i - label:  %s" % (self._current_index,
                                          self._images.get_n(), result_str)
        self._text_obj.text = text1
        self._text2_obj.text = text2

        self._text_obj.visible = True
        self._text2_obj.visible = True

    def _on_key_press(self, ev):
        """
        vispy keyboard callback
        """

        if not ev or not ev.key:
            # on Mac sometimes this callback is triggered with
            # NoneType key when clicking between desktops or full screen apps
            return

        # control_pressed = 'Control' in [e.name for e in ev.modifiers]
        shift_pressed = 'Shift' in [e.name for e in ev.modifiers]
        # print "Shift:  %s\nControl:%s" % (shift_pressed, control_pressed)

        if ev.key.name == "Left":
            self._advance_index(-1)

        elif ev.key.name == "Right":
            self._advance_index(1)

        elif ev.key.name == "X":
            self._classify_and_go_to_next(
                0, skip_to_next_unlabeled=not shift_pressed)

        elif ev.key.name == "O":
            self._classify_and_go_to_next(
                1, skip_to_next_unlabeled=not shift_pressed)

        else:
            logging.info("Unknown keypress:  %s" % (ev.key.name, ))

    def _advance_index(self, direction):
        new_index = self._current_index + direction
        if new_index >= 0 and new_index <= self._images.get_n() - 1:
            self._current_index = new_index
        self._update_image()
        self._update_text()

    def _classify_and_go_to_next(self, label, skip_to_next_unlabeled=True):
        self._images.apply_label(self._current_filename, label)
        self._images.save()
        if skip_to_next_unlabeled:
            self._current_filename, self._current_index = self._images.get_unlabeled(
            )
            self._update_image()
            self._update_text()
        else:
            self._advance_index(1)

    def _on_mouse_move(self, event):
        self._last_mouse_pos = event.pos

    def _on_mouse_press(self, event):
        self._last_mouse_pos = event.pos

    def _on_mouse_release(self, event):
        self._last_mouse_pos = event.pos