def addItem(self, x, y, legend, shape, color, fill, overlay, z): xView = numpy.array(x, copy=False) yView = numpy.array(y, copy=False) if shape == "line": item = self.ax.plot(x, y, label=legend, color=color, linestyle='-', marker=None)[0] elif shape == "hline": if hasattr(y, "__len__"): y = y[-1] item = self.ax.axhline(y, label=legend, color=color) elif shape == "vline": if hasattr(x, "__len__"): x = x[-1] item = self.ax.axvline(x, label=legend, color=color) elif shape == 'rectangle': xMin = numpy.nanmin(xView) xMax = numpy.nanmax(xView) yMin = numpy.nanmin(yView) yMax = numpy.nanmax(yView) w = xMax - xMin h = yMax - yMin item = Rectangle(xy=(xMin, yMin), width=w, height=h, fill=False, color=color) if fill: item.set_hatch('.') self.ax.add_patch(item) elif shape in ('polygon', 'polylines'): xView = xView.reshape(1, -1) yView = yView.reshape(1, -1) item = Polygon(numpy.vstack((xView, yView)).T, closed=(shape == 'polygon'), fill=False, label=legend, color=color) if fill and shape == 'polygon': item.set_hatch('/') self.ax.add_patch(item) else: raise NotImplementedError("Unsupported item shape %s" % shape) item.set_zorder(z) if overlay: item.set_animated(True) self._overlays.add(item) return item
class RectArea: #because rectangle or circle were not added to figure a priori - figure and axes must be passed def __init__(self, fig, axes, xi, yi): self.width = 20 self.height = 10 self.x0 = xi self.y0 = yi self.edgecol = "red" self.r = 4 #angle is anticlockwise self.angle = 0.0 #storing the background of rectangle self.background = None #storing the backgroud of circle self.backgroundc = None #indicator of the selection of the rectangle - creating an instance makes it selected self.is_Recselected = True #indicator of the selection of circle self.is_Circselected = False self.rect = Rectangle((self.x0, self.y0), self.width, self.height, ec=self.edgecol, fill=False, ls="solid") #upper right circle - draggable self.xr = self.x0 + self.width self.yr = self.y0 + self.height self.circle = Circle((self.xr, self.yr), radius=self.r) #circle - origin of the rectangle -> left, bottom corner of the rectangle self.circle_o = Circle((self.xo, self.y0), radius=self.r) #pressing the button on the canvas creates new rectangle - it is inside the constructor canvas = fig.canvas axes = axes self.rect.set_animated(True) self.circle.set_animated(True) canvas.draw() self.background = canvas.copy_from_bbox(axes.bbox) axes.draw_artist(self.rect) axes.draw_artist(self.circle) canvas.blit(axes.bbox)
def addItem(self, x, y, shape, color, fill, overlay, z, linestyle, linewidth, linebgcolor): if (linebgcolor is not None and shape not in ('rectangle', 'polygon', 'polylines')): _logger.warning( 'linebgcolor not implemented for %s with matplotlib backend', shape) xView = numpy.array(x, copy=False) yView = numpy.array(y, copy=False) linestyle = normalize_linestyle(linestyle) if shape == "line": item = self.ax.plot(x, y, color=color, linestyle=linestyle, linewidth=linewidth, marker=None)[0] elif shape == "hline": if hasattr(y, "__len__"): y = y[-1] item = self.ax.axhline(y, color=color, linestyle=linestyle, linewidth=linewidth) elif shape == "vline": if hasattr(x, "__len__"): x = x[-1] item = self.ax.axvline(x, color=color, linestyle=linestyle, linewidth=linewidth) elif shape == 'rectangle': xMin = numpy.nanmin(xView) xMax = numpy.nanmax(xView) yMin = numpy.nanmin(yView) yMax = numpy.nanmax(yView) w = xMax - xMin h = yMax - yMin item = Rectangle(xy=(xMin, yMin), width=w, height=h, fill=False, color=color, linestyle=linestyle, linewidth=linewidth) if fill: item.set_hatch('.') if linestyle != "solid" and linebgcolor is not None: item = _DoubleColoredLinePatch(item) item.linebgcolor = linebgcolor self.ax.add_patch(item) elif shape in ('polygon', 'polylines'): points = numpy.array((xView, yView)).T if shape == 'polygon': closed = True else: # shape == 'polylines' closed = numpy.all(numpy.equal(points[0], points[-1])) item = Polygon(points, closed=closed, fill=False, color=color, linestyle=linestyle, linewidth=linewidth) if fill and shape == 'polygon': item.set_hatch('/') if linestyle != "solid" and linebgcolor is not None: item = _DoubleColoredLinePatch(item) item.linebgcolor = linebgcolor self.ax.add_patch(item) else: raise NotImplementedError("Unsupported item shape %s" % shape) item.set_zorder(z + 1) item.set_animated(True) return item
class WindowSelectionRectangle(object): def __init__(self, event, axis, on_window_selection_callback): self.axis = axis if event.inaxes != self.axis: return # Store the axes it has been initialized in. self.axes = event.inaxes ymin, ymax = self.axes.get_ylim() self.min_x = event.xdata self.intial_selection_active = True self.rect = Rectangle((event.xdata, ymin), 0, ymax - ymin, color="0.3", alpha=0.5, edgecolor="0.5") self.axes.add_patch(self.rect) # Get the canvas. self.canvas = self.rect.figure.canvas # Use blittig for fast animations. self.rect.set_animated(True) self.background = self.canvas.copy_from_bbox(self.rect.axes.bbox) self._connect() self.on_window_selection_callback = on_window_selection_callback #def __del__(self): #""" #Disconnect the events upon deallocating. #""" #self.canvas.mpl_disconnect(self.conn_button_press) #self.canvas.mpl_disconnect(self.conn_button_release) #self.canvas.mpl_disconnect(self.conn_mouse_motion) def _connect(self): """ Connect to the necessary events. """ self.conn_button_press = self.rect.figure.canvas.mpl_connect( 'button_press_event', self.on_button_press) self.conn_button_release = self.rect.figure.canvas.mpl_connect( 'button_release_event', self.on_button_release) self.conn_mouse_motion = self.rect.figure.canvas.mpl_connect( 'motion_notify_event', self.on_mouse_motion) def on_button_press(self, event): pass def on_button_release(self, event): if event.inaxes != self.axis: return if event.button != 1: return # turn off the rect animation property and reset the background self.rect.set_animated(False) self.background = None self.intial_selection_active = False self.canvas.draw() x = self.rect.get_x() width = self.rect.get_width() if width < 0: x = x + width width = abs(width) self.on_window_selection_callback(x, width, self.axis) def on_mouse_motion(self, event): if event.button != 1 or \ self.intial_selection_active is not True: return if event.xdata is not None: self.rect.set_width(event.xdata - self.min_x) # restore the background region self.canvas.restore_region(self.background) # redraw just the current rectangle self.axes.draw_artist(self.rect) # blit just the redrawn area self.canvas.blit(self.axes.bbox)
class Selector: def __init__(self, filenames): self.filenames = filenames try: self.filename = next(self.filenames) except: print("No more images to be labelled") self.image = Image.open(RAW_FOLDER + self.filename) print("Labeling", self.filename) self.counter = 0 self.fig, self.ax = plt.subplots(1, 1, figsize=(14, 8)) plt.subplots_adjust(left=0, right=1, top=1, bottom=0) self.x = [0, 0] self.y = [0, 0] self.samples = {} self.on = False self.hasNext = True self.options = None self.ax.imshow(self.image) self.rect = Rectangle((0, 0), 0, 0, fill=None, linewidth=2, color="r") self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.press) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.move) self.ax.figure.canvas.mpl_connect('button_release_event', self.release) self.fig.canvas.mpl_connect('key_press_event', self.terminate) self.fig.canvas.mpl_connect('close_event', self.close) plt.show() def terminate(self, event): """ x: close and save c: close without saving """ if event.key: if event.key == "x": self.hasNext = False plt.close() self.close() elif event.key == "c": plt.close() def press(self, event): """ Mouse click event """ if (-1 < event.xdata < self.image.size[0]) and (-1 < event.ydata < self.image.size[1]): self.on = True self.x[0], self.y[0] = event.xdata, event.ydata self.rect.set_visible(True) self.rect.set_animated(True) self.fig.canvas.draw() self.background = self.fig.canvas.copy_from_bbox( self.rect.axes.bbox) self.ax.draw_artist(self.rect) self.fig.canvas.blit(self.ax.bbox) def move(self, event): """ Mousemove event """ if self.on: if event.xdata is not None and event.ydata is not None: self.x[1], self.y[1] = event.xdata, event.ydata self.rect.set_width(abs(self.x[1] - self.x[0])) self.rect.set_height(abs(self.y[1] - self.y[0])) self.rect.set_xy((min(self.x), min(self.y))) self.fig.canvas.restore_region(self.background) self.ax.draw_artist(self.rect) self.fig.canvas.blit(self.ax.bbox) def release(self, event): """ Mouse release event """ if self.on: self.on = False self.background = None if self.options is not None: self.options.window.destroy() self.options = Select() self.options.window.mainloop() self.rect.set_width(0) self.rect.set_height(0) self.rect.set_visible(False) self.fig.canvas.draw() self.rect.set_animated(False) if self.options.selected != "None": points = (int(min(self.x)), int(min(self.y)), int(max(self.x)), int(max(self.y))) self.ax.add_patch( Rectangle(points[:2], points[2] - points[0], points[3] - points[1], fill=None, linewidth=2, hatch='\\', color="y", alpha=0.5)) self.ax.text(points[0] + 6, points[1] + 21, self.options.selected, color="w") self.ax.text(points[0] + 5, points[1] + 20, self.options.selected, color="k") self.samples[self.counter] = (self.options.selected, points) self.counter += 1 self.fig.canvas.draw() self.options = None def close(self, event): """ Close the current image and open the next one """ counts = {c: 0 for c in CATEGORIES} for i in self.samples: label = self.samples[i][0] filename = SAMPLE_FOLDER + label + "_" while os.path.exists(filename + str(counts[label]).zfill(5) + ".jpg"): counts[label] += 1 self.image.crop( self.samples[i][1]).save(filename + str(counts[label]).zfill(5) + ".jpg") os.rename(RAW_FOLDER + self.filename, DONE_FOLDER + self.filename) if self.options is not None: self.options.window.destroy() if self.hasNext: global sel sel = Selector(self.filenames)
class SpanSelector(_SelectorWidget): """Custom SpanSelector.""" # pylint: disable=too-many-instance-attributes # pylint: disable=too-many-arguments # pylint: disable=attribute-defined-outside-init # pylint: disable=invalid-name def __init__(self, ax, onselect, direction, minspan=None, useblit=False, rectprops=None, onmove_callback=None, span_stays=False, button=None): _SelectorWidget.__init__(self, ax, onselect, useblit=useblit, button=button) if rectprops is None: rectprops = dict(facecolor='red', alpha=0.5) rectprops['animated'] = self.useblit if direction not in ['horizontal', 'vertical']: msg = "direction must be in [ 'horizontal' | 'vertical' ]" raise ValueError(msg) self.direction = direction self.rect = None self.pressv = None self.rectprops = rectprops self.onmove_callback = onmove_callback self.minspan = minspan self.span_stays = span_stays # Needed when dragging out of axes self.prev = (0, 0) # Reset canvas so that `new_axes` connects events. self.canvas = None self.new_axes(ax) def new_axes(self, ax): """Set SpanSelector to operate on a new Axes""" self.ax = ax if self.canvas is not ax.figure.canvas: if self.canvas is not None: self.disconnect_events() self.canvas = ax.figure.canvas self.connect_default_events() if self.direction == 'horizontal': trans = blended_transform_factory(self.ax.transData, self.ax.transAxes) w, h = 0, 2 else: trans = blended_transform_factory(self.ax.transAxes, self.ax.transData) w, h = 1, 0 self.rect = Rectangle((0, -0.5), w, h, transform=trans, visible=False, **self.rectprops) if self.span_stays: self.stay_rect = Rectangle((0, 0), w, h, transform=trans, visible=False, **self.rectprops) self.stay_rect.set_animated(False) self.ax.add_patch(self.stay_rect) self.ax.add_patch(self.rect) self.artists = [self.rect] def set_rectprops(self, rectprops): """Custom: set new rectprops.""" self.rectprops = rectprops self.new_axes(self.ax) def ignore(self, event): """return *True* if *event* should be ignored""" return _SelectorWidget.ignore(self, event) or not self.visible def _press(self, event): """on button press event""" if self.ignore(event): return True self.rect.set_visible(self.visible) if self.span_stays: self.stay_rect.set_visible(False) # really force a draw so that the stay rect is not in # the blit background if self.useblit: self.canvas.draw() xdata, ydata = self._get_data(event) if self.direction == 'horizontal': self.pressv = xdata else: self.pressv = ydata return False def _release(self, event): """on button release event""" if self.ignore(event): return True if self.pressv is None: return True self.buttonDown = False self.rect.set_visible(False) if self.span_stays: self.stay_rect.set_x(self.rect.get_x()) self.stay_rect.set_y(self.rect.get_y()) self.stay_rect.set_width(self.rect.get_width()) self.stay_rect.set_height(self.rect.get_height()) self.stay_rect.set_visible(True) self.canvas.draw_idle() vmin = self.pressv xdata, ydata = self._get_data(event) if self.direction == 'horizontal': vmax = xdata or self.prev[0] else: vmax = ydata or self.prev[1] if vmin > vmax: vmin, vmax = vmax, vmin span = vmax - vmin if self.minspan is not None and span < self.minspan: return True self.onselect(vmin, vmax) self.pressv = None return False def _onmove(self, event): """on motion notify event""" if self.ignore(event): return True if self.pressv is None: return True x, y = self._get_data(event) if x is None: return True self.prev = x, y if self.direction == 'horizontal': v = x else: v = y minv, maxv = v, self.pressv if minv > maxv: minv, maxv = maxv, minv if self.direction == 'horizontal': self.rect.set_x(minv) self.rect.set_width(maxv - minv) else: self.rect.set_y(minv) self.rect.set_height(maxv - minv) if self.onmove_callback is not None: vmin = self.pressv xdata, ydata = self._get_data(event) if self.direction == 'horizontal': vmax = xdata or self.prev[0] else: vmax = ydata or self.prev[1] if vmin > vmax: vmin, vmax = vmax, vmin self.onmove_callback(vmin, vmax) self.update() return False
def addItem(self, x, y, legend, shape, color, fill, overlay, z, linestyle, linewidth, linebgcolor): if (linebgcolor is not None and shape not in ('rectangle', 'polygon', 'polylines')): _logger.warning( 'linebgcolor not implemented for %s with matplotlib backend', shape) xView = numpy.array(x, copy=False) yView = numpy.array(y, copy=False) linestyle = normalize_linestyle(linestyle) if shape == "line": item = self.ax.plot(x, y, label=legend, color=color, linestyle=linestyle, linewidth=linewidth, marker=None)[0] elif shape == "hline": if hasattr(y, "__len__"): y = y[-1] item = self.ax.axhline(y, label=legend, color=color, linestyle=linestyle, linewidth=linewidth) elif shape == "vline": if hasattr(x, "__len__"): x = x[-1] item = self.ax.axvline(x, label=legend, color=color, linestyle=linestyle, linewidth=linewidth) elif shape == 'rectangle': xMin = numpy.nanmin(xView) xMax = numpy.nanmax(xView) yMin = numpy.nanmin(yView) yMax = numpy.nanmax(yView) w = xMax - xMin h = yMax - yMin item = Rectangle(xy=(xMin, yMin), width=w, height=h, fill=False, color=color, linestyle=linestyle, linewidth=linewidth) if fill: item.set_hatch('.') if linestyle != "solid" and linebgcolor is not None: item = _DoubleColoredLinePatch(item) item.linebgcolor = linebgcolor self.ax.add_patch(item) elif shape in ('polygon', 'polylines'): points = numpy.array((xView, yView)).T if shape == 'polygon': closed = True else: # shape == 'polylines' closed = numpy.all(numpy.equal(points[0], points[-1])) item = Polygon(points, closed=closed, fill=False, label=legend, color=color, linestyle=linestyle, linewidth=linewidth) if fill and shape == 'polygon': item.set_hatch('/') if linestyle != "solid" and linebgcolor is not None: item = _DoubleColoredLinePatch(item) item.linebgcolor = linebgcolor self.ax.add_patch(item) else: raise NotImplementedError("Unsupported item shape %s" % shape) item.set_zorder(z) if overlay: item.set_animated(True) self._overlays.add(item) return item
class Selector: def __init__(self, filenames): self.filenames = filenames try: self.filename = next(self.filenames) except: print("No more images to be labelled") self.image = Image.open(RAW_FOLDER + self.filename) print("Labeling", self.filename) self.counter = 0 self.fig, self.ax = plt.subplots(1, 1, figsize=(14, 8)) plt.subplots_adjust(left=0, right=1, top=1, bottom=0) self.x = [0, 0] self.y = [0, 0] self.samples = {} self.on = False self.hasNext = True self.options = None self.ax.imshow(self.image) self.rect = Rectangle((0,0), 0, 0, fill=None, linewidth=2, color="r") self.ax.add_patch(self.rect) self.ax.figure.canvas.mpl_connect('button_press_event', self.press) self.ax.figure.canvas.mpl_connect('motion_notify_event', self.move) self.ax.figure.canvas.mpl_connect('button_release_event', self.release) self.fig.canvas.mpl_connect('key_press_event', self.terminate) self.fig.canvas.mpl_connect('close_event', self.close) plt.show() def terminate(self, event): """ x: close and save c: close without saving """ if event.key: if event.key == "x": self.hasNext = False plt.close() self.close() elif event.key == "c": plt.close() def press(self, event): """ Mouse click event """ if (-1 < event.xdata < self.image.size[0]) and (-1 < event.ydata < self.image.size[1]): self.on = True self.x[0], self.y[0] = event.xdata, event.ydata self.rect.set_visible(True) self.rect.set_animated(True) self.fig.canvas.draw() self.background = self.fig.canvas.copy_from_bbox(self.rect.axes.bbox) self.ax.draw_artist(self.rect) self.fig.canvas.blit(self.ax.bbox) def move(self, event): """ Mousemove event """ if self.on: if event.xdata is not None and event.ydata is not None: self.x[1], self.y[1] = event.xdata, event.ydata self.rect.set_width(abs(self.x[1] - self.x[0])) self.rect.set_height(abs(self.y[1] - self.y[0])) self.rect.set_xy((min(self.x), min(self.y))) self.fig.canvas.restore_region(self.background) self.ax.draw_artist(self.rect) self.fig.canvas.blit(self.ax.bbox) def release(self, event): """ Mouse release event """ if self.on: self.on = False self.background = None if self.options is not None: self.options.window.destroy() self.options = Select() self.options.window.mainloop() self.rect.set_width(0) self.rect.set_height(0) self.rect.set_visible(False) self.fig.canvas.draw() self.rect.set_animated(False) if self.options.selected != "None": points = (int(min(self.x)), int(min(self.y)), int(max(self.x)), int(max(self.y))) self.ax.add_patch( Rectangle(points[:2], points[2] - points[0], points[3] - points[1], fill=None, linewidth=2, hatch='\\', color="y", alpha=0.5)) self.ax.text(points[0] + 6, points[1] + 21, self.options.selected, color="w") self.ax.text(points[0] + 5, points[1] + 20, self.options.selected, color="k") self.samples[self.counter] = (self.options.selected, points) self.counter += 1 self.fig.canvas.draw() self.options = None def close(self, event): """ Close the current image and open the next one """ counts = {c: 0 for c in CATEGORIES} for i in self.samples: label = self.samples[i][0] filename = SAMPLE_FOLDER + label + "_" while os.path.exists(filename + str(counts[label]).zfill(5) + ".jpg"): counts[label] += 1 self.image.crop(self.samples[i][1]).save(filename + str(counts[label]).zfill(5) + ".jpg") os.rename(RAW_FOLDER + self.filename, DONE_FOLDER + self.filename) if self.options is not None: self.options.window.destroy() if self.hasNext: global sel sel = Selector(self.filenames)