megadetector 10.0.6__py3-none-any.whl → 10.0.8__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/cct_json_utils.py +16 -6
- megadetector/data_management/databases/subset_json_db.py +57 -2
- megadetector/detection/pytorch_detector.py +29 -15
- megadetector/detection/run_inference_with_yolov5_val.py +3 -1
- megadetector/detection/run_tiled_inference.py +5 -2
- megadetector/detection/video_utils.py +23 -7
- megadetector/postprocessing/classification_postprocessing.py +218 -69
- megadetector/postprocessing/convert_output_format.py +81 -87
- megadetector/postprocessing/subset_json_detector_output.py +3 -0
- megadetector/utils/directory_listing.py +19 -13
- megadetector/utils/path_utils.py +58 -8
- megadetector/utils/url_utils.py +91 -1
- megadetector/utils/wi_taxonomy_utils.py +44 -26
- megadetector/visualization/visualize_video_output.py +16 -6
- {megadetector-10.0.6.dist-info → megadetector-10.0.8.dist-info}/METADATA +134 -134
- {megadetector-10.0.6.dist-info → megadetector-10.0.8.dist-info}/RECORD +19 -19
- {megadetector-10.0.6.dist-info → megadetector-10.0.8.dist-info}/licenses/LICENSE +0 -0
- {megadetector-10.0.6.dist-info → megadetector-10.0.8.dist-info}/top_level.txt +0 -0
- {megadetector-10.0.6.dist-info → megadetector-10.0.8.dist-info}/WHEEL +0 -0
|
@@ -10,8 +10,6 @@ Functions related to working with the SpeciesNet / Wildlife Insights taxonomy.
|
|
|
10
10
|
|
|
11
11
|
import os
|
|
12
12
|
import json
|
|
13
|
-
import tempfile
|
|
14
|
-
import uuid
|
|
15
13
|
|
|
16
14
|
import pandas as pd
|
|
17
15
|
|
|
@@ -180,8 +178,10 @@ def taxonomy_level_index(s):
|
|
|
180
178
|
if len(tokens) == 7:
|
|
181
179
|
tokens = tokens[1:-1]
|
|
182
180
|
|
|
181
|
+
# Anything without a class is considered non-taxonomic
|
|
183
182
|
if len(tokens[0]) == 0:
|
|
184
183
|
return 0
|
|
184
|
+
|
|
185
185
|
# WI taxonomy strings start at class, so we'll never return 1 (kingdom) or 2 (phylum)
|
|
186
186
|
elif len(tokens[1]) == 0:
|
|
187
187
|
return 3
|
|
@@ -198,6 +198,22 @@ def taxonomy_level_index(s):
|
|
|
198
198
|
return 8
|
|
199
199
|
|
|
200
200
|
|
|
201
|
+
def is_taxonomic_prediction_string(s):
|
|
202
|
+
"""
|
|
203
|
+
Determines whether [s] is a classification string that has taxonomic properties; this
|
|
204
|
+
does not include, e.g., blanks/vehicles/no cv result. It also excludes "animal".
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
s (str): a five- or seven-token taxonomic string
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
bool: whether [s] is a taxonomic category
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
return (taxonomy_level_index(s) > 0)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
201
217
|
def get_kingdom(prediction_string):
|
|
202
218
|
"""
|
|
203
219
|
Return the kingdom field from a WI prediction string
|
|
@@ -381,11 +397,12 @@ def generate_whole_image_detections_for_classifications(classifications_json_fil
|
|
|
381
397
|
|
|
382
398
|
|
|
383
399
|
def generate_md_results_from_predictions_json(predictions_json_file,
|
|
384
|
-
md_results_file,
|
|
400
|
+
md_results_file=None,
|
|
385
401
|
base_folder=None,
|
|
386
402
|
max_decimals=5,
|
|
387
403
|
convert_human_to_person=True,
|
|
388
|
-
convert_homo_species_to_human=True
|
|
404
|
+
convert_homo_species_to_human=True,
|
|
405
|
+
verbose=False):
|
|
389
406
|
"""
|
|
390
407
|
Generate an MD-formatted .json file from a predictions.json file, generated by the
|
|
391
408
|
SpeciesNet ensemble. Typically, MD results files use relative paths, and predictions.json
|
|
@@ -406,7 +423,7 @@ def generate_md_results_from_predictions_json(predictions_json_file,
|
|
|
406
423
|
|
|
407
424
|
Args:
|
|
408
425
|
predictions_json_file (str): path to a predictions.json file, or a dict
|
|
409
|
-
md_results_file (str): path to which we should write an MD-formatted .json file
|
|
426
|
+
md_results_file (str, optional): path to which we should write an MD-formatted .json file
|
|
410
427
|
base_folder (str, optional): leading string to remove from each path in the
|
|
411
428
|
predictions.json file
|
|
412
429
|
max_decimals (int, optional): number of decimal places to which we should round
|
|
@@ -417,6 +434,10 @@ def generate_md_results_from_predictions_json(predictions_json_file,
|
|
|
417
434
|
convert_homo_species_to_human (bool, optional): the ensemble often rolls human predictions
|
|
418
435
|
up to "homo species", which isn't wrong, but looks odd. This forces these back to
|
|
419
436
|
"homo sapiens".
|
|
437
|
+
verbose (bool, optional): enable additional debug output
|
|
438
|
+
|
|
439
|
+
Returns:
|
|
440
|
+
dict: results in MD format
|
|
420
441
|
"""
|
|
421
442
|
|
|
422
443
|
# Read predictions file
|
|
@@ -540,7 +561,9 @@ def generate_md_results_from_predictions_json(predictions_json_file,
|
|
|
540
561
|
# but a non-blank prediction. For now, create a fake detection to handle this prediction.
|
|
541
562
|
if len(im_out['detections']) == 0:
|
|
542
563
|
|
|
543
|
-
|
|
564
|
+
if verbose:
|
|
565
|
+
print('Warning: creating fake detection for non-blank whole-image classification' + \
|
|
566
|
+
' in {}'.format(im_in['file']))
|
|
544
567
|
det_out = {}
|
|
545
568
|
all_unknown_detections.append(det_out)
|
|
546
569
|
|
|
@@ -622,12 +645,15 @@ def generate_md_results_from_predictions_json(predictions_json_file,
|
|
|
622
645
|
output_dict['classification_category_descriptions'] = classification_category_descriptions
|
|
623
646
|
output_dict['images'] = images_out
|
|
624
647
|
|
|
625
|
-
|
|
626
|
-
|
|
648
|
+
if md_results_file is not None:
|
|
649
|
+
with open(md_results_file,'w') as f:
|
|
650
|
+
json.dump(output_dict,f,indent=1)
|
|
627
651
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
652
|
+
validation_options = ValidateBatchResultsOptions()
|
|
653
|
+
validation_options.raise_errors = True
|
|
654
|
+
_ = validate_batch_results(md_results_file, options=validation_options)
|
|
655
|
+
|
|
656
|
+
return output_dict
|
|
631
657
|
|
|
632
658
|
# ...def generate_md_results_from_predictions_json(...)
|
|
633
659
|
|
|
@@ -867,24 +893,16 @@ def load_md_or_speciesnet_file(fn,verbose=True):
|
|
|
867
893
|
with open(fn,'r') as f:
|
|
868
894
|
detector_output = json.load(f)
|
|
869
895
|
|
|
870
|
-
#
|
|
896
|
+
# If this is a SpeicesNet file, convert to MD format
|
|
871
897
|
if 'predictions' in detector_output:
|
|
898
|
+
|
|
872
899
|
if verbose:
|
|
873
900
|
print('This appears to be a SpeciesNet output file, converting to MD format')
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
md_results_file=temp_results_file,
|
|
880
|
-
base_folder=None)
|
|
881
|
-
with open(temp_results_file,'r') as f:
|
|
882
|
-
detector_output = json.load(f)
|
|
883
|
-
try:
|
|
884
|
-
os.remove(temp_results_file)
|
|
885
|
-
except Exception:
|
|
886
|
-
if verbose:
|
|
887
|
-
print('Warning: error removing temporary .json {}'.format(temp_results_file))
|
|
901
|
+
detector_output = generate_md_results_from_predictions_json(predictions_json_file=fn,
|
|
902
|
+
md_results_file=None,
|
|
903
|
+
base_folder=None)
|
|
904
|
+
|
|
905
|
+
# ...if this is a SpeciesNet file
|
|
888
906
|
|
|
889
907
|
assert 'images' in detector_output, \
|
|
890
908
|
'Detector output file should be a json file with an "images" field.'
|
|
@@ -67,6 +67,10 @@ class VideoVisualizationOptions:
|
|
|
67
67
|
#: Skip frames before first and after last above-threshold detection
|
|
68
68
|
self.trim_to_detections = False
|
|
69
69
|
|
|
70
|
+
#: By default, output videos use the same extension as input videos,
|
|
71
|
+
#: use this to force a particular extension
|
|
72
|
+
self.output_extension = None
|
|
73
|
+
|
|
70
74
|
# ...class VideoVisualizationOptions
|
|
71
75
|
|
|
72
76
|
|
|
@@ -287,10 +291,16 @@ def _process_video(video_entry,
|
|
|
287
291
|
result['error'] = 'Video not found: {}'.format(input_video_path)
|
|
288
292
|
return result
|
|
289
293
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
output_fn_relative = video_entry['file']
|
|
295
|
+
|
|
296
|
+
if options.output_extension is not None:
|
|
297
|
+
ext = options.output_extension
|
|
298
|
+
if not ext.startswith('.'):
|
|
299
|
+
ext = '.' + ext
|
|
300
|
+
output_fn_relative = os.path.splitext(output_fn_relative)[0] + ext
|
|
301
|
+
|
|
302
|
+
output_fn_abs = os.path.join(out_dir, output_fn_relative)
|
|
303
|
+
os.makedirs(os.path.dirname(output_fn_abs), exist_ok=True)
|
|
294
304
|
|
|
295
305
|
# Get frames to process
|
|
296
306
|
frames_to_process = _get_frames_to_process(video_entry,
|
|
@@ -392,10 +402,10 @@ def _process_video(video_entry,
|
|
|
392
402
|
|
|
393
403
|
# Create VideoWriter
|
|
394
404
|
fourcc = cv2.VideoWriter_fourcc(*options.fourcc)
|
|
395
|
-
video_writer = cv2.VideoWriter(
|
|
405
|
+
video_writer = cv2.VideoWriter(output_fn_abs, fourcc, output_framerate, (width, height))
|
|
396
406
|
|
|
397
407
|
if not video_writer.isOpened():
|
|
398
|
-
result['error'] = 'Failed to open video writer for {}'.format(
|
|
408
|
+
result['error'] = 'Failed to open video writer for {}'.format(output_fn_abs)
|
|
399
409
|
return result
|
|
400
410
|
|
|
401
411
|
# Write frames
|
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: megadetector
|
|
3
|
-
Version: 10.0.
|
|
4
|
-
Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
|
|
5
|
-
Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
6
|
-
Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
7
|
-
License: MIT License
|
|
8
|
-
|
|
9
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
-
in the Software without restriction, including without limitation the rights
|
|
12
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
-
furnished to do so, subject to the following conditions:
|
|
15
|
-
|
|
16
|
-
The above copyright notice and this permission notice shall be included in all
|
|
17
|
-
copies or substantial portions of the Software.
|
|
18
|
-
|
|
19
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
-
SOFTWARE.
|
|
26
|
-
|
|
27
|
-
Project-URL: Homepage, https://github.com/agentmorris/MegaDetector
|
|
28
|
-
Project-URL: Documentation, https://megadetector.readthedocs.io
|
|
29
|
-
Project-URL: Bug Reports, https://github.com/agentmorris/MegaDetector/issues
|
|
30
|
-
Project-URL: Source, https://github.com/agentmorris/MegaDetector
|
|
31
|
-
Keywords: camera traps,conservation,wildlife,ai,megadetector
|
|
32
|
-
Classifier: Programming Language :: Python :: 3
|
|
33
|
-
Requires-Python: <3.14,>=3.9
|
|
34
|
-
Description-Content-Type: text/markdown
|
|
35
|
-
License-File: LICENSE
|
|
36
|
-
Requires-Dist: mkl==2024.0; sys_platform != "darwin"
|
|
37
|
-
Requires-Dist: numpy>=1.26.4
|
|
38
|
-
Requires-Dist: Pillow>=9.5
|
|
39
|
-
Requires-Dist: tqdm>=4.64.0
|
|
40
|
-
Requires-Dist: jsonpickle>=3.0.2
|
|
41
|
-
Requires-Dist: humanfriendly>=2.1
|
|
42
|
-
Requires-Dist: matplotlib>=3.8.0
|
|
43
|
-
Requires-Dist: opencv-python>=4.8.0
|
|
44
|
-
Requires-Dist: requests>=2.31.0
|
|
45
|
-
Requires-Dist: pyqtree>=1.0.0
|
|
46
|
-
Requires-Dist: scikit-learn>=1.3.1
|
|
47
|
-
Requires-Dist: pandas>=2.1.1
|
|
48
|
-
Requires-Dist: python-dateutil
|
|
49
|
-
Requires-Dist: send2trash
|
|
50
|
-
Requires-Dist: clipboard
|
|
51
|
-
Requires-Dist: dill
|
|
52
|
-
Requires-Dist: ruff
|
|
53
|
-
Requires-Dist: pytest
|
|
54
|
-
Requires-Dist: ultralytics-yolov5==0.1.1
|
|
55
|
-
Requires-Dist: yolov9pip==0.0.4
|
|
56
|
-
Dynamic: license-file
|
|
57
|
-
|
|
58
|
-
# MegaDetector
|
|
59
|
-
|
|
60
|
-
This package is a pip-installable version of the support/inference code for [MegaDetector](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector), an object detection model that helps conservation biologists spend less time doing boring things with camera trap images. Complete documentation for this Python package is available at [megadetector.readthedocs.io](https://megadetector.readthedocs.io).
|
|
61
|
-
|
|
62
|
-
If you aren't looking for the Python package specifically, and you just want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector).
|
|
63
|
-
|
|
64
|
-
If you don't want to run MegaDetector, and you just want to use the utilities in this package - postprocessing, manipulating large volumes of camera trap images, etc. - you may want to check out the [megadetector-utils](https://pypi.org/project/megadetector-utils/) package, which is identical to this one, but excludes all of the PyTorch/YOLO dependencies, and is thus approximately one zillion times smaller.
|
|
65
|
-
|
|
66
|
-
## Installation
|
|
67
|
-
|
|
68
|
-
Install with:
|
|
69
|
-
|
|
70
|
-
`pip install megadetector`
|
|
71
|
-
|
|
72
|
-
MegaDetector model weights aren't downloaded at the time you install the package, but they will be (optionally) automatically downloaded the first time you run the model.
|
|
73
|
-
|
|
74
|
-
## Package reference
|
|
75
|
-
|
|
76
|
-
See [megadetector.readthedocs.io](https://megadetector.readthedocs.io).
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
## Examples of things you can do with this package
|
|
80
|
-
|
|
81
|
-
### Run MegaDetector on one image and count the number of detections
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
from megadetector.utils import url_utils
|
|
85
|
-
from megadetector.visualization import visualization_utils as vis_utils
|
|
86
|
-
from megadetector.detection import run_detector
|
|
87
|
-
|
|
88
|
-
# This is the image at the bottom of this page, it has one animal in it
|
|
89
|
-
image_url = 'https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web.jpg'
|
|
90
|
-
temporary_filename = url_utils.download_url(image_url)
|
|
91
|
-
|
|
92
|
-
image = vis_utils.load_image(temporary_filename)
|
|
93
|
-
|
|
94
|
-
# This will automatically download MDv5a; you can also specify a filename.
|
|
95
|
-
model = run_detector.load_detector('MDV5A')
|
|
96
|
-
|
|
97
|
-
result = model.generate_detections_one_image(image)
|
|
98
|
-
|
|
99
|
-
detections_above_threshold = [d for d in result['detections'] if d['conf'] > 0.2]
|
|
100
|
-
print('Found {} detections above threshold'.format(len(detections_above_threshold)))
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Run MegaDetector on a folder of images
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
from megadetector.detection.run_detector_batch import \
|
|
107
|
-
load_and_run_detector_batch, write_results_to_file
|
|
108
|
-
from megadetector.utils import path_utils
|
|
109
|
-
import os
|
|
110
|
-
|
|
111
|
-
# Pick a folder to run MD on recursively, and an output file
|
|
112
|
-
image_folder = os.path.expanduser('~/megadetector_test_images')
|
|
113
|
-
output_file = os.path.expanduser('~/megadetector_output_test.json')
|
|
114
|
-
|
|
115
|
-
# Recursively find images
|
|
116
|
-
image_file_names = path_utils.find_images(image_folder,recursive=True)
|
|
117
|
-
|
|
118
|
-
# This will automatically download MDv5a; you can also specify a filename.
|
|
119
|
-
results = load_and_run_detector_batch('MDV5A', image_file_names)
|
|
120
|
-
|
|
121
|
-
# Write results to a format that Timelapse and other downstream tools like.
|
|
122
|
-
write_results_to_file(results,
|
|
123
|
-
output_file,
|
|
124
|
-
relative_path_base=image_folder,
|
|
125
|
-
detector_file=detector_filename)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## Contact
|
|
129
|
-
|
|
130
|
-
Contact <a href="cameratraps@lila.science">cameratraps@lila.science</a> with questions.
|
|
131
|
-
|
|
132
|
-
## Gratuitous animal picture
|
|
133
|
-
|
|
134
|
-
<img src="https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web_detections.jpg"><br/>Image credit University of Minnesota, from the [Orinoquía Camera Traps](http://lila.science/datasets/orinoquia-camera-traps/) data set.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: megadetector
|
|
3
|
+
Version: 10.0.8
|
|
4
|
+
Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
|
|
5
|
+
Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
6
|
+
Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
|
26
|
+
|
|
27
|
+
Project-URL: Homepage, https://github.com/agentmorris/MegaDetector
|
|
28
|
+
Project-URL: Documentation, https://megadetector.readthedocs.io
|
|
29
|
+
Project-URL: Bug Reports, https://github.com/agentmorris/MegaDetector/issues
|
|
30
|
+
Project-URL: Source, https://github.com/agentmorris/MegaDetector
|
|
31
|
+
Keywords: camera traps,conservation,wildlife,ai,megadetector
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Requires-Python: <3.14,>=3.9
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Requires-Dist: mkl==2024.0; sys_platform != "darwin"
|
|
37
|
+
Requires-Dist: numpy>=1.26.4
|
|
38
|
+
Requires-Dist: Pillow>=9.5
|
|
39
|
+
Requires-Dist: tqdm>=4.64.0
|
|
40
|
+
Requires-Dist: jsonpickle>=3.0.2
|
|
41
|
+
Requires-Dist: humanfriendly>=2.1
|
|
42
|
+
Requires-Dist: matplotlib>=3.8.0
|
|
43
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
44
|
+
Requires-Dist: requests>=2.31.0
|
|
45
|
+
Requires-Dist: pyqtree>=1.0.0
|
|
46
|
+
Requires-Dist: scikit-learn>=1.3.1
|
|
47
|
+
Requires-Dist: pandas>=2.1.1
|
|
48
|
+
Requires-Dist: python-dateutil
|
|
49
|
+
Requires-Dist: send2trash
|
|
50
|
+
Requires-Dist: clipboard
|
|
51
|
+
Requires-Dist: dill
|
|
52
|
+
Requires-Dist: ruff
|
|
53
|
+
Requires-Dist: pytest
|
|
54
|
+
Requires-Dist: ultralytics-yolov5==0.1.1
|
|
55
|
+
Requires-Dist: yolov9pip==0.0.4
|
|
56
|
+
Dynamic: license-file
|
|
57
|
+
|
|
58
|
+
# MegaDetector
|
|
59
|
+
|
|
60
|
+
This package is a pip-installable version of the support/inference code for [MegaDetector](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector), an object detection model that helps conservation biologists spend less time doing boring things with camera trap images. Complete documentation for this Python package is available at [megadetector.readthedocs.io](https://megadetector.readthedocs.io).
|
|
61
|
+
|
|
62
|
+
If you aren't looking for the Python package specifically, and you just want to learn more about what MegaDetector is all about, head over to the [MegaDetector repo](https://github.com/agentmorris/MegaDetector/?tab=readme-ov-file#megadetector).
|
|
63
|
+
|
|
64
|
+
If you don't want to run MegaDetector, and you just want to use the utilities in this package - postprocessing, manipulating large volumes of camera trap images, etc. - you may want to check out the [megadetector-utils](https://pypi.org/project/megadetector-utils/) package, which is identical to this one, but excludes all of the PyTorch/YOLO dependencies, and is thus approximately one zillion times smaller.
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
Install with:
|
|
69
|
+
|
|
70
|
+
`pip install megadetector`
|
|
71
|
+
|
|
72
|
+
MegaDetector model weights aren't downloaded at the time you install the package, but they will be (optionally) automatically downloaded the first time you run the model.
|
|
73
|
+
|
|
74
|
+
## Package reference
|
|
75
|
+
|
|
76
|
+
See [megadetector.readthedocs.io](https://megadetector.readthedocs.io).
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Examples of things you can do with this package
|
|
80
|
+
|
|
81
|
+
### Run MegaDetector on one image and count the number of detections
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
from megadetector.utils import url_utils
|
|
85
|
+
from megadetector.visualization import visualization_utils as vis_utils
|
|
86
|
+
from megadetector.detection import run_detector
|
|
87
|
+
|
|
88
|
+
# This is the image at the bottom of this page, it has one animal in it
|
|
89
|
+
image_url = 'https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web.jpg'
|
|
90
|
+
temporary_filename = url_utils.download_url(image_url)
|
|
91
|
+
|
|
92
|
+
image = vis_utils.load_image(temporary_filename)
|
|
93
|
+
|
|
94
|
+
# This will automatically download MDv5a; you can also specify a filename.
|
|
95
|
+
model = run_detector.load_detector('MDV5A')
|
|
96
|
+
|
|
97
|
+
result = model.generate_detections_one_image(image)
|
|
98
|
+
|
|
99
|
+
detections_above_threshold = [d for d in result['detections'] if d['conf'] > 0.2]
|
|
100
|
+
print('Found {} detections above threshold'.format(len(detections_above_threshold)))
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Run MegaDetector on a folder of images
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
from megadetector.detection.run_detector_batch import \
|
|
107
|
+
load_and_run_detector_batch, write_results_to_file
|
|
108
|
+
from megadetector.utils import path_utils
|
|
109
|
+
import os
|
|
110
|
+
|
|
111
|
+
# Pick a folder to run MD on recursively, and an output file
|
|
112
|
+
image_folder = os.path.expanduser('~/megadetector_test_images')
|
|
113
|
+
output_file = os.path.expanduser('~/megadetector_output_test.json')
|
|
114
|
+
|
|
115
|
+
# Recursively find images
|
|
116
|
+
image_file_names = path_utils.find_images(image_folder,recursive=True)
|
|
117
|
+
|
|
118
|
+
# This will automatically download MDv5a; you can also specify a filename.
|
|
119
|
+
results = load_and_run_detector_batch('MDV5A', image_file_names)
|
|
120
|
+
|
|
121
|
+
# Write results to a format that Timelapse and other downstream tools like.
|
|
122
|
+
write_results_to_file(results,
|
|
123
|
+
output_file,
|
|
124
|
+
relative_path_base=image_folder,
|
|
125
|
+
detector_file=detector_filename)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Contact
|
|
129
|
+
|
|
130
|
+
Contact <a href="cameratraps@lila.science">cameratraps@lila.science</a> with questions.
|
|
131
|
+
|
|
132
|
+
## Gratuitous animal picture
|
|
133
|
+
|
|
134
|
+
<img src="https://github.com/agentmorris/MegaDetector/raw/main/images/orinoquia-thumb-web_detections.jpg"><br/>Image credit University of Minnesota, from the [Orinoquía Camera Traps](http://lila.science/datasets/orinoquia-camera-traps/) data set.
|
|
@@ -32,7 +32,7 @@ megadetector/classification/efficientnet/utils.py,sha256=76SQdh0zK7CFcwTW4kiechC
|
|
|
32
32
|
megadetector/data_management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
33
33
|
megadetector/data_management/animl_to_md.py,sha256=Z6PDJxeM_5dMZJBM3j0mxDPW2_1bNkXx0M3_qq42_Ig,4416
|
|
34
34
|
megadetector/data_management/camtrap_dp_to_coco.py,sha256=HoCGMzZTEvnudnAjbOr-mCizXHmc8mMNSUChy_Q9PkI,9673
|
|
35
|
-
megadetector/data_management/cct_json_utils.py,sha256=
|
|
35
|
+
megadetector/data_management/cct_json_utils.py,sha256=Azyuwok6-g5YGVAdBzv3-eJIlplXCoTcjGWu6zy9bQ0,19917
|
|
36
36
|
megadetector/data_management/cct_to_md.py,sha256=e1fYevSz0m65n5H16uB6uwzNiXiwxjdB2ka5p68R4d0,5120
|
|
37
37
|
megadetector/data_management/cct_to_wi.py,sha256=wcBOmurXY5I-hiqV6SmRSGUAeYaKHEU1LgCZjqVmCyw,9561
|
|
38
38
|
megadetector/data_management/coco_to_labelme.py,sha256=uYJ60XoZfHUEfLzj-EjLyeNM590skNnMp-IThWwNISo,8683
|
|
@@ -59,7 +59,7 @@ megadetector/data_management/databases/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
|
|
|
59
59
|
megadetector/data_management/databases/add_width_and_height_to_db.py,sha256=EYfFGPkXyFz6ZGQfXjCK3pNXLBg0hu73wiACdEEB0E0,2964
|
|
60
60
|
megadetector/data_management/databases/combine_coco_camera_traps_files.py,sha256=Au7akR2KZHm_l8-MGGRGf0CQy1az_JVgZW5Yz1_XQeQ,6609
|
|
61
61
|
megadetector/data_management/databases/integrity_check_json_db.py,sha256=kxGCHpBADXT_LHVLUENGvmby-orvVYIsK6fdgqhABBI,17386
|
|
62
|
-
megadetector/data_management/databases/subset_json_db.py,sha256=
|
|
62
|
+
megadetector/data_management/databases/subset_json_db.py,sha256=AQF-12vnZJ73JrWvjUd2ME666MmQDiCOvO0e7zGjPpg,6243
|
|
63
63
|
megadetector/data_management/lila/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
64
64
|
megadetector/data_management/lila/create_lila_blank_set.py,sha256=tApCL4XN1Vzl6YvcdI6SY4TZbHeCyHLzNYweFfX0sy0,19490
|
|
65
65
|
megadetector/data_management/lila/create_lila_test_set.py,sha256=UWJPKrwNW-UVeGrMUrFvmIt2UHVyuFiPzRFKkbEbk5A,5014
|
|
@@ -73,21 +73,21 @@ megadetector/data_management/lila/test_lila_metadata_urls.py,sha256=ThU78Ks5V3rF
|
|
|
73
73
|
megadetector/detection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
74
|
megadetector/detection/change_detection.py,sha256=Ne3GajbH_0KPBU8ruHp4Rkr0uKd5oKAMQ3CQTRKRHgQ,28659
|
|
75
75
|
megadetector/detection/process_video.py,sha256=kuQHrpOC3LQo9ecqJPpzkds9fZVnoLmrfJw_yh-oxi8,17890
|
|
76
|
-
megadetector/detection/pytorch_detector.py,sha256=
|
|
76
|
+
megadetector/detection/pytorch_detector.py,sha256=4Ix6AOBciMbn5zFHXe4hgb5tXGOup57ju3z8gtsin3s,60567
|
|
77
77
|
megadetector/detection/run_detector.py,sha256=TTX29zxDN_O7ja61sOmMIVewUz3yRvKg1D1AAYhVEkc,46851
|
|
78
78
|
megadetector/detection/run_detector_batch.py,sha256=aZgiywL6arrdQ_l3jzlHctlccqL537lwVStjhi1hIWw,89823
|
|
79
|
-
megadetector/detection/run_inference_with_yolov5_val.py,sha256=
|
|
79
|
+
megadetector/detection/run_inference_with_yolov5_val.py,sha256=dJXh3BwKOQQ4OA-Mq_heEb7AfBAk7qKUAagnIGuFtaU,53689
|
|
80
80
|
megadetector/detection/run_md_and_speciesnet.py,sha256=Dp_SpJZp0pX9jzFtxM6zPCyBNq49uyQpMDAdNDLVorM,50280
|
|
81
|
-
megadetector/detection/run_tiled_inference.py,sha256=
|
|
81
|
+
megadetector/detection/run_tiled_inference.py,sha256=hVpR-URC67e6Ht-cy_EgIrJ4GFina29H_lBXOE3bzwM,39435
|
|
82
82
|
megadetector/detection/tf_detector.py,sha256=3b2MiqgMw8KBDzHQliUSDXWrmKpa9iZnfe6EgYpMcYo,8398
|
|
83
|
-
megadetector/detection/video_utils.py,sha256=
|
|
83
|
+
megadetector/detection/video_utils.py,sha256=M7yje6XeOnR_QwDyuG1o6bwTKvRysoA2NiOK2MSi98E,53943
|
|
84
84
|
megadetector/postprocessing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
85
85
|
megadetector/postprocessing/add_max_conf.py,sha256=9MYtsH2mwkiaZb7Qcor5J_HskfAj7d9srp8G_Qldpk0,1722
|
|
86
86
|
megadetector/postprocessing/categorize_detections_by_size.py,sha256=DpZpRNFlyeOfWuOc6ICuENgIWDCEtiErJ_frBZp9lYM,5382
|
|
87
|
-
megadetector/postprocessing/classification_postprocessing.py,sha256=
|
|
87
|
+
megadetector/postprocessing/classification_postprocessing.py,sha256=OoPVr34vXyLykB42SplcSKo9cj7dgf8Yju_DCDhd6_k,68574
|
|
88
88
|
megadetector/postprocessing/combine_batch_outputs.py,sha256=BEP8cVa0sMIPg7tkWQc_8vOEPnbmWjOsQdVJHe61uz8,8468
|
|
89
89
|
megadetector/postprocessing/compare_batch_results.py,sha256=RDlKLwea76rOWiDneSJUj6P_oMBMnD2BY4inoxLqQiw,84258
|
|
90
|
-
megadetector/postprocessing/convert_output_format.py,sha256=
|
|
90
|
+
megadetector/postprocessing/convert_output_format.py,sha256=3KLO6NqddofgIEYjV8_iZIf0iXaplFN2AroUq5i4R7k,14472
|
|
91
91
|
megadetector/postprocessing/create_crop_folder.py,sha256=T37HnvBEakikXY3n3Bgk5boFo_0-Z5aKnkEWXv-Ki4s,23166
|
|
92
92
|
megadetector/postprocessing/detector_calibration.py,sha256=UFjJ8D6tMghatLRj3CyrtJ7vrPIJkULMNsYMIj98j2M,20495
|
|
93
93
|
megadetector/postprocessing/generate_csv_report.py,sha256=KIGT8zFZev-cl4YOCq2BqnodBWsZG-7CZaWuep_211U,19169
|
|
@@ -100,7 +100,7 @@ megadetector/postprocessing/postprocess_batch_results.py,sha256=VJyXx8I6KZgefrLN
|
|
|
100
100
|
megadetector/postprocessing/remap_detection_categories.py,sha256=BE6Ce-PGBEx1FyG3XwbYp2D5sh5xUlVf6fonaMuPMAg,7927
|
|
101
101
|
megadetector/postprocessing/render_detection_confusion_matrix.py,sha256=oNvDTh5td5ynELNnhz4XaLP2HiwLuojkJlob15TpgcY,26365
|
|
102
102
|
megadetector/postprocessing/separate_detections_into_folders.py,sha256=Yvpkl_MsWbGoo4zvQHrXHkATRJaYdYligItfg9bvuV8,32262
|
|
103
|
-
megadetector/postprocessing/subset_json_detector_output.py,sha256=
|
|
103
|
+
megadetector/postprocessing/subset_json_detector_output.py,sha256=R6CtSMcriXq50EHawXWC5pHZ-vtJFSKqjeleGKiouDY,32325
|
|
104
104
|
megadetector/postprocessing/top_folders_to_bottom.py,sha256=zYrqMHjUZG8urh2CYphfs91ZQ620uqe-TL8jVYy8KVw,6049
|
|
105
105
|
megadetector/postprocessing/validate_batch_results.py,sha256=9nr7LeKMdki9Y821ag2bZFQCxuq0OqINDH7cPXyVcY8,12059
|
|
106
106
|
megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py,sha256=XgVeyga8iSC01MAjXxb2rn-CgJTYHqC_gfxxEoSn4aw,9420
|
|
@@ -121,17 +121,17 @@ megadetector/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
|
121
121
|
megadetector/tests/test_nms_synthetic.py,sha256=oY6xmT1sLSSN7weQJ8TPTaZgAiSiZ6s43EffUhwLWIw,14707
|
|
122
122
|
megadetector/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
123
123
|
megadetector/utils/ct_utils.py,sha256=IiZV8dWtJamveINv_joATMgMPHeDkZ8l82jDEQcLgQg,60502
|
|
124
|
-
megadetector/utils/directory_listing.py,sha256=
|
|
124
|
+
megadetector/utils/directory_listing.py,sha256=0-VMuQWo6rETIKERqfX6Zn7pRp_GJ4JiFiWvsw9PQcU,6500
|
|
125
125
|
megadetector/utils/extract_frames_from_video.py,sha256=vjSVgxtb5z2syHCVYWc2KdNUpc-O6yY8nkbj_wqsIvY,12255
|
|
126
126
|
megadetector/utils/gpu_test.py,sha256=5zUfAVeSjH8I08eCqayFmMxL-0mix8SjJJTe5ORABvU,3544
|
|
127
127
|
megadetector/utils/md_tests.py,sha256=Iup4KjyIpLUpZ4TzzwEyGK61rg6aH7NrEQsdQ-ov51I,80300
|
|
128
|
-
megadetector/utils/path_utils.py,sha256=
|
|
128
|
+
megadetector/utils/path_utils.py,sha256=tV8eh77m_uS8YYpOQZO8GUKR6l5sZrSSIkApqgi_DmY,101030
|
|
129
129
|
megadetector/utils/process_utils.py,sha256=gQcpH9WYvGPUs0FhtJ5_Xvl6JsvoGz8_mnDQk0PbTRM,5673
|
|
130
130
|
megadetector/utils/split_locations_into_train_val.py,sha256=fd_6pj1aWY6hybwaXvBn9kBcOHjI90U-OsTmEAGpeu8,10297
|
|
131
131
|
megadetector/utils/string_utils.py,sha256=r2Maw3zbzk3EyaZcNkdqr96yP_8m4ey6v0WxlemEY9U,6155
|
|
132
|
-
megadetector/utils/url_utils.py,sha256=
|
|
132
|
+
megadetector/utils/url_utils.py,sha256=PzqN-VquAZFBRin2ZaYi5U2WCsMYSwvM0X-NN45Fdh4,28448
|
|
133
133
|
megadetector/utils/wi_platform_utils.py,sha256=8CGpiox_aL6RVZKfJqPVwpW4_6Cjku0HIajJPcmeNpE,32019
|
|
134
|
-
megadetector/utils/wi_taxonomy_utils.py,sha256=
|
|
134
|
+
megadetector/utils/wi_taxonomy_utils.py,sha256=o4AvY5gZXfk69pPckdGxgIPhqsH2-hJQucavSRsUnoc,66513
|
|
135
135
|
megadetector/utils/write_html_image_list.py,sha256=6Tbe5wyUxoBYJgH9yVrxxKCeWF2BVre_wQMEOQJ-ZIU,9068
|
|
136
136
|
megadetector/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
137
137
|
megadetector/visualization/plot_utils.py,sha256=uDDlOhdaJ3V8sGj2kS9b0cgszKc8WCq2_ofl6TW_XUs,10727
|
|
@@ -139,9 +139,9 @@ megadetector/visualization/render_images_with_thumbnails.py,sha256=-XX4PG4wnrFjF
|
|
|
139
139
|
megadetector/visualization/visualization_utils.py,sha256=E5uvysS3F1S_yiPFxZty3U2f6cjuE8zG6XWggYOu-5o,75921
|
|
140
140
|
megadetector/visualization/visualize_db.py,sha256=8YDWSR0eMehXYdPtak9z8UUw35xV7hu-0eCuzgSLjWc,25558
|
|
141
141
|
megadetector/visualization/visualize_detector_output.py,sha256=HpWh7ugwo51YBHsFi40iAp9G-uRAMMjgsm8H_uBolBs,20295
|
|
142
|
-
megadetector/visualization/visualize_video_output.py,sha256=
|
|
143
|
-
megadetector-10.0.
|
|
144
|
-
megadetector-10.0.
|
|
145
|
-
megadetector-10.0.
|
|
146
|
-
megadetector-10.0.
|
|
147
|
-
megadetector-10.0.
|
|
142
|
+
megadetector/visualization/visualize_video_output.py,sha256=ibMGB5ynMwNXmaMlY8h8tURb-Lyvuxs1EB08x_jvev0,20606
|
|
143
|
+
megadetector-10.0.8.dist-info/licenses/LICENSE,sha256=RMa3qq-7Cyk7DdtqRj_bP1oInGFgjyHn9-PZ3PcrqIs,1100
|
|
144
|
+
megadetector-10.0.8.dist-info/METADATA,sha256=eMFedi5m5t_vYsJzAQsf7Q2Z9mHASAqEOuJjiQVWgZE,6486
|
|
145
|
+
megadetector-10.0.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
146
|
+
megadetector-10.0.8.dist-info/top_level.txt,sha256=wf9DXa8EwiOSZ4G5IPjakSxBPxTDjhYYnqWRfR-zS4M,13
|
|
147
|
+
megadetector-10.0.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|