Source code for ibeis.web.apis_detect

# -*- coding: utf-8 -*-
"""
Dependencies: flask, tornado
"""
from __future__ import absolute_import, division, print_function
from ibeis.control import accessor_decors, controller_inject
from ibeis import constants as const
import utool as ut
import simplejson as json
from os.path import join, dirname, abspath
from flask import url_for, request, current_app
from ibeis.constants import KEY_DEFAULTS, SPECIES_KEY
from ibeis.web import appfuncs as appf


try:
    import jpcnn  # NOQA
    USE_LOCALIZATIONS = False
    print('[apis_detect] USING DETECTIONS FOR DETECTIONS')
except ImportError:
    USE_LOCALIZATIONS = True
    print('[apis_detect] USING LOCALIZATIONS FOR DETECTIONS')


CLASS_INJECT_KEY, register_ibs_method = (
    controller_inject.make_ibs_register_decorator(__name__))
register_api   = controller_inject.get_ibeis_flask_api(__name__)
register_route = controller_inject.get_ibeis_flask_route(__name__)


@register_ibs_method
@accessor_decors.default_decorator
@accessor_decors.getter_1to1
@register_api('/api/detect/random_forest/', methods=['PUT', 'GET'])
[docs]def detect_random_forest(ibs, gid_list, species, commit=True, **kwargs): """ Runs animal detection in each image. Adds annotations to the database as they are found. Args: gid_list (list): list of image ids to run detection on species (str): string text of the species to identify Returns: aids_list (list): list of lists of annotation ids detected in each image CommandLine: python -m ibeis.web.apis_detect --test-detect_random_forest --show RESTful: Method: PUT, GET URL: /api/detect/random_forest/ Example: >>> # DISABLE_DOCTEST >>> from ibeis.web.apis_detect import * # NOQA >>> import ibeis >>> # build test data >>> ibs = ibeis.opendb('testdb1') >>> gid_list = ibs.get_valid_gids()[0:2] >>> species = ibeis.const.TEST_SPECIES.ZEB_PLAIN >>> # execute function >>> aids_list = ibs.detect_random_forest(gid_list, species) >>> # Visualize results >>> if ut.show_was_requested(): >>> import plottool as pt >>> from ibeis.viz import viz_image >>> for fnum, gid in enumerate(gid_list): >>> viz_image.show_image(ibs, gid, fnum=fnum) >>> pt.show_if_requested() >>> # Remove newly detected annotations >>> ibs.delete_annots(ut.flatten(aids_list)) """ # TODO: Return confidence here as well depc = ibs.depc_image config = { 'algo' : 'pyrf', 'species' : species, 'sensitivity' : 0.2, # 'classifier_sensitivity' : 0.64, # 'localizer_grid' : False, # 'localizer_sensitivity' : 0.16, # 'labeler_sensitivity' : 0.42, # 'detector_sensitivity' : 0.08, } if USE_LOCALIZATIONS: results_list = depc.get_property('localizations', gid_list, None, config=config) if commit: aids_list = ibs.commit_localization_results(gid_list, results_list, note='pyrfdetect') return aids_list else: results_list = depc.get_property('detections', gid_list, None, config=config) if commit: aids_list = ibs.commit_detection_results(gid_list, results_list, note='pyrfdetect') return aids_list
@register_route('/test/review/detect/cnn/yolo/', methods=['GET'])
[docs]def review_detection_test(): ibs = current_app.ibs results_dict = ibs.detection_yolo_test() image_uuid = results_dict['image_uuid_list'][0] result_list = results_dict['results_list'][0] callback_url = request.args.get('callback_url', url_for('process_detection_html')) callback_method = request.args.get('callback_method', 'POST') template_html = review_detection_html(ibs, image_uuid, result_list, callback_url, callback_method, include_jquery=True) template_html = ''' <script src="http://code.jquery.com/jquery-2.2.1.min.js" ia-dependency="javascript"></script> %s ''' % (template_html, ) return template_html
@register_ibs_method @register_api('/test/detect/cnn/yolo/', methods=['GET'])
[docs]def detection_yolo_test(ibs): from random import shuffle gid_list = ibs.get_valid_gids() shuffle(gid_list) gid_list = gid_list[:3] results_dict = ibs.detect_cnn_yolo_json(gid_list) return results_dict
@register_api('/api/review/detect/cnn/yolo/', methods=['GET'])
[docs]def review_detection_html(ibs, image_uuid, result_list, callback_url, callback_method='POST', include_jquery=False): """ Returns the detection review interface for a particular image UUID and a list of results for that image. Args: image_uuid (UUID): the UUID of the image you want to review detections for result_list (list of dict): list of detection results returned by the detector callback_url (str): URL that the review form will submit to (action) when the user is complete with their review callback_method (str): HTTP method the review form will submit to (method). Defaults to 'POST' Returns: template (html): json response with the detection web interface in html RESTful: Method: GET URL: /api/review/detect/cnn/yolo/ """ ibs.web_check_uuids(image_uuid_list=[image_uuid]) gid = ibs.get_image_gids_from_uuid(image_uuid) if gid is None: return 'INVALID IMAGE UUID' gpath = ibs.get_image_thumbpath(gid, ensure_paths=True, draw_annots=False) image = ibs.get_images(gid) image_src = appf.embed_image_html(image) width, height = ibs.get_image_sizes(gid) if width <= 0 or width is None or height <= 0 or height is None: vals = (image_uuid, width, height, ) raise IOError('Image %r for review has either no width or no height (w = %s, h = %s)' % vals) annotation_list = [] for result in result_list: annotation_list.append({ 'left' : 100.0 * (result['xtl'] / width), 'top' : 100.0 * (result['ytl'] / height), 'width' : 100.0 * (result['width'] / width), 'height' : 100.0 * (result['height'] / height), 'label' : result['class'], 'id' : None, 'theta' : result.get('theta', 0.0), }) species = KEY_DEFAULTS[SPECIES_KEY] root_path = dirname(abspath(__file__)) css_file_list = [ ['include', 'jquery-ui', 'jquery-ui.min.css'], ['include', 'jquery.ui.rotatable', 'jquery.ui.rotatable.css'], ['css', 'style.css'], ] json_file_list = [ ['include', 'jquery-ui', 'jquery-ui.min.js'], ['include', 'jquery.ui.rotatable', 'jquery.ui.rotatable.min.js'], ['include', 'bbox_annotator_percent.js'], ['javascript', 'script.js'], ['javascript', 'turk-detection.js'], ] if include_jquery: json_file_list = [ ['javascript', 'jquery.min.js'], ] + json_file_list EMBEDDED_CSS = '' EMBEDDED_JAVASCRIPT = '' css_template_fmtstr = '<style type="text/css" ia-dependency="css">%s</style>\n' json_template_fmtstr = '<script type="text/javascript" ia-dependency="javascript">%s</script>\n' for css_file in css_file_list: css_filepath_list = [root_path, 'static'] + css_file with open(join(*css_filepath_list)) as css_file: EMBEDDED_CSS += css_template_fmtstr % (css_file.read(), ) for json_file in json_file_list: json_filepath_list = [root_path, 'static'] + json_file with open(join(*json_filepath_list)) as json_file: EMBEDDED_JAVASCRIPT += json_template_fmtstr % (json_file.read(), ) return appf.template('turk', 'detection_insert', gid=gid, refer_aid=None, species=species, image_path=gpath, image_src=image_src, annotation_list=annotation_list, callback_url=callback_url, callback_method=callback_method, EMBEDDED_CSS=EMBEDDED_CSS, EMBEDDED_JAVASCRIPT=EMBEDDED_JAVASCRIPT)
@register_api('/api/review/detect/cnn/yolo/', methods=['POST'])
[docs]def process_detection_html(ibs, **kwargs): """ Processes the return from the detection review interface. Pass the POST result from the detection review form directly to this function unmodified Returns: detection results (dict): Same format as `func:start_detect_image` RESTful: Method: POST URL: /api/review/detect/cnn/yolo/ """ gid = int(request.form['detection-gid']) image_uuid = ibs.get_image_uuids(gid) width, height = ibs.get_image_sizes(gid) # Get aids annotation_list = json.loads(request.form['detection-annotations']) result_list = [ { 'xtl' : int( width * (annot['left'] / 100.0) ), 'ytl' : int( height * (annot['top'] / 100.0) ), 'width' : int( width * (annot['width'] / 100.0) ), 'height' : int( height * (annot['height'] / 100.0) ), 'theta' : float(annot['theta']), 'confidence' : 1.0, 'class' : annot['label'], } for annot in annotation_list ] result_dict = { 'image_uuid_list' : [image_uuid], 'results_list' : [result_list], 'score_list' : [1.0], } return result_dict
@register_ibs_method @accessor_decors.default_decorator @accessor_decors.getter_1to1
[docs]def detect_cnn_yolo_json(ibs, gid_list, **kwargs): """ Runs animal detection in each image and returns json-ready formatted results, does not return annotations Args: gid_list (list): list of image ids to run detection on Returns: results_dict (list): dict of detection results (not annotations) CommandLine: python -m ibeis.web.apis_detect --test-detect_cnn_yolo_json Example: >>> # DISABLE_DOCTEST >>> from ibeis.web.apis_detect import * # NOQA >>> import ibeis >>> # build test data >>> ibs = ibeis.opendb('testdb1') >>> gid_list = ibs.get_valid_gids()[0:2] >>> # execute function >>> results_dict = ibs.detect_cnn_yolo_json(gid_list) >>> print(results_dict) """ # TODO: Return confidence here as well image_uuid_list = ibs.get_image_uuids(gid_list) ibs.assert_valid_gids(gid_list) # Get detections from depc aids_list = ibs.detect_cnn_yolo(gid_list, **kwargs) results_list = [ [ { 'xtl' : ibs.get_annot_bboxes(aid)[0], 'ytl' : ibs.get_annot_bboxes(aid)[1], 'width' : ibs.get_annot_bboxes(aid)[2], 'height' : ibs.get_annot_bboxes(aid)[3], 'theta' : round(ibs.get_annot_thetas(aid), 4), 'confidence' : round(ibs.get_annot_detect_confidence(aid), 4), 'class' : ibs.get_annot_species_texts(aid), } for aid in aid_list ] for aid_list in aids_list ] score_list = [0.0] * len(gid_list) # Wrap up results with other information results_dict = { 'image_uuid_list' : image_uuid_list, 'results_list' : results_list, 'score_list' : score_list, } return results_dict
@register_ibs_method @accessor_decors.default_decorator @accessor_decors.getter_1to1 @register_api('/api/detect/cnn/yolo/', methods=['PUT', 'GET'])
[docs]def detect_cnn_yolo(ibs, gid_list, commit=True, **kwargs): """ Runs animal detection in each image. Adds annotations to the database as they are found. Args: gid_list (list): list of image ids to run detection on Returns: aids_list (list): list of lists of annotation ids detected in each image CommandLine: python -m ibeis.web.apis_detect --test-detect_cnn_yolo --show RESTful: Method: PUT, GET URL: /api/detect/cnn/yolo/ Example: >>> # DISABLE_DOCTEST >>> from ibeis.web.apis_detect import * # NOQA >>> import ibeis >>> # build test data >>> ibs = ibeis.opendb('PZ_MTEST') >>> gid_list = ibs.get_valid_gids()[:5] >>> # execute function >>> aids_list = ibs.detect_cnn_yolo(gid_list) >>> # Visualize results >>> if ut.show_was_requested(): >>> import plottool as pt >>> from ibeis.viz import viz_image >>> for fnum, gid in enumerate(gid_list): >>> viz_image.show_image(ibs, gid, fnum=fnum) >>> pt.show_if_requested() >>> # Remove newly detected annotations >>> ibs.delete_annots(ut.flatten(aids_list)) """ # TODO: Return confidence here as well depc = ibs.depc_image config = { 'algo' : 'yolo', 'sensitivity' : 0.2, # 'classifier_sensitivity' : 0.64, # 'localizer_grid' : False, # 'localizer_sensitivity' : 0.16, # 'labeler_sensitivity' : 0.42, # 'detector_sensitivity' : 0.08, } if USE_LOCALIZATIONS: results_list = depc.get_property('localizations', gid_list, None, config=config) if commit: aids_list = ibs.commit_localization_results(gid_list, results_list, note='cnnyolodetect') return aids_list else: results_list = depc.get_property('detections', gid_list, None, config=config) if commit: aids_list = ibs.commit_detection_results(gid_list, results_list, note='cnnyolodetect') return aids_list
@register_ibs_method
[docs]def commit_localization_results(ibs, gid_list, results_list, note=None): zipped_list = zip(gid_list, results_list) aids_list = [] for gid, (score, bbox_list, theta_list, conf_list, class_list) in zipped_list: num = len(bbox_list) notes_list = None if note is None else [note] * num aid_list = ibs.add_annots( [gid] * num, bbox_list, theta_list, class_list, detect_confidence_list=conf_list, notes_list=notes_list, quiet_delete_thumbs=True, skip_cleaning=True ) # ibs.set_annot_yaw_texts(aid_list, viewpoint_list) aids_list.append(aid_list) ibs._clean_species() return aids_list
@register_ibs_method
[docs]def commit_detection_results(ibs, gid_list, results_list, note=None): zipped_list = zip(gid_list, results_list) aids_list = [] for gid, (score, bbox_list, theta_list, species_list, viewpoint_list, conf_list) in zipped_list: num = len(bbox_list) notes_list = None if note is None else [note] * num aid_list = ibs.add_annots( [gid] * num, bbox_list, theta_list, species_list, detect_confidence_list=conf_list, notes_list=notes_list, quiet_delete_thumbs=True, skip_cleaning=True ) ibs.set_annot_yaw_texts(aid_list, viewpoint_list) aids_list.append(aid_list) ibs._clean_species() return aids_list
@register_ibs_method @accessor_decors.default_decorator @register_api('/api/detect/species/enabled/', methods=['GET'])
[docs]def has_species_detector(ibs, species_text): """ TODO: extend to use non-constant species RESTful: Method: GET URL: /api/detect/species/enabled/ """ # FIXME: infer this return species_text in const.SPECIES_WITH_DETECTORS
@register_ibs_method @accessor_decors.default_decorator @register_api('/api/detect/species/', methods=['GET'])
[docs]def get_species_with_detectors(ibs): """ RESTful: Method: GET URL: /api/detect/species/ """ # FIXME: infer this return const.SPECIES_WITH_DETECTORS
@register_ibs_method @accessor_decors.default_decorator @register_api('/api/detect/species/working/', methods=['GET'])
[docs]def get_working_species(ibs): """ RESTful: Method: GET URL: /api/detect/species/working/ """ RESTRICT_TO_ONLY_SPECIES_WITH_DETECTORS = ut.get_argflag('--no-allspecies') species_nice_list = ibs.get_all_species_nice() species_text_list = ibs.get_all_species_texts() species_tup_list = zip(species_nice_list, species_text_list) if RESTRICT_TO_ONLY_SPECIES_WITH_DETECTORS: working_species_tups = [ species_tup for species_tup in species_tup_list if ibs.has_species_detector(species_tup[1]) ] else: working_species_tups = species_tup_list return working_species_tups
if __name__ == '__main__': """ CommandLine: python -m ibeis.web.app python -m ibeis.web.app --allexamples python -m ibeis.web.app --allexamples --noface --nosrc """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()