def update_node_image_attribute(infr, use_image=False, graph=None): if graph is None: graph = infr.graph if not hasattr(infr, '_viz_image_config_dirty'): infr.initialize_visual_node_attrs() aid_list = list(graph.nodes()) if infr.ibs is not None: nx.set_node_attributes(graph, name='framewidth', values=3.0) nx.set_node_attributes(graph, name='shape', values=ut.dzip(aid_list, ['rect'])) if infr.ibs is None: raise ValueError('Cannot show images when ibs is None') imgpath_list = infr.ibs.depc_annot.get( 'chipthumb', aid_list, 'img', config=infr._viz_image_config, read_extern=False, ) nx.set_node_attributes(graph, name='image', values=ut.dzip(aid_list, imgpath_list)) if graph is infr.graph: infr._viz_image_config_dirty = False
def apply_match_scores(infr): """ Applies precomputed matching scores to edges that already exist in the graph. Typically you should run infr.apply_match_edges() before running this. CommandLine: python -m wbia.algo.graph.core apply_match_scores --show Example: >>> # xdoctest: +REQUIRES(--slow) >>> # ENABLE_DOCTEST >>> from wbia.algo.graph.core import * # NOQA >>> infr = testdata_infr('PZ_MTEST') >>> infr.exec_matching() >>> infr.apply_match_edges() >>> infr.apply_match_scores() >>> infr.get_edge_attrs('score') """ if infr.cm_list is None: infr.print('apply_match_scores - no scores to apply!') return infr.print('apply_match_scores', 1) edges = list(infr.graph.edges()) edge_to_data = infr._get_cm_edge_data(edges) # Remove existing attrs ut.nx_delete_edge_attr(infr.graph, 'score') ut.nx_delete_edge_attr(infr.graph, 'rank') ut.nx_delete_edge_attr(infr.graph, 'normscore') edges = list(edge_to_data.keys()) edge_scores = list(ut.take_column(edge_to_data.values(), 'score')) edge_scores = ut.replace_nones(edge_scores, np.nan) edge_scores = np.array(edge_scores) edge_ranks = np.array(ut.take_column(edge_to_data.values(), 'rank')) # take the inf-norm normscores = edge_scores / vt.safe_max(edge_scores, nans=False) # Add new attrs infr.set_edge_attrs('score', ut.dzip(edges, edge_scores)) infr.set_edge_attrs('rank', ut.dzip(edges, edge_ranks)) # Hack away zero probabilites # probs = np.vstack([p_nomatch, p_match, p_notcomp]).T + 1e-9 # probs = vt.normalize(probs, axis=1, ord=1, out=probs) # entropy = -(np.log2(probs) * probs).sum(axis=1) infr.set_edge_attrs('normscore', dict(zip(edges, normscores)))
def init_test_mode(infr): from ibeis.algo.graph import nx_dynamic_graph infr.print('init_test_mode') infr.test_mode = True # infr.edge_truth = {} infr.metrics_list = [] infr.test_state = { 'n_decision': 0, 'n_algo': 0, 'n_manual': 0, 'n_true_merges': 0, 'n_error_edges': 0, 'confusion': None, } infr.test_gt_pos_graph = nx_dynamic_graph.DynConnGraph() infr.test_gt_pos_graph.add_nodes_from(infr.aids) infr.nid_to_gt_cc = ut.group_items(infr.aids, infr.orig_name_labels) infr.node_truth = ut.dzip(infr.aids, infr.orig_name_labels) # infr.real_n_pcc_mst_edges = sum( # len(cc) - 1 for cc in infr.nid_to_gt_cc.values()) # ut.cprint('real_n_pcc_mst_edges = %r' % ( # infr.real_n_pcc_mst_edges,), 'red') infr.metrics_list = [] infr.nid_to_gt_cc = ut.group_items(infr.aids, infr.orig_name_labels) infr.real_n_pcc_mst_edges = sum( len(cc) - 1 for cc in infr.nid_to_gt_cc.values()) infr.print('real_n_pcc_mst_edges = %r' % ( infr.real_n_pcc_mst_edges,), color='red')
def hardcase_review_gen(infr): """ Subiterator for hardcase review Re-review non-confident edges that vsone did not classify correctly """ infr.print('==============================', color='white') infr.print('--- HARDCASE PRIORITY LOOP ---', color='white') verifiers = infr.learn_evaluation_verifiers() verif = verifiers['match_state'] edges_ = list(infr.edges()) real_ = list(infr.edge_decision_from(edges_)) flags_ = [r in {POSTV, NEGTV, INCMP} for r in real_] real = ut.compress(real_, flags_) edges = ut.compress(edges_, flags_) hardness = 1 - verif.easiness(edges, real) if True: df = pd.DataFrame({'edges': edges, 'real': real}) df['hardness'] = hardness pred = verif.predict(edges) df['pred'] = pred.values df.sort_values('hardness', ascending=False) infr.print('hardness analysis') infr.print(str(df)) infr.print('infr status: ' + ut.repr4(infr.status())) # Don't re-review anything that was confidently reviewed # CONFIDENCE = const.CONFIDENCE # CODE_TO_INT = CONFIDENCE.CODE_TO_INT.copy() # CODE_TO_INT[CONFIDENCE.CODE.UNKNOWN] = 0 # conf = ut.take(CODE_TO_INT, infr.gen_edge_values( # 'confidence', edges, on_missing='default', # default=CONFIDENCE.CODE.UNKNOWN)) # This should only be run with certain params assert not infr.params['autoreview.enabled'] assert not infr.params['redun.enabled'] assert not infr.params['ranking.enabled'] assert infr.params['inference.enabled'] # const.CONFIDENCE.CODE.PRETTY_SURE if infr.params['queue.conf.thresh'] is None: # != 'pretty_sure': infr.print('WARNING: should queue.conf.thresh = "pretty_sure"?') # work around add_candidate_edges infr.prioritize(metric='hardness', edges=edges, scores=hardness) infr.set_edge_attrs('hardness', ut.dzip(edges, hardness)) for _ in infr._inner_priority_gen(use_refresh=False): yield _
def predict_proba_df(verif, edges): """ CommandLine: python -m wbia.algo.graph.demo DummyVerif.predict_edges Example: >>> # ENABLE_DOCTEST >>> from wbia.algo.graph.demo import * # NOQA >>> from wbia.algo.graph import demo >>> import networkx as nx >>> kwargs = dict(num_pccs=40, size=2) >>> infr = demo.demodata_infr(**kwargs) >>> verif = infr.dummy_verif >>> edges = list(infr.graph.edges()) >>> probs = verif.predict_proba_df(edges) >>> #print('scores = %r' % (scores,)) >>> #hashid = ut.hash_data(scores) >>> #print('hashid = %r' % (hashid,)) >>> #assert hashid == 'cdlkytilfeqgmtsihvhqwffmhczqmpil' """ infr = verif.infr edges = list(it.starmap(verif.infr.e_, edges)) prob_cache = infr.task_probs['match_state'] is_miss = np.array([e not in prob_cache for e in edges]) # is_hit = ~is_miss if np.any(is_miss): miss_edges = ut.compress(edges, is_miss) miss_truths = [verif._get_truth(edge) for edge in miss_edges] grouped_edges = ut.group_items(miss_edges, miss_truths, sorted_=False) # Need to make this determenistic too states = [POSTV, NEGTV, INCMP] for key in sorted(grouped_edges.keys()): group = grouped_edges[key] probs0 = randn( shape=[len(group)], rng=verif.rng, a_max=1, a_min=0, **verif.dummy_params[key], ) # Just randomly assign other probs probs1 = verif.rng.rand(len(group)) * (1 - probs0) probs2 = 1 - (probs0 + probs1) for edge, probs in zip(group, zip(probs0, probs1, probs2)): prob_cache[edge] = ut.dzip(states, probs) from wbia.algo.graph import nx_utils as nxu import pandas as pd probs = pd.DataFrame( ut.take(prob_cache, edges), index=nxu.ensure_multi_index(edges, ('aid1', 'aid2')), ) return probs
def main(): tests_ = tests subset = ['consistent_info', 'inconsistent_info'] subset = ['chain1', 'chain2', 'chain3'] subset += ['triangle1', 'triangle2', 'triangle3'] # subset = ['inconsistent_info'] tests_ = ut.dict_subset(tests, subset) for name, func in tests_.items(): logger.info('\n==============') ut.cprint('name = %r' % (name, ), 'yellow') uvw_list, pass_values, fail_values = func() G = build_graph(uvw_list) nodes = sorted(G.nodes()) edges = [tuple(sorted(e)) for e in G.edges()] edges = ut.sortedby2(edges, edges) n_annots = len(nodes) n_names = n_annots annot_idxs = list(range(n_annots)) lookup_annot_idx = ut.dzip(nodes, annot_idxs) nx.set_node_attributes(G, name='annot_idx', values=lookup_annot_idx) edge_probs = np.array([ get_edge_id_probs(G, aid1, aid2, n_names) for aid1, aid2 in edges ]) logger.info('nodes = %r' % (nodes, )) # logger.info('edges = %r' % (edges,)) logger.info('Noisy Observations') logger.info( pd.DataFrame(edge_probs, columns=['same', 'diff'], index=pd.Series(edges))) edge_probs = None cut_step( G, nodes, edges, n_annots, n_names, lookup_annot_idx, edge_probs, pass_values, fail_values, ) edge_probs = bp_step(G, nodes, edges, n_annots, n_names, lookup_annot_idx)
def update_visual_attrs(infr, graph=None, show_reviewed_edges=True, show_unreviewed_edges=False, show_inferred_diff=True, show_inferred_same=True, show_recent_review=False, highlight_reviews=True, show_inconsistency=True, wavy=False, simple_labels=False, show_labels=True, reposition=True, use_image=False, edge_overrides=None, node_overrides=None, colorby='name_label', **kwargs # hide_unreviewed_inferred=True ): import wbia.plottool as pt infr.print('update_visual_attrs', 3) if graph is None: graph = infr.graph # if hide_cuts is not None: # # show_unreviewed_cuts = not hide_cuts # show_reviewed_cuts = not hide_cuts if not getattr(infr, '_viz_init_nodes', False): infr._viz_init_nodes = True nx.set_node_attributes(graph, name='shape', values='circle') # infr.set_node_attrs('shape', 'circle') if getattr(infr, '_viz_image_config_dirty', True): infr.update_node_image_attribute(graph=graph, use_image=use_image) def get_any(dict_, keys, default=None): for key in keys: if key in dict_: return dict_[key] return default show_cand = get_any( kwargs, ['show_candidate_edges', 'show_candidates', 'show_cand']) if show_cand is not None: show_cand = True show_reviewed_edges = True show_unreviewed_edges = True show_inferred_diff = True show_inferred_same = True if kwargs.get('show_all'): show_cand = True # alpha_low = .5 alpha_med = 0.9 alpha_high = 1.0 dark_background = graph.graph.get('dark_background', None) # Ensure we are starting from a clean slate # if reposition: ut.nx_delete_edge_attr(graph, infr.visual_edge_attrs_appearance) # Set annotation node labels node_to_nid = None if not show_labels: nx.set_node_attributes(graph, name='label', values=ut.dzip(graph.nodes(), [''])) else: if simple_labels: nx.set_node_attributes( graph, name='label', values={n: str(n) for n in graph.nodes()}) else: if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') node_to_view = nx.get_node_attributes(graph, 'viewpoint') if node_to_view: annotnode_to_label = { aid: 'aid=%r%s\nnid=%r' % (aid, node_to_view[aid], node_to_nid[aid]) for aid in graph.nodes() } else: annotnode_to_label = { aid: 'aid=%r\nnid=%r' % (aid, node_to_nid[aid]) for aid in graph.nodes() } nx.set_node_attributes(graph, name='label', values=annotnode_to_label) # NODE_COLOR: based on name_label ut.color_nodes(graph, labelattr=colorby, outof=kwargs.get('outof', None), sat_adjust=-0.4) # EDGES: # Grab different types of edges edges, edge_colors = infr.get_colored_edge_weights( graph, highlight_reviews) # reviewed_states = nx.get_edge_attributes(graph, 'evidence_decision') reviewed_states = { e: infr.edge_decision(e) for e in infr.graph.edges() } edge_to_inferred_state = nx.get_edge_attributes( graph, 'inferred_state') # dummy_edges = [edge for edge, flag in # nx.get_edge_attributes(graph, '_dummy_edge').items() # if flag] edge_to_reviewid = nx.get_edge_attributes(graph, 'review_id') recheck_edges = [ edge for edge, split in nx.get_edge_attributes( graph, 'maybe_error').items() if split ] decision_to_edge = ut.group_pairs(reviewed_states.items()) neg_edges = decision_to_edge[NEGTV] pos_edges = decision_to_edge[POSTV] incomp_edges = decision_to_edge[INCMP] unreviewed_edges = decision_to_edge[UNREV] inferred_same = [ edge for edge, state in edge_to_inferred_state.items() if state == 'same' ] inferred_diff = [ edge for edge, state in edge_to_inferred_state.items() if state == 'diff' ] inconsistent_external = [ edge for edge, state in edge_to_inferred_state.items() if state == 'inconsistent_external' ] inferred_notcomp = [ edge for edge, state in edge_to_inferred_state.items() if state == 'notcomp' ] reviewed_edges = incomp_edges + pos_edges + neg_edges compared_edges = pos_edges + neg_edges uncompared_edges = ut.setdiff(edges, compared_edges) nontrivial_inferred_same = ut.setdiff( inferred_same, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_diff = ut.setdiff( inferred_diff, pos_edges + neg_edges + incomp_edges) nontrivial_inferred_edges = nontrivial_inferred_same + nontrivial_inferred_diff # EDGE_COLOR: based on edge_weight nx.set_edge_attributes(graph, name='color', values=ut.dzip(edges, edge_colors)) # LINE_WIDTH: based on review_state # unreviewed_width = 2.0 # reviewed_width = 5.0 unreviewed_width = 1.0 reviewed_width = 2.0 if highlight_reviews: nx.set_edge_attributes( graph, name='linewidth', values=ut.dzip(reviewed_edges, [reviewed_width]), ) nx.set_edge_attributes( graph, name='linewidth', values=ut.dzip(unreviewed_edges, [unreviewed_width]), ) else: nx.set_edge_attributes(graph, name='linewidth', values=ut.dzip(edges, [unreviewed_width])) # EDGE_STROKE: based on decision and maybe_error # fg = pt.WHITE if dark_background else pt.BLACK # nx.set_edge_attributes(graph, name='stroke', values=ut.dzip(reviewed_edges, [{'linewidth': 3, 'foreground': fg}])) if show_inconsistency: nx.set_edge_attributes( graph, name='stroke', values=ut.dzip(recheck_edges, [{ 'linewidth': 5, 'foreground': infr._error_color }]), ) # Set linestyles to emphasize PCCs # Dash lines between PCCs inferred to be different nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inferred_diff, ['dashed'])) # Treat incomparable/incon-external inference as different nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inferred_notcomp, ['dashed'])) nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(inconsistent_external, ['dashed'])) # Dot lines that we are unsure of nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(unreviewed_edges, ['dotted'])) # Cut edges are implicit and dashed # nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(cut_edges, [True])) # nx.set_edge_attributes(graph, name='linestyle', values=ut.dzip(cut_edges, ['dashed'])) # nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(cut_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(uncompared_edges, [True])) # Only matching edges should impose constraints on the graph layout nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(neg_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(neg_edges, [alpha_med])) nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(incomp_edges, [True])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(incomp_edges, [alpha_med])) # Ensure reviewed edges are visible nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(reviewed_edges, [False])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(reviewed_edges, [alpha_high])) if True: # Infered same edges can be allowed to constrain in order # to make things look nice sometimes nx.set_edge_attributes(graph, name='implicit', values=ut.dzip(inferred_same, [False])) nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_same, [alpha_high])) if not kwargs.get('show_same', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_same, [0])) if not kwargs.get('show_diff', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(inferred_diff, [0])) if not kwargs.get('show_positive_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(pos_edges, [0])) if not kwargs.get('show_negative_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(neg_edges, [0])) if not kwargs.get('show_incomparable_edges', True): nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(incomp_edges, [0])) if not kwargs.get('show_between', True): if node_to_nid is None: node_to_nid = nx.get_node_attributes(graph, 'name_label') between_edges = [(u, v) for u, v in edges if node_to_nid[u] != node_to_nid[v]] nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(between_edges, [0])) # SKETCH: based on inferred_edges # Make inferred edges wavy if wavy: # dict(scale=3.0, length=18.0, randomness=None)] nx.set_edge_attributes( graph, name='sketch', values=ut.dzip( nontrivial_inferred_edges, [dict(scale=10.0, length=64.0, randomness=None)], ), ) # Make dummy edges more transparent # nx.set_edge_attributes(graph, name='alpha', values=ut.dzip(dummy_edges, [alpha_low])) selected_edges = kwargs.pop('selected_edges', None) # SHADOW: based on most recent # Increase visibility of nodes with the most recently changed timestamp if show_recent_review and edge_to_reviewid and selected_edges is None: review_ids = list(edge_to_reviewid.values()) recent_idxs = ut.argmax(review_ids, multi=True) recent_edges = ut.take(list(edge_to_reviewid.keys()), recent_idxs) selected_edges = recent_edges if selected_edges is not None: # TODO: add photoshop-like parameters like # spread and size. offset is the same as angle and distance. nx.set_edge_attributes( graph, name='shadow', values=ut.dzip( selected_edges, [{ 'rho': 0.3, 'alpha': 0.6, 'shadow_color': 'w' if dark_background else 'k', 'offset': (0, 0), 'scale': 3.0, }], ), ) # Z_ORDER: make sure nodes are on top nodes = list(graph.nodes()) nx.set_node_attributes(graph, name='zorder', values=ut.dzip(nodes, [10])) nx.set_edge_attributes(graph, name='zorder', values=ut.dzip(edges, [0])) nx.set_edge_attributes(graph, name='picker', values=ut.dzip(edges, [10])) # VISIBILITY: Set visibility of edges based on arguments if not show_reviewed_edges: infr.print('Making reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(reviewed_edges, ['invis'])) if not show_unreviewed_edges: infr.print('Making un-reviewed edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(unreviewed_edges, ['invis'])) if not show_inferred_same: infr.print('Making nontrivial_same edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(nontrivial_inferred_same, ['invis'])) if not show_inferred_diff: infr.print('Making nontrivial_diff edges invisible', 10) nx.set_edge_attributes(graph, name='style', values=ut.dzip(nontrivial_inferred_diff, ['invis'])) if selected_edges is not None: # Always show the most recent review (remove setting of invis) # infr.print('recent_edges = %r' % (recent_edges,)) nx.set_edge_attributes(graph, name='style', values=ut.dzip(selected_edges, [''])) if reposition: # LAYOUT: update the positioning layout def get_layoutkw(key, default): return kwargs.get(key, graph.graph.get(key, default)) layoutkw = dict( prog='neato', splines=get_layoutkw('splines', 'line'), fontsize=get_layoutkw('fontsize', None), fontname=get_layoutkw('fontname', None), sep=10 / 72, esep=1 / 72, nodesep=0.1, ) layoutkw.update(kwargs) # logger.info(ut.repr3(graph.edges)) pt.nx_agraph_layout(graph, inplace=True, **layoutkw) if edge_overrides: for key, edge_to_attr in edge_overrides.items(): nx.set_edge_attributes(graph, name=key, values=edge_to_attr) if node_overrides: for key, node_to_attr in node_overrides.items(): nx.set_node_attributes(graph, name=key, values=node_to_attr)
5334: {'aid': 5334, 'name_label': 5977, 'orig_name_label': 5977}, 5338: {'aid': 5338, 'name_label': 5977, 'orig_name_label': 5977}, 5344: {'aid': 5344, 'name_label': 5977, 'orig_name_label': 5977}, 5349: {'aid': 5349, 'name_label': 5977, 'orig_name_label': 5977}, 5383: {'aid': 5383, 'name_label': 5977, 'orig_name_label': 5977}, 5399: {'aid': 5399, 'name_label': 5977, 'orig_name_label': 5977}, 5430: {'aid': 5430, 'name_label': 5977, 'orig_name_label': 5977}, } graph = nx.Graph(edges) graph.add_nodes_from(nodes.keys()) df = pd.DataFrame.from_dict(nodes, orient='index') nx.set_node_attributes( graph, name='orig_name_label', values=ut.dzip(df['aid'], df['orig_name_label']) ) nx.set_node_attributes( graph, name='name_label', values=ut.dzip(df['aid'], df['name_label']) ) aug_graph = graph node_to_label = nx.get_node_attributes(graph, 'name_label') aid1, aid2 = 2265, 2280 label_to_nodes = ut.group_items(node_to_label.keys(), node_to_label.values()) aug_graph = graph.copy()
'orig_name_label': 5977 }, 5430: { 'aid': 5430, 'name_label': 5977, 'orig_name_label': 5977 } } graph = nx.Graph(edges) graph.add_nodes_from(nodes.keys()) df = pd.DataFrame.from_dict(nodes, orient='index') nx.set_node_attributes(graph, name='orig_name_label', values=ut.dzip(df['aid'], df['orig_name_label'])) nx.set_node_attributes(graph, name='name_label', values=ut.dzip(df['aid'], df['name_label'])) aug_graph = graph node_to_label = nx.get_node_attributes(graph, 'name_label') aid1, aid2 = 2265, 2280 label_to_nodes = ut.group_items(node_to_label.keys(), node_to_label.values()) aug_graph = graph.copy() # remove cut edges from augmented graph edge_to_iscut = nx.get_edge_attributes(aug_graph, 'is_cut')
def find_mst_edges(infr, label='name_label'): """ Returns edges to augment existing PCCs (by label) in order to ensure they are connected with positive edges. CommandLine: python -m wbia.algo.graph.mixin_helpers find_mst_edges --profile Example: >>> # ENABLE_DOCTEST >>> from wbia.algo.graph.mixin_helpers import * # NOQA >>> import wbia >>> ibs = wbia.opendb(defaultdb='PZ_MTEST') >>> infr = wbia.AnnotInference(ibs, 'all', autoinit=True) >>> label = 'orig_name_label' >>> label = 'name_label' >>> infr.find_mst_edges() >>> infr.ensure_mst() Ignore: old_mst_edges = [ e for e, d in infr.edges(data=True) if d.get('user_id', None) == 'algo:mst' ] infr.graph.remove_edges_from(old_mst_edges) infr.pos_graph.remove_edges_from(old_mst_edges) infr.neg_graph.remove_edges_from(old_mst_edges) infr.incomp_graph.remove_edges_from(old_mst_edges) """ # Find clusters by labels node_to_label = infr.get_node_attrs(label) label_to_nodes = ut.group_items(node_to_label.keys(), node_to_label.values()) weight_heuristic = infr.ibs is not None if weight_heuristic: annots = infr.ibs.annots(infr.aids) node_to_time = ut.dzip(annots, annots.time) node_to_view = ut.dzip(annots, annots.viewpoint_code) enabled_heuristics = { 'view_weight', 'time_weight', } def _heuristic_weighting(nodes, avail_uv): avail_uv = np.array(avail_uv) weights = np.ones(len(avail_uv)) if 'view_weight' in enabled_heuristics: from vtool import _rhomb_dist view_edge = [(node_to_view[u], node_to_view[v]) for (u, v) in avail_uv] view_weight = np.array( [_rhomb_dist.VIEW_CODE_DIST[(v1, v2)] for (v1, v2) in view_edge] ) # Assume comparable by default and prefer undefined # more than probably not, but less than definately so. view_weight[np.isnan(view_weight)] = 1.5 # Prefer viewpoint 10x more than time weights += 10 * view_weight if 'time_weight' in enabled_heuristics: # Prefer linking annotations closer in time times = ut.take(node_to_time, nodes) maxtime = vt.safe_max(times, fill=1, nans=False) mintime = vt.safe_min(times, fill=0, nans=False) time_denom = maxtime - mintime # Try linking by time for lynx data time_delta = np.array( [abs(node_to_time[u] - node_to_time[v]) for u, v in avail_uv] ) time_weight = time_delta / time_denom weights += time_weight weights = np.array(weights) weights[np.isnan(weights)] = 1.0 avail = [(u, v, {'weight': w}) for (u, v), w in zip(avail_uv, weights)] return avail new_edges = [] prog = ut.ProgIter( list(label_to_nodes.keys()), label='finding mst edges', enabled=infr.verbose > 0, ) for nid in prog: nodes = set(label_to_nodes[nid]) if len(nodes) == 1: continue # We want to make this CC connected pos_sub = infr.pos_graph.subgraph(nodes, dynamic=False) impossible = set( it.starmap( e_, it.chain( nxu.edges_inside(infr.neg_graph, nodes), nxu.edges_inside(infr.incomp_graph, nodes), # nxu.edges_inside(infr.unknown_graph, nodes), ), ) ) if len(impossible) == 0 and not weight_heuristic: # Simple mst augmentation aug_edges = list(nxu.k_edge_augmentation(pos_sub, k=1)) else: complement = it.starmap(e_, nxu.complement_edges(pos_sub)) avail_uv = [(u, v) for u, v in complement if (u, v) not in impossible] if weight_heuristic: # Can do heuristic weighting to improve the MST avail = _heuristic_weighting(nodes, avail_uv) else: avail = avail_uv # logger.info(len(pos_sub)) try: aug_edges = list(nxu.k_edge_augmentation(pos_sub, k=1, avail=avail)) except nx.NetworkXUnfeasible: logger.info('Warning: MST augmentation is not feasible') logger.info('explicit negative edges might disconnect a PCC') aug_edges = list( nxu.k_edge_augmentation(pos_sub, k=1, avail=avail, partial=True) ) new_edges.extend(aug_edges) prog.ensure_newline() for edge in new_edges: assert not infr.graph.has_edge(*edge), 'alrady have edge={}'.format(edge) return new_edges
def monkeypatch_encounters(ibs, aids, cache=None, **kwargs): """ Hacks in a temporary custom definition of encounters for this controller 50 days for PZ_MTEST kwargs = dict(days=50) if False: name_mindeltas = [] for name in annots.group_items(annots.nids).values(): times = name.image_unixtimes_asfloat deltas = [ut.unixtime_to_timedelta(np.abs(t1 - t2)) for t1, t2 in ut.combinations(times, 2)] if deltas: name_mindeltas.append(min(deltas)) print(ut.repr3(ut.lmap(ut.get_timedelta_str, sorted(name_mindeltas)))) """ from ibeis.algo.preproc.occurrence_blackbox import cluster_timespace_sec import numpy as np import datetime if len(aids) == 0: return annots = ibs.annots(sorted(set(aids))) thresh_sec = datetime.timedelta(**kwargs).total_seconds() # thresh_sec = datetime.timedelta(minutes=30).seconds if cache is None: cache = True # cache = len(aids) > 200 cfgstr = str(ut.combine_uuids(annots.visual_uuids)) + str(thresh_sec) cacher = ut.Cacher('occurrence_labels', cfgstr=cfgstr, enabled=cache) data = cacher.tryload() if data is None: print('Computing occurrences for monkey patch for %d aids' % (len(aids))) posixtimes = annots.image_unixtimes_asfloat latlons = annots.gps data = cluster_timespace_sec(posixtimes, latlons, thresh_sec=thresh_sec, km_per_sec=.002) cacher.save(data) occurrence_ids = data if occurrence_ids is None: # return # each annot is its own occurrence occurrence_ids = list(range(len(annots))) ndec = int(np.ceil(np.log10(max(occurrence_ids)))) suffmt = '-monkey-occur%0' + str(ndec) + 'd' encounter_labels = [ n + suffmt % (o, ) for o, n in zip(occurrence_ids, annots.names) ] occurrence_labels = [suffmt[1:] % (o, ) for o in occurrence_ids] enc_lookup = ut.dzip(annots.aids, encounter_labels) occur_lookup = ut.dzip(annots.aids, occurrence_labels) # annots_per_enc = ut.dict_hist(encounter_labels, ordered=True) # ut.get_stats(list(annots_per_enc.values())) # encounters = ibs._annot_groups(annots.group(encounter_labels)[1]) # enc_names = ut.take_column(encounters.nids, 0) # name_to_encounters = ut.group_items(encounters, enc_names) # print('name_to_encounters = %s' % (ut.repr3(name_to_encounters)),) # print('Names to num encounters') # name_to_num_enc = ut.dict_hist( # ut.map_dict_vals(len, name_to_encounters).values()) # monkey patch to override encounter info def _monkey_get_annot_occurrence_text(ibs, aids): return ut.dict_take(occur_lookup, aids) def _monkey_get_annot_encounter_text(ibs, aids): return ut.dict_take(enc_lookup, aids) ut.inject_func_as_method(ibs, _monkey_get_annot_encounter_text, 'get_annot_encounter_text', force=True) ut.inject_func_as_method(ibs, _monkey_get_annot_occurrence_text, 'get_annot_occurrence_text', force=True)
def convert_hsdb_to_ibeis(hsdir, dbdir=None, **kwargs): r""" Args hsdir (str): Directory to folder *containing* _hsdb dbdir (str): Output directory (defaults to same as hsdb) CommandLine: python -m ibeis convert_hsdb_to_ibeis --dbdir ~/work/Frogs python -m ibeis convert_hsdb_to_ibeis --hsdir "/raid/raw/RotanTurtles/Roatan HotSpotter Nov_21_2016" Ignore: from ibeis.dbio.ingest_hsdb import * # NOQA hsdir = "/raid/raw/RotanTurtles/Roatan HotSpotter Nov_21_2016" dbdir = "~/work/RotanTurtles" Example: >>> # SCRIPT >>> from ibeis.dbio.ingest_hsdb import * # NOQA >>> dbdir = ut.get_argval('--dbdir', type_=str, default=None) >>> hsdir = ut.get_argval('--hsdir', type_=str, default=dbdir) >>> result = convert_hsdb_to_ibeis(hsdir) >>> print(result) """ from ibeis.control import IBEISControl import utool as ut if dbdir is None: dbdir = hsdir print('[ingest] Ingesting hsdb: %r -> %r' % (hsdir, dbdir)) assert is_hsdb( hsdir ), 'not a hotspotter database. cannot even force convert: hsdir=%r' % ( hsdir, ) assert not is_succesful_convert(dbdir), 'hsdir=%r is already converted' % ( hsdir, ) #print('FORCE DELETE: %r' % (hsdir,)) #ibsfuncs.delete_ibeis_database(hsdir) imgdir = join(hsdir, 'images') internal_dir = get_hsinternal(hsdir) nametbl_fpath = join(internal_dir, 'name_table.csv') imgtbl_fpath = join(internal_dir, 'image_table.csv') chiptbl_fpath = join(internal_dir, 'chip_table.csv') # READ NAME TABLE name_text_list = ['____'] name_hs_nid_list = [0] with open(nametbl_fpath, 'r') as nametbl_file: name_reader = csv.reader(nametbl_file) for ix, row in enumerate(name_reader): #if ix >= 3: if len(row) == 0 or row[0].strip().startswith('#'): continue else: hs_nid = int(row[0]) name = row[1].strip() name_text_list.append(name) name_hs_nid_list.append(hs_nid) # READ IMAGE TABLE iamge_hs_gid_list = [] image_gname_list = [] image_reviewed_list = [] with open(imgtbl_fpath, 'r') as imgtb_file: image_reader = csv.reader(imgtb_file) for ix, row in enumerate(image_reader): if len(row) == 0 or row[0].strip().startswith('#'): continue else: hs_gid = int(row[0]) gname_ = row[1].strip() # aif in hotspotter is equivilant to reviewed in IBEIS reviewed = bool(row[2]) iamge_hs_gid_list.append(hs_gid) image_gname_list.append(gname_) image_reviewed_list.append(reviewed) image_gpath_list = [join(imgdir, gname) for gname in image_gname_list] ut.debug_duplicate_items(image_gpath_list) #print(image_gpath_list) image_exist_flags = list(map(exists, image_gpath_list)) missing_images = [] for image_gpath, flag in zip(image_gpath_list, image_exist_flags): if not flag: missing_images.append(image_gpath) print('Image does not exist: %s' % image_gpath) if not all(image_exist_flags): print('Only %d / %d image exist' % (sum(image_exist_flags), len(image_exist_flags))) SEARCH_FOR_IMAGES = False if SEARCH_FOR_IMAGES: # Hack to try and find the missing images from os.path import basename subfiles = ut.glob(hsdir, '*', recursive=True, fullpath=True, with_files=True) basename_to_existing = ut.group_items(subfiles, ut.lmap(basename, subfiles)) can_copy_list = [] for gpath in missing_images: gname = basename(gpath) if gname not in basename_to_existing: print('gname = %r' % (gname, )) pass else: existing = basename_to_existing[gname] can_choose = True if len(existing) > 1: if not ut.allsame(ut.lmap(ut.get_file_uuid, existing)): can_choose = False if can_choose: found = existing[0] can_copy_list.append((found, gpath)) else: print(existing) src, dst = ut.listT(can_copy_list) ut.copy_list(src, dst) # READ CHIP TABLE chip_bbox_list = [] chip_theta_list = [] chip_hs_nid_list = [] chip_hs_gid_list = [] chip_note_list = [] with open(chiptbl_fpath, 'r') as chiptbl_file: chip_reader = csv.reader(chiptbl_file) for ix, row in enumerate(chip_reader): if len(row) == 0 or row[0].strip().startswith('#'): continue else: hs_gid = int(row[1]) hs_nid = int(row[2]) bbox_text = row[3] theta = float(row[4]) notes = '<COMMA>'.join([item.strip() for item in row[5:]]) bbox_text = bbox_text.replace('[', '').replace(']', '').strip() bbox_text = re.sub(' *', ' ', bbox_text) bbox_strlist = bbox_text.split(' ') bbox = tuple(map(int, bbox_strlist)) #bbox = [int(item) for item in bbox_strlist] chip_hs_nid_list.append(hs_nid) chip_hs_gid_list.append(hs_gid) chip_bbox_list.append(bbox) chip_theta_list.append(theta) chip_note_list.append(notes) names = ut.ColumnLists({ 'hs_nid': name_hs_nid_list, 'text': name_text_list, }) images = ut.ColumnLists({ 'hs_gid': iamge_hs_gid_list, 'gpath': image_gpath_list, 'reviewed': image_reviewed_list, 'exists': image_exist_flags, }) chips = ut.ColumnLists({ 'hs_gid': chip_hs_gid_list, 'hs_nid': chip_hs_nid_list, 'bbox': chip_bbox_list, 'theta': chip_theta_list, 'note': chip_note_list, }) IGNORE_MISSING_IMAGES = True if IGNORE_MISSING_IMAGES: # Ignore missing information print('pre') print('chips = %r' % (chips, )) print('images = %r' % (images, )) print('names = %r' % (names, )) missing_gxs = ut.where(ut.not_list(images['exists'])) missing_gids = ut.take(images['hs_gid'], missing_gxs) gid_to_cxs = ut.dzip(*chips.group_indicies('hs_gid')) missing_cxs = ut.flatten(ut.take(gid_to_cxs, missing_gids)) # Remove missing images and dependant chips images = images.remove(missing_gxs) chips = chips.remove(missing_cxs) valid_nids = set(chips['hs_nid'] + [0]) isvalid = [nid in valid_nids for nid in names['hs_nid']] names = names.compress(isvalid) print('post') print('chips = %r' % (chips, )) print('images = %r' % (images, )) print('names = %r' % (names, )) assert all(images['exists']), 'some images dont exist' # if gid is None: # print('Not adding the ix=%r-th Chip. Its image is corrupted image.' % (ix,)) # # continue # # Build mappings to new indexes # names_nid_to_nid = {names_nid: nid for (names_nid, nid) in zip(hs_nid_list, nid_list)} # names_nid_to_nid[1] = names_nid_to_nid[0] # hsdb unknknown is 0 or 1 # images_gid_to_gid = {images_gid: gid for (images_gid, gid) in zip(hs_gid_list, gid_list)} ibs = IBEISControl.request_IBEISController(dbdir=dbdir, check_hsdb=False, **kwargs) assert len(ibs.get_valid_gids()) == 0, 'target database is not empty' # Add names, images, and annotations names['ibs_nid'] = ibs.add_names(names['text']) images['ibs_gid'] = ibs.add_images( images['gpath']) # any failed gids will be None if True: # Remove corrupted images print('pre') print('chips = %r' % (chips, )) print('images = %r' % (images, )) print('names = %r' % (names, )) missing_gxs = ut.where(ut.flag_None_items(images['ibs_gid'])) missing_gids = ut.take(images['hs_gid'], missing_gxs) gid_to_cxs = ut.dzip(*chips.group_indicies('hs_gid')) missing_cxs = ut.flatten(ut.take(gid_to_cxs, missing_gids)) # Remove missing images and dependant chips chips = chips.remove(missing_cxs) images = images.remove(missing_gxs) print('post') print('chips = %r' % (chips, )) print('images = %r' % (images, )) print('names = %r' % (names, )) # Index chips using new ibs rowids ibs_gid_lookup = ut.dzip(images['hs_gid'], images['ibs_gid']) ibs_nid_lookup = ut.dzip(names['hs_nid'], names['ibs_nid']) try: chips['ibs_gid'] = ut.take(ibs_gid_lookup, chips['hs_gid']) except KeyError: chips['ibs_gid'] = [ ibs_gid_lookup.get(index, None) for index in chips['hs_gid'] ] try: chips['ibs_nid'] = ut.take(ibs_nid_lookup, chips['hs_nid']) except KeyError: chips['ibs_nid'] = [ ibs_nid_lookup.get(index, None) for index in chips['hs_nid'] ] ibs.add_annots(chips['ibs_gid'], bbox_list=chips['bbox'], theta_list=chips['theta'], nid_list=chips['ibs_nid'], notes_list=chips['note']) # aid_list = ibs.get_valid_aids() # flag_list = [True] * len(aid_list) # ibs.set_annot_exemplar_flags(aid_list, flag_list) # assert(all(ibs.get_annot_exemplar_flags(aid_list))), 'exemplars not set correctly' # Write file flagging successful conversion with open(join(ibs.get_ibsdir(), SUCCESS_FLAG_FNAME), 'w') as file_: file_.write('Successfully converted hsdir=%r' % (hsdir, )) print('finished ingest') return ibs
def _enrich_matches_lnbnn(extr, matches, other_aids, other_nids, inplace=False): """ Given a set of one-vs-one matches, searches for LNBNN normalizers in a larger database to enrich the matches with database-level distinctiveness. """ from ibeis.algo.hots import nn_weights raise NotImplementedError('havent tested since the re-work. ' 'Need to ensure that things work correctly.') ibs = extr.ibs cfgdict = { 'can_match_samename': False, 'can_match_sameimg': True, 'K': 3, 'Knorm': 3, 'prescore_method': 'csum', 'score_method': 'csum' } custom_nid_lookup = ut.dzip(other_aids, other_nids) aids = [m.annot2['aid'] for m in matches] qreq_ = ibs.new_query_request(aids, other_aids, cfgdict=cfgdict, custom_nid_lookup=custom_nid_lookup, verbose=extr.verbose >= 2) qreq_.load_indexer() indexer = qreq_.indexer if not inplace: matches_ = [match.copy() for match in matches] else: matches_ = matches K = qreq_.qparams.K Knorm = qreq_.qparams.Knorm normalizer_rule = qreq_.qparams.normalizer_rule extr.print('Stacking vecs for batch lnbnn matching') offset_list = np.cumsum([0] + [match_.fm.shape[0] for match_ in matches_]) stacked_vecs = np.vstack([ match_.matched_vecs2() for match_ in ut.ProgIter(matches_, label='stack matched vecs') ]) vecs = stacked_vecs num = (K + Knorm) idxs, dists = indexer.batch_knn(vecs, num, chunksize=8192, label='lnbnn scoring') idx_list = [idxs[l:r] for l, r in ut.itertwo(offset_list)] dist_list = [dists[l:r] for l, r in ut.itertwo(offset_list)] iter_ = zip(matches_, idx_list, dist_list) prog = ut.ProgIter(iter_, length=len(matches_), label='lnbnn scoring') for match_, neighb_idx, neighb_dist in prog: qaid = match_.annot2['aid'] norm_k = nn_weights.get_normk(qreq_, qaid, neighb_idx, Knorm, normalizer_rule) ndist = vt.take_col_per_row(neighb_dist, norm_k) vdist = match_.local_measures['match_dist'] lnbnn_dist = nn_weights.lnbnn_fn(vdist, ndist) lnbnn_clip_dist = np.clip(lnbnn_dist, 0, np.inf) match_.local_measures['lnbnn_norm_dist'] = ndist match_.local_measures['lnbnn'] = lnbnn_dist match_.local_measures['lnbnn_clip'] = lnbnn_clip_dist match_.fs = lnbnn_dist return matches_
def ensure_priority_scores(infr, priority_edges): """ Ensures that priority attributes are assigned to the edges. This does not change the state of the queue. Doctest: >>> import wbia >>> ibs = wbia.opendb('PZ_MTEST') >>> infr = wbia.AnnotInference(ibs, aids='all') >>> infr.ensure_mst() >>> priority_edges = list(infr.edges())[0:1] >>> infr.ensure_priority_scores(priority_edges) Doctest: >>> import wbia >>> ibs = wbia.opendb('PZ_MTEST') >>> infr = wbia.AnnotInference(ibs, aids='all') >>> infr.ensure_mst() >>> # infr.load_published() >>> priority_edges = list(infr.edges()) >>> infr.ensure_priority_scores(priority_edges) Doctest: >>> from wbia.algo.graph import demo >>> infr = demo.demodata_infr(num_pccs=6, p_incon=.5, size_std=2) >>> edges = list(infr.edges()) >>> infr.ensure_priority_scores(edges) """ infr.print('Checking for verifiers: %r' % (infr.verifiers,)) if infr.verifiers and infr.ibs is not None: infr.print( 'Prioritizing {} edges with one-vs-one probs'.format(len(priority_edges)), 1, ) infr.print('Using thresholds: %r' % (infr.task_thresh,)) infr.print( 'Using infr.params[autoreview.enabled] : %r' % (infr.params['autoreview.enabled'],) ) infr.print( 'Using infr.params[autoreview.prioritize_nonpos]: %r' % (infr.params['autoreview.prioritize_nonpos'],) ) infr.ensure_task_probs(priority_edges) infr.load_published() primary_task = 'match_state' match_probs = infr.task_probs[primary_task] primary_thresh = infr.task_thresh[primary_task] # Read match_probs into a DataFrame primary_probs = pd.DataFrame( ut.take(match_probs, priority_edges), index=nxu.ensure_multi_index(priority_edges, ('aid1', 'aid2')), ) # Convert match-state probabilities into priorities prob_match = primary_probs[POSTV] # Initialize priorities to probability of matching default_priority = prob_match.copy() # If the edges are currently between the same individual, then # prioritize by non-positive probability (because those edges might # expose an inconsistency) already_pos = [ infr.pos_graph.node_label(u) == infr.pos_graph.node_label(v) for u, v in priority_edges ] default_priority[already_pos] = 1 - default_priority[already_pos] if infr.params['autoreview.enabled']: if infr.params['autoreview.prioritize_nonpos']: # Give positives that pass automatic thresholds high priority _probs = primary_probs[POSTV] flags = _probs > primary_thresh[POSTV] default_priority[flags] = ( np.maximum(default_priority[flags], _probs[flags]) + 1 ) # Give negatives that pass automatic thresholds high priority _probs = primary_probs[NEGTV] flags = _probs > primary_thresh[NEGTV] default_priority[flags] = ( np.maximum(default_priority[flags], _probs[flags]) + 1 ) # Give not-comps that pass automatic thresholds high priority _probs = primary_probs[INCMP] flags = _probs > primary_thresh[INCMP] default_priority[flags] = ( np.maximum(default_priority[flags], _probs[flags]) + 1 ) infr.set_edge_attrs('prob_match', prob_match.to_dict()) infr.set_edge_attrs('default_priority', default_priority.to_dict()) metric = 'default_priority' priority = default_priority elif infr.cm_list is not None: infr.print( 'Prioritizing {} edges with one-vs-vsmany scores'.format( len(priority_edges) ) ) # Not given any deploy classifier, this is the best we can do scores = infr._make_lnbnn_scores(priority_edges) metric = 'normscore' priority = scores else: infr.print( 'WARNING: No verifiers to prioritize {} edge(s)'.format( len(priority_edges) ) ) metric = 'random' priority = np.zeros(len(priority_edges)) + 1e-6 infr.set_edge_attrs(metric, ut.dzip(priority_edges, priority)) return metric, priority
def make_netx_graph_from_aid_groups(ibs, aids_list, only_reviewed_matches=True, invis_edges=None, ensure_edges=None, temp_nids=None, allow_directed=False): r""" Args: ibs (ibeis.IBEISController): image analysis api aids_list (list): Example: >>> # DISABLE_DOCTEST >>> from ibeis.viz.viz_graph import * # NOQA >>> import ibeis >>> ibs = ibeis.opendb(defaultdb='testdb1') >>> aids_list = [[1, 2, 3, 4], [5, 6, 7]] >>> invis_edges = [(1, 5)] >>> only_reviewed_matches = True >>> graph = make_netx_graph_from_aid_groups(ibs, aids_list, >>> only_reviewed_matches, >>> invis_edges) >>> list(nx.connected_components(graph.to_undirected())) """ #aids_list, nid_list = ibs.group_annots_by_name(aid_list) unique_aids = list(ut.flatten(aids_list)) # grouped version unflat_edges = (list(itertools.product(aids, aids)) for aids in aids_list) aid_pairs = [tup for tup in ut.iflatten(unflat_edges) if tup[0] != tup[1]] aids1 = ut.get_list_column(aid_pairs, 0) aids2 = ut.get_list_column(aid_pairs, 1) if only_reviewed_matches: annotmatch_rowids = ibs.get_annotmatch_rowid_from_undirected_superkey( aids1, aids2) annotmatch_rowids = ut.filter_Nones(annotmatch_rowids) aids1 = ibs.get_annotmatch_aid1(annotmatch_rowids) aids2 = ibs.get_annotmatch_aid2(annotmatch_rowids) graph = make_netx_graph_from_aidpairs(ibs, aids1, aids2, unique_aids=unique_aids) if ensure_edges is not None: if ensure_edges == 'all': ensure_edges = list(ut.upper_diag_self_prodx(list(graph.nodes()))) ensure_edges_ = [] for edge in ensure_edges: edge = tuple(edge) redge = tuple(edge[::-1]) # HACK if graph.has_edge(*edge): ensure_edges_.append(edge) pass #nx.set_edge_attributes(graph, name='weight', values={edge: .001}) elif (not allow_directed) and graph.has_edge(*redge): ensure_edges_.append(redge) #nx.set_edge_attributes(graph, name='weight', values={redge: .001}) pass else: ensure_edges_.append(edge) #graph.add_edge(*edge, weight=.001) graph.add_edge(*edge) if temp_nids is None: unique_nids = ibs.get_annot_nids(list(graph.nodes())) else: # HACK unique_nids = [1] * len(list(graph.nodes())) #unique_nids = temp_nids nx.set_node_attributes(graph, name='nid', value=ut.dzip(graph.nodes(), unique_nids)) import plottool as pt ensure_names_are_connected(graph, aids_list) # Color edges by nid color_by_nids(graph, unique_nids=unique_nids) if invis_edges: for edge in invis_edges: if graph.has_edge(*edge): nx.set_edge_attributes(graph, name='style', values={edge: 'invis'}) nx.set_edge_attributes(graph, name='invisible', values={edge: True}) else: graph.add_edge(*edge, style='invis', invisible=True) # Hack color images orange if ensure_edges: nx.set_edge_attributes( graph, name='color', values={tuple(edge): pt.ORANGE for edge in ensure_edges_}) return graph
def _dz(a, b): a = a.tolist() if isinstance(a, np.ndarray) else list(a) b = b.tolist() if isinstance(b, np.ndarray) else list(b) return ut.dzip(a, b)
def fix_bidirectional_annotmatch(ibs): import wbia infr = wbia.AnnotInference(ibs=ibs, aids='all', verbose=5) infr.initialize_graph() annots = ibs.annots() aid_to_nid = ut.dzip(annots.aids, annots.nids) # Delete bidirectional annotmatches annotmatch = ibs.db.get_table_as_pandas('annotmatch') df = annotmatch.set_index(['annot_rowid1', 'annot_rowid2']) # Find entires that have both directions pairs1 = annotmatch[['annot_rowid1', 'annot_rowid2']].values f_edges = {tuple(p) for p in pairs1} b_edges = {tuple(p[::-1]) for p in pairs1} isect_edges = {tuple(sorted(p)) for p in b_edges.intersection(f_edges)} logger.info('Found %d bidirectional edges' % len(isect_edges)) isect_edges1 = list(isect_edges) isect_edges2 = [p[::-1] for p in isect_edges] import pandas as pd extra_ = {} fixme_edges = [] d1 = df.loc[isect_edges1].reset_index(drop=False) d2 = df.loc[isect_edges2].reset_index(drop=False) flags = d1['annotmatch_evidence_decision'] != d2[ 'annotmatch_evidence_decision'] from wbia.tag_funcs import _parse_tags for f, r1, r2 in zip(flags, d1.iterrows(), d2.iterrows()): v1, v2 = r1[1], r2[1] aid1 = v1['annot_rowid1'] aid2 = v1['annot_rowid2'] truth_real = (ibs.const.EVIDENCE_DECISION.POSITIVE if aid_to_nid[aid1] == aid_to_nid[aid2] else ibs.const.EVIDENCE_DECISION.NEGATIVE) truth1 = v1['annotmatch_evidence_decision'] truth2 = v2['annotmatch_evidence_decision'] t1 = _parse_tags(v1['annotmatch_tag_text']) t2 = _parse_tags(v2['annotmatch_tag_text']) newtag = ut.union_ordered(t1, t2) fixme_flag = False if not pd.isnull(truth1): if truth_real != truth1: fixme_flag = True if not pd.isnull(truth2): if truth_real != truth2: fixme_flag = True if fixme_flag: logger.info('--') logger.info('t1, t2 = %r, %r' % (t1, t2)) logger.info('newtag = %r' % (newtag, )) logger.info('truth_real, truth1, truth2 = %r, %r, %r' % (truth_real, truth1, truth2)) logger.info('aid1, aid2 = %r, %r' % (aid1, aid2)) fixme_edges.append(tuple(sorted((aid1, aid2)))) else: extra_[(aid1, aid2)] = (truth_real, newtag) if len(fixme_edges) > 0: # need to manually fix these edges fix_infr = wbia.AnnotInference.from_pairs(fixme_edges, ibs=ibs, verbose=5) feedback = fix_infr.read_wbia_annotmatch_feedback( only_existing_edges=True) infr = fix_infr fix_infr.external_feedback = feedback fix_infr.apply_feedback_edges() fix_infr.start_qt_interface(loop=False) # DELETE OLD EDGES TWICE ams = ibs.get_annotmatch_rowid_from_edges(fixme_edges) ibs.delete_annotmatch(ams) ams = ibs.get_annotmatch_rowid_from_edges(fixme_edges) ibs.delete_annotmatch(ams) # MANUALLY CALL THIS ONCE FINISHED # TO ONLY CHANGE ANNOTMATCH EDGES infr.write_wbia_staging_feedback() infr.write_wbia_annotmatch_feedback() # extra_.update(custom_) new_pairs = extra_.keys() new_truths = ut.take_column(ut.dict_take(extra_, new_pairs), 0) new_tags = ut.take_column(ut.dict_take(extra_, new_pairs), 1) new_tag_texts = [';'.join(t) for t in new_tags] aids1, aids2 = ut.listT(new_pairs) # Delete the old ibs.delete_annotmatch((d1['annotmatch_rowid'].values.tolist() + d2['annotmatch_rowid'].values.tolist())) # Add the new ams = ibs.add_annotmatch_undirected(aids1, aids2) ibs.set_annotmatch_evidence_decision(ams, new_truths) ibs.set_annotmatch_tag_text(ams, new_tag_texts) if False: import wbia.guitool as gt gt.ensure_qapp() ut.qtensure() from wbia.gui import inspect_gui inspect_gui.show_vsone_tuner(ibs, aid1, aid2)
def _update_state_opengm(model, weight_key='cut_prob', name_label_key='name_label'): import opengm import scipy.special graph = model.graph n_annots = len(model.graph) n_names = n_annots nodes = sorted(graph.nodes()) edges = [tuple(sorted(e)) for e in graph.edges()] edges = ut.sortedby2(edges, edges) index_type = opengm.index_type node_state_card = np.ones(n_annots, dtype=index_type) * n_names numberOfStates = node_state_card annot_idxs = list(range(n_annots)) lookup_annot_idx = ut.dzip(nodes, annot_idxs) gm = opengm.graphicalModel(numberOfStates, operator='adder') # annot_idxs = list(range(n_annots)) # edge_idxs = list(range(n_annots, n_annots + n_edges)) # if use_unaries: # unaries = np.ones((n_annots, n_names)) / n_names # # unaries[0][0] = 1 # # unaries[0][1:] = 0 # for annot_idx in annot_idxs: # fid = gm.addFunction(unaries[annot_idx]) # gm.addFactor(fid, annot_idx) # Add Potts function for each edge pairwise_factor_idxs = [] for count, (aid1, aid2) in enumerate(edges, start=len(list(gm.factors()))): varx1, varx2 = ut.take(lookup_annot_idx, [aid1, aid2]) var_indicies = np.array([varx1, varx2]) p_same = graph.get_edge_data(aid1, aid2)['cut_prob'] # p_diff = 1 - p_same eps = 1E-9 p_same = np.clip(p_same, eps, 1.0 - eps) same_weight = scipy.special.logit(p_same) # valueEqual = -same_weight valueEqual = 0 valueNotEqual = same_weight if not np.isfinite(valueNotEqual): """ python -m plottool.draw_func2 --exec-plot_func --show --range=-1,1 --func=scipy.special.logit """ print('valueNotEqual = %r' % (valueNotEqual, )) print('p_same = %r' % (p_same, )) raise ValueError('valueNotEqual') pairwise_factor_idxs.append(count) potts_func = opengm.PottsFunction((n_names, n_names), valueEqual=valueEqual, valueNotEqual=valueNotEqual) potts_func_id = gm.addFunction(potts_func) gm.addFactor(potts_func_id, var_indicies) model.gm = gm
def fix_annotmatch_pzmaster1(): """ PZ_Master1 had annotmatch rowids that did not agree with the current name labeling. Looking at the inconsistencies in the graph interface was too cumbersome, because over 3000 annots were incorrectly grouped together. This function deletes any annotmatch rowid that is not consistent with the current labeling so we can go forward with using the new AnnotInference object """ import wbia ibs = wbia.opendb('PZ_Master1') infr = wbia.AnnotInference(ibs=ibs, aids=ibs.get_valid_aids(), verbose=5) infr.initialize_graph() annots = ibs.annots() aid_to_nid = ut.dzip(annots.aids, annots.nids) if False: infr.reset_feedback() infr.ensure_mst() infr.apply_feedback_edges() infr.relabel_using_reviews() infr.start_qt_interface() # Get annotmatch rowids that agree with current labeling if False: annotmatch = ibs.db.get_table_as_pandas('annotmatch') import pandas as pd flags1 = pd.isnull(annotmatch['annotmatch_evidence_decision']) flags2 = annotmatch['annotmatch_tag_text'] == '' bad_part = annotmatch[flags1 & flags2] rowids = bad_part.index.tolist() ibs.delete_annotmatch(rowids) if False: # Delete bidirectional annotmatches annotmatch = ibs.db.get_table_as_pandas('annotmatch') df = annotmatch.set_index(['annot_rowid1', 'annot_rowid2']) # Find entires that have both directions pairs1 = annotmatch[['annot_rowid1', 'annot_rowid2']].values f_edges = {tuple(p) for p in pairs1} b_edges = {tuple(p[::-1]) for p in pairs1} isect_edges = {tuple(sorted(p)) for p in b_edges.intersection(f_edges)} isect_edges1 = list(isect_edges) isect_edges2 = [p[::-1] for p in isect_edges] # cols = ['annotmatch_evidence_decision', 'annotmatch_tag_text'] import pandas as pd custom_ = { (559, 4909): (False, ['photobomb']), (7918, 8041): (False, ['photobomb']), (6634, 6754): (False, ['photobomb']), (3707, 3727): (False, ['photobomb']), (86, 103): (False, ['photobomb']), } extra_ = {} fixme_edges = [] d1 = df.loc[isect_edges1].reset_index(drop=False) d2 = df.loc[isect_edges2].reset_index(drop=False) flags = d1['annotmatch_evidence_decision'] != d2[ 'annotmatch_evidence_decision'] from wbia.tag_funcs import _parse_tags for f, r1, r2 in zip(flags, d1.iterrows(), d2.iterrows()): v1, v2 = r1[1], r2[1] aid1 = v1['annot_rowid1'] aid2 = v1['annot_rowid2'] truth_real = (ibs.const.EVIDENCE_DECISION.POSITIVE if aid_to_nid[aid1] == aid_to_nid[aid2] else ibs.const.EVIDENCE_DECISION.NEGATIVE) truth1 = v1['annotmatch_evidence_decision'] truth2 = v2['annotmatch_evidence_decision'] t1 = _parse_tags(v1['annotmatch_tag_text']) t2 = _parse_tags(v2['annotmatch_tag_text']) newtag = ut.union_ordered(t1, t2) if (aid1, aid2) in custom_: continue fixme_flag = False if not pd.isnull(truth1): if truth_real != truth1: fixme_flag = True if not pd.isnull(truth2): if truth_real != truth2: fixme_flag = True if fixme_flag: logger.info('newtag = %r' % (newtag, )) logger.info('truth_real = %r' % (truth_real, )) logger.info('truth1 = %r' % (truth1, )) logger.info('truth2 = %r' % (truth2, )) logger.info('aid1 = %r' % (aid1, )) logger.info('aid2 = %r' % (aid2, )) fixme_edges.append((aid1, aid2)) else: extra_[(aid1, aid2)] = (truth_real, newtag) extra_.update(custom_) new_pairs = extra_.keys() new_truths = ut.take_column(ut.dict_take(extra_, new_pairs), 0) new_tags = ut.take_column(ut.dict_take(extra_, new_pairs), 1) new_tag_texts = [';'.join(t) for t in new_tags] aids1, aids2 = ut.listT(new_pairs) # Delete the old ibs.delete_annotmatch((d1['annotmatch_rowid'].values.tolist() + d2['annotmatch_rowid'].values.tolist())) # Add the new ams = ibs.add_annotmatch_undirected(aids1, aids2) ibs.set_annotmatch_evidence_decision(ams, new_truths) ibs.set_annotmatch_tag_text(ams, new_tag_texts) if False: import wbia.guitool as gt gt.ensure_qapp() ut.qtensure() from wbia.gui import inspect_gui inspect_gui.show_vsone_tuner(ibs, aid1, aid2) # pairs2 = pairs1.T[::-1].T # idx1, idx2 = ut.isect_indices(list(map(tuple, pairs1)), # list(map(tuple, pairs2))) # r_edges = list(set(map(tuple, map(sorted, pairs1[idx1])))) # unique_pairs = list(set(map(tuple, map(sorted, pairs1[idx1])))) # df = annotmatch.set_index(['annot_rowid1', 'annot_rowid2']) x = ut.ddict(list) annotmatch = ibs.db.get_table_as_pandas('annotmatch') import ubelt as ub _iter = annotmatch.iterrows() prog = ub.ProgIter(_iter, length=len(annotmatch)) for k, m in prog: aid1 = m['annot_rowid1'] aid2 = m['annot_rowid2'] if m['annotmatch_evidence_decision'] == ibs.const.EVIDENCE_DECISION.POSITIVE: if aid_to_nid[aid1] == aid_to_nid[aid2]: x['agree1'].append(k) else: x['disagree1'].append(k) elif m['annotmatch_evidence_decision'] == ibs.const.EVIDENCE_DECISION.NEGATIVE: if aid_to_nid[aid1] == aid_to_nid[aid2]: x['disagree2'].append(k) else: x['agree2'].append(k) ub.map_vals(len, x) ut.dict_hist(annotmatch.loc[x['disagree1']]['annotmatch_tag_text']) disagree1 = annotmatch.loc[x['disagree1']] pb_disagree1 = disagree1[disagree1['annotmatch_tag_text'] == 'photobomb'] aids1 = pb_disagree1['annot_rowid1'].values.tolist() aids2 = pb_disagree1['annot_rowid2'].values.tolist() aid_pairs = list(zip(aids1, aids2)) infr = wbia.AnnotInference.from_pairs(aid_pairs, ibs=ibs, verbose=5) if False: feedback = infr.read_wbia_annotmatch_feedback(edges=infr.edges()) infr.external_feedback = feedback infr.apply_feedback_edges() infr.start_qt_interface(loop=False) # Delete these values if False: nonpb_disagree1 = disagree1[ disagree1['annotmatch_tag_text'] != 'photobomb'] disagree2 = annotmatch.loc[x['disagree2']] ibs.delete_annotmatch(nonpb_disagree1['annotmatch_rowid']) ibs.delete_annotmatch(disagree2['annotmatch_rowid']) # ut.dict_hist(disagree1['annotmatch_tag_text']) import networkx as nx graph = nx.Graph() graph.add_edges_from( zip(pb_disagree1['annot_rowid1'], pb_disagree1['annot_rowid2'])) list(nx.connected_components(graph)) set(annotmatch.loc[x['disagree2']]['annotmatch_tag_text'])