megadetector 5.0.14__py3-none-any.whl → 5.0.16__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/data_management/importers/import_desert_lion_conservation_camera_traps.py +387 -0
- megadetector/data_management/lila/generate_lila_per_image_labels.py +3 -3
- megadetector/data_management/lila/test_lila_metadata_urls.py +2 -2
- megadetector/data_management/remove_exif.py +61 -36
- megadetector/data_management/yolo_to_coco.py +25 -6
- megadetector/detection/process_video.py +261 -128
- megadetector/detection/pytorch_detector.py +13 -11
- megadetector/detection/run_detector.py +9 -2
- megadetector/detection/run_detector_batch.py +14 -2
- megadetector/detection/run_inference_with_yolov5_val.py +58 -10
- megadetector/detection/tf_detector.py +8 -2
- megadetector/detection/video_utils.py +204 -16
- megadetector/postprocessing/md_to_coco.py +31 -9
- megadetector/postprocessing/postprocess_batch_results.py +19 -3
- megadetector/postprocessing/subset_json_detector_output.py +22 -12
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +3 -3
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +2 -1
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +1 -1
- megadetector/taxonomy_mapping/simple_image_download.py +5 -0
- megadetector/taxonomy_mapping/species_lookup.py +1 -1
- megadetector/utils/md_tests.py +362 -100
- megadetector/utils/path_utils.py +2 -2
- megadetector/utils/url_utils.py +7 -1
- megadetector/visualization/visualize_db.py +16 -0
- {megadetector-5.0.14.dist-info → megadetector-5.0.16.dist-info}/LICENSE +0 -0
- {megadetector-5.0.14.dist-info → megadetector-5.0.16.dist-info}/METADATA +2 -2
- {megadetector-5.0.14.dist-info → megadetector-5.0.16.dist-info}/RECORD +29 -28
- {megadetector-5.0.14.dist-info → megadetector-5.0.16.dist-info}/WHEEL +1 -1
- {megadetector-5.0.14.dist-info → megadetector-5.0.16.dist-info}/top_level.txt +0 -0
|
@@ -949,6 +949,13 @@ def process_batch_results(options):
|
|
|
949
949
|
f'negative, {n_positive} positive, {n_unknown} unknown, '
|
|
950
950
|
f'{n_ambiguous} ambiguous')
|
|
951
951
|
|
|
952
|
+
if n_positive == 0:
|
|
953
|
+
print('\n*** Warning: no positives found in ground truth, analysis won\'t be very meaningful ***\n')
|
|
954
|
+
if n_negative == 0:
|
|
955
|
+
print('\n*** Warning: no negatives found in ground truth, analysis won\'t be very meaningful ***\n')
|
|
956
|
+
if n_ambiguous > 0:
|
|
957
|
+
print('\n*** Warning: {} images with ambiguous positive/negative status found in ground truth ***\n'.format(
|
|
958
|
+
n_ambiguous))
|
|
952
959
|
|
|
953
960
|
##%% Load detection (and possibly classification) results
|
|
954
961
|
|
|
@@ -1095,25 +1102,34 @@ def process_batch_results(options):
|
|
|
1095
1102
|
|
|
1096
1103
|
##%% Detection evaluation: compute precision/recall
|
|
1097
1104
|
|
|
1098
|
-
# numpy array of
|
|
1105
|
+
# numpy array of maximum confidence values
|
|
1099
1106
|
p_detection = detections_df['max_detection_conf'].values
|
|
1100
|
-
|
|
1107
|
+
n_detection_values = len(p_detection)
|
|
1101
1108
|
|
|
1102
1109
|
# numpy array of bools (0.0/1.0), and -1 as null value
|
|
1103
|
-
gt_detections = np.zeros(
|
|
1110
|
+
gt_detections = np.zeros(n_detection_values, dtype=float)
|
|
1104
1111
|
|
|
1112
|
+
n_positive = 0
|
|
1113
|
+
n_negative = 0
|
|
1114
|
+
|
|
1105
1115
|
for i_detection, fn in enumerate(detector_files):
|
|
1116
|
+
|
|
1106
1117
|
image_id = ground_truth_indexed_db.filename_to_id[fn]
|
|
1107
1118
|
image = ground_truth_indexed_db.image_id_to_image[image_id]
|
|
1108
1119
|
detection_status = image['_detection_status']
|
|
1109
1120
|
|
|
1110
1121
|
if detection_status == DetectionStatus.DS_NEGATIVE:
|
|
1111
1122
|
gt_detections[i_detection] = 0.0
|
|
1123
|
+
n_negative += 1
|
|
1112
1124
|
elif detection_status == DetectionStatus.DS_POSITIVE:
|
|
1113
1125
|
gt_detections[i_detection] = 1.0
|
|
1126
|
+
n_positive += 1
|
|
1114
1127
|
else:
|
|
1115
1128
|
gt_detections[i_detection] = -1.0
|
|
1116
1129
|
|
|
1130
|
+
print('Of {} ground truth values, found {} positives and {} negatives'.format(
|
|
1131
|
+
len(detections_df),n_positive,n_negative))
|
|
1132
|
+
|
|
1117
1133
|
# Don't include ambiguous/unknown ground truth in precision/recall analysis
|
|
1118
1134
|
b_valid_ground_truth = gt_detections >= 0.0
|
|
1119
1135
|
|
|
@@ -124,7 +124,7 @@ class SubsetJsonDetectorOutputOptions:
|
|
|
124
124
|
self.remove_failed_images = False
|
|
125
125
|
|
|
126
126
|
#: Either a list of category IDs (as string-ints) (not names), or a dictionary mapping category *IDs*
|
|
127
|
-
#: (as string-ints) (not names) to thresholds. Removes
|
|
127
|
+
#: (as string-ints) (not names) to thresholds. Removes non-matching detections, does not
|
|
128
128
|
#: remove images. Not technically mutually exclusize with category_names_to_keep, but it's an esoteric
|
|
129
129
|
#: scenario indeed where you would want to specify both.
|
|
130
130
|
self.categories_to_keep = None
|
|
@@ -517,7 +517,7 @@ def subset_json_detector_output(input_filename, output_filename, options, data=N
|
|
|
517
517
|
else:
|
|
518
518
|
|
|
519
519
|
# Map images to unique folders
|
|
520
|
-
print('Finding unique folders')
|
|
520
|
+
print('Finding unique folders')
|
|
521
521
|
|
|
522
522
|
folders_to_images = {}
|
|
523
523
|
|
|
@@ -670,16 +670,26 @@ def main():
|
|
|
670
670
|
parser = argparse.ArgumentParser()
|
|
671
671
|
parser.add_argument('input_file', type=str, help='Input .json filename')
|
|
672
672
|
parser.add_argument('output_file', type=str, help='Output .json filename')
|
|
673
|
-
parser.add_argument('--query', type=str, default=None,
|
|
674
|
-
|
|
675
|
-
parser.add_argument('--
|
|
676
|
-
|
|
677
|
-
parser.add_argument('--
|
|
678
|
-
|
|
679
|
-
parser.add_argument('--
|
|
680
|
-
|
|
681
|
-
parser.add_argument('--
|
|
682
|
-
|
|
673
|
+
parser.add_argument('--query', type=str, default=None,
|
|
674
|
+
help='Query string to search for (omitting this matches all)')
|
|
675
|
+
parser.add_argument('--replacement', type=str, default=None,
|
|
676
|
+
help='Replace [query] with this')
|
|
677
|
+
parser.add_argument('--confidence_threshold', type=float, default=None,
|
|
678
|
+
help='Remove detections below this confidence level')
|
|
679
|
+
parser.add_argument('--split_folders', action='store_true',
|
|
680
|
+
help='Split .json files by leaf-node folder')
|
|
681
|
+
parser.add_argument('--split_folder_param', type=int,
|
|
682
|
+
help='Directory level count for n_from_bottom and n_from_top splitting')
|
|
683
|
+
parser.add_argument('--split_folder_mode', type=str,
|
|
684
|
+
help='Folder level to use for splitting ("top" or "bottom")')
|
|
685
|
+
parser.add_argument('--make_folder_relative', action='store_true',
|
|
686
|
+
help='Make image paths relative to their containing folder (only meaningful with split_folders)')
|
|
687
|
+
parser.add_argument('--overwrite_json_files', action='store_true',
|
|
688
|
+
help='Overwrite output files')
|
|
689
|
+
parser.add_argument('--copy_jsons_to_folders', action='store_true',
|
|
690
|
+
help='When using split_folders and make_folder_relative, copy jsons to their corresponding folders (relative to output_file)')
|
|
691
|
+
parser.add_argument('--create_folders', action='store_true',
|
|
692
|
+
help='When using copy_jsons_to_folders, create folders that don''t exist')
|
|
683
693
|
|
|
684
694
|
if len(sys.argv[1:]) == 0:
|
|
685
695
|
parser.print_help()
|
|
@@ -15,10 +15,10 @@ import json
|
|
|
15
15
|
# Created by get_lila_category_list.py
|
|
16
16
|
input_lila_category_list_file = os.path.expanduser('~/lila/lila_categories_list/lila_dataset_to_categories.json')
|
|
17
17
|
|
|
18
|
-
output_file = os.path.expanduser('~/lila/
|
|
18
|
+
output_file = os.path.expanduser('~/lila/lila_additions_2024.07.16.csv')
|
|
19
19
|
|
|
20
20
|
datasets_to_map = [
|
|
21
|
-
'
|
|
21
|
+
'Desert Lion Conservation Camera Traps'
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
|
|
@@ -133,7 +133,7 @@ if False:
|
|
|
133
133
|
# q = 'white-throated monkey'
|
|
134
134
|
# q = 'cingulata'
|
|
135
135
|
# q = 'notamacropus'
|
|
136
|
-
q = '
|
|
136
|
+
q = 'aves'
|
|
137
137
|
taxonomy_preference = 'inat'
|
|
138
138
|
m = get_preferred_taxonomic_match(q,taxonomy_preference)
|
|
139
139
|
# print(m.scientific_name); import clipboard; clipboard.copy(m.scientific_name)
|
|
@@ -24,7 +24,7 @@ if False:
|
|
|
24
24
|
release_taxonomy_file = os.path.expanduser('~/lila/lila-taxonomy-mapping_release.csv')
|
|
25
25
|
# import clipboard; clipboard.copy(release_taxonomy_file)
|
|
26
26
|
|
|
27
|
-
# Created by
|
|
27
|
+
# Created by get_lila_annotation_counts.py... contains counts for each category
|
|
28
28
|
lila_dataset_to_categories_file = os.path.expanduser('~/lila/lila_categories_list/lila_dataset_to_categories.json')
|
|
29
29
|
|
|
30
30
|
assert os.path.isfile(lila_dataset_to_categories_file)
|
|
@@ -140,3 +140,4 @@ if False:
|
|
|
140
140
|
|
|
141
141
|
print('Wrote final output to {}'.format(release_taxonomy_file))
|
|
142
142
|
|
|
143
|
+
# ...if False
|
|
@@ -16,7 +16,7 @@ import os
|
|
|
16
16
|
import pandas as pd
|
|
17
17
|
|
|
18
18
|
# lila_taxonomy_file = r"c:\git\agentmorrisprivate\lila-taxonomy\lila-taxonomy-mapping.csv"
|
|
19
|
-
lila_taxonomy_file = os.path.expanduser('~/lila/
|
|
19
|
+
lila_taxonomy_file = os.path.expanduser('~/lila/lila_additions_2024.07.16.csv')
|
|
20
20
|
|
|
21
21
|
preview_base = os.path.expanduser('~/lila/lila_taxonomy_preview')
|
|
22
22
|
os.makedirs(preview_base,exist_ok=True)
|
|
@@ -208,7 +208,7 @@ def initialize_taxonomy_lookup(force_init=False) -> None:
|
|
|
208
208
|
# Load GBIF taxonomy
|
|
209
209
|
gbif_taxonomy_file = os.path.join(taxonomy_download_dir, 'GBIF', 'Taxon.tsv')
|
|
210
210
|
print('Loading GBIF taxonomy from {}'.format(gbif_taxonomy_file))
|
|
211
|
-
gbif_taxonomy = pd.read_csv(gbif_taxonomy_file, sep='\t')
|
|
211
|
+
gbif_taxonomy = pd.read_csv(gbif_taxonomy_file, sep='\t', encoding='utf-8',on_bad_lines='warn')
|
|
212
212
|
gbif_taxonomy['scientificName'] = gbif_taxonomy['scientificName'].fillna('').str.strip()
|
|
213
213
|
gbif_taxonomy['canonicalName'] = gbif_taxonomy['canonicalName'].fillna('').str.strip()
|
|
214
214
|
|