megadetector 5.0.20__py3-none-any.whl → 5.0.21__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.

@@ -672,6 +672,36 @@ def draw_bounding_boxes_on_image(image,
672
672
  # ...draw_bounding_boxes_on_image(...)
673
673
 
674
674
 
675
+ def get_text_size(font,s):
676
+ """
677
+ Get the expected width and height when rendering the string [s] in the font
678
+ [font].
679
+
680
+ Args:
681
+ font (PIL.ImageFont): the font whose size we should query
682
+ s (str): the string whose size we should query
683
+
684
+ Returns:
685
+ tuple: (w,h), both floats in pixel coordinatess
686
+ """
687
+
688
+ # This is what we did w/Pillow 9
689
+ # w,h = font.getsize(s)
690
+
691
+ # I would *think* this would be the equivalent for Pillow 10
692
+ # l,t,r,b = font.getbbox(s); w = r-l; h=b-t
693
+
694
+ # ...but this actually produces the most similar results to Pillow 9
695
+ # l,t,r,b = font.getbbox(s); w = r; h=b
696
+
697
+ try:
698
+ l,t,r,b = font.getbbox(s); w = r; h=b
699
+ except Exception:
700
+ w,h = font.getsize(s)
701
+
702
+ return w,h
703
+
704
+
675
705
  def draw_bounding_box_on_image(image,
676
706
  ymin,
677
707
  xmin,
@@ -773,24 +803,6 @@ def draw_bounding_box_on_image(image,
773
803
  except IOError:
774
804
  font = ImageFont.load_default()
775
805
 
776
- def get_text_size(font,s):
777
-
778
- # This is what we did w/Pillow 9
779
- # w,h = font.getsize(s)
780
-
781
- # I would *think* this would be the equivalent for Pillow 10
782
- # l,t,r,b = font.getbbox(s); w = r-l; h=b-t
783
-
784
- # ...but this actually produces the most similar results to Pillow 9
785
- # l,t,r,b = font.getbbox(s); w = r; h=b
786
-
787
- try:
788
- l,t,r,b = font.getbbox(s); w = r; h=b
789
- except Exception:
790
- w,h = font.getsize(s)
791
-
792
- return w,h
793
-
794
806
  # If the total height of the display strings added to the top of the bounding
795
807
  # box exceeds the top of the image, stack the strings below the bounding box
796
808
  # instead of above.
@@ -972,7 +984,7 @@ def draw_bounding_boxes_on_file(input_file,
972
984
  boxes are length-four arrays formatted as [x,y,w,h], normalized,
973
985
  upper-left origin (this is the standard MD detection format)
974
986
  detector_label_map (dict, optional): a dict mapping category IDs to strings. If this
975
- is None, no confidence values or identifiers are shown If this is {}, just category
987
+ is None, no confidence values or identifiers are shown. If this is {}, just category
976
988
  indices and confidence values are shown.
977
989
  thickness (int, optional): line width in pixels for box rendering
978
990
  expansion (int, optional): box expansion in pixels
@@ -1043,7 +1055,7 @@ def draw_db_boxes_on_file(input_file,
1043
1055
  classes = [0] * len(boxes)
1044
1056
 
1045
1057
  render_db_bounding_boxes(boxes, classes, image, original_size=None,
1046
- label_map=label_map, thickness=thickness, expansion=expansion)
1058
+ label_map=label_map, thickness=thickness, expansion=expansion)
1047
1059
 
1048
1060
  image.save(output_file)
1049
1061
 
@@ -1125,7 +1137,6 @@ def gray_scale_fraction(image,crop_size=(0.1,0.1)):
1125
1137
  if r == g and r == b and g == b:
1126
1138
  n_gray_pixels += 1
1127
1139
 
1128
-
1129
1140
  # ...def gray_scale_fraction(...)
1130
1141
 
1131
1142
 
@@ -1376,6 +1387,98 @@ def resize_image_folder(input_folder,
1376
1387
  # ...def resize_image_folder(...)
1377
1388
 
1378
1389
 
1390
+ def get_image_size(im,verbose=False):
1391
+ """
1392
+ Retrieve the size of an image. Returns None if the image fails to load.
1393
+
1394
+ Args:
1395
+ im (str or PIL.Image): filename or PIL image
1396
+
1397
+ Returns:
1398
+ tuple (w,h), or None if the image fails to load.
1399
+ """
1400
+
1401
+ image_name = '[in memory]'
1402
+
1403
+ try:
1404
+ if isinstance(im,str):
1405
+ image_name = im
1406
+ im = load_image(im)
1407
+ w = im.width
1408
+ h = im.height
1409
+ if w <= 0 or h <= 0:
1410
+ if verbose:
1411
+ print('Error reading width from image {}: {},{}'.format(
1412
+ image_name,w,h))
1413
+ return None
1414
+ return (w,h)
1415
+ except Exception as e:
1416
+ if verbose:
1417
+ print('Error reading width from image {}: {}'.format(
1418
+ image_name,str(e)))
1419
+ return None
1420
+
1421
+ # ...def get_image_size(...)
1422
+
1423
+
1424
+ def parallel_get_image_sizes(filenames,
1425
+ max_workers=16,
1426
+ use_threads=True,
1427
+ recursive=True,
1428
+ verbose=False):
1429
+ """
1430
+ Retrieve image sizes for a list or folder of images
1431
+
1432
+ Args:
1433
+ filenames (list or str): a list of image filenames or a folder
1434
+ max_workers (int, optional): the number of parallel workers to use; set to <=1 to disable
1435
+ parallelization
1436
+ use_threads (bool, optional): whether to use threads (True) or processes (False) for
1437
+ parallelization
1438
+ recursive (bool, optional): if [filenames] is a folder, whether to search recursively for images.
1439
+ Ignored if [filenames] is a list.
1440
+ verbose (bool, optional): enable additional debug output
1441
+
1442
+ Returns:
1443
+ dict: a dict mapping filenames to (w,h) tuples; values will be None for images that fail
1444
+ to load.
1445
+ """
1446
+
1447
+ if isinstance(filenames,str) and os.path.isdir(filenames):
1448
+ if verbose:
1449
+ print('Enumerating images in {}'.format(filenames))
1450
+ filenames = find_images(filenames,recursive=recursive,return_relative_paths=False)
1451
+
1452
+ n_workers = min(max_workers,len(filenames))
1453
+
1454
+ if verbose:
1455
+ print('Getting image sizes for {} images'.format(len(filenames)))
1456
+
1457
+ if n_workers <= 1:
1458
+
1459
+ results = []
1460
+ for filename in filenames:
1461
+ results.append(get_image_size(filename,verbose=verbose))
1462
+
1463
+ else:
1464
+
1465
+ if use_threads:
1466
+ pool = ThreadPool(n_workers)
1467
+ else:
1468
+ pool = Pool(n_workers)
1469
+
1470
+ results = list(tqdm(pool.imap(
1471
+ partial(get_image_size,verbose=verbose),filenames), total=len(filenames)))
1472
+
1473
+ assert len(filenames) == len(results), 'Internal error in parallel_get_image_sizes'
1474
+
1475
+ to_return = {}
1476
+ for i_file,filename in enumerate(filenames):
1477
+ to_return[filename] = results[i_file]
1478
+
1479
+ return to_return
1480
+
1481
+
1379
1482
  #%% Image integrity checking functions
1380
1483
 
1381
1484
  def check_image_integrity(filename,modes=None):
@@ -1494,13 +1597,13 @@ def parallel_check_image_integrity(filenames,
1494
1597
  with either 'success' or 'error').
1495
1598
  """
1496
1599
 
1497
- n_workers = min(max_workers,len(filenames))
1498
-
1499
1600
  if isinstance(filenames,str) and os.path.isdir(filenames):
1500
1601
  if verbose:
1501
1602
  print('Enumerating images in {}'.format(filenames))
1502
1603
  filenames = find_images(filenames,recursive=recursive,return_relative_paths=False)
1503
1604
 
1605
+ n_workers = min(max_workers,len(filenames))
1606
+
1504
1607
  if verbose:
1505
1608
  print('Checking image integrity for {} filenames'.format(len(filenames)))
1506
1609
 
@@ -32,6 +32,9 @@ from megadetector.utils.write_html_image_list import write_html_image_list
32
32
  from megadetector.data_management.cct_json_utils import IndexedJsonDb
33
33
  from megadetector.visualization import visualization_utils as vis_utils
34
34
 
35
+ def isnan(x):
36
+ return (isinstance(x,float) and np.isnan(x))
37
+
35
38
 
36
39
  #%% Settings
37
40
 
@@ -84,12 +87,12 @@ class DbVizOptions:
84
87
  #: Number of pixels to expand each bounding box
85
88
  self.box_expansion = 0
86
89
 
87
- #: Only include images that contain annotations with these class names (not IDs)
90
+ #: Only include images that contain annotations with these class names (not IDs) (list)
88
91
  #:
89
92
  #: Mutually exclusive with classes_to_exclude
90
93
  self.classes_to_include = None
91
94
 
92
- #: Exclude images that contain annotations with these class names (not IDs)
95
+ #: Exclude images that contain annotations with these class names (not IDs) (list)
93
96
  #:
94
97
  #: Mutually exclusive with classes_to_include
95
98
  self.classes_to_exclude = None
@@ -117,6 +120,12 @@ class DbVizOptions:
117
120
  #: Should we show absolute (True) or relative (False) paths for each image?
118
121
  self.show_full_paths = False
119
122
 
123
+ #: List of additional fields in the image struct that we should print in image headers
124
+ self.extra_image_fields_to_print = None
125
+
126
+ #: List of additional fields in the annotation struct that we should print in image headers
127
+ self.extra_annotation_fields_to_print = None
128
+
120
129
  #: Set to False to skip existing images
121
130
  self.force_rendering = True
122
131
 
@@ -164,6 +173,12 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
164
173
  if options is None:
165
174
  options = DbVizOptions()
166
175
 
176
+ # Consistency checking for fields with specific format requirements
177
+
178
+ # This should be a list, but if someone specifies a string, do a reasonable thing
179
+ if isinstance(options.extra_image_fields_to_print,str):
180
+ options.extra_image_fields_to_print = [options.extra_image_fields_to_print]
181
+
167
182
  if not options.parallelize_rendering_with_threads:
168
183
  print('Warning: process-based parallelization is not yet supported by visualize_db')
169
184
  options.parallelize_rendering_with_threads = True
@@ -190,61 +205,69 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
190
205
  annotations = image_db['annotations']
191
206
  images = image_db['images']
192
207
  categories = image_db['categories']
193
-
208
+
194
209
  # Optionally remove all images without bounding boxes, *before* sampling
195
210
  if options.trim_to_images_with_bboxes:
196
211
 
197
- bHasBbox = [False] * len(annotations)
198
- for iAnn,ann in enumerate(annotations):
212
+ b_has_bbox = [False] * len(annotations)
213
+ for i_ann,ann in enumerate(annotations):
199
214
  if 'bbox' in ann:
200
215
  assert isinstance(ann['bbox'],list)
201
- bHasBbox[iAnn] = True
202
- annotationsWithBboxes = list(compress(annotations, bHasBbox))
216
+ b_has_bbox[i_ann] = True
217
+ annotations_with_boxes = list(compress(annotations, b_has_bbox))
203
218
 
204
- imageIDsWithBboxes = [x['image_id'] for x in annotationsWithBboxes]
205
- imageIDsWithBboxes = set(imageIDsWithBboxes)
219
+ image_ids_with_boxes = [x['image_id'] for x in annotations_with_boxes]
220
+ image_ids_with_boxes = set(image_ids_with_boxes)
206
221
 
207
- bImageHasBbox = [False] * len(images)
208
- for iImage,image in enumerate(images):
222
+ image_has_box = [False] * len(images)
223
+ for i_image,image in enumerate(images):
209
224
  imageID = image['id']
210
- if imageID in imageIDsWithBboxes:
211
- bImageHasBbox[iImage] = True
212
- imagesWithBboxes = list(compress(images, bImageHasBbox))
213
- images = imagesWithBboxes
225
+ if imageID in image_ids_with_boxes:
226
+ image_has_box[i_image] = True
227
+ images_with_bboxes = list(compress(images, image_has_box))
228
+ images = images_with_bboxes
214
229
 
215
230
  # Optionally include/remove images with specific labels, *before* sampling
216
231
 
217
232
  assert (not ((options.classes_to_exclude is not None) and \
218
233
  (options.classes_to_include is not None))), \
219
234
  'Cannot specify an inclusion and exclusion list'
220
-
235
+
236
+ if options.classes_to_exclude is not None:
237
+ assert isinstance(options.classes_to_exclude,list), \
238
+ 'If supplied, classes_to_exclude should be a list'
239
+
240
+ if options.classes_to_include is not None:
241
+ assert isinstance(options.classes_to_include,list), \
242
+ 'If supplied, classes_to_include should be a list'
243
+
221
244
  if (options.classes_to_exclude is not None) or (options.classes_to_include is not None):
222
245
 
223
246
  print('Indexing database')
224
247
  indexed_db = IndexedJsonDb(image_db)
225
- bValidClass = [True] * len(images)
226
- for iImage,image in enumerate(images):
248
+ b_valid_class = [True] * len(images)
249
+ for i_image,image in enumerate(images):
227
250
  classes = indexed_db.get_classes_for_image(image)
228
251
  if options.classes_to_exclude is not None:
229
- for excludedClass in options.classes_to_exclude:
230
- if excludedClass in classes:
231
- bValidClass[iImage] = False
252
+ for excluded_class in options.classes_to_exclude:
253
+ if excluded_class in classes:
254
+ b_valid_class[i_image] = False
232
255
  break
233
256
  elif options.classes_to_include is not None:
234
- bValidClass[iImage] = False
257
+ b_valid_class[i_image] = False
235
258
  if options.multiple_categories_tag in options.classes_to_include:
236
259
  if len(classes) > 1:
237
- bValidClass[iImage] = True
238
- if not bValidClass[iImage]:
260
+ b_valid_class[i_image] = True
261
+ if not b_valid_class[i_image]:
239
262
  for c in classes:
240
263
  if c in options.classes_to_include:
241
- bValidClass[iImage] = True
264
+ b_valid_class[i_image] = True
242
265
  break
243
266
  else:
244
267
  raise ValueError('Illegal include/exclude combination')
245
268
 
246
- imagesWithValidClasses = list(compress(images, bValidClass))
247
- images = imagesWithValidClasses
269
+ images_with_valid_classes = list(compress(images, b_valid_class))
270
+ images = images_with_valid_classes
248
271
 
249
272
  # ...if we need to include/exclude categories
250
273
 
@@ -270,12 +293,12 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
270
293
 
271
294
  # Set of dicts representing inputs to render_db_bounding_boxes:
272
295
  #
273
- # bboxes, boxClasses, image_path
296
+ # bboxes, box_classes, image_path
274
297
  rendering_info = []
275
298
 
276
299
  print('Preparing rendering list')
277
300
 
278
- for iImage,img in tqdm(df_img.iterrows(),total=len(df_img)):
301
+ for i_image,img in tqdm(df_img.iterrows(),total=len(df_img)):
279
302
 
280
303
  img_id = img['id']
281
304
  assert img_id is not None
@@ -291,17 +314,27 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
291
314
  annos_i = df_anno.loc[df_anno['image_id'] == img_id, :] # all annotations on this image
292
315
 
293
316
  bboxes = []
294
- boxClasses = []
317
+ box_classes = []
295
318
 
296
319
  # All the class labels we've seen for this image (with out without bboxes)
297
- imageCategories = set()
320
+ image_categories = set()
298
321
 
299
- annotationLevelForImage = ''
322
+ extra_annotation_field_string = ''
323
+ annotation_level_for_image = ''
300
324
 
301
325
  # Iterate over annotations for this image
302
- # iAnn = 0; anno = annos_i.iloc[iAnn]
303
- for iAnn,anno in annos_i.iterrows():
304
-
326
+ # i_ann = 0; anno = annos_i.iloc[i_ann]
327
+ for i_ann,anno in annos_i.iterrows():
328
+
329
+ if options.extra_annotation_fields_to_print is not None:
330
+ field_names = list(anno.index)
331
+ for field_name in field_names:
332
+ if field_name in options.extra_annotation_fields_to_print:
333
+ field_value = anno[field_name]
334
+ if (field_value is not None) and (not isnan(field_value)):
335
+ extra_annotation_field_string += ' ({}:{})'.format(
336
+ field_name,field_value)
337
+
305
338
  if options.confidence_threshold is not None:
306
339
  assert options.confidence_field_name in anno, \
307
340
  'Error: confidence thresholding requested, ' + \
@@ -316,18 +349,18 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
316
349
  annLevel = 'sequence'
317
350
  else:
318
351
  annLevel = 'image'
319
- if annotationLevelForImage == '':
320
- annotationLevelForImage = annLevel
321
- elif annotationLevelForImage != annLevel:
322
- annotationLevelForImage = 'mixed'
352
+ if annotation_level_for_image == '':
353
+ annotation_level_for_image = annLevel
354
+ elif annotation_level_for_image != annLevel:
355
+ annotation_level_for_image = 'mixed'
323
356
 
324
- categoryID = anno['category_id']
325
- categoryName = label_map[categoryID]
357
+ category_id = anno['category_id']
358
+ category_name = label_map[category_id]
326
359
  if options.add_search_links:
327
- categoryName = categoryName.replace('"','')
328
- categoryName = '<a href="https://www.google.com/search?tbm=isch&q={}">{}</a>'.format(
329
- categoryName,categoryName)
330
- imageCategories.add(categoryName)
360
+ category_name = category_name.replace('"','')
361
+ category_name = '<a href="https://www.google.com/search?tbm=isch&q={}">{}</a>'.format(
362
+ category_name,category_name)
363
+ image_categories.add(category_name)
331
364
 
332
365
  if 'bbox' in anno:
333
366
  bbox = anno['bbox']
@@ -335,11 +368,11 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
335
368
  assert math.isnan(bbox), "I shouldn't see a bbox that's neither a box nor NaN"
336
369
  continue
337
370
  bboxes.append(bbox)
338
- boxClasses.append(anno['category_id'])
371
+ box_classes.append(anno['category_id'])
339
372
 
340
373
  # ...for each of this image's annotations
341
374
 
342
- imageClasses = ', '.join(imageCategories)
375
+ image_classes = ', '.join(image_categories)
343
376
 
344
377
  img_id_string = str(img_id).lower()
345
378
  file_name = '{}_gt.jpg'.format(os.path.splitext(img_id_string)[0])
@@ -349,19 +382,19 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
349
382
  for c in illegal_characters:
350
383
  file_name = file_name.replace(c,'~')
351
384
 
352
- rendering_info.append({'bboxes':bboxes, 'boxClasses':boxClasses, 'img_path':img_path,
385
+ rendering_info.append({'bboxes':bboxes, 'box_classes':box_classes, 'img_path':img_path,
353
386
  'output_file_name':file_name})
354
387
 
355
- labelLevelString = ' '
356
- if len(annotationLevelForImage) > 0:
357
- labelLevelString = ' (annotation level: {})'.format(annotationLevelForImage)
388
+ label_level_string = ''
389
+ if len(annotation_level_for_image) > 0:
390
+ label_level_string = ' (annotation level: {})'.format(annotation_level_for_image)
358
391
 
359
392
  if 'frame_num' in img and 'seq_num_frames' in img:
360
- frameString = ' frame: {} of {}, '.format(img['frame_num'],img['seq_num_frames'])
393
+ frame_string = ' frame: {} of {},'.format(img['frame_num'],img['seq_num_frames'])
361
394
  elif 'frame_num' in img:
362
- frameString = ' frame: {}, '.format(img['frame_num'])
395
+ frame_string = ' frame: {},'.format(img['frame_num'])
363
396
  else:
364
- frameString = ' '
397
+ frame_string = ''
365
398
 
366
399
  if options.show_full_paths:
367
400
  filename_text = img_path
@@ -370,22 +403,30 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
370
403
  if options.include_filename_links:
371
404
  filename_text = '<a href="{}">{}</a>'.format(img_path,filename_text)
372
405
 
373
- flagString = ''
374
-
375
- def isnan(x):
376
- return (isinstance(x,float) and np.isnan(x))
406
+ flag_string = ''
377
407
 
378
408
  if ('flags' in img) and (not isnan(img['flags'])):
379
- flagString = ', flags: {}'.format(str(img['flags']))
409
+ flag_string = ', flags: {}'.format(str(img['flags']))
380
410
 
411
+ extra_field_string = ''
412
+
413
+ if options.extra_image_fields_to_print is not None:
414
+ for field_name in options.extra_image_fields_to_print:
415
+ if field_name in img:
416
+ # Always include a leading comma; this either separates us from the
417
+ # previous field in [extra_fields_to_print] or from the rest of the string
418
+ extra_field_string += ', {}: {}'.format(
419
+ field_name,str(img[field_name]))
420
+
381
421
  # We're adding html for an image before we render it, so it's possible this image will
382
422
  # fail to render. For applications where this script is being used to debua a database
383
423
  # (the common case?), this is useful behavior, for other applications, this is annoying.
384
424
  image_dict = \
385
425
  {
386
426
  'filename': '{}/{}'.format('rendered_images', file_name),
387
- 'title': '{}<br/>{}, num boxes: {}, {}class labels: {}{}{}'.format(
388
- filename_text, img_id, len(bboxes), frameString, imageClasses, labelLevelString, flagString),
427
+ 'title': '{}<br/>{}, num boxes: {},{} class labels: {}{}{}{}{}'.format(
428
+ filename_text, img_id, len(bboxes), frame_string, image_classes,
429
+ label_level_string, flag_string, extra_field_string, extra_annotation_field_string),
389
430
  'textStyle': 'font-family:verdana,arial,calibri;font-size:80%;' + \
390
431
  'text-align:left;margin-top:20;margin-bottom:5'
391
432
  }
@@ -400,7 +441,7 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
400
441
 
401
442
  img_path = rendering_info['img_path']
402
443
  bboxes = rendering_info['bboxes']
403
- bboxClasses = rendering_info['boxClasses']
444
+ bbox_classes = rendering_info['box_classes']
404
445
  output_file_name = rendering_info['output_file_name']
405
446
  output_full_path = os.path.join(output_dir, 'rendered_images', output_file_name)
406
447
 
@@ -426,7 +467,7 @@ def visualize_db(db_path, output_dir, image_base_dir, options=None):
426
467
  print('Image {} failed to open, error: {}'.format(img_path, e))
427
468
  return False
428
469
 
429
- vis_utils.render_db_bounding_boxes(boxes=bboxes, classes=bboxClasses,
470
+ vis_utils.render_db_bounding_boxes(boxes=bboxes, classes=bbox_classes,
430
471
  image=image, original_size=original_size,
431
472
  label_map=label_map,
432
473
  thickness=options.box_thickness,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: megadetector
3
- Version: 5.0.20
3
+ Version: 5.0.21
4
4
  Summary: MegaDetector is an AI model that helps conservation folks spend less time doing boring things with camera trap images.
5
5
  Author-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
6
6
  Maintainer-email: Your friendly neighborhood MegaDetector team <cameratraps@lila.science>
@@ -69,7 +69,7 @@ megadetector/data_management/remove_exif.py,sha256=vIWnJfw1i9JgyQKUDGEzzqkHro4nd
69
69
  megadetector/data_management/rename_images.py,sha256=AG3YIxXEYdGmK4G-rv0_XZIylPqOZpS6gfEkydF6oDg,6918
70
70
  megadetector/data_management/resize_coco_dataset.py,sha256=AaiV7efIcNnqsXsnQckmHq2G__7ZQHBV_jN6rhZfMjo,6810
71
71
  megadetector/data_management/wi_download_csv_to_coco.py,sha256=ilnJZhNZK-FGUR-AfUSWjIDUk9Gytgxw7IOK_N8WKLE,8350
72
- megadetector/data_management/yolo_output_to_md_output.py,sha256=1RUJSWiVa7CVVQ_CresOVXAD3Eb7oHjdgPg7fTX_Vwg,17563
72
+ megadetector/data_management/yolo_output_to_md_output.py,sha256=VuU9G6QOeAXOa7JsuHjSYhE3Y7MjEd2bPtceugOOILY,17920
73
73
  megadetector/data_management/yolo_to_coco.py,sha256=TzAagQ2ATbB_tn1oZxrHCWsrFGO_OhfZmi-3X45WdDU,26180
74
74
  megadetector/data_management/annotations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
75
  megadetector/data_management/annotations/annotation_constants.py,sha256=1597MpAr_HdidIHoDFj4RgUO3K5e2Xm2bGafGeonR2k,953
@@ -101,10 +101,9 @@ megadetector/data_management/importers/mcgill_to_json.py,sha256=dfSxU1hHimyGT6Zt
101
101
  megadetector/data_management/importers/missouri_to_json.py,sha256=C0ia3eCEZujVUKE2gmQc6ScsK8kXWM7m0ibeKgHfXNo,14848
102
102
  megadetector/data_management/importers/nacti_fieldname_adjustments.py,sha256=1oDCSuFXhc2b7JPIzkSb3DkusacdAjMM2GQZnhfFQCg,2027
103
103
  megadetector/data_management/importers/noaa_seals_2019.py,sha256=oar378j46fm27ygcbjrgN1rbq6h1SC8utAdSPNqiQt4,5152
104
- megadetector/data_management/importers/osu-small-animals-to-json.py,sha256=Xr6vZ_WMNZQoTQw4qoYJqkYwBwqYf3FywCLX4hKFFPs,10096
104
+ megadetector/data_management/importers/osu-small-animals-to-json.py,sha256=wBbnY8kqZrzRiujrNK750DB3mq14EyIz4Zlx9JHRTkw,10096
105
105
  megadetector/data_management/importers/pc_to_json.py,sha256=VmVvY5Fr8jMLmRkDZI9CuyLvrNuLrspJA9Q8Auxbw1A,10762
106
106
  megadetector/data_management/importers/plot_wni_giraffes.py,sha256=KdEjbItDOXbXj0fr0celfMp7z31Rr3S29SLWBCMY-4M,3772
107
- megadetector/data_management/importers/prepare-noaa-fish-data-for-lila.py,sha256=Pq5tSKWTIGEAGxBiGaO5Tz0QvKZ6QgJTIQ3raDAhjkk,12435
108
107
  megadetector/data_management/importers/prepare_zsl_imerit.py,sha256=ohrUaTXIGg1M4_liptWaPa-4g3yNvc1E4o_knfHSE-8,3775
109
108
  megadetector/data_management/importers/rspb_to_json.py,sha256=y03v1d1un9mI3HZRCZinMB1pEkNvTb70S7Qkr3F76qg,9841
110
109
  megadetector/data_management/importers/save_the_elephants_survey_A.py,sha256=lugw8m5Nh2Fhs-FYo9L0mDL3_29nAweLxEul6GekdkI,10669
@@ -143,27 +142,28 @@ megadetector/detection/run_detector_batch.py,sha256=a98fzorcGtQaOYa5AGW2XPoJpbHe
143
142
  megadetector/detection/run_inference_with_yolov5_val.py,sha256=2miU2QZG_zp3rEPyoKf2XozuMpW6zAW4bAoyg6hSe-k,48691
144
143
  megadetector/detection/run_tiled_inference.py,sha256=vw0713eNuMiEOjHfweQl58zPHNxPOMdFWZ8bTDLhlMY,37883
145
144
  megadetector/detection/tf_detector.py,sha256=5V94a0gR6WmGPacKm59hl1eYEZI8cG04frF4EvHrmzU,8285
146
- megadetector/detection/video_utils.py,sha256=1u5DKMcHikKPi0OYmJUCyPdjEomGEXfayIkVD_VX3_0,42622
145
+ megadetector/detection/video_utils.py,sha256=TmUIcnnqk3VEXtk9MXHKAvixqCCVMvj5HHuBOmPBNDk,43036
147
146
  megadetector/detection/detector_training/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
147
  megadetector/detection/detector_training/model_main_tf2.py,sha256=YwNsZ7hkIFaEuwKU0rHG_VyqiR_0E01BbdlD0Yx4Smo,4936
149
148
  megadetector/postprocessing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
149
  megadetector/postprocessing/add_max_conf.py,sha256=qTE1_0RwGAy6jLDkHrIo2pS84yNbUV11s4IZuAYGdIU,1514
151
150
  megadetector/postprocessing/categorize_detections_by_size.py,sha256=YdapcvjA6Dz2dPa2AFf1Dwyl7C-OmmP4G4OjhTOuaF4,5797
152
151
  megadetector/postprocessing/classification_postprocessing.py,sha256=8uvlA0Gc8nakM5IE5Pud7WZfmF5kEhcYvxgQXcI9kl0,30429
153
- megadetector/postprocessing/combine_api_outputs.py,sha256=xCJHEKca8YW-mupEr0yNNwwSBeL9NvcV1w3VtEzN4lk,8535
152
+ megadetector/postprocessing/combine_api_outputs.py,sha256=zBGpSLbcQUiLYxgJrjZXjBwc2dOwAytV30UFnroP2Fg,8536
154
153
  megadetector/postprocessing/compare_batch_results.py,sha256=7O5c6-JsIDpuIGobks_R9j8MPuiZQRnEtNnJQsJqICM,38918
155
154
  megadetector/postprocessing/convert_output_format.py,sha256=HwThfK76UPEAGa3KQbJ_tMKIrUvJ3JhKoQVWJt9dPBk,15447
155
+ megadetector/postprocessing/detector_calibration.py,sha256=WHIj-i91geXZjNV2Am2783PL2iGAebkeVFJZhc1K6uY,12702
156
156
  megadetector/postprocessing/load_api_results.py,sha256=FqcaiPMuqTojZOV3Jn14pJESpuwjWGbZtcvJuVXUaDM,6861
157
- megadetector/postprocessing/md_to_coco.py,sha256=x3sUnOLd2lVfdG2zRN7k-oUvx6rvRD7DWmWJymPc108,12359
157
+ megadetector/postprocessing/md_to_coco.py,sha256=AhlI2w2kOu1Y1b4yliyu81WsMBxYXcBJ0YAF5laX9v8,12406
158
158
  megadetector/postprocessing/md_to_labelme.py,sha256=hejMKVxaz_xdtsGDPTQkeWuis7gzT-VOrL2Qf8ym1x0,11703
159
159
  megadetector/postprocessing/merge_detections.py,sha256=AEMgMivhph1vph_t_Qv85d9iHynT2nvq7otN4KGrDLU,17776
160
- megadetector/postprocessing/postprocess_batch_results.py,sha256=xa1FCQnzo1B6Inq8EWqS_In5xDu3qNzES_YdZ0INKr0,78978
160
+ megadetector/postprocessing/postprocess_batch_results.py,sha256=JnH3bezK9lm5Sljlsxgp9_JFUgUzcjRDjRRbLOYy7qk,79879
161
161
  megadetector/postprocessing/remap_detection_categories.py,sha256=d9IYTa0i_KbbrarJc_mczABmdwypscl5-KpK8Hx_z8o,6640
162
162
  megadetector/postprocessing/render_detection_confusion_matrix.py,sha256=_wsk4W0PbNiqmFuHy-EA0Z07B1tQLMsdCTPatnHAdZw,27382
163
163
  megadetector/postprocessing/separate_detections_into_folders.py,sha256=k42gxnL8hbBiV0e2T-jmFrhxzIxnhi57Nx9cDSSL5s0,31218
164
164
  megadetector/postprocessing/subset_json_detector_output.py,sha256=PDgb6cnsFm9d4E7_sMVIguLIU7s79uFQa2CRCxAO0F4,27064
165
165
  megadetector/postprocessing/top_folders_to_bottom.py,sha256=Dqk-KZXiRlIYlmLZmk6aUapmaaLJUKOf8wK1kxt9W6A,6283
166
- megadetector/postprocessing/validate_batch_results.py,sha256=uFS-Iag7tZYMWJeDuIYwDhEdc8F_5BGKhV4V7y3SGVw,5551
166
+ megadetector/postprocessing/validate_batch_results.py,sha256=bC2wSuR1ir3gW-VF6zFq6TqoMIxDXIK4eyTM8oBq6u8,8598
167
167
  megadetector/postprocessing/repeat_detection_elimination/find_repeat_detections.py,sha256=e4Y9CyMyd-bLN3il8tu76vI0nVYHZlhZr6vcL0J4zQ0,9832
168
168
  megadetector/postprocessing/repeat_detection_elimination/remove_repeat_detections.py,sha256=tARPxuY0OyQgpKU2XqiQPko3f-hHnWuISB8ZlZgXwxI,2819
169
169
  megadetector/postprocessing/repeat_detection_elimination/repeat_detections_core.py,sha256=vEmWLSSv0_rxDwhjz_S9YaKZ_LM2tADTz2JYb_zUCnc,67923
@@ -182,23 +182,23 @@ megadetector/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
182
182
  megadetector/utils/azure_utils.py,sha256=0BdnkG2hW-X0yFpsJqmBhOd2wysz_LvhuyImPJMVPJs,6271
183
183
  megadetector/utils/ct_utils.py,sha256=Ecac5CLEIrEi89JFuoqdOMxiOdmbno106a1MT2SVdJY,19956
184
184
  megadetector/utils/directory_listing.py,sha256=r4rg2xA4O9ZVxVtzPZzXIXa0DOEukAJMTTNcNSiQcuM,9668
185
- megadetector/utils/md_tests.py,sha256=6aufzNsFi_7cQGuMd4BLfjEosO3-iLAqmP5_PkE_SOs,61001
186
- megadetector/utils/path_utils.py,sha256=o68jfPDaLj3NizipVCQEnmB5GfPHpMOLUmQWamYM4w0,37165
185
+ megadetector/utils/md_tests.py,sha256=DvGfRZXpes4bg8S_-btA2NEW8X7k8vXfRaOZewauVxM,61189
186
+ megadetector/utils/path_utils.py,sha256=Kn7Ro37MapRW78_eraK_V_4_I-V8H9pgtvTDL4q7_a8,40571
187
187
  megadetector/utils/process_utils.py,sha256=2SdFVxqob-YUW2BTjUEavNuRH3jA4V05fbKMtrVSd3c,5635
188
188
  megadetector/utils/sas_blob_utils.py,sha256=k76EcMmJc_otrEHcfV2fxAC6fNhxU88FxM3ddSYrsKU,16917
189
189
  megadetector/utils/split_locations_into_train_val.py,sha256=jvaDu1xKB51L3Xq2nXQo0XtXRjNRf8RglBApl1g6gHo,10101
190
190
  megadetector/utils/string_utils.py,sha256=ZQapJodzvTDyQhjZgMoMl3-9bqnKAUlORpws8Db9AkA,2050
191
191
  megadetector/utils/torch_test.py,sha256=aEYE-1vGt5PujD0bHAVRTJiLrKFlGWpS8zeYhqEYZLY,853
192
192
  megadetector/utils/url_utils.py,sha256=yybWwJ-vl2A6Fci66i-xt_dl3Uqh72Ylnb8XOT2Grog,14835
193
- megadetector/utils/write_html_image_list.py,sha256=apzoWkgZWG-ybCT4k92PlS4-guN_sNBSMMMbj7Cfm1k,8638
193
+ megadetector/utils/write_html_image_list.py,sha256=zz98QFQlUIb-kKC-I7llf4EXbNh3PULZBtCZpfMVMfM,9148
194
194
  megadetector/visualization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
195
195
  megadetector/visualization/plot_utils.py,sha256=lOfU3uPrcuHZagV_1SN8erT8PujIepocgw6KZ17Ej6c,10671
196
196
  megadetector/visualization/render_images_with_thumbnails.py,sha256=kgJYW8BsqRO4C7T3sqItdBuSkZ64I1vOtIWAsVG4XBI,10589
197
- megadetector/visualization/visualization_utils.py,sha256=J53VsI8aQmzzBBeu-msm8c-qC6pm_HCMkMKYvnylqjo,63083
198
- megadetector/visualization/visualize_db.py,sha256=x9jScwG-3V-mZGy5cB1s85KWbiAIfvgVUcLqUplHxGA,22110
197
+ megadetector/visualization/visualization_utils.py,sha256=1_xUzuiA-GTD7XNsRwZiemXjQZooOa4p4_nqMd9u6F4,66269
198
+ megadetector/visualization/visualize_db.py,sha256=tswoWqyAo_S5RW76yvPEEWkUVEzn2NJrX1lfDl2jqY4,24392
199
199
  megadetector/visualization/visualize_detector_output.py,sha256=LY8QgDWpWlXVLZJUskvT29CdkNvIlEsFTk4DC_lS6pk,17052
200
- megadetector-5.0.20.dist-info/LICENSE,sha256=RMa3qq-7Cyk7DdtqRj_bP1oInGFgjyHn9-PZ3PcrqIs,1100
201
- megadetector-5.0.20.dist-info/METADATA,sha256=mpalvNnG04pMLXU6BD8IZ7YTumaa8uS9KPOFdS87KGk,7468
202
- megadetector-5.0.20.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
203
- megadetector-5.0.20.dist-info/top_level.txt,sha256=wf9DXa8EwiOSZ4G5IPjakSxBPxTDjhYYnqWRfR-zS4M,13
204
- megadetector-5.0.20.dist-info/RECORD,,
200
+ megadetector-5.0.21.dist-info/LICENSE,sha256=RMa3qq-7Cyk7DdtqRj_bP1oInGFgjyHn9-PZ3PcrqIs,1100
201
+ megadetector-5.0.21.dist-info/METADATA,sha256=Spj46ZROGJbmTdn_D-pOTHFAODg1npXS8xyiErghlKo,7468
202
+ megadetector-5.0.21.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
203
+ megadetector-5.0.21.dist-info/top_level.txt,sha256=wf9DXa8EwiOSZ4G5IPjakSxBPxTDjhYYnqWRfR-zS4M,13
204
+ megadetector-5.0.21.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5