Source code for wbia.plottool.interact_multi_image

# -*- coding: utf-8 -*-
# import matplotlib.image as mpimg
from wbia.plottool import viz_image2
from wbia.plottool import interact_annotations
from . import draw_func2 as df2
from wbia.plottool import plot_helpers as ph
from wbia.plottool import interact_helpers as ih
from wbia.plottool import abstract_interaction

from matplotlib.widgets import Button  # NOQA
import matplotlib.pyplot as plt  # NOQA
import matplotlib as mpl  # NOQA

try:
    import vtool as vt
except ImportError:
    pass
# import utool
import utool as ut

ut.noinject(__name__, '[pt.interact_multiimage]')


BASE_CLASS = abstract_interaction.AbstractInteraction
# BASE_CLASS = object


[docs]@ut.reloadable_class class MultiImageInteraction(BASE_CLASS): """ CommandLine: python -m wbia.plottool.interact_multi_image --exec-MultiImageInteraction --show Example: >>> # ENABLE_DOCTEST >>> from wbia.plottool.interact_multi_image import * # NOQA >>> import utool as ut >>> TEST_IMAGES_URL = 'https://wildbookiarepository.azureedge.net/data/testdata.zip' >>> test_image_dir = ut.grab_zipped_url(TEST_IMAGES_URL, appname='utool') >>> # test image paths >>> imgpaths = ut.list_images(test_image_dir, fullpath=True, recursive=False) >>> bboxes_list = [[]] * len(imgpaths) >>> #bboxes_list[0] = [(-200, -100, 400, 400)] >>> bboxes_list[0] = [(20, 10, 400, 400)] >>> iteract_obj = MultiImageInteraction(imgpaths, nPerPage=4, >>> bboxes_list=bboxes_list) >>> import wbia.plottool as pt >>> pt.show_if_requested() """ def __init__( self, gpath_list, nPerPage=4, bboxes_list=None, thetas_list=None, verts_list=None, gid_list=None, nImgs=None, fnum=None, context_option_funcs=None, xlabel_list=None, vizkw=None, **kwargs, ): # TODO: overlay function or draw function using a metadata object print('Creating multi-image interaction') # def __init__(self, img_list, nImgs=None, gid_list=None, aids_list=None, # bboxes_list=None, nPerPage=10,fnum=None): print('[pt] maX ', nPerPage) self.context_option_funcs = context_option_funcs if nImgs is None: nImgs = len(gpath_list) if bboxes_list is None: bboxes_list = [[]] * nImgs if thetas_list is None: thetas_list = [[0] * len(bboxes) for bboxes in bboxes_list] # How many images we are showing and per page self.thetas_list = thetas_list self.bboxes_list = bboxes_list self.xlabel_list = xlabel_list if gid_list is None: self.gid_list = None else: self.gid_list = gid_list self.vizkw = vizkw self.nImgs = nImgs self.nPerPage = min(nPerPage, nImgs) self.current_index = 0 self.page_number = -1 # Initialize iterator over the image paths self.gpath_list = gpath_list # Display the first page self.first_load = True self.scope = [] self.current_pagenum = 0 self.nPages = vt.iceil(self.nImgs / nPerPage) # self.show_page() super(MultiImageInteraction, self).__init__(fnum=fnum, **kwargs) # self.start()
[docs] def dump_to_disk(self, dpath, num=None, prefix='temp_img'): import numpy as np import wbia.plottool as pt dpath = ut.ensurepath(dpath) num_zeros = np.ceil(np.log10(len(self.gpath_list))) total = len(self.gpath_list) if num is None: num = total fmtstr = prefix + '_%0' + str(num_zeros) + 'd.jpg' fig = pt.figure(fnum=self.fnum) for index in ut.ProgIter(range(num), lbl='dumping images to disk'): fig = pt.figure(fnum=self.fnum) fig.clf() ax = self._plot_index(index, {'fnum': self.fnum}) fig = ax.figure axes_extents = pt.extract_axes_extents(fig) assert len(axes_extents) == 1, 'more than one axes' extent = axes_extents[0] fpath = ut.unixjoin(dpath, fmtstr % (index)) fig.savefig(fpath, bbox_inches=extent) pt.plt.close(fig)
[docs] def make_hud(self): """Creates heads up display""" # Button positioning hl_slot, hr_slot = df2.make_bbox_positioners( y=0.02, w=0.08, h=0.04, xpad=0.05, startx=0, stopx=1 ) prev_rect = hl_slot(0) next_rect = hr_slot(0) # Create buttons if self.current_pagenum != 0: self.append_button('prev', callback=self.prev_page, rect=prev_rect) if self.current_pagenum != self.nPages - 1: self.append_button('next', callback=self.next_page, rect=next_rect)
[docs] def next_page(self, event): self.show_page(self.current_pagenum + 1)
[docs] def prev_page(self, event): self.show_page(self.current_pagenum - 1)
[docs] def prepare_page(self, pagenum): """Gets indexes for the pagenum ready to be displayed""" # Set the start index self.start_index = pagenum * self.nPerPage # Clip based on nImgs self.nDisplay = min(self.nImgs - self.start_index, self.nPerPage) nRows, nCols = ph.get_square_row_cols(self.nDisplay) # Create a grid to hold nPerPage self.pnum_ = df2.get_pnum_func(nRows, nCols) # Adjust stop index self.stop_index = self.start_index + self.nDisplay # Clear current figure self.clean_scope() self.fig = df2.figure(fnum=self.fnum, pnum=self.pnum_(0), doclf=True, docla=False) # For some reason clf isn't working correctly in figure self.fig.clf() ih.disconnect_callback(self.fig, 'button_press_event') ih.connect_callback(self.fig, 'button_press_event', self.on_click)
[docs] def show_page(self, pagenum=None): """Displays a page of matches""" if pagenum is None: pagenum = self.current_pagenum # print('[iqr2] show page: %r' % pagenum) self.current_pagenum = pagenum self.prepare_page(pagenum) # Begin showing matches index = self.start_index start_index = self.start_index stop_index = self.stop_index for px, index in enumerate(range(start_index, stop_index)): self.plot_image(index) self.make_hud() self.draw()
def _plot_index(self, index, _vizkw): gpath = self.gpath_list[index] if ut.is_funclike(gpath): showfunc = gpath # HACK # override of plot image function showfunc(**_vizkw) import wbia.plottool as pt ax = pt.gca() else: if isinstance(gpath, str): img = vt.imread(gpath) else: img = gpath bbox_list = self.bboxes_list[index] # print('bbox_list %r in display for px: %r ' % (bbox_list, px)) theta_list = self.thetas_list[index] label_list = [ix + 1 for ix in range(len(bbox_list))] # Add true values for every bbox to display sel_list = [True for ix in range(len(bbox_list))] _vizkw.update( { # title should always be the image number 'title': str(index), 'bbox_list': bbox_list, 'theta_list': theta_list, 'sel_list': sel_list, 'label_list': label_list, } ) # print(utool.repr2(_vizkw)) # print('vizkw = ' + utool.repr2(_vizkw)) _, ax = viz_image2.show_image(img, **_vizkw) if self.xlabel_list is not None: import wbia.plottool as pt pt.set_xlabel(self.xlabel_list[index]) # print(index) ph.set_plotdat(ax, 'bbox_list', bbox_list) ph.set_plotdat(ax, 'gpath', gpath) return ax
[docs] def plot_image(self, index): px = index - self.start_index if self.vizkw is None: _vizkw = {} else: _vizkw = self.vizkw.copy() _vizkw.update({'fnum': self.fnum, 'pnum': self.pnum_(px)}) ax = self._plot_index(index, _vizkw) ph.set_plotdat(ax, 'px', str(px)) ph.set_plotdat(ax, 'index', index)
[docs] def update_images( self, img_ind, updated_bbox_list, updated_theta_list, changed_annottups, new_annottups, ): """Insert code for viz_image2 redrawing here""" # print('update called') index = int(img_ind) # print('index: %r' % index) # print('Images bbox before: %r' % (self.bboxes_list[index],)) self.bboxes_list[index] = updated_bbox_list self.thetas_list[index] = updated_theta_list # print('Images bbox after: %r' % (self.bboxes_list[index],)) self.plot_image(index) self.draw()
[docs] def on_click_inside(self, event, ax): index = ph.get_plotdat(ax, 'index') print('index = %r' % (index,)) if index is not None: if self.MOUSE_BUTTONS[event.button] == 'right': if self.context_option_funcs is not None: # if event.button == 3: options = self.context_option_funcs[index]() self.show_popup_menu(options, event) elif self.MOUSE_BUTTONS[event.button] == 'left': # bbox_list = ph.get_plotdat(ax, 'bbox_list') gpath = self.gpath_list[index] if ut.is_funclike(gpath): print('gpath_isfunklike') print('gpath = %r' % (gpath,)) import wbia.plottool as pt fnum = pt.next_fnum() gpath(fnum=fnum) df2.update() else: bbox_list = self.bboxes_list[index] print('Bbox of figure: %r' % (bbox_list,)) theta_list = self.thetas_list[index] print('theta_list = %r' % (theta_list,)) # img = mpimg.imread(gpath) if isinstance(gpath, str): img = vt.imread(gpath) else: img = gpath fnum = df2.next_fnum() mc = interact_annotations.AnnotationInteraction( img, index, self.update_images, bbox_list=bbox_list, theta_list=theta_list, fnum=fnum, ) mc.start() self.mc = mc # """wait for accept # have a flag to tell if a bbox has been changed, on the bbox # list that is brought it" on accept: viz_image2.show_image # callback # """ df2.update() print('Clicked: ax: num=%r' % index)
[docs] def on_key_press(self, event): if event.key == 'n': self.display_next_page() if event.key == 'p': self.display_prev_page()
# def clean_scope(self): # """ Removes any widgets saved in the interaction scope """ # #for (but, ax) in self.scope: # # but.disconnect_events() # # ax.set_visible(False) # # assert len(ax.callbacks.callbacks) == 0 # self.scope = [] # def draw(self): # self.fig.canvas.draw() # def append_button(self, text, divider=None, rect=None, callback=None, # **kwargs): # """ Adds a button to the current page """ # if divider is not None: # new_ax = divider.append_axes('bottom', size='9%', pad=.05) # if rect is not None: # new_ax = df2.plt.axes(rect) # new_but = mpl.widgets.Button(new_ax, text) # if callback is not None: # new_but.on_clicked(callback) # ph.set_plotdat(new_ax, 'viztype', 'button') # ph.set_plotdat(new_ax, 'text', text) # for key, val in kwargs.items(): # ph.set_plotdat(new_ax, key, val) # # Keep buttons from losing scrop # self.scope.append((new_but, new_ax)) # def display_buttons(self): # # Create the button for scrolling forwards # self.next_ax = plt.axes([0.75, 0.025, 0.15, 0.075]) # self.next_but = Button(self.next_ax, 'next') # self.next_but.on_clicked(self.display_next_page) # # Create the button for scrolling backwards # self.prev_ax = plt.axes([0.1, .025, 0.15, 0.075]) # self.prev_but = Button(self.prev_ax, 'prev') # self.prev_but.on_clicked(self.display_prev_page) # # Connect the callback whenever the figure is clicked