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,209 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
tf_detector.py
|
|
4
|
+
|
|
5
|
+
Module containing the class TFDetector, for loading and running a TensorFlow detection model.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
#%% Imports and constants
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
from megadetector.detection.run_detector import \
|
|
14
|
+
CONF_DIGITS, COORD_DIGITS, FAILURE_INFER
|
|
15
|
+
from megadetector.utils.ct_utils import truncate_float
|
|
16
|
+
|
|
17
|
+
import tensorflow.compat.v1 as tf
|
|
18
|
+
|
|
19
|
+
print('TensorFlow version:', tf.__version__)
|
|
20
|
+
print('Is GPU available? tf.test.is_gpu_available:', tf.test.is_gpu_available())
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#%% Classes
|
|
24
|
+
|
|
25
|
+
class TFDetector:
|
|
26
|
+
"""
|
|
27
|
+
A detector model loaded at the time of initialization. It is intended to be used with
|
|
28
|
+
TensorFlow-based versions of MegaDetector (v2, v3, or v4). If someone can find v1, I
|
|
29
|
+
suppose you could use this class for v1 also.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
#: TF versions of MD were trained with batch size of 1, and the resizing function is a
|
|
33
|
+
#: part of the inference graph, so this is fixed.
|
|
34
|
+
#:
|
|
35
|
+
#: :meta private:
|
|
36
|
+
BATCH_SIZE = 1
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __init__(self, model_path, detector_options=None):
|
|
40
|
+
"""
|
|
41
|
+
Loads a model from [model_path] and starts a tf.Session with this graph. Obtains
|
|
42
|
+
input and output tensor handles.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
model_path (str): path to .pb file
|
|
46
|
+
detector_options (dict, optional): key-value pairs that control detector
|
|
47
|
+
options; currently not used by TFDetector
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
detection_graph = TFDetector.__load_model(model_path)
|
|
51
|
+
self.tf_session = tf.Session(graph=detection_graph)
|
|
52
|
+
self.image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
|
|
53
|
+
self.box_tensor = detection_graph.get_tensor_by_name('detection_boxes:0')
|
|
54
|
+
self.score_tensor = detection_graph.get_tensor_by_name('detection_scores:0')
|
|
55
|
+
self.class_tensor = detection_graph.get_tensor_by_name('detection_classes:0')
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def __round_and_make_float(d, precision=4):
|
|
60
|
+
return truncate_float(float(d), precision=precision)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def __convert_coords(tf_coords):
|
|
65
|
+
"""
|
|
66
|
+
Converts coordinates from the model's output format [y1, x1, y2, x2] to the
|
|
67
|
+
format used by our API and MegaDB: [x1, y1, width, height]. All coordinates
|
|
68
|
+
(including model outputs) are normalized in the range [0, 1].
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
tf_coords: np.array of predicted bounding box coordinates from the TF detector,
|
|
72
|
+
has format [y1, x1, y2, x2]
|
|
73
|
+
|
|
74
|
+
Returns: list of Python float, predicted bounding box coordinates [x1, y1, width, height]
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# change from [y1, x1, y2, x2] to [x1, y1, width, height]
|
|
78
|
+
width = tf_coords[3] - tf_coords[1]
|
|
79
|
+
height = tf_coords[2] - tf_coords[0]
|
|
80
|
+
|
|
81
|
+
new = [tf_coords[1], tf_coords[0], width, height] # must be a list instead of np.array
|
|
82
|
+
|
|
83
|
+
# convert numpy floats to Python floats
|
|
84
|
+
for i, d in enumerate(new):
|
|
85
|
+
new[i] = TFDetector.__round_and_make_float(d, precision=COORD_DIGITS)
|
|
86
|
+
return new
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def __load_model(model_path):
|
|
91
|
+
"""
|
|
92
|
+
Loads a detection model (i.e., create a graph) from a .pb file.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
model_path: .pb file of the model.
|
|
96
|
+
|
|
97
|
+
Returns: the loaded graph.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
print('TFDetector: Loading graph...')
|
|
101
|
+
detection_graph = tf.Graph()
|
|
102
|
+
with detection_graph.as_default():
|
|
103
|
+
od_graph_def = tf.GraphDef()
|
|
104
|
+
with tf.gfile.GFile(model_path, 'rb') as fid:
|
|
105
|
+
serialized_graph = fid.read()
|
|
106
|
+
od_graph_def.ParseFromString(serialized_graph)
|
|
107
|
+
tf.import_graph_def(od_graph_def, name='')
|
|
108
|
+
print('TFDetector: Detection graph loaded.')
|
|
109
|
+
|
|
110
|
+
return detection_graph
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _generate_detections_one_image(self, image):
|
|
114
|
+
"""
|
|
115
|
+
Runs the detector on a single image.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
if isinstance(image,np.ndarray):
|
|
119
|
+
np_im = image
|
|
120
|
+
else:
|
|
121
|
+
np_im = np.asarray(image, np.uint8)
|
|
122
|
+
im_w_batch_dim = np.expand_dims(np_im, axis=0)
|
|
123
|
+
|
|
124
|
+
# need to change the above line to the following if supporting a batch size > 1 and resizing to the same size
|
|
125
|
+
# np_images = [np.asarray(image, np.uint8) for image in images]
|
|
126
|
+
# images_stacked = np.stack(np_images, axis=0) if len(images) > 1 else np.expand_dims(np_images[0], axis=0)
|
|
127
|
+
|
|
128
|
+
# performs inference
|
|
129
|
+
(box_tensor_out, score_tensor_out, class_tensor_out) = self.tf_session.run(
|
|
130
|
+
[self.box_tensor, self.score_tensor, self.class_tensor],
|
|
131
|
+
feed_dict={self.image_tensor: im_w_batch_dim})
|
|
132
|
+
|
|
133
|
+
return box_tensor_out, score_tensor_out, class_tensor_out
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def generate_detections_one_image(self,
|
|
137
|
+
image,
|
|
138
|
+
image_id,
|
|
139
|
+
detection_threshold,
|
|
140
|
+
image_size=None,
|
|
141
|
+
augment=False,
|
|
142
|
+
verbose=False):
|
|
143
|
+
"""
|
|
144
|
+
Runs the detector on an image.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
image (Image): the PIL Image object (or numpy array) on which we should run the detector, with
|
|
148
|
+
EXIF rotation already handled.
|
|
149
|
+
image_id (str): a path to identify the image; will be in the "file" field of the output object
|
|
150
|
+
detection_threshold (float): only detections above this threshold will be included in the return
|
|
151
|
+
value
|
|
152
|
+
image_size (tuple, optional): image size to use for inference, only mess with this
|
|
153
|
+
if (a) you're using a model other than MegaDetector or (b) you know what you're
|
|
154
|
+
doing
|
|
155
|
+
augment (bool, optional): enable image augmentation. Not currently supported, but included
|
|
156
|
+
here for compatibility with PTDetector.
|
|
157
|
+
verbose (bool, optional): enable additional debug output
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
dict: a dictionary with the following fields:
|
|
161
|
+
- 'file' (filename, always present)
|
|
162
|
+
- 'max_detection_conf' (removed from MegaDetector output files by default, but generated here)
|
|
163
|
+
- 'detections' (a list of detection objects containing keys 'category', 'conf', and 'bbox')
|
|
164
|
+
- 'failure' (a failure string, or None if everything went fine)
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
assert image_size is None, 'Image sizing not supported for TF detectors'
|
|
168
|
+
assert not augment, 'Image augmentation is not supported for TF detectors'
|
|
169
|
+
|
|
170
|
+
if detection_threshold is None:
|
|
171
|
+
detection_threshold = 0
|
|
172
|
+
|
|
173
|
+
result = { 'file': image_id }
|
|
174
|
+
|
|
175
|
+
try:
|
|
176
|
+
|
|
177
|
+
b_box, b_score, b_class = self._generate_detections_one_image(image)
|
|
178
|
+
|
|
179
|
+
# our batch size is 1; need to loop the batch dim if supporting batch size > 1
|
|
180
|
+
boxes, scores, classes = b_box[0], b_score[0], b_class[0]
|
|
181
|
+
|
|
182
|
+
detections_cur_image = [] # will be empty for an image with no confident detections
|
|
183
|
+
max_detection_conf = 0.0
|
|
184
|
+
for b, s, c in zip(boxes, scores, classes): #noqa
|
|
185
|
+
if s > detection_threshold:
|
|
186
|
+
detection_entry = {
|
|
187
|
+
'category': str(int(c)), # use string type for the numerical class label, not int
|
|
188
|
+
'conf': truncate_float(float(s), # cast to float for json serialization
|
|
189
|
+
precision=CONF_DIGITS),
|
|
190
|
+
'bbox': TFDetector.__convert_coords(b)
|
|
191
|
+
}
|
|
192
|
+
detections_cur_image.append(detection_entry)
|
|
193
|
+
if s > max_detection_conf:
|
|
194
|
+
max_detection_conf = s
|
|
195
|
+
|
|
196
|
+
result['max_detection_conf'] = truncate_float(float(max_detection_conf),
|
|
197
|
+
precision=CONF_DIGITS)
|
|
198
|
+
result['detections'] = detections_cur_image
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
|
|
202
|
+
result['failure'] = FAILURE_INFER
|
|
203
|
+
print('TFDetector: image {} failed during inference: {}'.format(image_id, str(e)))
|
|
204
|
+
|
|
205
|
+
return result
|
|
206
|
+
|
|
207
|
+
# ...def generate_detections_one_image(...)
|
|
208
|
+
|
|
209
|
+
# ...class TFDetector
|