megadetector 5.0.21__py3-none-any.whl → 5.0.23__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 +143 -7
- megadetector/data_management/cct_to_md.py +12 -5
- megadetector/data_management/databases/integrity_check_json_db.py +83 -77
- megadetector/data_management/importers/raic_csv_to_md_results.py +416 -0
- megadetector/data_management/importers/zamba_results_to_md_results.py +1 -2
- megadetector/data_management/lila/create_lila_test_set.py +25 -11
- megadetector/data_management/lila/download_lila_subset.py +9 -2
- megadetector/data_management/lila/generate_lila_per_image_labels.py +3 -2
- megadetector/data_management/lila/test_lila_metadata_urls.py +5 -1
- megadetector/data_management/read_exif.py +10 -14
- megadetector/data_management/rename_images.py +1 -1
- megadetector/detection/process_video.py +14 -3
- megadetector/detection/pytorch_detector.py +15 -3
- megadetector/detection/run_detector.py +4 -3
- megadetector/detection/run_detector_batch.py +2 -2
- megadetector/detection/run_inference_with_yolov5_val.py +121 -13
- megadetector/detection/video_utils.py +21 -10
- megadetector/postprocessing/classification_postprocessing.py +1 -1
- megadetector/postprocessing/compare_batch_results.py +931 -142
- megadetector/postprocessing/detector_calibration.py +243 -45
- megadetector/postprocessing/md_to_coco.py +85 -20
- megadetector/postprocessing/postprocess_batch_results.py +0 -1
- megadetector/postprocessing/validate_batch_results.py +65 -15
- megadetector/taxonomy_mapping/map_new_lila_datasets.py +15 -12
- megadetector/taxonomy_mapping/prepare_lila_taxonomy_release.py +1 -1
- megadetector/taxonomy_mapping/preview_lila_taxonomy.py +3 -1
- megadetector/utils/ct_utils.py +71 -14
- megadetector/utils/md_tests.py +9 -1
- megadetector/utils/path_utils.py +14 -7
- megadetector/utils/process_utils.py +9 -3
- megadetector/utils/write_html_image_list.py +5 -1
- megadetector/visualization/visualization_utils.py +211 -87
- {megadetector-5.0.21.dist-info → megadetector-5.0.23.dist-info}/METADATA +19 -18
- {megadetector-5.0.21.dist-info → megadetector-5.0.23.dist-info}/RECORD +37 -36
- {megadetector-5.0.21.dist-info → megadetector-5.0.23.dist-info}/WHEEL +1 -1
- {megadetector-5.0.21.dist-info → megadetector-5.0.23.dist-info}/LICENSE +0 -0
- {megadetector-5.0.21.dist-info → megadetector-5.0.23.dist-info}/top_level.txt +0 -0
|
@@ -40,6 +40,10 @@ EXIF_IMAGE_ROTATIONS = {
|
|
|
40
40
|
|
|
41
41
|
TEXTALIGN_LEFT = 0
|
|
42
42
|
TEXTALIGN_RIGHT = 1
|
|
43
|
+
TEXTALIGN_CENTER = 2
|
|
44
|
+
|
|
45
|
+
VTEXTALIGN_TOP = 0
|
|
46
|
+
VTEXTALIGN_BOTTOM = 1
|
|
43
47
|
|
|
44
48
|
# Convert category ID from int to str
|
|
45
49
|
DEFAULT_DETECTOR_LABEL_MAP = {
|
|
@@ -413,6 +417,7 @@ def render_detection_bounding_boxes(detections,
|
|
|
413
417
|
max_classifications=3,
|
|
414
418
|
colormap=None,
|
|
415
419
|
textalign=TEXTALIGN_LEFT,
|
|
420
|
+
vtextalign=VTEXTALIGN_TOP,
|
|
416
421
|
label_font_size=DEFAULT_LABEL_FONT_SIZE,
|
|
417
422
|
custom_strings=None):
|
|
418
423
|
"""
|
|
@@ -469,37 +474,27 @@ def render_detection_bounding_boxes(detections,
|
|
|
469
474
|
]
|
|
470
475
|
|
|
471
476
|
image (PIL.Image.Image): image on which we should render detections
|
|
472
|
-
|
|
473
477
|
label_map (dict, optional): optional, mapping the numeric label to a string name. The type of the
|
|
474
478
|
numeric label (typically strings) needs to be consistent with the keys in label_map; no casting is
|
|
475
479
|
carried out. If [label_map] is None, no labels are shown (not even numbers and confidence values).
|
|
476
480
|
If you want category numbers and confidence values without class labels, use the default value,
|
|
477
481
|
the string 'show_categories'.
|
|
478
|
-
|
|
479
482
|
classification_label_map (dict, optional): optional, mapping of the string class labels to the actual
|
|
480
483
|
class names. The type of the numeric label (typically strings) needs to be consistent with the keys
|
|
481
484
|
in label_map; no casting is carried out. If [label_map] is None, no labels are shown (not even numbers
|
|
482
485
|
and confidence values).
|
|
483
|
-
|
|
484
486
|
confidence_threshold (float or dict, optional), threshold above which boxes are rendered. Can also be a
|
|
485
|
-
dictionary mapping category IDs to thresholds.
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
expansion (int, optional): number of pixels to expand bounding boxes on each side
|
|
490
|
-
|
|
487
|
+
dictionary mapping category IDs to thresholds.
|
|
488
|
+
thickness (int, optional): line thickness in pixels
|
|
489
|
+
expansion (int, optional): number of pixels to expand bounding boxes on each side
|
|
491
490
|
classification_confidence_threshold (float, optional): confidence above which classification results
|
|
492
|
-
are displayed
|
|
493
|
-
|
|
494
|
-
max_classifications (int, optional): maximum number of classification results rendered for one image
|
|
495
|
-
|
|
491
|
+
are displayed
|
|
492
|
+
max_classifications (int, optional): maximum number of classification results rendered for one image
|
|
496
493
|
colormap (list, optional): list of color names, used to choose colors for categories by
|
|
497
|
-
indexing with the values in [classes]; defaults to a reasonable set of colors
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
label_font_size (float, optional): font size for labels
|
|
502
|
-
|
|
494
|
+
indexing with the values in [classes]; defaults to a reasonable set of colors
|
|
495
|
+
textalign (int, optional): TEXTALIGN_LEFT, TEXTALIGN_CENTER, or TEXTALIGN_RIGHT
|
|
496
|
+
vtextalign (int, optional): VTEXTALIGN_TOP or VTEXTALIGN_BOTTOM
|
|
497
|
+
label_font_size (float, optional): font size for labels
|
|
503
498
|
custom_strings: optional set of strings to append to detection labels, should have the
|
|
504
499
|
same length as [detections]. Appended before any classification labels.
|
|
505
500
|
"""
|
|
@@ -613,7 +608,8 @@ def render_detection_bounding_boxes(detections,
|
|
|
613
608
|
|
|
614
609
|
draw_bounding_boxes_on_image(image, display_boxes, classes,
|
|
615
610
|
display_strs=display_strs, thickness=thickness,
|
|
616
|
-
expansion=expansion, colormap=colormap,
|
|
611
|
+
expansion=expansion, colormap=colormap,
|
|
612
|
+
textalign=textalign, vtextalign=vtextalign,
|
|
617
613
|
label_font_size=label_font_size)
|
|
618
614
|
|
|
619
615
|
# ...render_detection_bounding_boxes(...)
|
|
@@ -627,6 +623,8 @@ def draw_bounding_boxes_on_image(image,
|
|
|
627
623
|
display_strs=None,
|
|
628
624
|
colormap=None,
|
|
629
625
|
textalign=TEXTALIGN_LEFT,
|
|
626
|
+
vtextalign=VTEXTALIGN_TOP,
|
|
627
|
+
text_rotation=None,
|
|
630
628
|
label_font_size=DEFAULT_LABEL_FONT_SIZE):
|
|
631
629
|
"""
|
|
632
630
|
Draws bounding boxes on an image. Modifies the image in place.
|
|
@@ -647,7 +645,9 @@ def draw_bounding_boxes_on_image(image,
|
|
|
647
645
|
or classification categories and/or confidence values.
|
|
648
646
|
colormap (list, optional): list of color names, used to choose colors for categories by
|
|
649
647
|
indexing with the values in [classes]; defaults to a reasonable set of colors
|
|
650
|
-
textalign (int, optional): TEXTALIGN_LEFT or TEXTALIGN_RIGHT
|
|
648
|
+
textalign (int, optional): TEXTALIGN_LEFT, TEXTALIGN_CENTER, or TEXTALIGN_RIGHT
|
|
649
|
+
vtextalign (int, optional): VTEXTALIGN_TOP or VTEXTALIGN_BOTTOM
|
|
650
|
+
text_rotation (float, optional): rotation to apply to text
|
|
651
651
|
label_font_size (float, optional): font size for labels
|
|
652
652
|
"""
|
|
653
653
|
|
|
@@ -655,19 +655,21 @@ def draw_bounding_boxes_on_image(image,
|
|
|
655
655
|
if not boxes_shape:
|
|
656
656
|
return
|
|
657
657
|
if len(boxes_shape) != 2 or boxes_shape[1] != 4:
|
|
658
|
-
|
|
659
|
-
return # no object detection on this image, return
|
|
658
|
+
return
|
|
660
659
|
for i in range(boxes_shape[0]):
|
|
660
|
+
display_str_list = None
|
|
661
661
|
if display_strs:
|
|
662
662
|
display_str_list = display_strs[i]
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
663
|
+
draw_bounding_box_on_image(image,
|
|
664
|
+
boxes[i, 0], boxes[i, 1], boxes[i, 2], boxes[i, 3],
|
|
665
|
+
classes[i],
|
|
666
|
+
thickness=thickness, expansion=expansion,
|
|
667
|
+
display_str_list=display_str_list,
|
|
668
|
+
colormap=colormap,
|
|
669
|
+
textalign=textalign,
|
|
670
|
+
vtextalign=vtextalign,
|
|
671
|
+
text_rotation=text_rotation,
|
|
672
|
+
label_font_size=label_font_size)
|
|
671
673
|
|
|
672
674
|
# ...draw_bounding_boxes_on_image(...)
|
|
673
675
|
|
|
@@ -682,7 +684,7 @@ def get_text_size(font,s):
|
|
|
682
684
|
s (str): the string whose size we should query
|
|
683
685
|
|
|
684
686
|
Returns:
|
|
685
|
-
tuple: (w,h), both floats in pixel
|
|
687
|
+
tuple: (w,h), both floats in pixel coordinates
|
|
686
688
|
"""
|
|
687
689
|
|
|
688
690
|
# This is what we did w/Pillow 9
|
|
@@ -714,7 +716,9 @@ def draw_bounding_box_on_image(image,
|
|
|
714
716
|
use_normalized_coordinates=True,
|
|
715
717
|
label_font_size=DEFAULT_LABEL_FONT_SIZE,
|
|
716
718
|
colormap=None,
|
|
717
|
-
textalign=TEXTALIGN_LEFT
|
|
719
|
+
textalign=TEXTALIGN_LEFT,
|
|
720
|
+
vtextalign=VTEXTALIGN_TOP,
|
|
721
|
+
text_rotation=None):
|
|
718
722
|
"""
|
|
719
723
|
Adds a bounding box to an image. Modifies the image in place.
|
|
720
724
|
|
|
@@ -747,7 +751,9 @@ def draw_bounding_box_on_image(image,
|
|
|
747
751
|
label_font_size (float, optional): font size
|
|
748
752
|
colormap (list, optional): list of color names, used to choose colors for categories by
|
|
749
753
|
indexing with the values in [classes]; defaults to a reasonable set of colors
|
|
750
|
-
textalign (int, optional): TEXTALIGN_LEFT or TEXTALIGN_RIGHT
|
|
754
|
+
textalign (int, optional): TEXTALIGN_LEFT, TEXTALIGN_CENTER, or TEXTALIGN_RIGHT
|
|
755
|
+
vtextalign (int, optional): VTEXTALIGN_TOP or VTEXTALIGN_BOTTOM
|
|
756
|
+
text_rotation (float, optional): rotation to apply to text
|
|
751
757
|
"""
|
|
752
758
|
|
|
753
759
|
if colormap is None:
|
|
@@ -798,53 +804,98 @@ def draw_bounding_box_on_image(image,
|
|
|
798
804
|
draw.line([(left, top), (left, bottom), (right, bottom),
|
|
799
805
|
(right, top), (left, top)], width=thickness, fill=color)
|
|
800
806
|
|
|
801
|
-
|
|
802
|
-
font = ImageFont.truetype('arial.ttf', label_font_size)
|
|
803
|
-
except IOError:
|
|
804
|
-
font = ImageFont.load_default()
|
|
805
|
-
|
|
806
|
-
# If the total height of the display strings added to the top of the bounding
|
|
807
|
-
# box exceeds the top of the image, stack the strings below the bounding box
|
|
808
|
-
# instead of above.
|
|
809
|
-
display_str_heights = [get_text_size(font,ds)[1] for ds in display_str_list]
|
|
810
|
-
|
|
811
|
-
# Each display_str has a top and bottom margin of 0.05x.
|
|
812
|
-
total_display_str_height = (1 + 2 * 0.05) * sum(display_str_heights)
|
|
813
|
-
|
|
814
|
-
if top > total_display_str_height:
|
|
815
|
-
text_bottom = top
|
|
816
|
-
else:
|
|
817
|
-
text_bottom = bottom + total_display_str_height
|
|
818
|
-
|
|
819
|
-
# Reverse list and print from bottom to top.
|
|
820
|
-
for display_str in display_str_list[::-1]:
|
|
807
|
+
if display_str_list is not None:
|
|
821
808
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
809
|
+
try:
|
|
810
|
+
font = ImageFont.truetype('arial.ttf', label_font_size)
|
|
811
|
+
except IOError:
|
|
812
|
+
font = ImageFont.load_default()
|
|
813
|
+
|
|
814
|
+
display_str_heights = [get_text_size(font,ds)[1] for ds in display_str_list]
|
|
815
|
+
|
|
816
|
+
# Each display_str has a top and bottom margin of 0.05x.
|
|
817
|
+
total_display_str_height = (1 + 2 * 0.05) * sum(display_str_heights)
|
|
818
|
+
|
|
819
|
+
# Reverse list and print from bottom to top
|
|
820
|
+
for i_str,display_str in enumerate(display_str_list[::-1]):
|
|
821
|
+
|
|
822
|
+
# Skip empty strings
|
|
823
|
+
if len(display_str) == 0:
|
|
824
|
+
continue
|
|
832
825
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
826
|
+
text_width, text_height = get_text_size(font,display_str)
|
|
827
|
+
margin = int(np.ceil(0.05 * text_height))
|
|
828
|
+
|
|
829
|
+
if text_rotation is not None and text_rotation != 0:
|
|
830
|
+
|
|
831
|
+
assert text_rotation == -90, \
|
|
832
|
+
'Only -90-degree text rotation is supported'
|
|
833
|
+
|
|
834
|
+
image_tmp = Image.new('RGB',(text_width+2*margin,text_height+2*margin))
|
|
835
|
+
image_tmp_draw = ImageDraw.Draw(image_tmp)
|
|
836
|
+
image_tmp_draw.rectangle([0,0,text_width+2*margin,text_height+2*margin],fill=color)
|
|
837
|
+
image_tmp_draw.text( (margin,margin), display_str, font=font, fill='black')
|
|
838
|
+
rotated_text = image_tmp.rotate(text_rotation,expand=1)
|
|
839
|
+
|
|
840
|
+
if textalign == TEXTALIGN_RIGHT:
|
|
841
|
+
text_left = right
|
|
842
|
+
else:
|
|
843
|
+
text_left = left
|
|
844
|
+
text_left = int(text_left + (text_height) * i_str)
|
|
845
|
+
|
|
846
|
+
if vtextalign == VTEXTALIGN_BOTTOM:
|
|
847
|
+
text_top = bottom - text_width
|
|
848
|
+
else:
|
|
849
|
+
text_top = top
|
|
850
|
+
text_left = int(text_left)
|
|
851
|
+
text_top = int(text_top)
|
|
852
|
+
|
|
853
|
+
image.paste(rotated_text,[text_left,text_top])
|
|
854
|
+
|
|
855
|
+
else:
|
|
856
|
+
|
|
857
|
+
# If the total height of the display strings added to the top of the bounding
|
|
858
|
+
# box exceeds the top of the image, stack the strings below the bounding box
|
|
859
|
+
# instead of above, and vice-versa if we're bottom-aligning.
|
|
860
|
+
#
|
|
861
|
+
# If the text just doesn't fit outside the box, we don't try anything fancy,
|
|
862
|
+
# it will just appear outside the image.
|
|
863
|
+
if vtextalign == VTEXTALIGN_TOP:
|
|
864
|
+
text_bottom = top
|
|
865
|
+
if (text_bottom - total_display_str_height) < 0:
|
|
866
|
+
text_bottom = bottom + total_display_str_height
|
|
867
|
+
else:
|
|
868
|
+
assert vtextalign == VTEXTALIGN_BOTTOM, \
|
|
869
|
+
'Unrecognized vertical text alignment {}'.format(vtextalign)
|
|
870
|
+
text_bottom = bottom + total_display_str_height
|
|
871
|
+
if (text_bottom + total_display_str_height) > im_height:
|
|
872
|
+
text_bottom = top
|
|
873
|
+
|
|
874
|
+
text_bottom = int(text_bottom) - i_str * (int(text_height + (2 * margin)))
|
|
875
|
+
|
|
876
|
+
text_left = left
|
|
877
|
+
|
|
878
|
+
if textalign == TEXTALIGN_RIGHT:
|
|
879
|
+
text_left = right - text_width
|
|
880
|
+
elif textalign == TEXTALIGN_CENTER:
|
|
881
|
+
text_left = ((right + left) / 2.0) - (text_width / 2.0)
|
|
882
|
+
text_left = int(text_left)
|
|
883
|
+
|
|
884
|
+
draw.rectangle(
|
|
885
|
+
[(text_left, (text_bottom - text_height) - (2 * margin)),
|
|
886
|
+
(text_left + text_width, text_bottom)],
|
|
887
|
+
fill=color)
|
|
888
|
+
|
|
889
|
+
draw.text(
|
|
890
|
+
(text_left + margin, text_bottom - text_height - margin),
|
|
891
|
+
display_str,
|
|
892
|
+
fill='black',
|
|
893
|
+
font=font)
|
|
894
|
+
|
|
895
|
+
# ...if we're rotating text
|
|
847
896
|
|
|
897
|
+
# ...if we're rendering text
|
|
898
|
+
|
|
848
899
|
# ...def draw_bounding_box_on_image(...)
|
|
849
900
|
|
|
850
901
|
|
|
@@ -897,7 +948,12 @@ def render_db_bounding_boxes(boxes,
|
|
|
897
948
|
original_size=None,
|
|
898
949
|
label_map=None,
|
|
899
950
|
thickness=DEFAULT_BOX_THICKNESS,
|
|
900
|
-
expansion=0
|
|
951
|
+
expansion=0,
|
|
952
|
+
colormap=None,
|
|
953
|
+
textalign=TEXTALIGN_LEFT,
|
|
954
|
+
vtextalign=VTEXTALIGN_TOP,
|
|
955
|
+
text_rotation=None,
|
|
956
|
+
label_font_size=DEFAULT_LABEL_FONT_SIZE):
|
|
901
957
|
"""
|
|
902
958
|
Render bounding boxes (with class labels) on an image. This is a wrapper for
|
|
903
959
|
draw_bounding_boxes_on_image, allowing the caller to operate on a resized image
|
|
@@ -919,6 +975,12 @@ def render_db_bounding_boxes(boxes,
|
|
|
919
975
|
thickness (int, optional): line width
|
|
920
976
|
expansion (int, optional): a number of pixels to include on each side of a cropped
|
|
921
977
|
detection
|
|
978
|
+
colormap (list, optional): list of color names, used to choose colors for categories by
|
|
979
|
+
indexing with the values in [classes]; defaults to a reasonable set of colors
|
|
980
|
+
textalign (int, optional): TEXTALIGN_LEFT, TEXTALIGN_CENTER, or TEXTALIGN_RIGHT
|
|
981
|
+
vtextalign (int, optional): VTEXTALIGN_TOP or VTEXTALIGN_BOTTOM
|
|
982
|
+
text_rotation (float, optional): rotation to apply to text
|
|
983
|
+
label_font_size (float, optional): font size for labels
|
|
922
984
|
"""
|
|
923
985
|
|
|
924
986
|
display_boxes = []
|
|
@@ -956,7 +1018,12 @@ def render_db_bounding_boxes(boxes,
|
|
|
956
1018
|
classes,
|
|
957
1019
|
display_strs=display_strs,
|
|
958
1020
|
thickness=thickness,
|
|
959
|
-
expansion=expansion
|
|
1021
|
+
expansion=expansion,
|
|
1022
|
+
colormap=colormap,
|
|
1023
|
+
textalign=textalign,
|
|
1024
|
+
vtextalign=vtextalign,
|
|
1025
|
+
text_rotation=text_rotation,
|
|
1026
|
+
label_font_size=label_font_size)
|
|
960
1027
|
|
|
961
1028
|
# ...def render_db_bounding_boxes(...)
|
|
962
1029
|
|
|
@@ -980,9 +1047,9 @@ def draw_bounding_boxes_on_file(input_file,
|
|
|
980
1047
|
Args:
|
|
981
1048
|
input_file (str): filename or URL to load
|
|
982
1049
|
output_file (str, optional): filename to which we should write the rendered image
|
|
983
|
-
detections (list): a list of dictionaries with keys 'conf' and '
|
|
1050
|
+
detections (list): a list of dictionaries with keys 'conf', 'bbox', and 'category';
|
|
984
1051
|
boxes are length-four arrays formatted as [x,y,w,h], normalized,
|
|
985
|
-
upper-left origin (this is the standard MD detection format)
|
|
1052
|
+
upper-left origin (this is the standard MD detection format). 'category' is a string-int.
|
|
986
1053
|
detector_label_map (dict, optional): a dict mapping category IDs to strings. If this
|
|
987
1054
|
is None, no confidence values or identifiers are shown. If this is {}, just category
|
|
988
1055
|
indices and confidence values are shown.
|
|
@@ -1422,10 +1489,10 @@ def get_image_size(im,verbose=False):
|
|
|
1422
1489
|
|
|
1423
1490
|
|
|
1424
1491
|
def parallel_get_image_sizes(filenames,
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1492
|
+
max_workers=16,
|
|
1493
|
+
use_threads=True,
|
|
1494
|
+
recursive=True,
|
|
1495
|
+
verbose=False):
|
|
1429
1496
|
"""
|
|
1430
1497
|
Retrieve image sizes for a list or folder of images
|
|
1431
1498
|
|
|
@@ -1440,7 +1507,7 @@ def parallel_get_image_sizes(filenames,
|
|
|
1440
1507
|
verbose (bool, optional): enable additional debug output
|
|
1441
1508
|
|
|
1442
1509
|
Returns:
|
|
1443
|
-
dict: a dict mapping filenames to (w,h) tuples;
|
|
1510
|
+
dict: a dict mapping filenames to (w,h) tuples; the value will be None for images that fail
|
|
1444
1511
|
to load.
|
|
1445
1512
|
"""
|
|
1446
1513
|
|
|
@@ -1630,6 +1697,63 @@ def parallel_check_image_integrity(filenames,
|
|
|
1630
1697
|
|
|
1631
1698
|
if False:
|
|
1632
1699
|
|
|
1700
|
+
#%% Text rendering tests
|
|
1701
|
+
|
|
1702
|
+
import os # noqa
|
|
1703
|
+
import numpy as np # noqa
|
|
1704
|
+
from megadetector.visualization.visualization_utils import \
|
|
1705
|
+
draw_bounding_boxes_on_image, exif_preserving_save, load_image, \
|
|
1706
|
+
TEXTALIGN_LEFT,TEXTALIGN_RIGHT,VTEXTALIGN_BOTTOM,VTEXTALIGN_TOP, \
|
|
1707
|
+
DEFAULT_LABEL_FONT_SIZE
|
|
1708
|
+
|
|
1709
|
+
fn = os.path.expanduser('~\AppData\Local\Temp\md-tests\md-test-images\ena24_7904.jpg')
|
|
1710
|
+
output_fn = r'g:\temp\test.jpg'
|
|
1711
|
+
|
|
1712
|
+
image = load_image(fn)
|
|
1713
|
+
|
|
1714
|
+
w = 0.2; h = 0.2
|
|
1715
|
+
all_boxes = [[0.05, 0.05, 0.25, 0.25],
|
|
1716
|
+
[0.05, 0.35, 0.25, 0.6],
|
|
1717
|
+
[0.35, 0.05, 0.6, 0.25],
|
|
1718
|
+
[0.35, 0.35, 0.6, 0.6]]
|
|
1719
|
+
|
|
1720
|
+
alignments = [
|
|
1721
|
+
[TEXTALIGN_LEFT,VTEXTALIGN_TOP],
|
|
1722
|
+
[TEXTALIGN_LEFT,VTEXTALIGN_BOTTOM],
|
|
1723
|
+
[TEXTALIGN_RIGHT,VTEXTALIGN_TOP],
|
|
1724
|
+
[TEXTALIGN_RIGHT,VTEXTALIGN_BOTTOM]
|
|
1725
|
+
]
|
|
1726
|
+
|
|
1727
|
+
labels = ['left_top','left_bottom','right_top','right_bottom']
|
|
1728
|
+
|
|
1729
|
+
text_rotation = -90
|
|
1730
|
+
n_label_copies = 2
|
|
1731
|
+
|
|
1732
|
+
for i_box,box in enumerate(all_boxes):
|
|
1733
|
+
|
|
1734
|
+
boxes = [box]
|
|
1735
|
+
boxes = np.array(boxes)
|
|
1736
|
+
classes = [i_box]
|
|
1737
|
+
display_strs = [[labels[i_box]]*n_label_copies]
|
|
1738
|
+
textalign = alignments[i_box][0]
|
|
1739
|
+
vtextalign = alignments[i_box][1]
|
|
1740
|
+
draw_bounding_boxes_on_image(image,
|
|
1741
|
+
boxes,
|
|
1742
|
+
classes,
|
|
1743
|
+
thickness=2,
|
|
1744
|
+
expansion=0,
|
|
1745
|
+
display_strs=display_strs,
|
|
1746
|
+
colormap=None,
|
|
1747
|
+
textalign=textalign,
|
|
1748
|
+
vtextalign=vtextalign,
|
|
1749
|
+
label_font_size=DEFAULT_LABEL_FONT_SIZE,
|
|
1750
|
+
text_rotation=text_rotation)
|
|
1751
|
+
|
|
1752
|
+
exif_preserving_save(image,output_fn)
|
|
1753
|
+
from megadetector.utils.path_utils import open_file
|
|
1754
|
+
open_file(output_fn)
|
|
1755
|
+
|
|
1756
|
+
|
|
1633
1757
|
#%% Recursive resize test
|
|
1634
1758
|
|
|
1635
1759
|
from megadetector.visualization.visualization_utils import resize_image_folder # noqa
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: megadetector
|
|
3
|
-
Version: 5.0.
|
|
3
|
+
Version: 5.0.23
|
|
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>
|
|
7
|
-
License:
|
|
7
|
+
License: MIT License
|
|
8
8
|
|
|
9
9
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
10
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -32,23 +32,24 @@ Keywords: camera traps,conservation,wildlife,ai,megadetector
|
|
|
32
32
|
Classifier: Development Status :: 3 - Alpha
|
|
33
33
|
Classifier: License :: OSI Approved :: MIT License
|
|
34
34
|
Classifier: Programming Language :: Python :: 3
|
|
35
|
-
Requires-Python:
|
|
35
|
+
Requires-Python: <=3.13,>=3.9
|
|
36
36
|
Description-Content-Type: text/markdown
|
|
37
37
|
License-File: LICENSE
|
|
38
|
-
Requires-Dist: Pillow
|
|
39
|
-
Requires-Dist: tqdm
|
|
40
|
-
Requires-Dist: jsonpickle
|
|
41
|
-
Requires-Dist: humanfriendly
|
|
42
|
-
Requires-Dist: numpy
|
|
43
|
-
Requires-Dist: matplotlib
|
|
44
|
-
Requires-Dist: opencv-python
|
|
45
|
-
Requires-Dist: requests
|
|
46
|
-
Requires-Dist: pyqtree
|
|
47
|
-
Requires-Dist: seaborn
|
|
48
|
-
Requires-Dist: scikit-learn
|
|
49
|
-
Requires-Dist: pandas
|
|
50
|
-
Requires-Dist: PyYAML
|
|
51
|
-
Requires-Dist: ultralytics-yolov5
|
|
38
|
+
Requires-Dist: Pillow>=9.5
|
|
39
|
+
Requires-Dist: tqdm>=4.64.0
|
|
40
|
+
Requires-Dist: jsonpickle>=3.0.2
|
|
41
|
+
Requires-Dist: humanfriendly>=10.0
|
|
42
|
+
Requires-Dist: numpy<2.0,>=1.26.4
|
|
43
|
+
Requires-Dist: matplotlib>=3.8.0
|
|
44
|
+
Requires-Dist: opencv-python>=4.8.0
|
|
45
|
+
Requires-Dist: requests>=2.31.0
|
|
46
|
+
Requires-Dist: pyqtree>=1.0.0
|
|
47
|
+
Requires-Dist: seaborn>=0.12.2
|
|
48
|
+
Requires-Dist: scikit-learn>=1.3.1
|
|
49
|
+
Requires-Dist: pandas>=2.1.1
|
|
50
|
+
Requires-Dist: PyYAML>=6.0.1
|
|
51
|
+
Requires-Dist: ultralytics-yolov5==0.1.1
|
|
52
|
+
Requires-Dist: python-dateutil
|
|
52
53
|
|
|
53
54
|
# MegaDetector
|
|
54
55
|
|