megadetector 10.0.13__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/__init__.py +0 -0
- megadetector/api/__init__.py +0 -0
- megadetector/api/batch_processing/integration/digiKam/setup.py +6 -0
- megadetector/api/batch_processing/integration/digiKam/xmp_integration.py +465 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/config_template.py +5 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/push_annotations_to_emammal.py +125 -0
- megadetector/api/batch_processing/integration/eMammal/test_scripts/select_images_for_testing.py +55 -0
- megadetector/classification/__init__.py +0 -0
- megadetector/classification/aggregate_classifier_probs.py +108 -0
- megadetector/classification/analyze_failed_images.py +227 -0
- megadetector/classification/cache_batchapi_outputs.py +198 -0
- megadetector/classification/create_classification_dataset.py +626 -0
- megadetector/classification/crop_detections.py +516 -0
- megadetector/classification/csv_to_json.py +226 -0
- megadetector/classification/detect_and_crop.py +853 -0
- megadetector/classification/efficientnet/__init__.py +9 -0
- megadetector/classification/efficientnet/model.py +415 -0
- megadetector/classification/efficientnet/utils.py +608 -0
- megadetector/classification/evaluate_model.py +520 -0
- megadetector/classification/identify_mislabeled_candidates.py +152 -0
- megadetector/classification/json_to_azcopy_list.py +63 -0
- megadetector/classification/json_validator.py +696 -0
- megadetector/classification/map_classification_categories.py +276 -0
- megadetector/classification/merge_classification_detection_output.py +509 -0
- megadetector/classification/prepare_classification_script.py +194 -0
- megadetector/classification/prepare_classification_script_mc.py +228 -0
- megadetector/classification/run_classifier.py +287 -0
- megadetector/classification/save_mislabeled.py +110 -0
- megadetector/classification/train_classifier.py +827 -0
- megadetector/classification/train_classifier_tf.py +725 -0
- megadetector/classification/train_utils.py +323 -0
- megadetector/data_management/__init__.py +0 -0
- megadetector/data_management/animl_to_md.py +161 -0
- megadetector/data_management/annotations/__init__.py +0 -0
- megadetector/data_management/annotations/annotation_constants.py +33 -0
- megadetector/data_management/camtrap_dp_to_coco.py +270 -0
- megadetector/data_management/cct_json_utils.py +566 -0
- megadetector/data_management/cct_to_md.py +184 -0
- megadetector/data_management/cct_to_wi.py +293 -0
- megadetector/data_management/coco_to_labelme.py +284 -0
- megadetector/data_management/coco_to_yolo.py +702 -0
- megadetector/data_management/databases/__init__.py +0 -0
- megadetector/data_management/databases/add_width_and_height_to_db.py +107 -0
- megadetector/data_management/databases/combine_coco_camera_traps_files.py +210 -0
- megadetector/data_management/databases/integrity_check_json_db.py +528 -0
- megadetector/data_management/databases/subset_json_db.py +195 -0
- megadetector/data_management/generate_crops_from_cct.py +200 -0
- megadetector/data_management/get_image_sizes.py +164 -0
- megadetector/data_management/labelme_to_coco.py +559 -0
- megadetector/data_management/labelme_to_yolo.py +349 -0
- megadetector/data_management/lila/__init__.py +0 -0
- megadetector/data_management/lila/create_lila_blank_set.py +556 -0
- megadetector/data_management/lila/create_lila_test_set.py +187 -0
- megadetector/data_management/lila/create_links_to_md_results_files.py +106 -0
- megadetector/data_management/lila/download_lila_subset.py +182 -0
- megadetector/data_management/lila/generate_lila_per_image_labels.py +777 -0
- megadetector/data_management/lila/get_lila_annotation_counts.py +174 -0
- megadetector/data_management/lila/get_lila_image_counts.py +112 -0
- megadetector/data_management/lila/lila_common.py +319 -0
- megadetector/data_management/lila/test_lila_metadata_urls.py +164 -0
- megadetector/data_management/mewc_to_md.py +344 -0
- megadetector/data_management/ocr_tools.py +873 -0
- megadetector/data_management/read_exif.py +964 -0
- megadetector/data_management/remap_coco_categories.py +195 -0
- megadetector/data_management/remove_exif.py +156 -0
- megadetector/data_management/rename_images.py +194 -0
- megadetector/data_management/resize_coco_dataset.py +663 -0
- megadetector/data_management/speciesnet_to_md.py +41 -0
- megadetector/data_management/wi_download_csv_to_coco.py +247 -0
- megadetector/data_management/yolo_output_to_md_output.py +594 -0
- megadetector/data_management/yolo_to_coco.py +876 -0
- megadetector/data_management/zamba_to_md.py +188 -0
- megadetector/detection/__init__.py +0 -0
- megadetector/detection/change_detection.py +840 -0
- megadetector/detection/process_video.py +479 -0
- megadetector/detection/pytorch_detector.py +1451 -0
- megadetector/detection/run_detector.py +1267 -0
- megadetector/detection/run_detector_batch.py +2159 -0
- megadetector/detection/run_inference_with_yolov5_val.py +1314 -0
- megadetector/detection/run_md_and_speciesnet.py +1494 -0
- megadetector/detection/run_tiled_inference.py +1038 -0
- megadetector/detection/tf_detector.py +209 -0
- megadetector/detection/video_utils.py +1379 -0
- megadetector/postprocessing/__init__.py +0 -0
- megadetector/postprocessing/add_max_conf.py +72 -0
- megadetector/postprocessing/categorize_detections_by_size.py +166 -0
- megadetector/postprocessing/classification_postprocessing.py +1752 -0
- megadetector/postprocessing/combine_batch_outputs.py +249 -0
- megadetector/postprocessing/compare_batch_results.py +2110 -0
- megadetector/postprocessing/convert_output_format.py +403 -0
- megadetector/postprocessing/create_crop_folder.py +629 -0
- megadetector/postprocessing/detector_calibration.py +570 -0
- megadetector/postprocessing/generate_csv_report.py +522 -0
- megadetector/postprocessing/load_api_results.py +223 -0
- megadetector/postprocessing/md_to_coco.py +428 -0
- megadetector/postprocessing/md_to_labelme.py +351 -0
- megadetector/postprocessing/md_to_wi.py +41 -0
- megadetector/postprocessing/merge_detections.py +392 -0
- megadetector/postprocessing/postprocess_batch_results.py +2077 -0
- megadetector/postprocessing/remap_detection_categories.py +226 -0
- megadetector/postprocessing/render_detection_confusion_matrix.py +677 -0
- megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py +206 -0
- megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +82 -0
- megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py +1665 -0
- megadetector/postprocessing/separate_detections_into_folders.py +795 -0
- megadetector/postprocessing/subset_json_detector_output.py +964 -0
- megadetector/postprocessing/top_folders_to_bottom.py +238 -0
- megadetector/postprocessing/validate_batch_results.py +332 -0
- megadetector/taxonomy_mapping/__init__.py +0 -0
- megadetector/taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +491 -0
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +213 -0
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +165 -0
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +543 -0
- megadetector/taxonomy_mapping/retrieve_sample_image.py +71 -0
- megadetector/taxonomy_mapping/simple_image_download.py +224 -0
- megadetector/taxonomy_mapping/species_lookup.py +1008 -0
- megadetector/taxonomy_mapping/taxonomy_csv_checker.py +159 -0
- megadetector/taxonomy_mapping/taxonomy_graph.py +346 -0
- megadetector/taxonomy_mapping/validate_lila_category_mappings.py +83 -0
- megadetector/tests/__init__.py +0 -0
- megadetector/tests/test_nms_synthetic.py +335 -0
- megadetector/utils/__init__.py +0 -0
- megadetector/utils/ct_utils.py +1857 -0
- megadetector/utils/directory_listing.py +199 -0
- megadetector/utils/extract_frames_from_video.py +307 -0
- megadetector/utils/gpu_test.py +125 -0
- megadetector/utils/md_tests.py +2072 -0
- megadetector/utils/path_utils.py +2832 -0
- megadetector/utils/process_utils.py +172 -0
- megadetector/utils/split_locations_into_train_val.py +237 -0
- megadetector/utils/string_utils.py +234 -0
- megadetector/utils/url_utils.py +825 -0
- megadetector/utils/wi_platform_utils.py +968 -0
- megadetector/utils/wi_taxonomy_utils.py +1759 -0
- megadetector/utils/write_html_image_list.py +239 -0
- megadetector/visualization/__init__.py +0 -0
- megadetector/visualization/plot_utils.py +309 -0
- megadetector/visualization/render_images_with_thumbnails.py +243 -0
- megadetector/visualization/visualization_utils.py +1940 -0
- megadetector/visualization/visualize_db.py +630 -0
- megadetector/visualization/visualize_detector_output.py +479 -0
- megadetector/visualization/visualize_video_output.py +705 -0
- megadetector-10.0.13.dist-info/METADATA +134 -0
- megadetector-10.0.13.dist-info/RECORD +147 -0
- megadetector-10.0.13.dist-info/WHEEL +5 -0
- megadetector-10.0.13.dist-info/licenses/LICENSE +19 -0
- megadetector-10.0.13.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
retrieve_sample_image.py
|
|
4
|
+
|
|
5
|
+
Downloader that retrieves images from Google images, used for verifying taxonomy
|
|
6
|
+
lookups and looking for egregious mismappings (e.g., "snake" being mapped to a fish called
|
|
7
|
+
"snake").
|
|
8
|
+
|
|
9
|
+
Simple wrapper around simple_image_download, but I've had to swap in and out the underlying
|
|
10
|
+
downloader a few times.
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
#%% Imports and environment
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
|
|
18
|
+
output_folder = os.path.expanduser('~/tmp/image-download-test')
|
|
19
|
+
os.makedirs(output_folder,exist_ok=True)
|
|
20
|
+
|
|
21
|
+
method = 'simple_image_download' # 'google_images_download'
|
|
22
|
+
|
|
23
|
+
if method == 'simple_image_download':
|
|
24
|
+
|
|
25
|
+
from megadetector.taxonomy_mapping import simple_image_download
|
|
26
|
+
google_image_downloader = simple_image_download.Downloader()
|
|
27
|
+
google_image_downloader.directory = output_folder
|
|
28
|
+
|
|
29
|
+
elif method == 'google_images_download':
|
|
30
|
+
|
|
31
|
+
from google_images_download import google_images_download
|
|
32
|
+
|
|
33
|
+
else:
|
|
34
|
+
|
|
35
|
+
raise ValueError('Unrecognized method {}'.format(method))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
#%% Main entry point
|
|
39
|
+
|
|
40
|
+
def download_images(query,output_directory,limit=100,verbose=False):
|
|
41
|
+
|
|
42
|
+
query = query.replace(' ','+')
|
|
43
|
+
|
|
44
|
+
if method == 'simple_image_download':
|
|
45
|
+
|
|
46
|
+
google_image_downloader.directory = output_directory
|
|
47
|
+
paths = google_image_downloader.download(query, limit=limit,
|
|
48
|
+
verbose=verbose, cache=False, download_cache=False)
|
|
49
|
+
return paths
|
|
50
|
+
|
|
51
|
+
elif method == 'google_images_download':
|
|
52
|
+
|
|
53
|
+
response = google_images_download.googleimagesdownload()
|
|
54
|
+
arguments = {'keywords':query,'limit':limit,'print_urls':verbose,
|
|
55
|
+
'image-directory':output_directory}
|
|
56
|
+
response.download(arguments)
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
else:
|
|
60
|
+
|
|
61
|
+
raise ValueError('Unrecognized method {}'.format(method))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
#%% Test driver
|
|
65
|
+
|
|
66
|
+
if False:
|
|
67
|
+
|
|
68
|
+
#%%
|
|
69
|
+
|
|
70
|
+
paths = download_images(query='redunca',output_directory=output_folder,
|
|
71
|
+
limit=20,verbose=True)
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
simple_image_download.py
|
|
4
|
+
|
|
5
|
+
Web image downloader, used in preview_lila_taxonomy.py
|
|
6
|
+
|
|
7
|
+
Slightly modified from:
|
|
8
|
+
|
|
9
|
+
https://github.com/RiddlerQ/simple_image_download
|
|
10
|
+
|
|
11
|
+
pip install python-magic
|
|
12
|
+
|
|
13
|
+
# On Windows, also run:
|
|
14
|
+
pip install python-magic-bin
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
#%% Imports
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import urllib
|
|
22
|
+
import requests
|
|
23
|
+
import magic
|
|
24
|
+
import random
|
|
25
|
+
|
|
26
|
+
from urllib.parse import quote
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
#%% Constants
|
|
30
|
+
|
|
31
|
+
BASE_URL = 'https://www.google.com/search?q='
|
|
32
|
+
GOOGLE_PICTURE_ID = '''&biw=1536&bih=674&tbm=isch&sxsrf=ACYBGNSXXpS6YmAKUiLKKBs6xWb4uUY5gA:1581168823770&source=lnms&sa=X&ved=0ahUKEwioj8jwiMLnAhW9AhAIHbXTBMMQ_AUI3QUoAQ'''
|
|
33
|
+
HEADERS = {
|
|
34
|
+
'User-Agent':
|
|
35
|
+
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"
|
|
36
|
+
}
|
|
37
|
+
SCANNER_COUNTER = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
#%% Support functions
|
|
41
|
+
|
|
42
|
+
def generate_search_url(keywords):
|
|
43
|
+
keywords_to_search = [str(item).strip() for item in keywords.split(',')][0].split()
|
|
44
|
+
keywords_count = len(keywords_to_search)
|
|
45
|
+
return keywords_to_search, keywords_count
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def generate_urls(search):
|
|
49
|
+
"""
|
|
50
|
+
Generate Google search URLs for all tokens in the list [search]
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
return [(BASE_URL+quote(word)+GOOGLE_PICTURE_ID) for word in search]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def check_webpage(url):
|
|
57
|
+
checked_url = None
|
|
58
|
+
try:
|
|
59
|
+
request = requests.get(url, allow_redirects=True, timeout=10)
|
|
60
|
+
if 'html' not in str(request.content):
|
|
61
|
+
checked_url = request
|
|
62
|
+
except Exception as err:
|
|
63
|
+
print(err)
|
|
64
|
+
return checked_url
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def scan_webpage(webpage, extensions, timer):
|
|
68
|
+
"""
|
|
69
|
+
Scan for pictures to download based on keywords
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
global SCANNER_COUNTER
|
|
73
|
+
scanner = webpage.find
|
|
74
|
+
found = False
|
|
75
|
+
counter = 0
|
|
76
|
+
while counter < timer:
|
|
77
|
+
new_line = scanner('"https://', SCANNER_COUNTER + 1) # How Many New lines
|
|
78
|
+
SCANNER_COUNTER = scanner('"', new_line + 1) # Ends of line
|
|
79
|
+
buffer = scanner('\\', new_line + 1, SCANNER_COUNTER)
|
|
80
|
+
if buffer != -1:
|
|
81
|
+
object_raw = webpage[new_line + 1:buffer]
|
|
82
|
+
else:
|
|
83
|
+
object_raw = webpage[new_line + 1:SCANNER_COUNTER]
|
|
84
|
+
if any(extension in object_raw for extension in extensions):
|
|
85
|
+
found = True
|
|
86
|
+
break
|
|
87
|
+
counter += 1
|
|
88
|
+
if found:
|
|
89
|
+
object_ready = check_webpage(object_raw)
|
|
90
|
+
return object_ready
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
#%% Main class
|
|
94
|
+
|
|
95
|
+
class Downloader:
|
|
96
|
+
"""
|
|
97
|
+
Main Downloader
|
|
98
|
+
::param extension:iterable of Files extensions
|
|
99
|
+
"""
|
|
100
|
+
def __init__(self, extensions=None):
|
|
101
|
+
if extensions:
|
|
102
|
+
self._extensions = set(*[extensions])
|
|
103
|
+
else:
|
|
104
|
+
self._extensions = {'.jpg', '.png', '.ico', '.gif', '.jpeg'}
|
|
105
|
+
self._directory = "simple_images/"
|
|
106
|
+
self.get_dirs = set()
|
|
107
|
+
self._cached_urls = {}
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def directory(self):
|
|
111
|
+
return self._directory
|
|
112
|
+
|
|
113
|
+
@directory.setter
|
|
114
|
+
def directory(self, value):
|
|
115
|
+
self._directory = value
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def cached_urls(self):
|
|
119
|
+
return self._cached_urls
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def extensions(self):
|
|
123
|
+
return self._extensions
|
|
124
|
+
|
|
125
|
+
@extensions.setter
|
|
126
|
+
def extensions(self, value):
|
|
127
|
+
self._extensions = set([value])
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_urls(self):
|
|
131
|
+
return [self._cached_urls[url][1].url
|
|
132
|
+
for url in self._cached_urls]
|
|
133
|
+
|
|
134
|
+
def _download_page(self, url):
|
|
135
|
+
req = urllib.request.Request(url, headers=HEADERS)
|
|
136
|
+
resp = urllib.request.urlopen(req)
|
|
137
|
+
resp_data = str(resp.read())
|
|
138
|
+
return resp_data
|
|
139
|
+
|
|
140
|
+
def search_urls(self, keywords, limit=1, verbose=False, cache=True, timer=None):
|
|
141
|
+
cache_out = {}
|
|
142
|
+
search, count = generate_search_url(keywords)
|
|
143
|
+
urls_ = generate_urls(search)
|
|
144
|
+
timer = timer if timer else 1000
|
|
145
|
+
# max_progressbar = count * (list(range(limit+1))[-1]+1)
|
|
146
|
+
|
|
147
|
+
# bar = progressbar.ProgressBar(maxval=max_progressbar,
|
|
148
|
+
# widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()]).start()
|
|
149
|
+
i = 0
|
|
150
|
+
while i < count:
|
|
151
|
+
global SCANNER_COUNTER
|
|
152
|
+
SCANNER_COUNTER = -1
|
|
153
|
+
url = urls_[i]
|
|
154
|
+
path = self.generate_dir(search[i])
|
|
155
|
+
raw_html = self._download_page(url) # Download the entire page from the google Picture search
|
|
156
|
+
for _ in range(limit+1):
|
|
157
|
+
webpage_url = scan_webpage(raw_html, self._extensions, timer)
|
|
158
|
+
if webpage_url:
|
|
159
|
+
file_name = Downloader.gen_fn(webpage_url, search[i])
|
|
160
|
+
cache_out[file_name] = [path, webpage_url]
|
|
161
|
+
else:
|
|
162
|
+
pass
|
|
163
|
+
# bar.update(bar.currval + 1)
|
|
164
|
+
i += 1
|
|
165
|
+
# bar.finish()
|
|
166
|
+
if verbose:
|
|
167
|
+
for url in cache_out:
|
|
168
|
+
print(url)
|
|
169
|
+
if cache:
|
|
170
|
+
self._cached_urls = cache_out
|
|
171
|
+
if not cache_out:
|
|
172
|
+
print('==='*15 + ' < ' + 'NO PICTURES FOUND' + ' > ' + '==='*15)
|
|
173
|
+
return cache_out
|
|
174
|
+
|
|
175
|
+
def download(self, keywords=None, limit=1, verbose=False, cache=True, download_cache=False,
|
|
176
|
+
timer=None):
|
|
177
|
+
if not download_cache:
|
|
178
|
+
content = self.search_urls(keywords, limit, verbose, cache, timer)
|
|
179
|
+
else:
|
|
180
|
+
content = self._cached_urls
|
|
181
|
+
if not content:
|
|
182
|
+
print('Downloader has not URLs saved in Memory yet, run Downloader.search_urls to find pics first')
|
|
183
|
+
paths = []
|
|
184
|
+
for name, (path, url) in content.items():
|
|
185
|
+
fullpath = os.path.join(path, name)
|
|
186
|
+
paths.append(fullpath)
|
|
187
|
+
with open(fullpath, 'wb') as file:
|
|
188
|
+
file.write(url.content)
|
|
189
|
+
if verbose:
|
|
190
|
+
print(f'File Name={name}, Downloaded from {url.url}')
|
|
191
|
+
return paths
|
|
192
|
+
|
|
193
|
+
def _create_directories(self, name):
|
|
194
|
+
dir_path = os.path.join(self._directory, name)
|
|
195
|
+
try:
|
|
196
|
+
if not os.path.exists(dir_path):
|
|
197
|
+
os.makedirs(dir_path)
|
|
198
|
+
except OSError:
|
|
199
|
+
raise
|
|
200
|
+
self.get_dirs.update([name])
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
def generate_dir(self, dir_name):
|
|
204
|
+
"""Generate Path and Directory, also check if Directory exists or not """
|
|
205
|
+
dir_name = dir_name.replace(" ", "_")
|
|
206
|
+
if dir_name in self.get_dirs:
|
|
207
|
+
pass
|
|
208
|
+
else:
|
|
209
|
+
self._create_directories(dir_name)
|
|
210
|
+
return os.path.join(self._directory,dir_name)
|
|
211
|
+
|
|
212
|
+
@staticmethod
|
|
213
|
+
def gen_fn(check, name):
|
|
214
|
+
"""Create a file name string and generate a random identifiers otherwise won't import same pic twice"""
|
|
215
|
+
id = str(hex(random.randrange(1000)))
|
|
216
|
+
mime = magic.Magic(mime=True)
|
|
217
|
+
file_type = mime.from_buffer(check.content)
|
|
218
|
+
file_extension = f'.{file_type.split("/")[1]}'
|
|
219
|
+
file_name = str(name) + "_" + id[2:] + file_extension
|
|
220
|
+
return file_name
|
|
221
|
+
|
|
222
|
+
def flush_cache(self):
|
|
223
|
+
"""Clear the Downloader instance cache"""
|
|
224
|
+
self._cached_urls = set()
|