megadetector 5.0.9__py3-none-any.whl → 5.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of megadetector might be problematic. Click here for more details.
- {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/LICENSE +0 -0
- {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/METADATA +12 -11
- megadetector-5.0.11.dist-info/RECORD +5 -0
- megadetector-5.0.11.dist-info/top_level.txt +1 -0
- api/__init__.py +0 -0
- api/batch_processing/__init__.py +0 -0
- api/batch_processing/api_core/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/__init__.py +0 -0
- api/batch_processing/api_core/batch_service/score.py +0 -439
- api/batch_processing/api_core/server.py +0 -294
- api/batch_processing/api_core/server_api_config.py +0 -98
- api/batch_processing/api_core/server_app_config.py +0 -55
- api/batch_processing/api_core/server_batch_job_manager.py +0 -220
- api/batch_processing/api_core/server_job_status_table.py +0 -152
- api/batch_processing/api_core/server_orchestration.py +0 -360
- api/batch_processing/api_core/server_utils.py +0 -92
- api/batch_processing/api_core_support/__init__.py +0 -0
- api/batch_processing/api_core_support/aggregate_results_manually.py +0 -46
- api/batch_processing/api_support/__init__.py +0 -0
- api/batch_processing/api_support/summarize_daily_activity.py +0 -152
- api/batch_processing/data_preparation/__init__.py +0 -0
- api/batch_processing/data_preparation/manage_local_batch.py +0 -2391
- api/batch_processing/data_preparation/manage_video_batch.py +0 -327
- api/batch_processing/integration/digiKam/setup.py +0 -6
- api/batch_processing/integration/digiKam/xmp_integration.py +0 -465
- api/batch_processing/integration/eMammal/test_scripts/config_template.py +0 -5
- api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +0 -126
- api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +0 -55
- api/batch_processing/postprocessing/__init__.py +0 -0
- api/batch_processing/postprocessing/add_max_conf.py +0 -64
- api/batch_processing/postprocessing/categorize_detections_by_size.py +0 -163
- api/batch_processing/postprocessing/combine_api_outputs.py +0 -249
- api/batch_processing/postprocessing/compare_batch_results.py +0 -958
- api/batch_processing/postprocessing/convert_output_format.py +0 -397
- api/batch_processing/postprocessing/load_api_results.py +0 -195
- api/batch_processing/postprocessing/md_to_coco.py +0 -310
- api/batch_processing/postprocessing/md_to_labelme.py +0 -330
- api/batch_processing/postprocessing/merge_detections.py +0 -401
- api/batch_processing/postprocessing/postprocess_batch_results.py +0 -1904
- api/batch_processing/postprocessing/remap_detection_categories.py +0 -170
- api/batch_processing/postprocessing/render_detection_confusion_matrix.py +0 -661
- api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +0 -211
- api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +0 -82
- api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +0 -1631
- api/batch_processing/postprocessing/separate_detections_into_folders.py +0 -731
- api/batch_processing/postprocessing/subset_json_detector_output.py +0 -696
- api/batch_processing/postprocessing/top_folders_to_bottom.py +0 -223
- api/synchronous/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/__init__.py +0 -0
- api/synchronous/api_core/animal_detection_api/api_backend.py +0 -152
- api/synchronous/api_core/animal_detection_api/api_frontend.py +0 -266
- api/synchronous/api_core/animal_detection_api/config.py +0 -35
- api/synchronous/api_core/animal_detection_api/data_management/annotations/annotation_constants.py +0 -47
- api/synchronous/api_core/animal_detection_api/detection/detector_training/copy_checkpoints.py +0 -43
- api/synchronous/api_core/animal_detection_api/detection/detector_training/model_main_tf2.py +0 -114
- api/synchronous/api_core/animal_detection_api/detection/process_video.py +0 -543
- api/synchronous/api_core/animal_detection_api/detection/pytorch_detector.py +0 -304
- api/synchronous/api_core/animal_detection_api/detection/run_detector.py +0 -627
- api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +0 -1029
- api/synchronous/api_core/animal_detection_api/detection/run_inference_with_yolov5_val.py +0 -581
- api/synchronous/api_core/animal_detection_api/detection/run_tiled_inference.py +0 -754
- api/synchronous/api_core/animal_detection_api/detection/tf_detector.py +0 -165
- api/synchronous/api_core/animal_detection_api/detection/video_utils.py +0 -495
- api/synchronous/api_core/animal_detection_api/md_utils/azure_utils.py +0 -174
- api/synchronous/api_core/animal_detection_api/md_utils/ct_utils.py +0 -262
- api/synchronous/api_core/animal_detection_api/md_utils/directory_listing.py +0 -251
- api/synchronous/api_core/animal_detection_api/md_utils/matlab_porting_tools.py +0 -97
- api/synchronous/api_core/animal_detection_api/md_utils/path_utils.py +0 -416
- api/synchronous/api_core/animal_detection_api/md_utils/process_utils.py +0 -110
- api/synchronous/api_core/animal_detection_api/md_utils/sas_blob_utils.py +0 -509
- api/synchronous/api_core/animal_detection_api/md_utils/string_utils.py +0 -59
- api/synchronous/api_core/animal_detection_api/md_utils/url_utils.py +0 -144
- api/synchronous/api_core/animal_detection_api/md_utils/write_html_image_list.py +0 -226
- api/synchronous/api_core/animal_detection_api/md_visualization/visualization_utils.py +0 -841
- api/synchronous/api_core/tests/__init__.py +0 -0
- api/synchronous/api_core/tests/load_test.py +0 -110
- classification/__init__.py +0 -0
- classification/aggregate_classifier_probs.py +0 -108
- classification/analyze_failed_images.py +0 -227
- classification/cache_batchapi_outputs.py +0 -198
- classification/create_classification_dataset.py +0 -627
- classification/crop_detections.py +0 -516
- classification/csv_to_json.py +0 -226
- classification/detect_and_crop.py +0 -855
- classification/efficientnet/__init__.py +0 -9
- classification/efficientnet/model.py +0 -415
- classification/efficientnet/utils.py +0 -610
- classification/evaluate_model.py +0 -520
- classification/identify_mislabeled_candidates.py +0 -152
- classification/json_to_azcopy_list.py +0 -63
- classification/json_validator.py +0 -695
- classification/map_classification_categories.py +0 -276
- classification/merge_classification_detection_output.py +0 -506
- classification/prepare_classification_script.py +0 -194
- classification/prepare_classification_script_mc.py +0 -228
- classification/run_classifier.py +0 -286
- classification/save_mislabeled.py +0 -110
- classification/train_classifier.py +0 -825
- classification/train_classifier_tf.py +0 -724
- classification/train_utils.py +0 -322
- data_management/__init__.py +0 -0
- data_management/annotations/__init__.py +0 -0
- data_management/annotations/annotation_constants.py +0 -34
- data_management/camtrap_dp_to_coco.py +0 -238
- data_management/cct_json_utils.py +0 -395
- data_management/cct_to_md.py +0 -176
- data_management/cct_to_wi.py +0 -289
- data_management/coco_to_labelme.py +0 -272
- data_management/coco_to_yolo.py +0 -662
- data_management/databases/__init__.py +0 -0
- data_management/databases/add_width_and_height_to_db.py +0 -33
- data_management/databases/combine_coco_camera_traps_files.py +0 -206
- data_management/databases/integrity_check_json_db.py +0 -477
- data_management/databases/subset_json_db.py +0 -115
- data_management/generate_crops_from_cct.py +0 -149
- data_management/get_image_sizes.py +0 -188
- data_management/importers/add_nacti_sizes.py +0 -52
- data_management/importers/add_timestamps_to_icct.py +0 -79
- data_management/importers/animl_results_to_md_results.py +0 -158
- data_management/importers/auckland_doc_test_to_json.py +0 -372
- data_management/importers/auckland_doc_to_json.py +0 -200
- data_management/importers/awc_to_json.py +0 -189
- data_management/importers/bellevue_to_json.py +0 -273
- data_management/importers/cacophony-thermal-importer.py +0 -796
- data_management/importers/carrizo_shrubfree_2018.py +0 -268
- data_management/importers/carrizo_trail_cam_2017.py +0 -287
- data_management/importers/cct_field_adjustments.py +0 -57
- data_management/importers/channel_islands_to_cct.py +0 -913
- data_management/importers/eMammal/copy_and_unzip_emammal.py +0 -180
- data_management/importers/eMammal/eMammal_helpers.py +0 -249
- data_management/importers/eMammal/make_eMammal_json.py +0 -223
- data_management/importers/ena24_to_json.py +0 -275
- data_management/importers/filenames_to_json.py +0 -385
- data_management/importers/helena_to_cct.py +0 -282
- data_management/importers/idaho-camera-traps.py +0 -1407
- data_management/importers/idfg_iwildcam_lila_prep.py +0 -294
- data_management/importers/jb_csv_to_json.py +0 -150
- data_management/importers/mcgill_to_json.py +0 -250
- data_management/importers/missouri_to_json.py +0 -489
- data_management/importers/nacti_fieldname_adjustments.py +0 -79
- data_management/importers/noaa_seals_2019.py +0 -181
- data_management/importers/pc_to_json.py +0 -365
- data_management/importers/plot_wni_giraffes.py +0 -123
- data_management/importers/prepare-noaa-fish-data-for-lila.py +0 -359
- data_management/importers/prepare_zsl_imerit.py +0 -131
- data_management/importers/rspb_to_json.py +0 -356
- data_management/importers/save_the_elephants_survey_A.py +0 -320
- data_management/importers/save_the_elephants_survey_B.py +0 -332
- data_management/importers/snapshot_safari_importer.py +0 -758
- data_management/importers/snapshot_safari_importer_reprise.py +0 -665
- data_management/importers/snapshot_serengeti_lila.py +0 -1067
- data_management/importers/snapshotserengeti/make_full_SS_json.py +0 -150
- data_management/importers/snapshotserengeti/make_per_season_SS_json.py +0 -153
- data_management/importers/sulross_get_exif.py +0 -65
- data_management/importers/timelapse_csv_set_to_json.py +0 -490
- data_management/importers/ubc_to_json.py +0 -399
- data_management/importers/umn_to_json.py +0 -507
- data_management/importers/wellington_to_json.py +0 -263
- data_management/importers/wi_to_json.py +0 -441
- data_management/importers/zamba_results_to_md_results.py +0 -181
- data_management/labelme_to_coco.py +0 -548
- data_management/labelme_to_yolo.py +0 -272
- data_management/lila/__init__.py +0 -0
- data_management/lila/add_locations_to_island_camera_traps.py +0 -97
- data_management/lila/add_locations_to_nacti.py +0 -147
- data_management/lila/create_lila_blank_set.py +0 -557
- data_management/lila/create_lila_test_set.py +0 -151
- data_management/lila/create_links_to_md_results_files.py +0 -106
- data_management/lila/download_lila_subset.py +0 -177
- data_management/lila/generate_lila_per_image_labels.py +0 -515
- data_management/lila/get_lila_annotation_counts.py +0 -170
- data_management/lila/get_lila_image_counts.py +0 -111
- data_management/lila/lila_common.py +0 -300
- data_management/lila/test_lila_metadata_urls.py +0 -132
- data_management/ocr_tools.py +0 -874
- data_management/read_exif.py +0 -681
- data_management/remap_coco_categories.py +0 -84
- data_management/remove_exif.py +0 -66
- data_management/resize_coco_dataset.py +0 -189
- data_management/wi_download_csv_to_coco.py +0 -246
- data_management/yolo_output_to_md_output.py +0 -441
- data_management/yolo_to_coco.py +0 -676
- detection/__init__.py +0 -0
- detection/detector_training/__init__.py +0 -0
- detection/detector_training/model_main_tf2.py +0 -114
- detection/process_video.py +0 -703
- detection/pytorch_detector.py +0 -337
- detection/run_detector.py +0 -779
- detection/run_detector_batch.py +0 -1219
- detection/run_inference_with_yolov5_val.py +0 -917
- detection/run_tiled_inference.py +0 -935
- detection/tf_detector.py +0 -188
- detection/video_utils.py +0 -606
- docs/source/conf.py +0 -43
- md_utils/__init__.py +0 -0
- md_utils/azure_utils.py +0 -174
- md_utils/ct_utils.py +0 -612
- md_utils/directory_listing.py +0 -246
- md_utils/md_tests.py +0 -968
- md_utils/path_utils.py +0 -1044
- md_utils/process_utils.py +0 -157
- md_utils/sas_blob_utils.py +0 -509
- md_utils/split_locations_into_train_val.py +0 -228
- md_utils/string_utils.py +0 -92
- md_utils/url_utils.py +0 -323
- md_utils/write_html_image_list.py +0 -225
- md_visualization/__init__.py +0 -0
- md_visualization/plot_utils.py +0 -293
- md_visualization/render_images_with_thumbnails.py +0 -275
- md_visualization/visualization_utils.py +0 -1537
- md_visualization/visualize_db.py +0 -551
- md_visualization/visualize_detector_output.py +0 -406
- megadetector-5.0.9.dist-info/RECORD +0 -224
- megadetector-5.0.9.dist-info/top_level.txt +0 -8
- taxonomy_mapping/__init__.py +0 -0
- taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +0 -491
- taxonomy_mapping/map_new_lila_datasets.py +0 -154
- taxonomy_mapping/prepare_lila_taxonomy_release.py +0 -142
- taxonomy_mapping/preview_lila_taxonomy.py +0 -591
- taxonomy_mapping/retrieve_sample_image.py +0 -71
- taxonomy_mapping/simple_image_download.py +0 -218
- taxonomy_mapping/species_lookup.py +0 -834
- taxonomy_mapping/taxonomy_csv_checker.py +0 -159
- taxonomy_mapping/taxonomy_graph.py +0 -346
- taxonomy_mapping/validate_lila_category_mappings.py +0 -83
- {megadetector-5.0.9.dist-info → megadetector-5.0.11.dist-info}/WHEEL +0 -0
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
########
|
|
2
|
-
#
|
|
3
|
-
# pytorch_detector.py
|
|
4
|
-
#
|
|
5
|
-
# Module to run MegaDetector v5, a PyTorch YOLOv5 animal detection model.
|
|
6
|
-
#
|
|
7
|
-
########
|
|
8
|
-
|
|
9
|
-
#%% Imports
|
|
10
|
-
|
|
11
|
-
import torch
|
|
12
|
-
import numpy as np
|
|
13
|
-
import traceback
|
|
14
|
-
|
|
15
|
-
from detection.run_detector import CONF_DIGITS, COORD_DIGITS, FAILURE_INFER
|
|
16
|
-
from md_utils import ct_utils
|
|
17
|
-
|
|
18
|
-
# We support a few ways of accessing the YOLOv5 dependencies:
|
|
19
|
-
#
|
|
20
|
-
# * The standard configuration as of 9.2023 expects that the YOLOv5 repo is checked
|
|
21
|
-
# out and on the PYTHONPATH (import utils)
|
|
22
|
-
#
|
|
23
|
-
# * Experimental: pip install ultralytics (doesn't totally work yet)
|
|
24
|
-
#
|
|
25
|
-
# * Experimental but works so far: pip install yolov5
|
|
26
|
-
|
|
27
|
-
utils_imported = False
|
|
28
|
-
try_yolov5_import = True
|
|
29
|
-
|
|
30
|
-
# This still encounters some namespace issues
|
|
31
|
-
try_ultralytics_import = False
|
|
32
|
-
|
|
33
|
-
# First try importing from the yolov5 package
|
|
34
|
-
if try_yolov5_import and not utils_imported:
|
|
35
|
-
|
|
36
|
-
try:
|
|
37
|
-
from yolov5.utils.general import non_max_suppression, xyxy2xywh # noqa
|
|
38
|
-
from yolov5.utils.augmentations import letterbox # noqa
|
|
39
|
-
from yolov5.utils.general import scale_boxes as scale_coords # noqa
|
|
40
|
-
utils_imported = True
|
|
41
|
-
print('Imported YOLOv5 from YOLOv5 package')
|
|
42
|
-
except Exception:
|
|
43
|
-
# print('YOLOv5 module import failed, falling back to path-based import')
|
|
44
|
-
pass
|
|
45
|
-
|
|
46
|
-
# If we haven't succeeded yet, import from the ultralytics package
|
|
47
|
-
if try_ultralytics_import and not utils_imported:
|
|
48
|
-
|
|
49
|
-
try:
|
|
50
|
-
from ultralytics.utils.ops import non_max_suppression # noqa
|
|
51
|
-
from ultralytics.utils.ops import xyxy2xywh # noqa
|
|
52
|
-
from ultralytics.utils.ops import scale_coords # noqa
|
|
53
|
-
from ultralytics.data.augment import LetterBox
|
|
54
|
-
|
|
55
|
-
# letterbox() became a LetterBox class in the ultralytics package
|
|
56
|
-
def letterbox(img,new_shape,stride,auto=True): # noqa
|
|
57
|
-
L = LetterBox(new_shape,stride=stride,auto=auto)
|
|
58
|
-
letterbox_result = L(image=img)
|
|
59
|
-
return [letterbox_result]
|
|
60
|
-
utils_imported = True
|
|
61
|
-
print('Imported YOLOv5 from ultralytics package')
|
|
62
|
-
except Exception:
|
|
63
|
-
# print('Ultralytics module import failed, falling back to yolov5 import')
|
|
64
|
-
pass
|
|
65
|
-
|
|
66
|
-
# If we haven't succeeded yet, import from the YOLOv5 repo
|
|
67
|
-
if not utils_imported:
|
|
68
|
-
|
|
69
|
-
try:
|
|
70
|
-
# import pre- and post-processing functions from the YOLOv5 repo
|
|
71
|
-
from utils.general import non_max_suppression, xyxy2xywh # noqa
|
|
72
|
-
from utils.augmentations import letterbox # noqa
|
|
73
|
-
|
|
74
|
-
# scale_coords() became scale_boxes() in later YOLOv5 versions
|
|
75
|
-
try:
|
|
76
|
-
from utils.general import scale_coords # noqa
|
|
77
|
-
except ImportError:
|
|
78
|
-
from utils.general import scale_boxes as scale_coords
|
|
79
|
-
utils_imported = True
|
|
80
|
-
print('Imported YOLOv5 from PYTHONPATH')
|
|
81
|
-
except ModuleNotFoundError:
|
|
82
|
-
raise ModuleNotFoundError('Could not import YOLOv5 functions.')
|
|
83
|
-
|
|
84
|
-
assert utils_imported, 'YOLOv5 import error'
|
|
85
|
-
|
|
86
|
-
print(f'Using PyTorch version {torch.__version__}')
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
#%% Classes
|
|
90
|
-
|
|
91
|
-
class PTDetector:
|
|
92
|
-
|
|
93
|
-
IMAGE_SIZE = 1280 # image size used in training
|
|
94
|
-
STRIDE = 64
|
|
95
|
-
|
|
96
|
-
def __init__(self, model_path: str,
|
|
97
|
-
force_cpu: bool = False,
|
|
98
|
-
use_model_native_classes: bool = False):
|
|
99
|
-
self.device = 'cpu'
|
|
100
|
-
if not force_cpu:
|
|
101
|
-
if torch.cuda.is_available():
|
|
102
|
-
self.device = torch.device('cuda:0')
|
|
103
|
-
try:
|
|
104
|
-
if torch.backends.mps.is_built and torch.backends.mps.is_available():
|
|
105
|
-
self.device = 'mps'
|
|
106
|
-
except AttributeError:
|
|
107
|
-
pass
|
|
108
|
-
self.model = PTDetector._load_model(model_path, self.device)
|
|
109
|
-
if (self.device != 'cpu'):
|
|
110
|
-
print('Sending model to GPU')
|
|
111
|
-
self.model.to(self.device)
|
|
112
|
-
|
|
113
|
-
self.printed_image_size_warning = False
|
|
114
|
-
self.use_model_native_classes = use_model_native_classes
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
@staticmethod
|
|
118
|
-
def _load_model(model_pt_path, device):
|
|
119
|
-
|
|
120
|
-
# There are two very slightly different ways to load the model, (1) using the
|
|
121
|
-
# map_location=device parameter to torch.load and (2) calling .to(device) after
|
|
122
|
-
# loading the model. The former is what we did for a zillion years, but is not
|
|
123
|
-
# supported on Apple silicon at of 2029.09. Switching to the latter causes
|
|
124
|
-
# very slight changes to the output, which always make me nervous, so I'm not
|
|
125
|
-
# doing a wholesale swap just yet. Instead, we'll just do this on M1 hardware.
|
|
126
|
-
use_map_location = (device != 'mps')
|
|
127
|
-
|
|
128
|
-
if use_map_location:
|
|
129
|
-
checkpoint = torch.load(model_pt_path, map_location=device)
|
|
130
|
-
else:
|
|
131
|
-
checkpoint = torch.load(model_pt_path)
|
|
132
|
-
|
|
133
|
-
# Compatibility fix that allows us to load older YOLOv5 models with
|
|
134
|
-
# newer versions of YOLOv5/PT
|
|
135
|
-
for m in checkpoint['model'].modules():
|
|
136
|
-
t = type(m)
|
|
137
|
-
if t is torch.nn.Upsample and not hasattr(m, 'recompute_scale_factor'):
|
|
138
|
-
m.recompute_scale_factor = None
|
|
139
|
-
|
|
140
|
-
if use_map_location:
|
|
141
|
-
model = checkpoint['model'].float().fuse().eval()
|
|
142
|
-
else:
|
|
143
|
-
model = checkpoint['model'].float().fuse().eval().to(device)
|
|
144
|
-
|
|
145
|
-
return model
|
|
146
|
-
|
|
147
|
-
def generate_detections_one_image(self, img_original, image_id='unknown',
|
|
148
|
-
detection_threshold=0.00001, image_size=None,
|
|
149
|
-
skip_image_resizing=False):
|
|
150
|
-
"""
|
|
151
|
-
Apply the detector to an image.
|
|
152
|
-
|
|
153
|
-
Args:
|
|
154
|
-
img_original: the PIL Image object with EXIF rotation taken into account
|
|
155
|
-
image_id: a path to identify the image; will be in the "file" field of the output object
|
|
156
|
-
detection_threshold: confidence above which to include the detection proposal
|
|
157
|
-
skip_image_resizing: whether to skip internal image resizing and rely on external resizing
|
|
158
|
-
|
|
159
|
-
Returns:
|
|
160
|
-
A dict with the following fields, see the 'images' key in https://github.com/agentmorris/MegaDetector/tree/master/api/batch_processing#batch-processing-api-output-format
|
|
161
|
-
- 'file' (always present)
|
|
162
|
-
- 'max_detection_conf' (removed from MegaDetector output by default, but generated here)
|
|
163
|
-
- 'detections', which is a list of detection objects containing keys 'category',
|
|
164
|
-
'conf' and 'bbox'
|
|
165
|
-
- 'failure'
|
|
166
|
-
"""
|
|
167
|
-
|
|
168
|
-
result = {
|
|
169
|
-
'file': image_id
|
|
170
|
-
}
|
|
171
|
-
detections = []
|
|
172
|
-
max_conf = 0.0
|
|
173
|
-
|
|
174
|
-
try:
|
|
175
|
-
|
|
176
|
-
img_original = np.asarray(img_original)
|
|
177
|
-
|
|
178
|
-
# padded resize
|
|
179
|
-
target_size = PTDetector.IMAGE_SIZE
|
|
180
|
-
|
|
181
|
-
# Image size can be an int (which translates to a square target size) or (h,w)
|
|
182
|
-
if image_size is not None:
|
|
183
|
-
|
|
184
|
-
assert isinstance(image_size,int) or (len(image_size)==2)
|
|
185
|
-
|
|
186
|
-
if not self.printed_image_size_warning:
|
|
187
|
-
print('Warning: using user-supplied image size {}'.format(image_size))
|
|
188
|
-
self.printed_image_size_warning = True
|
|
189
|
-
|
|
190
|
-
target_size = image_size
|
|
191
|
-
|
|
192
|
-
else:
|
|
193
|
-
|
|
194
|
-
self.printed_image_size_warning = False
|
|
195
|
-
|
|
196
|
-
# ...if the caller has specified an image size
|
|
197
|
-
|
|
198
|
-
if skip_image_resizing:
|
|
199
|
-
img = img_original
|
|
200
|
-
else:
|
|
201
|
-
letterbox_result = letterbox(img_original, new_shape=target_size,
|
|
202
|
-
stride=PTDetector.STRIDE, auto=True)
|
|
203
|
-
img = letterbox_result[0]
|
|
204
|
-
|
|
205
|
-
# HWC to CHW; PIL Image is RGB already
|
|
206
|
-
img = img.transpose((2, 0, 1))
|
|
207
|
-
img = np.ascontiguousarray(img)
|
|
208
|
-
img = torch.from_numpy(img)
|
|
209
|
-
img = img.to(self.device)
|
|
210
|
-
img = img.float()
|
|
211
|
-
img /= 255
|
|
212
|
-
|
|
213
|
-
# In practice this is always true
|
|
214
|
-
if len(img.shape) == 3:
|
|
215
|
-
img = torch.unsqueeze(img, 0)
|
|
216
|
-
|
|
217
|
-
pred: list = self.model(img)[0]
|
|
218
|
-
|
|
219
|
-
# NMS
|
|
220
|
-
if self.device == 'mps':
|
|
221
|
-
# As of v1.13.0.dev20220824, nms is not implemented for MPS.
|
|
222
|
-
#
|
|
223
|
-
# Send predication back to the CPU to fix.
|
|
224
|
-
pred = non_max_suppression(prediction=pred.cpu(), conf_thres=detection_threshold)
|
|
225
|
-
else:
|
|
226
|
-
pred = non_max_suppression(prediction=pred, conf_thres=detection_threshold)
|
|
227
|
-
|
|
228
|
-
# format detections/bounding boxes
|
|
229
|
-
#
|
|
230
|
-
# normalization gain whwh
|
|
231
|
-
gn = torch.tensor(img_original.shape)[[1, 0, 1, 0]]
|
|
232
|
-
|
|
233
|
-
# This is a loop over detection batches, which will always be length 1 in our case,
|
|
234
|
-
# since we're not doing batch inference.
|
|
235
|
-
for det in pred:
|
|
236
|
-
|
|
237
|
-
if len(det):
|
|
238
|
-
|
|
239
|
-
# Rescale boxes from img_size to im0 size
|
|
240
|
-
det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img_original.shape).round()
|
|
241
|
-
|
|
242
|
-
for *xyxy, conf, cls in reversed(det):
|
|
243
|
-
|
|
244
|
-
# normalized center-x, center-y, width and height
|
|
245
|
-
xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()
|
|
246
|
-
|
|
247
|
-
api_box = ct_utils.convert_yolo_to_xywh(xywh)
|
|
248
|
-
|
|
249
|
-
conf = ct_utils.truncate_float(conf.tolist(), precision=CONF_DIGITS)
|
|
250
|
-
|
|
251
|
-
if not self.use_model_native_classes:
|
|
252
|
-
# MegaDetector output format's categories start at 1, but the MD
|
|
253
|
-
# model's categories start at 0.
|
|
254
|
-
cls = int(cls.tolist()) + 1
|
|
255
|
-
if cls not in (1, 2, 3):
|
|
256
|
-
raise KeyError(f'{cls} is not a valid class.')
|
|
257
|
-
else:
|
|
258
|
-
cls = int(cls.tolist())
|
|
259
|
-
|
|
260
|
-
detections.append({
|
|
261
|
-
'category': str(cls),
|
|
262
|
-
'conf': conf,
|
|
263
|
-
'bbox': ct_utils.truncate_float_array(api_box, precision=COORD_DIGITS)
|
|
264
|
-
})
|
|
265
|
-
max_conf = max(max_conf, conf)
|
|
266
|
-
|
|
267
|
-
# ...for each detection in this batch
|
|
268
|
-
|
|
269
|
-
# ...if this is a non-empty batch
|
|
270
|
-
|
|
271
|
-
# ...for each detection batch
|
|
272
|
-
|
|
273
|
-
# ...try
|
|
274
|
-
|
|
275
|
-
except Exception as e:
|
|
276
|
-
|
|
277
|
-
result['failure'] = FAILURE_INFER
|
|
278
|
-
print('PTDetector: image {} failed during inference: {}\n'.format(image_id, str(e)))
|
|
279
|
-
traceback.print_exc(e)
|
|
280
|
-
|
|
281
|
-
result['max_detection_conf'] = max_conf
|
|
282
|
-
result['detections'] = detections
|
|
283
|
-
|
|
284
|
-
return result
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
#%% Command-line driver
|
|
288
|
-
|
|
289
|
-
if __name__ == '__main__':
|
|
290
|
-
|
|
291
|
-
# For testing only... you don't really want to run this module directly
|
|
292
|
-
|
|
293
|
-
#%%
|
|
294
|
-
|
|
295
|
-
import md_visualization.visualization_utils as vis_utils
|
|
296
|
-
import os
|
|
297
|
-
|
|
298
|
-
model_file = os.path.expanduser('~/models/camera_traps/megadetector/md_v5.0.0/md_v5a.0.0.pt')
|
|
299
|
-
im_file = r"G:\temp\coyote\DSCF0043.JPG"
|
|
300
|
-
|
|
301
|
-
detector = PTDetector(model_file)
|
|
302
|
-
image = vis_utils.load_image(im_file)
|
|
303
|
-
|
|
304
|
-
res = detector.generate_detections_one_image(image, im_file, detection_threshold=0.00001)
|