# -*- coding: utf-8 -*-
"""
CommandLine:
python -m wbia.gui.inspect_gui --test-test_review_widget --show
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from functools import partial
from wbia.viz import viz_helpers as vh
import wbia.guitool as gt
import numpy as np
import utool as ut
(print, rrr, profile) = ut.inject2(__name__, '[id_review_api]')
MATCHED_STATUS_TEXT = 'Matched'
REVIEWED_STATUS_TEXT = 'Reviewed'
REVIEW_CFG_DEFAULTS = {
'ranks_top': 5,
'directed': False,
'name_scoring': True,
'filter_reviewed': True,
'filter_photobombs': True,
'filter_true_matches': True,
'show_chips': True,
'filter_duplicate_true_matches': False,
}
[docs]@profile
def get_review_edges(cm_list, ibs=None, review_cfg={}):
r"""
Needs to be moved to a better file. Maybe something to do with
identification.
Returns a list of matches that should be inspected
This function is more lightweight than orgres or allres.
Used in id_review_api and interact_qres2
Args:
cm_list (list): list of chip match objects
ranks_top (int): put all ranks less than this number into the graph
directed (bool):
Returns:
tuple: review_edges = (qaid_arr, daid_arr, score_arr, rank_arr)
CommandLine:
python -m wbia.gui.id_review_api get_review_edges:0
Example0:
>>> # ENABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> ibs = wbia.opendb('PZ_MTEST')
>>> qreq_ = wbia.main_helpers.testdata_qreq_()
>>> cm_list = qreq_.execute()
>>> review_cfg = dict(ranks_top=5, directed=True, name_scoring=False,
>>> filter_true_matches=True)
>>> review_edges = get_review_edges(cm_list, ibs=ibs, review_cfg=review_cfg)
>>> print(review_edges)
Example1:
>>> # UNSTABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> cm_list, qreq_ = wbia.testdata_cmlist('PZ_MTEST', a='default:qsize=5,dsize=20')
>>> review_cfg = dict(ranks_top=5, directed=True, name_scoring=False,
>>> filter_reviewed=False, filter_true_matches=True)
>>> review_edges = get_review_edges(cm_list, review_cfg=review_cfg, ibs=ibs)
>>> print(review_edges)
Example3:
>>> # UNSTABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> cm_list, qreq_ = wbia.testdata_cmlist('PZ_MTEST', a='default:qsize=1,dsize=100')
>>> review_cfg = dict(ranks_top=1, directed=False, name_scoring=False,
>>> filter_reviewed=False, filter_true_matches=True)
>>> review_edges = get_review_edges(cm_list, review_cfg=review_cfg, ibs=ibs)
>>> print(review_edges)
Example4:
>>> # UNSTABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> cm_list, qreq_ = wbia.testdata_cmlist('PZ_MTEST', a='default:qsize=10,dsize=10')
>>> ranks_top = 3
>>> review_cfg = dict(ranks_top=3, directed=False, name_scoring=False,
>>> filter_reviewed=False, filter_true_matches=True)
>>> review_edges = get_review_edges(cm_list, review_cfg=review_cfg, ibs=ibs)
>>> print(review_edges)
"""
import vtool as vt
from wbia.algo.hots import chip_match
automatch_kw = REVIEW_CFG_DEFAULTS.copy()
automatch_kw = ut.update_existing(automatch_kw, review_cfg)
print('[resorg] get_review_edges(%s)' % (ut.repr2(automatch_kw)))
print('[resorg] len(cm_list) = %d' % (len(cm_list)))
qaids_stack = []
daids_stack = []
ranks_stack = []
scores_stack = []
# For each QueryResult, Extract inspectable candidate matches
if isinstance(cm_list, dict):
cm_list = list(cm_list.values())
if len(cm_list) == 0:
return ([], [], [], [])
for cm in cm_list:
if isinstance(cm, chip_match.ChipMatch):
daids = cm.get_top_aids(ntop=automatch_kw['ranks_top'])
scores = cm.get_top_scores(ntop=automatch_kw['ranks_top'])
ranks = np.arange(len(daids))
qaids = np.full(daids.shape, cm.qaid, dtype=daids.dtype)
else:
(qaids, daids, scores, ranks) = cm.get_match_tbldata(
ranks_top=automatch_kw['ranks_top'],
name_scoring=automatch_kw['name_scoring'],
ibs=ibs,
)
qaids_stack.append(qaids)
daids_stack.append(daids)
scores_stack.append(scores)
ranks_stack.append(ranks)
# Stack them into a giant array
qaid_arr = np.hstack(qaids_stack)
daid_arr = np.hstack(daids_stack)
score_arr = np.hstack(scores_stack)
rank_arr = np.hstack(ranks_stack)
# Sort by scores
sortx = score_arr.argsort()[::-1]
qaid_arr = qaid_arr[sortx]
daid_arr = daid_arr[sortx]
score_arr = score_arr[sortx]
rank_arr = rank_arr[sortx]
# IS_REVIEWED DOES NOT WORK
if automatch_kw['filter_reviewed']:
_is_reviewed = ibs.get_annot_pair_is_reviewed(
qaid_arr.tolist(), daid_arr.tolist()
)
is_unreviewed = ~np.array(_is_reviewed, dtype=np.bool)
qaid_arr = qaid_arr.compress(is_unreviewed)
daid_arr = daid_arr.compress(is_unreviewed)
score_arr = score_arr.compress(is_unreviewed)
rank_arr = rank_arr.compress(is_unreviewed)
# Remove directed edges
if not automatch_kw['directed']:
# nodes = np.unique(directed_edges.flatten())
directed_edges = np.vstack((qaid_arr, daid_arr)).T
# idx1, idx2 = vt.intersect2d_indices(directed_edges, directed_edges[:, ::-1])
unique_rowx = vt.find_best_undirected_edge_indexes(directed_edges, score_arr)
qaid_arr = qaid_arr.take(unique_rowx)
daid_arr = daid_arr.take(unique_rowx)
score_arr = score_arr.take(unique_rowx)
rank_arr = rank_arr.take(unique_rowx)
# Filter Double Name Matches
if automatch_kw['filter_duplicate_true_matches']:
# filter_dup_namepairs
qnid_arr = ibs.get_annot_nids(qaid_arr)
dnid_arr = ibs.get_annot_nids(daid_arr)
if not automatch_kw['directed']:
directed_name_edges = np.vstack((qnid_arr, dnid_arr)).T
unique_rowx2 = vt.find_best_undirected_edge_indexes(
directed_name_edges, score_arr
)
else:
namepair_id_list = np.array(
vt.compute_unique_data_ids_(list(zip(qnid_arr, dnid_arr)))
)
unique_namepair_ids, namepair_groupxs = vt.group_indices(namepair_id_list)
score_namepair_groups = vt.apply_grouping(score_arr, namepair_groupxs)
unique_rowx2 = np.array(
sorted(
[
groupx[score_group.argmax()]
for groupx, score_group in zip(
namepair_groupxs, score_namepair_groups
)
]
),
dtype=np.int32,
)
qaid_arr = qaid_arr.take(unique_rowx2)
daid_arr = daid_arr.take(unique_rowx2)
score_arr = score_arr.take(unique_rowx2)
rank_arr = rank_arr.take(unique_rowx2)
# Filter all true matches
if automatch_kw['filter_true_matches']:
qnid_arr = ibs.get_annot_nids(qaid_arr)
dnid_arr = ibs.get_annot_nids(daid_arr)
valid_flags = qnid_arr != dnid_arr
qaid_arr = qaid_arr.compress(valid_flags)
daid_arr = daid_arr.compress(valid_flags)
score_arr = score_arr.compress(valid_flags)
rank_arr = rank_arr.compress(valid_flags)
if automatch_kw['filter_photobombs']:
unique_aids = ut.unique(ut.flatten([qaid_arr, daid_arr]))
# grouped_aids, unique_nids = ibs.group_annots_by_name(unique_aids)
invalid_nid_map = get_photobomber_map(ibs, qaid_arr)
nid2_aids = ut.group_items(unique_aids, ibs.get_annot_nids(unique_aids))
expanded_aid_map = ut.ddict(set)
for nid1, other_nids in invalid_nid_map.items():
for aid1 in nid2_aids[nid1]:
for nid2 in other_nids:
for aid2 in nid2_aids[nid2]:
expanded_aid_map[aid1].add(aid2)
expanded_aid_map[aid2].add(aid1)
valid_flags = [
daid not in expanded_aid_map[qaid] for qaid, daid in zip(qaid_arr, daid_arr)
]
qaid_arr = qaid_arr.compress(valid_flags)
daid_arr = daid_arr.compress(valid_flags)
score_arr = score_arr.compress(valid_flags)
rank_arr = rank_arr.compress(valid_flags)
review_edges = (qaid_arr, daid_arr, score_arr, rank_arr)
return review_edges
[docs]def make_review_api(ibs, cm_list, review_cfg, qreq_=None):
"""
Builds columns which are displayable in a ColumnListTableWidget
CommandLine:
python -m wbia.gui.id_review_api --test-test_review_widget --show
python -m wbia.gui.id_review_api --test-make_review_api
Example:
>>> # ENABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> import wbia.guitool as gt
>>> from wbia.gui import id_review_api
>>> cm_list, qreq_ = wbia.main_helpers.testdata_cmlist()
>>> tblname = 'chipmatch'
>>> name_scoring = False
>>> ranks_top = 5
>>> review_cfg = dict(ranks_top=ranks_top, name_scoring=name_scoring)
>>> review_api = make_review_api(qreq_.ibs, cm_list, review_cfg, qreq_=qreq_)
>>> print('review_api = %r' % (review_api,))
"""
# TODO: Add in timedelta to column info
if ut.VERBOSE:
print('[inspect] make_review_api')
review_edges = get_review_edges(cm_list, ibs=ibs, review_cfg=review_cfg)
# Get extra info
(qaids, daids, scores, ranks) = review_edges
RES_THUMB_TEXT = 'ResThumb' # NOQA
QUERY_THUMB_TEXT = 'querythumb'
MATCH_THUMB_TEXT = 'MatchThumb'
col_name_list = [
'result_index',
'score',
REVIEWED_STATUS_TEXT,
]
if review_cfg.get('show_chips', True):
col_name_list += [
MATCHED_STATUS_TEXT,
QUERY_THUMB_TEXT,
]
col_name_list += [
RES_THUMB_TEXT,
'qaid',
'aid',
'rank',
'timedelta',
'dnGt',
'qnGt',
'tags',
'qname',
'name',
]
col_types_dict = dict(
[
('qaid', int),
('aid', int),
('dnGt', int),
('qnGt', int),
('timedelta', float),
# ('review', 'BUTTON'),
(MATCHED_STATUS_TEXT, str),
(REVIEWED_STATUS_TEXT, str),
(QUERY_THUMB_TEXT, 'PIXMAP'),
(RES_THUMB_TEXT, 'PIXMAP'),
('qname', str),
('name', str),
('score', float),
('rank', int),
('truth', bool),
('opt', int),
('result_index', int),
]
)
timedelta_list = np.array(
ut.take_column(ibs.get_unflat_annots_timedelta_list(list(zip(qaids, daids))), 0)
)
# TODO: make a display role
# timediff_list = [ut.get_posix_timedelta_str(t, year=True, approx=True) for t in (timedelta_list * 60 * 60)]
def get_pair_tags(edge):
aid1, aid2 = edge
assert not ut.isiterable(aid1), 'aid1=%r, aid2=%r' % (aid1, aid2)
assert not ut.isiterable(aid2), 'aid1=%r, aid2=%r' % (aid1, aid2)
am_rowids = ibs.get_annotmatch_rowid_from_undirected_superkey([aid1], [aid2])
tag_text = ibs.get_annotmatch_tag_text(am_rowids)[0]
if tag_text is None:
tag_text = ''
return str(tag_text)
col_getter_dict = dict(
[
('qaid', np.array(qaids)),
('aid', np.array(daids)),
('dnGt', ibs.get_annot_num_groundtruth),
('qnGt', ibs.get_annot_num_groundtruth),
('timedelta', np.array(timedelta_list)),
# ('review', lambda rowid: get_buttontup),
(MATCHED_STATUS_TEXT, partial(get_match_status, ibs)),
(REVIEWED_STATUS_TEXT, partial(get_reviewed_status, ibs)),
(QUERY_THUMB_TEXT, ibs.get_annot_chip_thumbtup),
(RES_THUMB_TEXT, ibs.get_annot_chip_thumbtup),
('qname', ibs.get_annot_names),
('name', ibs.get_annot_names),
('score', np.array(scores)),
('rank', np.array(ranks)),
('result_index', np.arange(len(ranks))),
('tags', get_pair_tags),
# lambda aid_pair: ibs.get_annotmatch_tag_text(ibs.get_annotmatch_rowid_from_undirected_superkey(ut.ensure_iterable(aid_pair[0]), ut.ensure_iterable(aid_pair[1])))[0]),
# ('truth', truths),
# ('opt', opts),
]
)
# default is 100
col_width_dict = {
'score': 75,
REVIEWED_STATUS_TEXT: 75,
MATCHED_STATUS_TEXT: 75,
'rank': 42,
'qaid': 42,
'aid': 42,
'result_index': 42,
'qname': 60,
'name': 60,
'dnGt': 50,
'timedelta': 75,
'tags': 75,
'qnGt': 50,
}
USE_MATCH_THUMBS = 1
if USE_MATCH_THUMBS:
def get_match_thumbtup(
ibs,
qaid2_cm,
qaids,
daids,
index,
qreq_=None,
thumbsize=(128, 128),
match_thumbtup_cache={},
):
daid = daids[index]
qaid = qaids[index]
cm = qaid2_cm[qaid]
assert cm.qaid == qaid, 'aids do not aggree'
OLD = False
if OLD:
fpath = ensure_match_img(
ibs, cm, daid, qreq_=qreq_, match_thumbtup_cache=match_thumbtup_cache,
)
if isinstance(thumbsize, int):
thumbsize = (thumbsize, thumbsize)
thumbtup = (
ut.augpath(fpath, 'thumb_%d,%d' % thumbsize),
fpath,
thumbsize,
[],
[],
)
return thumbtup
else:
# Hacky new way of drawing
fpath, func, func2 = make_ensure_match_img_nosql_func(qreq_, cm, daid)
# match_thumbdir = ibs.get_match_thumbdir()
# match_thumb_fname = get_match_thumb_fname(cm, daid, qreq_)
# fpath = ut.unixjoin(match_thumbdir, match_thumb_fname)
thumbdat = {
'fpath': fpath,
'thread_func': func,
'main_func': func2,
#'args': (ibs, cm, daid),
#'kwargs': dict(qreq_=qreq_,
# match_thumbtup_cache=match_thumbtup_cache)
}
return thumbdat
col_name_list.insert(col_name_list.index('qaid'), MATCH_THUMB_TEXT)
col_types_dict[MATCH_THUMB_TEXT] = 'PIXMAP'
# col_types_dict[MATCH_THUMB_TEXT] = CustomMatchThumbDelegate
qaid2_cm = {cm.qaid: cm for cm in cm_list}
get_match_thumbtup_ = partial(
get_match_thumbtup,
ibs,
qaid2_cm,
qaids,
daids,
qreq_=qreq_,
match_thumbtup_cache={},
)
col_getter_dict[MATCH_THUMB_TEXT] = get_match_thumbtup_
col_bgrole_dict = {
MATCHED_STATUS_TEXT: partial(get_match_status_bgrole, ibs),
REVIEWED_STATUS_TEXT: partial(get_reviewed_status_bgrole, ibs),
}
# TODO: remove ider dict.
# it is massively unuseful
col_ider_dict = {
MATCHED_STATUS_TEXT: ('qaid', 'aid'),
REVIEWED_STATUS_TEXT: ('qaid', 'aid'),
'tags': ('qaid', 'aid'),
QUERY_THUMB_TEXT: ('qaid'),
RES_THUMB_TEXT: ('aid'),
'dnGt': ('aid'),
'qnGt': ('qaid'),
'qname': ('qaid'),
'name': ('aid'),
}
col_setter_dict = {'qname': ibs.set_annot_names, 'name': ibs.set_annot_names}
editable_colnames = ['truth', 'notes', 'qname', 'name', 'opt']
sortby = 'score'
def get_thumb_size():
return ibs.cfg.other_cfg.thumb_size
col_display_role_func_dict = {
'timedelta': ut.partial(ut.get_posix_timedelta_str, year=True, approx=2),
}
if not review_cfg.get('show_chips', True):
del col_getter_dict[QUERY_THUMB_TEXT]
del col_getter_dict[RES_THUMB_TEXT]
del col_types_dict[RES_THUMB_TEXT]
del col_types_dict[QUERY_THUMB_TEXT]
del col_ider_dict[RES_THUMB_TEXT]
del col_ider_dict[QUERY_THUMB_TEXT]
# del col_bgrole_dict[RES_THUMB_TEXT]
# del col_bgrole_dict[QUERY_THUMB_TEXT]
# Insert info into dict
review_api = gt.CustomAPI(
col_name_list=col_name_list,
col_types_dict=col_types_dict,
col_getter_dict=col_getter_dict,
col_bgrole_dict=col_bgrole_dict,
col_ider_dict=col_ider_dict,
col_setter_dict=col_setter_dict,
editable_colnames=editable_colnames,
col_display_role_func_dict=col_display_role_func_dict,
sortby=sortby,
get_thumb_size=get_thumb_size,
sort_reverse=True,
col_width_dict=col_width_dict,
)
# review_api.review_edges = review_edges
return review_api
[docs]def get_match_status(ibs, aid_pair):
""" Data role for status column """
aid1, aid2 = aid_pair
assert not ut.isiterable(aid1), 'aid1=%r, aid2=%r' % (aid1, aid2)
assert not ut.isiterable(aid2), 'aid1=%r, aid2=%r' % (aid1, aid2)
text = ibs.get_match_text(aid1, aid2)
if text is None:
raise AssertionError('impossible state id_review_api')
return text
[docs]def get_reviewed_status(ibs, aid_pair):
""" Data role for status column """
aid1, aid2 = aid_pair
assert not ut.isiterable(aid1), 'aid1=%r, aid2=%r' % (aid1, aid2)
assert not ut.isiterable(aid2), 'aid1=%r, aid2=%r' % (aid1, aid2)
# FIXME: use new api
state = ibs.get_annot_pair_is_reviewed([aid1], [aid2])[0]
state_to_text = {
None: 'Unreviewed',
2: 'Auto-reviewed',
1: 'User-reviewed',
}
default = '??? unknown mode %r' % (state,)
text = state_to_text.get(state, default)
return text
[docs]def get_match_status_bgrole(ibs, aid_pair):
""" Background role for status column """
aid1, aid2 = aid_pair
truth = ibs.get_match_truth(aid1, aid2)
# print('get status bgrole: %r truth=%r' % (aid_pair, truth))
truth_color = vh.get_truth_color(truth, base255=True, lighten_amount=0.35)
return truth_color
[docs]def get_reviewed_status_bgrole(ibs, aid_pair):
""" Background role for status column """
aid1, aid2 = aid_pair
truth = ibs.get_match_truth(aid1, aid2)
annotmach_reviewed = ibs.get_annot_pair_is_reviewed([aid1], [aid2])[0]
if annotmach_reviewed == 0 or annotmach_reviewed is None:
lighten_amount = 0.9
elif annotmach_reviewed == 2:
lighten_amount = 0.7
else:
lighten_amount = 0.35
truth_color = vh.get_truth_color(truth, base255=True, lighten_amount=lighten_amount)
# truth = ibs.get_match_truth(aid1, aid2)
# print('get status bgrole: %r truth=%r' % (aid_pair, truth))
# truth_color = vh.get_truth_color(truth, base255=True, lighten_amount=0.35)
return truth_color
[docs]def get_match_thumb_fname(
cm, daid, qreq_, view_orientation='vertical', draw_matches=True, draw_heatmask=False
):
"""
CommandLine:
python -m wbia.gui.id_review_api --exec-get_match_thumb_fname
Example:
>>> # DISABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> cm, qreq_ = wbia.testdata_cm('PZ_MTEST')
>>> thumbsize = (128, 128)
>>> daid = cm.get_top_aids()[0]
>>> match_thumb_fname = get_match_thumb_fname(cm, daid, qreq_)
>>> result = match_thumb_fname
>>> print(result)
match_aids=1,1_cfgstr=ubpzwu5k54h6xbnr.jpg
"""
# Make thumbnail name
config_hash = ut.hashstr27(qreq_.get_cfgstr())
qaid = cm.qaid
args = (
qaid,
daid,
config_hash,
draw_matches,
draw_heatmask,
view_orientation,
)
match_thumb_fname = (
'match_aids=%d,%d_cfgstr=%s_draw=%s_mask=%s_orientation=%s.jpg' % args
)
return match_thumb_fname
[docs]def ensure_match_img(ibs, cm, daid, qreq_=None, match_thumbtup_cache={}):
r"""
CommandLine:
python -m wbia.gui.id_review_api --test-ensure_match_img --show
Example:
>>> # ENABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> # build test data
>>> cm, qreq_ = wbia.testdata_cm()
>>> daid = cm.get_top_aids()[0]
>>> match_thumbtup_cache = {}
>>> # execute function
>>> match_thumb_fpath_ = ensure_match_img(qreq_.ibs, cm, daid, qreq_,
>>> match_thumbtup_cache)
>>> # verify results
>>> result = str(match_thumb_fpath_)
>>> print(result)
>>> ut.quit_if_noshow()
>>> ut.startfile(match_thumb_fpath_, quote=True)
"""
# from os.path import exists
match_thumbdir = ibs.get_match_thumbdir()
match_thumb_fname = get_match_thumb_fname(cm, daid, qreq_)
match_thumb_fpath_ = ut.unixjoin(match_thumbdir, match_thumb_fname)
# if exists(match_thumb_fpath_):
# return match_thumb_fpath_
if match_thumb_fpath_ in match_thumbtup_cache:
fpath = match_thumbtup_cache[match_thumb_fpath_]
else:
# TODO: just draw the image at the correct thumbnail size
# TODO: draw without matplotlib?
# with ut.Timer('render-1'):
fpath = cm.imwrite_single_annotmatch(
qreq_,
daid,
fpath=match_thumb_fpath_,
saveax=True,
fnum=32,
notitle=True,
verbose=False,
)
# with ut.Timer('render-2'):
# img = cm.render_single_annotmatch(qreq_, daid, fnum=32, notitle=True, dpi=30)
# cv2.imwrite(match_thumb_fpath_, img)
# fpath = match_thumb_fpath_
# with ut.Timer('render-3'):
# fpath = match_thumb_fpath_
# render_config = {
# 'dpi' : 60,
# 'draw_fmatches' : True,
# #'vert' : view_orientation == 'vertical',
# 'show_aidstr' : False,
# 'show_name' : False,
# 'show_exemplar' : False,
# 'show_num_gt' : False,
# 'show_timedelta' : False,
# 'show_name_rank' : False,
# 'show_score' : False,
# 'show_annot_score' : False,
# 'show_name_score' : False,
# 'draw_lbl' : False,
# 'draw_border' : False,
# }
# cm.imwrite_single_annotmatch2(qreq_, daid, fpath, fnum=32, notitle=True, **render_config)
# print('fpath = %r' % (fpath,))
match_thumbtup_cache[match_thumb_fpath_] = fpath
return fpath
[docs]def make_ensure_match_img_nosql_func(qreq_, cm, daid):
r"""
CommandLine:
python -m wbia.gui.id_review_api --test-ensure_match_img --show
Example:
>>> # ENABLE_DOCTEST
>>> from wbia.gui.id_review_api import * # NOQA
>>> import wbia
>>> # build test data
>>> cm, qreq_ = wbia.testdata_cm()
>>> ibs = qreq_.ibs
>>> daid = cm.get_top_aids()[0]
>>> match_thumbtup_cache = {}
>>> # execute function
>>> match_thumb_fpath_ = ensure_match_img(qreq_.ibs, cm, daid, qreq_, match_thumbtup_cache)
>>> # verify results
>>> result = str(match_thumb_fpath_)
>>> print(result)
>>> ut.quit_if_noshow()
>>> ut.startfile(match_thumb_fpath_, quote=True)
"""
# import wbia.viz
from wbia.viz import viz_matches
import cv2
import io
import wbia.plottool as pt
import vtool as vt
import matplotlib as mpl
if cm.__class__.__name__ == 'PairwiseMatch':
# HACK DO THIS THE VTOOL WAY
match = cm
ibs = qreq_ # VERY HACK
match_thumbdir = ibs.get_match_thumbdir()
cfgstr = hash(match.config) # HACK only works if config is already a hashdict
match_thumb_fname = 'tmpmatch-%d-%d-%s.jpg' % (
match.annot1['aid'],
match.annot2['aid'],
cfgstr,
)
fpath = ut.unixjoin(match_thumbdir, match_thumb_fname)
def main_thread_load2():
rchip1, kpts1 = ut.dict_take(match.annot1, ['rchip', 'kpts'])
rchip2, kpts2 = ut.dict_take(match.annot2, ['rchip', 'kpts'])
return (match,)
def nosql_draw2(check_func, match):
from matplotlib.backends.backend_agg import FigureCanvas
try:
from matplotlib.backends.backend_agg import Figure
except ImportError:
from matplotlib.figure import Figure
was_interactive = mpl.is_interactive()
if was_interactive:
mpl.interactive(False)
# fnum = 32
fig = Figure()
canvas = FigureCanvas(fig) # NOQA
# fig.clf()
ax = fig.add_subplot(1, 1, 1)
if check_func is not None and check_func():
return
ax, xywh1, xywh2 = match.show(ax=ax)
if check_func is not None and check_func():
return
savekw = {
# 'dpi' : 60,
'dpi': 80,
}
axes_extents = pt.extract_axes_extents(fig)
# assert len(axes_extents) == 1, 'more than one axes'
extent = axes_extents[0]
with io.BytesIO() as stream:
# This call takes 23% - 15% of the time depending on settings
fig.savefig(stream, bbox_inches=extent, **savekw)
stream.seek(0)
data = np.fromstring(stream.getvalue(), dtype=np.uint8)
if check_func is not None and check_func():
return
pt.plt.close(fig)
image = cv2.imdecode(data, 1)
thumbsize = 221
max_dsize = (thumbsize, thumbsize)
dsize, sx, sy = vt.resized_clamped_thumb_dims(vt.get_size(image), max_dsize)
if check_func is not None and check_func():
return
image = vt.resize(image, dsize)
vt.imwrite(fpath, image)
if check_func is not None and check_func():
return
# fig.savefig(fpath, bbox_inches=extent, **savekw)
# match_thumbtup_cache[match_thumb_fpath_] = fpath
return fpath, nosql_draw2, main_thread_load2
aid1 = cm.qaid
aid2 = daid
ibs = qreq_.ibs
resize_factor = 0.5
match_thumbdir = ibs.get_match_thumbdir()
match_thumb_fname = get_match_thumb_fname(cm, daid, qreq_)
fpath = ut.unixjoin(match_thumbdir, match_thumb_fname)
def main_thread_load():
# This gets executed in the main thread and collects data
# from sql
rchip1_fpath, rchip2_fpath, kpts1, kpts2 = viz_matches._get_annot_pair_info(
ibs, aid1, aid2, qreq_, draw_fmatches=True, as_fpath=True
)
return rchip1_fpath, rchip2_fpath, kpts1, kpts2
def nosql_draw(check_func, rchip1_fpath, rchip2_fpath, kpts1, kpts2):
# This gets executed in the child thread and does drawing async style
# from matplotlib.backends.backend_pdf import FigureCanvasPdf as FigureCanvas
# from matplotlib.backends.backend_pdf import Figure
# from matplotlib.backends.backend_svg import FigureCanvas
# from matplotlib.backends.backend_svg import Figure
from matplotlib.backends.backend_agg import FigureCanvas
try:
from matplotlib.backends.backend_agg import Figure
except ImportError:
from matplotlib.figure import Figure
kpts1_ = vt.offset_kpts(kpts1, (0, 0), (resize_factor, resize_factor))
kpts2_ = vt.offset_kpts(kpts2, (0, 0), (resize_factor, resize_factor))
# from matplotlib.figure import Figure
if check_func is not None and check_func():
return
rchip1 = vt.imread(rchip1_fpath)
rchip1 = vt.resize_image_by_scale(rchip1, resize_factor)
if check_func is not None and check_func():
return
rchip2 = vt.imread(rchip2_fpath)
rchip2 = vt.resize_image_by_scale(rchip2, resize_factor)
if check_func is not None and check_func():
return
try:
idx = cm.daid2_idx[daid]
fm = cm.fm_list[idx]
fsv = None if cm.fsv_list is None else cm.fsv_list[idx]
fs = None if fsv is None else fsv.prod(axis=1)
except KeyError:
fm = []
fs = None
fsv = None
maxnum = 200
if fs is not None and len(fs) > maxnum:
# HACK TO ONLY SHOW TOP MATCHES
sortx = fs.argsort()[::-1]
fm = fm.take(sortx[:maxnum], axis=0)
fs = fs.take(sortx[:maxnum], axis=0)
was_interactive = mpl.is_interactive()
if was_interactive:
mpl.interactive(False)
# fnum = 32
fig = Figure()
canvas = FigureCanvas(fig) # NOQA
# fig.clf()
ax = fig.add_subplot(1, 1, 1)
if check_func is not None and check_func():
return
# fig = pt.plt.figure(fnum)
# H1 = np.eye(3)
# H2 = np.eye(3)
# H1[0, 0] = .5
# H1[1, 1] = .5
# H2[0, 0] = .5
# H2[1, 1] = .5
ax, xywh1, xywh2 = pt.show_chipmatch2(
rchip1, rchip2, kpts1_, kpts2_, fm, fs=fs, colorbar_=False, ax=ax
)
if check_func is not None and check_func():
return
savekw = {
# 'dpi' : 60,
'dpi': 80,
}
axes_extents = pt.extract_axes_extents(fig)
# assert len(axes_extents) == 1, 'more than one axes'
extent = axes_extents[0]
with io.BytesIO() as stream:
# This call takes 23% - 15% of the time depending on settings
fig.savefig(stream, bbox_inches=extent, **savekw)
stream.seek(0)
data = np.fromstring(stream.getvalue(), dtype=np.uint8)
if check_func is not None and check_func():
return
pt.plt.close(fig)
image = cv2.imdecode(data, 1)
thumbsize = 221
max_dsize = (thumbsize, thumbsize)
dsize, sx, sy = vt.resized_clamped_thumb_dims(vt.get_size(image), max_dsize)
if check_func is not None and check_func():
return
image = vt.resize(image, dsize)
vt.imwrite(fpath, image)
if check_func is not None and check_func():
return
# fig.savefig(fpath, bbox_inches=extent, **savekw)
# match_thumbtup_cache[match_thumb_fpath_] = fpath
return fpath, nosql_draw, main_thread_load
[docs]def get_photobomber_map(ibs, aids, aid_to_nid=None):
"""
Builds map of which names that photobomb other names.
python -m wbia.gui.id_review_api --test-test_review_widget --show --db PZ_MTEST -a default:qindex=0
>>> import wbia
>>> dbdir = ut.truepath('~/lev/media/danger/GGR/GGR-IBEIS')
>>> ibs = wbia.opendb(dbdir='/home/joncrall/lev/media/danger/GGR/GGR-IBEIS')
>>> filter_kw = {
>>> 'multiple': False,
>>> 'minqual': 'good',
>>> 'is_known': True,
>>> 'min_pername': 2,
>>> 'view': ['right'],
>>> }
>>> aids = ibs.filter_annots_general(ibs.get_valid_aids(), filter_kw=filter_kw)
"""
ams_list = ibs.get_annotmatch_rowids_from_aid(aids)
flags_list = ibs.unflat_map(
ut.partial(ibs.get_annotmatch_prop, 'Photobomb'), ams_list
)
pb_ams = ut.zipcompress(ams_list, flags_list)
has_pb_ams = [len(ams) > 0 for ams in pb_ams]
pb_ams_ = ut.compress(pb_ams, has_pb_ams)
# aids_ = ut.compress(aids, has_pb_ams)
pb_ams_flat = ut.flatten(pb_ams_)
pb_aids1_ = ibs.get_annotmatch_aid1(pb_ams_flat)
pb_aids2_ = ibs.get_annotmatch_aid2(pb_ams_flat)
pb_aid_pairs_ = list(zip(pb_aids1_, pb_aids2_))
if aid_to_nid is None:
pb_nid_pairs_ = ibs.unflat_map(ibs.get_annot_nids, pb_aid_pairs_)
else:
pb_nid_pairs_ = ibs.unflat_map(ut.partial(ut.take, aid_to_nid), pb_aid_pairs_)
# invalid_aid_map = ut.ddict(set)
# for aid1, aid2 in pb_aid_pairs_:
# if aid1 != aid2:
# invalid_aid_map[aid1].add(aid2)
# invalid_aid_map[aid2].add(aid1)
invalid_nid_map = ut.ddict(set)
for nid1, nid2 in pb_nid_pairs_:
if nid1 != nid2:
invalid_nid_map[nid1].add(nid2)
invalid_nid_map[nid2].add(nid1)
return invalid_nid_map