# -*- coding: utf-8 -*-
"""
TODO: make qparams and qreq_ serializeable
TODO:
Rename to IdentifyRequest
"""
from __future__ import absolute_import, division, print_function, unicode_literals
from ibeis.model.hots import neighbor_index
from ibeis.model.hots import multi_index
from ibeis.model.hots import score_normalization
from ibeis.model.hots import distinctiveness_normalizer
from ibeis.model.hots import query_params
from ibeis.model.hots import chip_match
from ibeis.model.hots import _pipeline_helpers as plh # NOQA
from os.path import join
import vtool as vt
#import copy
import six
import utool as ut
import numpy as np
import warnings
#from ibeis.model.hots import hots_query_result
(print, print_, printDBG, rrr, profile) = ut.inject(__name__, '[qreq]')
VERBOSE = ut.VERBOSE or ut.get_argflag(('--verbose-qreq', '--verbqreq'))
[docs]def testdata_newqreq(defaultdb):
import ibeis
ibs = ibeis.opendb(defaultdb=defaultdb)
qaid_list = [1]
daid_list = [1, 2, 3, 4, 5]
return ibs, qaid_list, daid_list
[docs]def testdata_qreq():
import ibeis
qaid_list = [1, 2]
daid_list = [1, 2, 3, 4, 5]
ibs = ibeis.opendb(db='testdb1')
qreq_ = new_ibeis_query_request(ibs, qaid_list, daid_list)
return qreq_, ibs
@profile
[docs]def new_ibeis_query_request(ibs, qaid_list, daid_list, cfgdict=None,
verbose=ut.NOT_QUIET, unique_species=None,
use_memcache=True, query_cfg=None):
"""
ibeis entry point to create a new query request object
CommandLine:
python -m ibeis.model.hots.query_request --test-new_ibeis_query_request
python -m ibeis.model.hots.query_request --test-new_ibeis_query_request:2
Example0:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> ibs, qaid_list, daid_list = testdata_newqreq('PZ_MTEST')
>>> unique_species = None
>>> verbose = ut.NOT_QUIET
>>> cfgdict = {'sv_on': False, 'fg_on': True} # 'featweight_detector': 'rf'}
>>> # Execute test
>>> qreq_ = new_ibeis_query_request(ibs, qaid_list, daid_list, cfgdict=cfgdict)
>>> # Check Results
>>> print(qreq_.qparams.query_cfgstr)
>>> assert qreq_.qparams.sv_on is False, (
... 'qreq_.qparams.sv_on = %r ' % qreq_.qparams.sv_on)
>>> result = ibs.get_dbname() + qreq_.get_data_hashid()
>>> print(result)
PZ_MTEST_DSUUIDS((5)@5wlqu@jl+j8l9io)
PZ_MTEST_DSUUIDS((5)@n7v0df!&j5o8pni)
PZ_MTEST_DSUUIDS((5)q87ho9a0@9s02imh)
Example1:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> ibs, qaid_list, daid_list = testdata_newqreq('NAUT_test')
>>> unique_species = None
>>> verbose = ut.NOT_QUIET
>>> cfgdict = {'sv_on': True, 'fg_on': True}
>>> # Execute test
>>> qreq_ = new_ibeis_query_request(ibs, qaid_list, daid_list, cfgdict=cfgdict)
>>> # Check Results.
>>> # Featweight should be off because there is no Naut detector
>>> print(qreq_.qparams.query_cfgstr)
>>> assert qreq_.qparams.sv_on is True, (
... 'qreq_.qparams.sv_on = %r ' % qreq_.qparams.sv_on)
>>> result = ibs.get_dbname() + qreq_.get_data_hashid()
>>> print(result)
NAUT_test_DSUUIDS((5)2s8!cj@nrf6iuqgd)
NAUT_test_DSUUIDS((5)&flvjboruwyi08%t)
Example2:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> ibs, qaid_list, daid_list = testdata_newqreq('PZ_MTEST')
>>> unique_species = None
>>> verbose = ut.NOT_QUIET
>>> cfgdict = {'sv_on': False, 'augment_queryside_hack': True}
>>> # Execute test
>>> qreq_ = new_ibeis_query_request(ibs, qaid_list, daid_list, cfgdict=cfgdict)
>>> # Check Results.
>>> # Featweight should be off because there is no Naut detector
>>> print(qreq_.qparams.query_cfgstr)
>>> assert qreq_.qparams.sv_on is False, (
... 'qreq_.qparams.sv_on = %r ' % qreq_.qparams.sv_on)
>>> result = ibs.get_dbname() + qreq_.get_data_hashid()
>>> print(result)
PZ_MTEST_DSUUIDS((5)@5wlqu@jl+j8l9io)
PZ_MTEST_DSUUIDS((5)@n7v0df!&j5o8pni)
Ignore:
# This is supposed to be the begginings of the code to transition the
# pipeline configuration into the new minimal dict based structure that
# supports different configs for query and database annotations.
dcfg = qreq_.get_external_data_config2()
qcfg = qreq_.get_external_query_config2()
ut.dict_intersection(qcfg.__dict__, dcfg.__dict__)
from ibeis.expt import cfghelpers
cfg_list = [qcfg.__dict__, dcfg.__dict__]
nonvaried_cfg, varied_cfg_list = cfghelpers.partition_varied_cfg_list(
cfg_list, recursive=True)
qvaried, dvaried = varied_cfg_list
"""
if verbose:
print('[qreq] +--- New IBEIS QRequest --- ')
cfg = ibs.cfg.query_cfg if query_cfg is None else query_cfg
qresdir = ibs.get_qres_cachedir()
cfgdict = {} if cfgdict is None else cfgdict.copy()
DYNAMIC_K = False
if DYNAMIC_K and 'K' not in cfgdict:
model_params = [0.2, 0.5]
from ibeis.other.optimize_k import compute_K
nDaids = len(daid_list)
cfgdict['K'] = compute_K(nDaids, model_params)
# <HACK>
if unique_species is None:
unique_species_ = apply_species_with_detector_hack(
ibs, cfgdict, qaid_list, daid_list)
else:
unique_species_ = unique_species
# </HACK>
qparams = query_params.QueryParams(cfg, cfgdict)
data_config2_ = qparams
#
# <HACK>
# MAKE A SECOND CONFIG FOR QUERIES AND DATABASE VECTORS ONLY
# allow query and database annotations to have different feature configs
if qparams.augment_queryside_hack:
query_cfgdict = cfgdict.copy()
query_cfgdict['augment_orientation'] = True
query_config2_ = query_params.QueryParams(cfg, query_cfgdict)
else:
query_config2_ = qparams
# </HACK>
_indexer_request_params = dict(use_memcache=use_memcache)
qreq_ = QueryRequest.new_query_request(
qaid_list, daid_list, qparams, qresdir, ibs, _indexer_request_params)
qreq_.query_config2_ = query_config2_
qreq_.data_config2_ = data_config2_
qreq_.unique_species = unique_species_ # HACK
if verbose:
print('[qreq] * query_cfgstr = %s' % (qreq_.qparams.query_cfgstr,))
print('[qreq] * unique_species = %s' % (qreq_.unique_species,))
print('[qreq] * len(qaid_list) = %s' % (len(qaid_list),))
print('[qreq] * len(daid_list) = %s' % (len(daid_list),))
print('[qreq] * data_hashid = %s' % (qreq_.get_data_hashid(),))
print('[qreq] * query_hashid = %s' % (qreq_.get_query_hashid(),))
print('[qreq] L___ New IBEIS QRequest ___ ')
return qreq_
@profile
[docs]def apply_species_with_detector_hack(ibs, cfgdict, qaids, daids,
verbose=VERBOSE):
"""
HACK turns of featweights if they cannot be applied
"""
# Only apply the hack with repsect to the queried annotations
aid_list = np.hstack((qaids, daids)).tolist()
unique_species = ibs.get_database_species(aid_list)
# turn off featureweights when not absolutely sure they are ok to us,)
candetect = (len(unique_species) == 1 and
ibs.has_species_detector(unique_species[0]))
if not candetect:
if ut.NOT_QUIET:
print('[qreq] HACKING FG_WEIGHT OFF (db species is not supported)')
if len(unique_species) != 1:
print('[qreq] * len(unique_species) = %r' % len(unique_species))
else:
print('[qreq] * unique_species = %r' % (unique_species,))
#print('[qreq] * valid species = %r' % (
# ibs.get_species_with_detectors(),))
#cfg._featweight_cfg.featweight_enabled = 'ERR'
cfgdict['featweight_enabled'] = 'ERR'
cfgdict['fg_on'] = False
else:
#print(ibs.get_annot_species_texts(aid_list))
if verbose:
print('[qreq] Using fgweights of unique_species=%r' % (
unique_species,))
pass
#, aid_list=%r' % (unique_species, aid_list))
return unique_species
@six.add_metaclass(ut.ReloadingMetaclass)
[docs]class QueryRequest(object):
"""
Request object for pipline paramter run
"""
@classmethod
[docs] def new_query_request(cls, qaid_list, daid_list, qparams, qresdir, ibs,
_indexer_request_params):
"""
old way of calling new
"""
qreq_ = cls()
qreq_.ibs = ibs
qreq_.qparams = qparams # Parameters relating to pipeline execution
qreq_.qresdir = qresdir
qreq_._indexer_request_params = _indexer_request_params
qreq_.set_external_daids(daid_list)
qreq_.set_external_qaids(qaid_list)
return qreq_
def __init__(qreq_):
# Reminder:
# lists and other objects are functionally equivalent to pointers
#
# Conceptually immutable State
qreq_.unique_species = None # num categories
qreq_.internal_qspeciesid_list = None # category species id label list
qreq_.internal_qaids = None
qreq_.internal_daids = None
# Conceptually mutable state
qreq_.internal_qaids_mask = None
qreq_.internal_daids_mask = None
# Loaded Objects
qreq_.ibs = None # Handle to parent IBEIS Controller
qreq_.indexer = None # The nearest neighbor mechanism
qreq_.normalizer = None # The scoring normalization mechanism
qreq_.dstcnvs_normer = None
qreq_.hasloaded = False
# Pipeline configuration
qreq_.qparams = None # Parameters relating to pipeline execution
qreq_.query_config2_ = None
qreq_.data_config2_ = None
qreq_._indexer_request_params = None
# Set values
qreq_.unique_species = None # HACK
qreq_.qresdir = None
qreq_.prog_hook = None
#def write_query_request(qreq_, fpath):
# ut.save_cPickle(fpath, qreq_)
[docs] def __getstate__(qreq_):
"""
Make QueryRequest pickleable
CommandLine:
python -m ibeis.dev -t candidacy --db testdb1
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> from six.moves import cPickle as pickle
>>> qreq_, ibs = testdata_qreq()
>>> qreq_dump = pickle.dumps(qreq_)
>>> qreq2_ = pickle.loads(qreq_dump)
"""
state_dict = qreq_.__dict__.copy()
state_dict['dbdir'] = qreq_.ibs.get_dbdir()
state_dict['ibs'] = None
state_dict['prog_hook'] = None
state_dict['indexer'] = None
state_dict['normalizer'] = None
state_dict['dstcnvs_normer'] = None
state_dict['hasloaded'] = False
return state_dict
def __setstate__(qreq_, state_dict):
#print('[!!!!!!!!!!!!!!!!!!!!] Calling set state.')
import ibeis
dbdir = state_dict['dbdir']
del state_dict['dbdir']
state_dict['ibs'] = ibeis.opendb(dbdir=dbdir, web=False)
qreq_.__dict__.update(state_dict)
@profile
[docs] def shallowcopy(qreq_, qaids=None, qx=None, dx=None):
"""
Creates a copy of qreq with the same qparams object and a subset of the
qx and dx objects. used to generate chunks of vsone and vsmany queries
CommandLine:
python -m ibeis.model.hots.query_request --exec-shallowcopy
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> qreq_, ibs = testdata_qreq()
>>> qreq2_ = qreq_.shallowcopy(qx=0)
>>> assert qreq_.get_external_daids() is qreq2_.get_external_daids()
>>> assert len(qreq_.get_external_qaids()) != len(qreq2_.get_external_qaids())
>>> #assert qreq_.metadata is not qreq2_.metadata
"""
#qreq2_ = copy.copy(qreq_) # copy calls setstate and getstate
qreq2_ = QueryRequest()
qreq2_.__dict__.update(qreq_.__dict__)
if qx is not None:
qaid_list = qreq2_.get_external_qaids()
qaid_list = qaid_list[qx:qx + 1]
qreq2_.set_external_qaids(qaid_list) # , quuid_list)
elif qaids is not None:
assert qx is None, 'cannot specify both qx and qaids'
_intersect = np.intersect1d(qaids, qreq2_.get_external_qaids())
assert len(_intersect) == len(qaids), 'not a subset'
qreq2_.set_external_qaids(qaids) # , quuid_list)
if dx is not None:
daid_list = qreq2_.get_external_daids()
daid_list = daid_list[dx:dx + 1]
#duuid_list = qreq2_.get_external_duuids()
#duuid_list = duuid_list[dx:dx + 1]
qreq2_.set_external_daids(daid_list)
# The shallow copy does not bring over output / query data
qreq2_.indexer = None
#qreq2_.metadata = {}
qreq2_.hasloaded = False
return qreq2_
# --- State Modification ---
@profile
[docs] def remove_internal_daids(qreq_, remove_daids):
r"""
State Modification: remove daids from the query request. Do not call
this function often. It invalidates the indexer, which is very slow to
rebuild. Should only be done between query pipeline runs.
CommandLine:
python -m ibeis.model.hots.query_request --test-remove_internal_daids
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> # build test data
>>> ibs = ibeis.opendb('testdb1')
>>> species = ibeis.const.Species.ZEB_PLAIN
>>> daids = ibs.get_valid_aids(species=species, is_exemplar=True)
>>> qaids = ibs.get_valid_aids(species=species, is_exemplar=False)
>>> qreq_ = ibs.new_query_request(qaids, daids)
>>> remove_daids = daids[0:1]
>>> # execute function
>>> assert len(qreq_.internal_daids) == 4, 'bad setup data'
>>> qreq_.remove_internal_daids(remove_daids)
>>> # verify results
>>> assert len(qreq_.internal_daids) == 3, 'did not remove'
"""
# Invalidate the current indexer, mask and metadata
qreq_.indexer = None
qreq_.internal_daids_mask = None
#qreq_.metadata = {}
# Find indices to remove
delete_flags = vt.get_covered_mask(qreq_.internal_daids, remove_daids)
delete_indices = np.where(delete_flags)[0]
assert len(delete_indices) == len(remove_daids), (
'requested removal of nonexistant daids')
# Remove indices
qreq_.internal_daids = np.delete(qreq_.internal_daids, delete_indices)
# TODO: multi-indexer delete support
if qreq_.indexer is not None:
warnings.warn('Implement point removal from trees')
qreq_.indexer.remove_ibeis_support(qreq_, remove_daids)
@profile
[docs] def add_internal_daids(qreq_, new_daids):
"""
State Modification: add new daid to query request. Should only be
done between query pipeline runs
"""
if ut.DEBUG2:
species = qreq_.ibs.get_annot_species(new_daids)
assert set(qreq_.unique_species) == set(species), (
'inconsistent species')
qreq_.internal_daids_mask = None
#qreq_.metadata = {}
qreq_.internal_daids = np.append(qreq_.internal_daids, new_daids)
# TODO: multi-indexer add_support
if qreq_.indexer is not None:
#qreq_.load_indexer(verbose=True)
qreq_.indexer.add_ibeis_support(qreq_, new_daids)
@profile
[docs] def set_external_daids(qreq_, daid_list):
if qreq_.qparams.vsmany:
qreq_.set_internal_daids(daid_list)
else:
qreq_.set_internal_qaids(daid_list)
@profile
[docs] def set_external_qaids(qreq_, qaid_list):
if qreq_.qparams.vsmany:
qreq_.set_internal_qaids(qaid_list)
else:
qreq_.set_internal_daids(qaid_list)
@profile
[docs] def set_external_qaid_mask(qreq_, masked_qaid_list):
r"""
Args:
qaid_list (list):
CommandLine:
python -m ibeis.model.hots.query_request --test-set_external_qaid_mask
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> ibs = ibeis.opendb(db='testdb1')
>>> qaid_list = [1, 2, 3, 4, 5]
>>> daid_list = [1, 2, 3, 4, 5]
>>> qreq_ = ibs.new_query_request(qaid_list, daid_list)
>>> masked_qaid_list = [2, 4, 5]
>>> qreq_.set_external_qaid_mask(masked_qaid_list)
>>> result = np.array_str(qreq_.get_external_qaids())
>>> print(result)
[1 3]
"""
if qreq_.qparams.vsmany:
qreq_.set_internal_masked_qaids(masked_qaid_list)
else:
qreq_.set_internal_masked_daids(masked_qaid_list)
# --- Internal Annotation ID Masks ----
@profile
[docs] def set_internal_masked_daids(qreq_, masked_daid_list):
""" used by the pipeline to execute a subset of the query request
without modifying important state """
if masked_daid_list is None or len(masked_daid_list) == 0:
qreq_.internal_daids_mask = None
else:
#with ut.EmbedOnException():
# input denotes invalid elements mark all elements not in that
# list as True
flags = vt.get_uncovered_mask(qreq_.internal_daids,
masked_daid_list)
assert len(flags) == len(qreq_.internal_daids), (
'unequal len internal daids')
qreq_.internal_daids_mask = flags
@profile
[docs] def set_internal_masked_qaids(qreq_, masked_qaid_list):
"""
used by the pipeline to execute a subset of the query request
without modifying important state
Example:
>>> # ENABLE_DOCTEST
>>> import utool as ut
>>> from ibeis.model.hots import pipeline
>>> cfgdict1 = dict(codename='vsone', sv_on=True)
>>> qaid_list = [1, 2, 3, 4]
>>> daid_list = [1, 2, 3, 4]
>>> ibs, qreq_ = plh.get_pipeline_testdata(cfgdict=cfgdict1,
... qaid_list=qaid_list, daid_list=daid_list)
>>> qaids = qreq_.get_internal_qaids()
>>> ut.assert_lists_eq(qaid_list, qaids)
>>> masked_qaid_list = [1, 2, 3,]
>>> qreq_.set_internal_masked_qaids(masked_qaid_list)
>>> new_internal_aids = qreq_.get_internal_qaids()
>>> ut.assert_lists_eq(new_internal_aids, [4])
"""
if masked_qaid_list is None or len(masked_qaid_list) == 0:
qreq_.internal_qaids_mask = None
else:
#with ut.EmbedOnException():
# input denotes invalid elements mark all elements not in that
# list as True
flags = vt.get_uncovered_mask(qreq_.internal_qaids,
masked_qaid_list)
assert len(flags) == len(qreq_.internal_qaids), (
'unequal len internal qaids')
qreq_.internal_qaids_mask = flags
@profile
[docs] def set_internal_unmasked_qaids(qreq_, unmasked_qaid_list):
"""
used by the pipeline to execute a subset of the query request
without modifying important state
Example:
>>> # ENABLE_DOCTEST
>>> import utool as ut
>>> from ibeis.model.hots import pipeline
>>> cfgdict1 = dict(codename='vsone', sv_on=True)
>>> qaid_list = [1, 2, 3, 4]
>>> daid_list = [1, 2, 3, 4]
>>> ibs, qreq_ = plh.get_pipeline_testdata(cfgdict=cfgdict1,
... qaid_list=qaid_list, daid_list=daid_list)
>>> qaids = qreq_.get_internal_qaids()
>>> ut.assert_lists_eq(qaid_list, qaids)
>>> unmasked_qaid_list = [1, 2, 3,]
>>> qreq_.set_internal_unmasked_qaids(unmasked_qaid_list)
>>> new_internal_aids = qreq_.get_internal_qaids()
>>> ut.assert_lists_eq(new_internal_aids, unmasked_qaid_list)
"""
if unmasked_qaid_list is None:
qreq_.internal_qaids_mask = None
else:
# input denotes valid elements
# mark all elements not in that list as False
flags = vt.get_covered_mask(
qreq_.internal_qaids, unmasked_qaid_list)
assert len(flags) == len(qreq_.internal_qaids), (
'unequal len internal qaids')
qreq_.internal_qaids_mask = flags
# --- Internal Annotation IDs ----
@profile
[docs] def set_internal_daids(qreq_, daid_list):
qreq_.internal_daids_mask = None # Invalidate mask
qreq_.internal_daids = np.array(daid_list)
@profile
[docs] def set_internal_qaids(qreq_, qaid_list):
qreq_.internal_qaids_mask = None # Invalidate mask
qreq_.internal_qaids = np.array(qaid_list)
# --- INTERNAL INTERFACE ---
# For within pipeline use only
@profile
[docs] def get_internal_daids(qreq_):
if qreq_.internal_daids_mask is None:
return qreq_.internal_daids
else:
return qreq_.internal_daids[qreq_.internal_daids_mask]
@profile
[docs] def get_internal_qaids(qreq_):
if qreq_.internal_qaids_mask is None:
return qreq_.internal_qaids
else:
return qreq_.internal_qaids[qreq_.internal_qaids_mask]
@profile
[docs] def get_internal_duuids(qreq_):
return qreq_.ibs.get_annot_semantic_uuids(qreq_.get_internal_daids())
@profile
[docs] def get_internal_quuids(qreq_):
return qreq_.ibs.get_annot_semantic_uuids(qreq_.get_internal_qaids())
[docs] def get_internal_data_config2(qreq_):
return (qreq_.data_config2_ if qreq_.qparams.vsmany else
qreq_.query_config2_)
[docs] def get_internal_query_config2(qreq_):
return (qreq_.query_config2_ if qreq_.qparams.vsmany else
qreq_.data_config2_)
[docs] def get_external_data_config2(qreq_):
return qreq_.data_config2_
[docs] def get_external_query_config2(qreq_):
return qreq_.query_config2_
# --- EXTERNAL INTERFACE ---
[docs] def get_unique_species(qreq_):
return qreq_.unique_species
# External id-lists
@property
def daids(qreq_):
return qreq_.get_external_daids()
@property
def qaids(qreq_):
return qreq_.get_external_qaids()
@property
def extern_data_config2(qreq_):
return qreq_.get_external_data_config2()
@property
def extern_query_config2(qreq_):
return qreq_.get_external_query_config2()
@profile
[docs] def get_external_daids(qreq_):
""" These are the users daids in vsone mode """
if qreq_.qparams.vsmany:
return qreq_.get_internal_daids()
else:
return qreq_.get_internal_qaids()
@profile
[docs] def get_external_qaids(qreq_):
""" These are the users qaids in vsone mode """
if qreq_.qparams.vsmany:
return qreq_.get_internal_qaids()
else:
return qreq_.get_internal_daids()
@profile
[docs] def get_external_quuids(qreq_):
""" These are the users qauuids in vsone mode """
if qreq_.qparams.vsmany:
return qreq_.get_internal_quuids()
else:
return qreq_.get_internal_duuids()
@profile
[docs] def get_external_duuids(qreq_):
""" These are the users qauuids in vsone mode """
if qreq_.qparams.vsmany:
return qreq_.get_internal_duuids()
else:
return qreq_.get_internal_quuids()
@profile
[docs] def get_external_query_groundtruth(qreq_, qaids):
""" gets groundtruth that are accessible via this query """
external_daids = qreq_.get_external_daids()
gt_aids = qreq_.ibs.get_annot_groundtruth(
qaids, daid_list=external_daids)
return gt_aids
# External id-hashes
#@ut.memoize
[docs] def get_data_hashid(qreq_):
daids = qreq_.get_external_daids()
try:
assert len(daids) > 0, 'QRequest not populated. len(daids)=0'
except AssertionError as ex:
ut.printex(ex, iswarning=True)
# TODO: SYSTEM : semantic should only be used if name scoring is on
data_hashid = qreq_.ibs.get_annot_hashid_semantic_uuid(
daids, prefix='D')
return data_hashid
#@ut.memoize
[docs] def get_query_hashid(qreq_):
qaids = qreq_.get_external_qaids()
assert len(qaids) > 0, 'QRequest not populated. len(qaids)=0'
# TODO: SYSTEM : semantic should only be used if name scoring is on
query_hashid = qreq_.ibs.get_annot_hashid_semantic_uuid(
qaids, prefix='Q')
return query_hashid
[docs] def get_internal_query_hashid(qreq_):
if qreq_.qparams.vsmany:
return qreq_.get_query_hashid()
else:
return qreq_.get_data_hashid()
[docs] def get_internal_data_hashid(qreq_):
if qreq_.qparams.vsmany:
return qreq_.get_data_hashid()
else:
return qreq_.get_query_hashid()
[docs] def get_pipe_cfgstr(qreq_):
"""
FIXME: name
params only """
#query_cfgstr = qreq_.qparams.query_cfgstr
pipe_cfgstr = qreq_.qparams.query_cfgstr
return pipe_cfgstr
[docs] def get_pipe_hashstr(qreq_):
# this changes invalidates match_chip4 bibcaches generated before
# august 24 2015
#pipe_hashstr = ut.hashstr(qreq_.get_pipe_cfgstr())
pipe_hashstr = ut.hashstr27(qreq_.get_pipe_cfgstr())
return pipe_hashstr
@profile
[docs] def get_cfgstr(qreq_, with_query=False, with_data=True, with_pipe=True):
r"""
main cfgstring used to identify the 'querytype'
FIXME: name params + data
TODO:
rename query_cfgstr to pipe_cfgstr or pipeline_cfgstr EVERYWHERE
Args:
with_query (bool): (default = False)
Returns:
str: cfgstr
CommandLine:
python -m ibeis.model.hots.query_request --exec-get_cfgstr
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> ibs = ibeis.opendb(defaultdb='testdb1')
>>> species = ibeis.const.Species.ZEB_PLAIN
>>> daids = ibs.get_valid_aids(species=species)
>>> qaids = ibs.get_valid_aids(species=species)
>>> qreq_ = ibs.new_query_request(qaids, daids)
>>> with_query = True
>>> cfgstr = qreq_.get_cfgstr(with_query)
>>> result = ('cfgstr = %s' % (str(cfgstr),))
>>> print(result)
"""
cfgstr_list = []
if with_query:
cfgstr_list.append(qreq_.get_query_hashid())
if with_data:
cfgstr_list.append(qreq_.get_data_hashid())
if with_pipe:
cfgstr_list.append(qreq_.get_pipe_cfgstr())
cfgstr = ''.join(cfgstr_list)
return cfgstr
[docs] def get_full_cfgstr(qreq_):
""" main cfgstring used to identify the 'querytype'
FIXME: name
params + data + query
"""
full_cfgstr = qreq_.get_cfgstr(with_query=True)
return full_cfgstr
[docs] def get_qresdir(qreq_):
return qreq_.qresdir
# --- Lazy Loading ---
@profile
[docs] def lazy_preload(qreq_, verbose=ut.NOT_QUIET):
"""
feature weights and normalizers should be loaded before vsone queries
are issued. They do not depened only on qparams
Load non-query specific normalizers / weights
"""
if verbose:
print('[qreq] lazy preloading')
qreq_.ensure_features(verbose=verbose)
if qreq_.qparams.fg_on is True:
qreq_.ensure_featweights(verbose=verbose)
if qreq_.qparams.score_normalization is True:
qreq_.load_score_normalizer(verbose=verbose)
if qreq_.qparams.use_external_distinctiveness:
qreq_.load_distinctiveness_normalizer(verbose=verbose)
@profile
[docs] def lazy_load(qreq_, verbose=ut.NOT_QUIET):
"""
Performs preloading of all data needed for a batch of queries
"""
print('[qreq] lazy loading')
#with ut.Indenter('[qreq.lazy_load]'):
qreq_.hasloaded = True
#qreq_.ibs = ibs # HACK
qreq_.lazy_preload(verbose=verbose)
if qreq_.qparams.pipeline_root in ['vsone', 'vsmany']:
qreq_.load_indexer(verbose=verbose)
#if qreq_.qparams.pipeline_root in ['smk']:
# # TODO load vocabulary indexer
# load query data structures
@profile
[docs] def ensure_chips(qreq_, verbose=ut.NOT_QUIET, extra_tries=1):
r""" ensure chips are computed (used in expt, not used in pipeline)
Args:
verbose (bool): verbosity flag(default = True)
extra_tries (int): (default = 0)
CommandLine:
python -m ibeis.model.hots.query_request --test-ensure_chips
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> ibs = ibeis.opendb(defaultdb='testdb1')
>>> daids = ibs.get_valid_aids()[0:3]
>>> qaids = ibs.get_valid_aids()[0:6]
>>> qreq_ = ibs.new_query_request(qaids, daids)
>>> verbose = True
>>> extra_tries = 1
>>> ut.remove_file_list(ibs.get_annot_chip_fpath(qaids, config2_=qreq_.get_external_query_config2()))
>>> ut.remove_file_list(ibs.get_annot_chip_fpath(daids, config2_=qreq_.get_external_data_config2()))
>>> result = qreq_.ensure_chips(verbose, extra_tries)
>>> print(result)
"""
if verbose:
print('[qreq] ensure_chips')
external_qaids = qreq_.get_external_qaids()
external_daids = qreq_.get_external_daids()
#np.union1d(external_qaids, external_daids)
# TODO check if configs are the same
externgetkw = dict(
ensure=True,
check_external_storage=True,
extra_tries=extra_tries
)
q_chip_fpath = qreq_.ibs.get_annot_chip_fpath( # NOQA
external_qaids,
config2_=qreq_.get_external_query_config2(), **externgetkw)
d_chip_fpath = qreq_.ibs.get_annot_chip_fpath( # NOQA
external_daids,
config2_=qreq_.get_external_data_config2(), **externgetkw)
@profile
[docs] def ensure_features(qreq_, verbose=ut.NOT_QUIET):
r""" ensure features are computed
Args:
verbose (bool): verbosity flag(default = True)
CommandLine:
python -m ibeis.model.hots.query_request --test-ensure_features
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> ibs = ibeis.opendb(defaultdb='testdb1')
>>> daids = ibs.get_valid_aids()[0:3]
>>> qaids = ibs.get_valid_aids()[0:6]
>>> qreq_ = ibs.new_query_request(qaids, daids)
>>> ibs.delete_annot_feats(qaids, config2_=qreq_.get_external_query_config2()) # Remove the chips
>>> ut.remove_file_list(ibs.get_annot_chip_fpath(qaids, config2_=qreq_.get_external_query_config2()))
>>> verbose = True
>>> result = qreq_.ensure_features(verbose)
>>> print(result)
"""
#with ut.EmbedOnException():
if verbose:
print('[qreq] ensure_features')
external_qaids = qreq_.get_external_qaids()
external_daids = qreq_.get_external_daids()
qfids = qreq_.ibs.get_annot_feat_rowids( # NOQA
external_qaids, ensure=True,
config2_=qreq_.get_external_query_config2())
dfids = qreq_.ibs.get_annot_feat_rowids( # NOQA
external_daids, ensure=True,
config2_=qreq_.get_external_data_config2())
if ut.DEBUG2:
qkpts = qreq_.ibs.get_annot_kpts(
external_qaids, ensure=False,
config2_=qreq_.get_external_query_config2())
dkpts = qreq_.ibs.get_annot_kpts( # NOQA
external_daids, ensure=False,
config2_=qreq_.get_external_data_config2())
#if verbose:
try:
assert len(qkpts) > 0, 'no query keypoint'
assert qkpts[0].size > 0, (
'Query keypoints are corrupted! qkpts=%r' % (qkpts,))
except Exception:
print('qkpts = %r' % (qkpts,))
raise
@profile
[docs] def ensure_featweights(qreq_, verbose=ut.NOT_QUIET):
""" ensure feature weights are computed """
#with ut.EmbedOnException():
if verbose:
print('[qreq] ensure_featweights')
#internal_qaids = qreq_.get_internal_qaids()
#internal_daids = qreq_.get_internal_daids()
#qreq_.ibs.get_annot_fgweights(internal_qaids, ensure=True, config2_=qreq_.qparams)
#qreq_.ibs.get_annot_fgweights(internal_daids, ensure=True, config2_=qreq_.qparams)
external_qaids = qreq_.get_external_qaids()
external_daids = qreq_.get_external_daids()
qfw_rowids = qreq_.ibs.get_annot_featweight_rowids( # NOQA
external_qaids, ensure=True,
config2_=qreq_.get_external_query_config2())
dfw_rowids = qreq_.ibs.get_annot_featweight_rowids( # NOQA
external_daids, ensure=True,
config2_=qreq_.get_external_data_config2())
if ut.DEBUG2:
qfeatweights = qreq_.ibs.get_annot_fgweights(
external_qaids, ensure=True,
config2_=qreq_.get_external_query_config2())
dfeatweights = qreq_.ibs.get_annot_fgweights( # NOQA
external_daids, ensure=True,
config2_=qreq_.get_external_data_config2())
#if verbose:
try:
assert len(qfeatweights) > 0, 'no query featweights'
assert qfeatweights[0].size > 0, (
'Query featweights are corrupted! qfeatweights=%r' %
(qfeatweights,))
except Exception:
print('qfeatweights = %r' % (qfeatweights,))
raise
#print('Featweight hash')
#print(qkpts)
#print(dkpts)
#print(ut.hashstr27(str(qfeatweights)))
#print(ut.hashstr27(str(dfeatweights)))
@profile
[docs] def load_indexer(qreq_, verbose=ut.NOT_QUIET, force=False):
if not force and qreq_.indexer is not None:
return False
else:
index_method = qreq_.qparams.index_method
if index_method == 'single':
# TODO: SYSTEM updatable indexer
if ut.VERYVERBOSE or verbose:
print('[qreq] loading single indexer normalizer')
indexer = neighbor_index.request_ibeis_nnindexer(
qreq_, verbose=verbose, **qreq_._indexer_request_params)
elif index_method == 'multi':
if ut.VERYVERBOSE or verbose:
print('[qreq] loading multi indexer normalizer')
indexer = multi_index.request_ibeis_mindexer(
qreq_, verbose=verbose)
else:
raise AssertionError('uknown index_method=%r' % (index_method,))
qreq_.indexer = indexer
return True
@profile
[docs] def load_score_normalizer(qreq_, verbose=ut.NOT_QUIET):
if qreq_.normalizer is not None:
return False
if verbose:
print('[qreq] loading score normalizer')
# TODO: SYSTEM updatable normalizer
normalizer = score_normalization.request_ibeis_normalizer(
qreq_, verbose=verbose)
qreq_.normalizer = normalizer
@profile
[docs] def load_distinctiveness_normalizer(qreq_, verbose=ut.NOT_QUIET):
"""
Example:
>>> from ibeis.model.hots import distinctiveness_normalizer
>>> verbose = True
"""
if qreq_.dstcnvs_normer is not None:
return False
if verbose:
print('[qreq] loading external distinctiveness normalizer')
# TODO: SYSTEM updatable dstcnvs_normer
_ = distinctiveness_normalizer
request_dcvs_normer = _.request_ibeis_distinctiveness_normalizer
dstcnvs_normer = request_dcvs_normer(qreq_, verbose=verbose)
qreq_.dstcnvs_normer = dstcnvs_normer
if verbose:
print('qreq_.dstcnvs_normer = %r' % (qreq_.dstcnvs_normer,))
[docs] def get_infostr(qreq_):
infostr_list = []
app = infostr_list.append
qaid_internal = qreq_.get_internal_qaids()
daid_internal = qreq_.get_internal_daids()
qd_intersection = ut.intersect_ordered(daid_internal, qaid_internal)
app(' * len(internal_daids) = %r' % len(daid_internal))
app(' * len(internal_qaids) = %r' % len(qaid_internal))
app(' * len(qd_intersection) = %r' % len(qd_intersection))
infostr = '\n'.join(infostr_list)
return infostr
[docs] def assert_self(qreq_, ibs):
print('[qreq] ASSERT SELF')
qaids = qreq_.get_external_qaids()
qauuids = qreq_.get_external_quuids()
daids = qreq_.get_external_daids()
dauuids = qreq_.get_external_duuids()
_qaids = qreq_.get_internal_qaids()
_qauuids = qreq_.get_internal_quuids()
_daids = qreq_.get_internal_daids()
_dauuids = qreq_.get_internal_duuids()
def assert_uuids(aids, uuids):
if ut.NOT_QUIET:
print('[qreq_] asserting %s aids' % len(aids))
assert len(aids) == len(uuids)
assert all([u1 == u2 for u1, u2 in
zip(ibs.get_annot_semantic_uuids(aids), uuids)])
assert_uuids(qaids, qauuids)
assert_uuids(daids, dauuids)
assert_uuids(_qaids, _qauuids)
assert_uuids(_daids, _dauuids)
#def make_empty_query_results(qreq_):
# """
# DEPRICATE in favor of chipmatch
# returns empty query results for each external qaid """
# external_qaids = qreq_.get_external_qaids()
# external_qauuids = qreq_.get_external_quuids()
# daids = qreq_.get_external_daids()
# cfgstr = qreq_.get_cfgstr()
# qres_list = [
# hots_query_result.QueryResult(qaid, qauuid, cfgstr, daids)
# for qaid, qauuid in zip(external_qaids, external_qauuids)
# ]
# for qres in qres_list:
# qres.aid2_score = {}
# return qres_list
[docs] def make_empty_chip_matches(qreq_):
"""
returns empty query results for each external qaid
Returns:
list: cm_list
CommandLine:
python -m ibeis.model.hots.query_request --exec-make_empty_chip_matches
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> import ibeis
>>> qreq_ = ibeis.main_helpers.testdata_qreq_()
>>> cm_list = qreq_.make_empty_chip_matches()
>>> cm = cm_list[0]
>>> cm.print_rawinfostr()
>>> result = ('cm_list = %s' % (str(cm_list),))
>>> print(result)
"""
external_qaids = qreq_.get_external_qaids()
#external_daids = qreq_.get_external_daids()
#external_dnids = qreq_.ibs.get_annot_name_rowids(external_daids)
# FIXME: hacky
cm_list = [
chip_match.ChipMatch2(qaid, [], qnid=qreq_.ibs.get_annot_name_rowids(qaid))
for qaid in (external_qaids)
]
for cm in cm_list:
cm._empty_hack()
return cm_list
#def make_empty_query_result(qreq_, qaid):
# """
# DEPRICATE in favor of chipmatch
# makes an empty result for some query aid. Hack used in case qres
# returned is None to get a single qres """
# qauuid = qreq_.ibs.get_annot_semantic_uuids(qaid)
# daids = qreq_.get_external_daids()
# cfgstr = qreq_.get_cfgstr()
# qres = hots_query_result.QueryResult(qaid, qauuid, cfgstr, daids)
# qres.aid2_score = {}
# return qres
@profile
[docs] def get_chipmatch_fpaths(qreq_, qaid_list):
"""
Efficient function to get a list of chipmatch paths
"""
dpath = qreq_.get_qresdir()
cfgstr = qreq_.get_cfgstr(with_query=False, with_data=True, with_pipe=True)
qauuid_list = qreq_.ibs.get_annot_semantic_uuids(qaid_list)
fpath_list = [
join(dpath, chip_match.get_chipmatch_fname(
qaid, qreq_, qauuid=qauuid, cfgstr=cfgstr))
for qaid, qauuid in zip(qaid_list, qauuid_list)
]
return fpath_list
@profile
[docs] def load_cached_chipmatch(qreq_, qaid=None):
"""
DEPRICATE in favor of chipmatch
convinience function for loading a query that has already been
cached """
if qaid is None:
qaid = qreq_.get_external_qaids()
shallow_qreq_ = qreq_.shallowcopy()
is_scalar = not ut.isiterable(qaid)
qaid_list = [qaid] if is_scalar else qaid
shallow_qreq_.set_external_qaids(qaid_list)
cm_list = shallow_qreq_.ibs.query_chips(
qaid_list, qreq_.get_external_daids(), use_cache=True,
use_bigcache=False, qreq_=shallow_qreq_, return_cm=True)
if is_scalar:
return cm_list[0]
else:
return cm_list
#def load_cached_qres(qreq_, qaid):
# """
# DEPRICATE in favor of chipmatch
# convinience function for loading a query that has already been
# cached """
# shallow_qreq_ = qreq_.shallowcopy()
# shallow_qreq_.set_external_qaids([qaid])
# qres = shallow_qreq_.ibs.query_chips(
# [qaid], qreq_.get_external_daids(), use_cache=True,
# use_bigcache=False, qreq_=shallow_qreq_)[0]
# return qres
[docs]def test_cfg_deepcopy():
"""
TESTING FUNCTION
Example:
>>> # ENABLE_DOCTEST
>>> from ibeis.model.hots.query_request import * # NOQA
>>> result = test_cfg_deepcopy()
>>> print(result)
"""
import ibeis
ibs = ibeis.opendb('testdb1')
cfg1 = ibs.cfg.query_cfg
cfg2 = cfg1.deepcopy()
cfg3 = cfg2
assert cfg1.get_cfgstr() == cfg2.get_cfgstr()
assert cfg2.sv_cfg is not cfg1.sv_cfg
assert cfg3.sv_cfg is cfg2.sv_cfg
cfg2.update_query_cfg(sv_on=False)
assert cfg1.get_cfgstr() != cfg2.get_cfgstr()
assert cfg2.get_cfgstr() == cfg3.get_cfgstr()
if __name__ == '__main__':
"""
CommandLine:
python -m ibeis.model.hots.query_request --test-QueryParams
utprof.sh -m ibeis.model.hots.query_request --test-QueryParams
python -m ibeis.model.hots.query_request
python -m ibeis.model.hots.query_request --allexamples
python -m ibeis.model.hots.query_request --allexamples --noface --nosrc
"""
import multiprocessing
multiprocessing.freeze_support() # for win32
ut.doctest_funcs()