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) logger.info( '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), ) logger.info('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: logger.info('user canceled negative match')
def guiselect_workdir(): """ Prompts the user to specify a work directory """ from wbia 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 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) logger.info('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: logger.info('[context] Multiple %d selection' % (len(selected_qtindex_list), ))
def confirm(self, event=None): """ CommandLine: python -m wbia.viz.interact.interact_query_decision --test-confirm Example: >>> # DISABLE_DOCTEST >>> from wbia.viz.interact.interact_query_decision import * # NOQA >>> import utool as ut >>> # build test data >>> import wbia >>> ibs = wbia.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) """ import wbia.guitool as gt 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 = gt.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,) )