def wait_for_user_exemplar_decision(autoexemplar_msg, exemplar_decision, exemplar_condience, incinfo=None): r""" hooks into to some method of getting user input for exemplars TODO: really good interface Args: autoexemplar_msg (?): exemplar_decision (?): exemplar_condience (?): Returns: ?: True CommandLine: python -m ibeis.algo.hots.automated_matcher --test-get_user_exemplar_decision Example: >>> # DISABLE_DOCTEST >>> from ibeis.algo.hots.automated_matcher import * # NOQA >>> import ibeis # NOQA >>> # build test data >>> autoexemplar_msg = '?' >>> exemplar_decision = '?' >>> exemplar_condience = '?' >>> get_user_exemplar_decision(autoexemplar_msg, exemplar_decision, >>> exemplar_condience) >>> # verify results >>> result = str(True) >>> print(result) """ import guitool options = ['No', 'Yes'] msg = 'Add query as new exemplar?. IBEIS suggests: ' + options[exemplar_decision] title = 'exemplar decision' responce = guitool.user_option(None, msg, title, options) # NOQA if responce is None: raise AssertionError('User Canceled Query') if responce == 'Yes': exemplar_decision = True elif responce == 'No': exemplar_decision = False else: raise AssertionError('answer yes or no') # TODO CALLBACK HERE exemplar_decision_callback = incinfo['exemplar_decision_callback'] exemplar_decision_callback(exemplar_decision)
def imagesDropped(ibswgt, url_list): from os.path import isdir print('[drop_event] url_list=%r' % (url_list,)) gpath_list = filter(utool.matches_image, url_list) dir_list = filter(isdir, url_list) if len(dir_list) > 0: ans = guitool.user_option(ibswgt, title='Non-Images dropped', msg='Recursively import from directories?') if ans == 'Yes': gpath_list.extend(map(utool.unixpath, utool.flatten([utool.list_images(dir_, fullpath=True, recursive=True) for dir_ in dir_list]))) else: return print('[drop_event] gpath_list=%r' % (gpath_list,)) if len(gpath_list) > 0: ibswgt.back.import_images_from_file(gpath_list=gpath_list)
def guiselect_workdir(): """ Prompts the user to specify a work directory """ import guitool guitool.ensure_qtapp() # Gui selection work_dir = guitool.select_directory('Select a work directory') # Make sure selection is ok if not exists(work_dir): try_again = guitool.user_option( paremt=None, msg='Directory %r does not exist.' % work_dir, title='get work dir failed', options=['Try Again'], use_cache=False) if try_again == 'Try Again': return guiselect_workdir() return work_dir
def guiselect_workdir(): """ Prompts the user to specify a work directory """ import guitool guitool.ensure_qtapp() # Gui selection work_dir = guitool.select_directory('Select a work directory') # Make sure selection is ok if not exists(work_dir): try_again = guitool.user_option(paremt=None, msg='Directory %r does not exist.' % work_dir, title='get work dir failed', options=['Try Again'], use_cache=False) if try_again == 'Try Again': return guiselect_workdir() return work_dir
def set_annot_pair_as_negative_match_(ibs, aid1, aid2, cm, qreq_, **kwargs): """ MARK AS INCORRECT """ def on_nontrivial_split(ibs, aid1, aid2): aid1_groundtruth = ibs.get_annot_groundtruth(aid1, noself=True) print( 'There are %d annots in this name. Need more sophisticated split' % (len(aid1_groundtruth))) raise guiexcept.NeedsUserInput('non-trivial split') try: status = ibs.set_annot_pair_as_negative_match( aid1, aid2, on_nontrivial_split=on_nontrivial_split, logger=kwargs.get('logger', None)) print('status = %r' % (status, )) except guiexcept.NeedsUserInput: options = ['Flag for later', 'Review now'] reply = gt.user_option(msg=ut.codeblock(''' Marking this as False induces a split case. Choose how to handle this. '''), options=options) if reply == options[0]: prop = 'SplitCase' if 'logger' in kwargs: log = kwargs['logger'].info else: log = print annot_uuid_pair = ibs.get_annot_uuids((aid1, aid2)) log('FLAG SplitCase: (annot_uuid_pair=%r)' % annot_uuid_pair) am_rowid = ibs.add_annotmatch_undirected([aid1], [aid2])[0] ibs.set_annotmatch_prop(prop, [am_rowid], [True]) ibs.set_annotmatch_evidence_decision( [am_rowid], [ibs.const.EVIDENCE_DECISION.NEGATIVE]) elif reply == options[1]: review_match(ibs, aid1, aid2, qreq_=qreq_, cm=cm, **kwargs) except guiexcept.UserCancel: print('user canceled negative match')
def confirm(self, event=None): """ CommandLine: python -m ibeis.viz.interact.interact_query_decision --test-confirm Example: >>> # DISABLE_DOCTEST >>> from ibeis.viz.interact.interact_query_decision import * # NOQA >>> import utool as ut >>> # build test data >>> import ibeis >>> ibs = ibeis.opendb('testdb1') >>> self = ibs >>> self.ibs = ibs >>> selected_aids = ut.get_list_column(ibs.get_name_aids(ibs.get_valid_nids()), 0) >>> comfirm_res = 'jeff' >>> # execute function >>> #result = self.confirm(event) >>> # verify results >>> #print(result) """ print('[interact_query_decision] Confirming selected animals.') selected_aids = [ aid for aid in self.comp_aids if aid is not None and self.aid_checkbox_states[aid] ] if len(selected_aids) == 0: print('[interact_query_decision] Confirming no match.') chosen_aids = [] if self.other_checkbox_states['none']: chosen_aids = 'newname' elif self.other_checkbox_states['junk']: chosen_aids = 'junk' else: msg = 'INTERACT_QUERY_DECISION IMPOSSIBLE STATE' raise AssertionError(msg) elif len(selected_aids) == 1: print('[interact_query_decision] Confirming single match') chosen_aids = selected_aids else: print('[interact_query_decision] Confirming merge') msg = ut.textblock(''' You have selected more than one animal as a match to the query animal. By doing this you are telling IBEIS that these are ALL the SAME ANIMAL. \n\n\nIf this is not what you want, click Cancel. If it is what you want, choose one of the names below as the name to keep. ''') selected_names = self.ibs.get_annot_names(selected_aids) options = selected_names parent = None title = 'Confirm Merge' merge_name = guitool.user_option(parent, msg=msg, title=title, options=options) if merge_name is None: print('[interact_query_decision] cancelled merge') self.update_callback() self.backend_callback() self.show_page() return else: print('[interact_query_decision] confirmed merge') is_merge_name = [ merge_name == name_ for name_ in selected_names ] chosen_aids = ut.sortedby(selected_aids, is_merge_name)[::-1] print('[interact_query_decision] Calling update callbacks') self.update_callback() self.backend_callback() print('[interact_query_decision] Calling decision callback') print('[interact_query_decision] self.name_decision_callback = %r' % (self.name_decision_callback, )) if isinstance(chosen_aids, six.string_types): # hack for string non-match commands chosen_names = chosen_aids else: chosen_names = self.ibs.get_annot_names(chosen_aids) self.name_decision_callback(chosen_names) print( '[interact_query_decision] sent name_decision_callback(chosen_names=%r)' % (chosen_names, ))
def user_option(back, **kwargs): return guitool.user_option(parent=back.front, **kwargs)
def confirm(self, event=None): """ CommandLine: python -m ibeis.viz.interact.interact_query_decision --test-confirm Example: >>> # DISABLE_DOCTEST >>> from ibeis.viz.interact.interact_query_decision import * # NOQA >>> import utool as ut >>> # build test data >>> import ibeis >>> ibs = ibeis.opendb('testdb1') >>> self = ibs >>> self.ibs = ibs >>> selected_aids = ut.get_list_column(ibs.get_name_aids(ibs.get_valid_nids()), 0) >>> comfirm_res = 'jeff' >>> # execute function >>> #result = self.confirm(event) >>> # verify results >>> #print(result) """ print('[interact_query_decision] Confirming selected animals.') selected_aids = [aid for aid in self.comp_aids if aid is not None and self.aid_checkbox_states[aid]] if len(selected_aids) == 0: print('[interact_query_decision] Confirming no match.') chosen_aids = [] if self.other_checkbox_states['none']: chosen_aids = 'newname' elif self.other_checkbox_states['junk']: chosen_aids = 'junk' else: msg = 'INTERACT_QUERY_DECISION IMPOSSIBLE STATE' raise AssertionError(msg) elif len(selected_aids) == 1: print('[interact_query_decision] Confirming single match') chosen_aids = selected_aids else: print('[interact_query_decision] Confirming merge') msg = ut.textblock( ''' You have selected more than one animal as a match to the query animal. By doing this you are telling IBEIS that these are ALL the SAME ANIMAL. \n\n\nIf this is not what you want, click Cancel. If it is what you want, choose one of the names below as the name to keep. ''') selected_names = self.ibs.get_annot_names(selected_aids) options = selected_names parent = None title = 'Confirm Merge' merge_name = guitool.user_option(parent, msg=msg, title=title, options=options) if merge_name is None: print('[interact_query_decision] cancelled merge') self.update_callback() self.backend_callback() self.show_page() return else: print('[interact_query_decision] confirmed merge') is_merge_name = [merge_name == name_ for name_ in selected_names] chosen_aids = ut.sortedby(selected_aids, is_merge_name)[::-1] print('[interact_query_decision] Calling update callbacks') self.update_callback() self.backend_callback() print('[interact_query_decision] Calling decision callback') print('[interact_query_decision] self.name_decision_callback = %r' % (self.name_decision_callback,)) if isinstance(chosen_aids, six.string_types): # hack for string non-match commands chosen_names = chosen_aids else: chosen_names = self.ibs.get_annot_names(chosen_aids) self.name_decision_callback(chosen_names) print('[interact_query_decision] sent name_decision_callback(chosen_names=%r)' % (chosen_names,))
def wait_for_user_name_decision(ibs, cm, qreq_, choicetup, name_suggest_tup, incinfo=None): r""" Prompts the user for input hooks into to some method of getting user input for names Args: ibs (IBEISController): cm (QueryResult): object of feature correspondences and scores autoname_func (function): CommandLine: python -m ibeis.algo.hots.user_dialogs --test-wait_for_user_name_decision --show Example: >>> # DISABLE_DOCTEST >>> from ibeis.algo.hots.user_dialogs import * # NOQA >>> import ibeis >>> # build test data >>> ibs = ibeis.opendb('testdb1') >>> qaids = [1] >>> daids = [2, 3, 4, 5] >>> cm, qreq_ = ibs.query_chips(qaids, daids, cfgdict=dict(), >>> return_request=True)[0] >>> choicetup = '?' >>> name_suggest_tup = '?' >>> incinfo = None >>> # execute function >>> result = wait_for_user_name_decision(ibs, cm, qreq_, choicetup, >>> name_suggest_tup, incinfo) >>> # verify results >>> print(result) >>> ut.show_if_requested() """ import plottool as pt if cm is None: print('WARNING: chipmatch is None') new_mplshow = True and cm is not None mplshowtop = False and cm is not None qtinspect = False and cm is not None if new_mplshow: from ibeis.viz.interact import interact_query_decision print('Showing matplotlib window') # convert name choices into data for gui comp_aids, suggest_aids = convert_name_suggestion_to_aids(ibs, choicetup, name_suggest_tup) # Update names tree callback # Let the harness do these callbacks #backend_callback = incinfo.get('backend_callback', None) #update_callback = incinfo.get('update_callback', None) name_decision_callback = incinfo['name_decision_callback'] progress_current = incinfo['count'] progress_total = incinfo['nTotal'] fnum = incinfo['fnum'] qvi = interact_query_decision.QueryVerificationInteraction( qreq_, cm, comp_aids, suggest_aids, name_decision_callback=name_decision_callback, #update_callback=update_callback, #backend_callback=backend_callback, progress_current=progress_current, progress_total=progress_total, fnum=fnum) qvi.fig.show() pt.bring_to_front(qvi.fig) if mplshowtop: import guitool fnum = 513 pt.figure(fnum=fnum, pnum=(2, 3, 1), doclf=True, docla=True) fig = cm.ishow_top(qreq_, fnum=fnum, in_image=False, annot_mode=0, sidebyside=False, show_query=True) fig.show() #fig.canvas.raise_() #from plottool import fig_presenter #fig_presenter.bring_to_front(fig) newname = ibs.make_next_name() newname_prefix = 'New Name:\n' # FIXME or remoev name = None #if chosen_names is None: # name = newname_prefix + newname aid_list = ut.get_list_column(choicetup.sorted_aids, 0) name_options = ibs.get_annot_names(aid_list) + [newname_prefix + newname] msg = 'Decide on query name. System suggests; ' + str(name) title = 'name decision' options = name_options[::-1] user_chosen_name = guitool.user_option(None, msg, title, options) # NOQA if user_chosen_name is None: raise AssertionError('User Canceled Query') user_chosen_name = user_chosen_name.replace(newname_prefix, '') # TODO: Make the old interface use the correct sorted_aids format #name_decision_callback(user_chosen_name) if qtinspect: print('Showing qt inspect window') qres_wgt = cm.qt_inspect_gui(qreq_) qres_wgt.show() qres_wgt.raise_()
def mark_unreviewed_above_score_as_correct(qres_wgt): selected_qtindex_list = qres_wgt.selectedRows() if len(selected_qtindex_list) == 1: qtindex = selected_qtindex_list[0] #aid1, aid2 = qres_wgt.get_aidpair_from_qtindex(qtindex) thresh = qtindex.model().get_header_data('score', qtindex) print('thresh = %r' % (thresh, )) rows = qres_wgt.review_api.ider() scores_ = qres_wgt.review_api.get( qres_wgt.review_api.col_name_list.index('score'), rows) valid_rows = ut.compress(rows, scores_ >= thresh) aids1 = qres_wgt.review_api.get( qres_wgt.review_api.col_name_list.index('qaid'), valid_rows) aids2 = qres_wgt.review_api.get( qres_wgt.review_api.col_name_list.index('aid'), valid_rows) #ibs = qres_wgt.ibs ibs = qres_wgt.ibs am_rowids = ibs.get_annotmatch_rowid_from_undirected_superkey( aids1, aids2) reviewed = ibs.get_annotmatch_reviewed(am_rowids) unreviewed = ut.not_list(reviewed) valid_rows = ut.compress(valid_rows, unreviewed) aids1 = ut.compress(aids1, unreviewed) aids2 = ut.compress(aids2, unreviewed) import networkx as nx graph = nx.Graph() graph.add_edges_from(list(zip(aids1, aids2)), {'user_thresh_match': True}) review_groups = list(nx.connected_component_subgraphs(graph)) changing_aids = list(graph.nodes()) nids = ibs.get_annot_nids(changing_aids) nid2_aids = ut.group_items(changing_aids, nids) for nid, aids in nid2_aids.items(): # Connect all original names in the database to denote merges for u, v in ut.itertwo(aids): graph.add_edge(u, v) dbside_groups = list(nx.connected_component_subgraphs(graph)) options = [ 'Accept', #'Review More' ] msg = ut.codeblock(''' There are %d names and %d annotations in this mass review set. Mass review has discovered %d internal groups. Accepting will induce a database grouping of %d names. ''') % (len(nid2_aids), len(changing_aids), len(review_groups), len(dbside_groups)) reply = gt.user_option(msg=msg, options=options) if reply == options[0]: # This is not the smartest way to group names. # Ideally what will happen here, is that reviewed edges will go into # the new graph name inference algorithm. # then the chosen point will be used as the threshold. Then # the graph cut algorithm will be applied. logger = qres_wgt.logger logger.debug(msg) logger.info('START MASS_THRESHOLD_MERGE') logger.info('num_groups=%d thresh=%r' % ( len(dbside_groups), thresh, )) for count, subgraph in enumerate(dbside_groups): thresh_aid_pairs = [ edge for edge, flag in nx.get_edge_attributes( graph, 'user_thresh_match').items() if flag ] thresh_uuid_pairs = ibs.unflat_map(ibs.get_annot_uuids, thresh_aid_pairs) aids = list(subgraph.nodes()) nids = ibs.get_annot_name_rowids(aids) flags = ut.not_list(ibs.is_aid_unknown(aids)) previous_names = ibs.get_name_texts(nids) valid_nids = ut.compress(nids, flags) if len(valid_nids) == 0: merge_nid = ibs.make_next_nids(num=1)[0] type_ = 'new' else: merge_nid = min(valid_nids) type_ = 'existing' # Need to find other non-exemplar / query names that may # need merging other_aids = ibs.get_name_aids(valid_nids) other_aids = set(ut.flatten(other_aids)) - set(aids) other_auuids = ibs.get_annot_uuids(other_aids) other_previous_names = ibs.get_annot_names(other_aids) merge_name = ibs.get_name_texts(merge_nid) annot_uuids = ibs.get_annot_uuids(aids) ### # Set as reviewed (so we dont see them again), but mark it # with a different code to denote that it was a MASS review aid1_list = ut.take_column(thresh_aid_pairs, 0) aid2_list = ut.take_column(thresh_aid_pairs, 1) am_rowids = ibs.add_annotmatch_undirected( aid1_list, aid2_list) ibs.set_annotmatch_reviewer( am_rowids, ['algo:lnbnn_thresh'] * len(am_rowids)) logger.info('START GROUP %d' % (count, )) logger.info( 'GROUP BASED ON %d ANNOT_PAIRS WITH SCORE ABOVE (thresh=%r)' % ( len(thresh_uuid_pairs), thresh, )) logger.debug('(uuid_pairs=%r)' % (thresh_uuid_pairs)) logger.debug('(merge_name=%r)' % (merge_name)) logger.debug( 'CHANGE NAME OF %d (annot_uuids=%r) WITH (previous_names=%r) TO (%s) (merge_name=%r)' % (len(annot_uuids), annot_uuids, previous_names, type_, merge_name)) logger.debug( 'ADDITIONAL CHANGE NAME OF %d (annot_uuids=%r) WITH (previous_names=%r) TO (%s) (merge_name=%r)' % (len(other_auuids), other_auuids, other_previous_names, type_, merge_name)) logger.info('END GROUP %d' % (count, )) new_nids = [merge_nid] * len(aids) ibs.set_annot_name_rowids(aids, new_nids) logger.info('END MASS_THRESHOLD_MERGE') else: print('[context] Multiple %d selection' % (len(selected_qtindex_list), ))