megadetector 5.0.5__py3-none-any.whl → 5.0.7__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.
- api/batch_processing/data_preparation/manage_local_batch.py +302 -263
- api/batch_processing/data_preparation/manage_video_batch.py +81 -2
- api/batch_processing/postprocessing/add_max_conf.py +1 -0
- api/batch_processing/postprocessing/categorize_detections_by_size.py +50 -19
- api/batch_processing/postprocessing/compare_batch_results.py +110 -60
- api/batch_processing/postprocessing/load_api_results.py +56 -70
- api/batch_processing/postprocessing/md_to_coco.py +1 -1
- api/batch_processing/postprocessing/md_to_labelme.py +2 -1
- api/batch_processing/postprocessing/postprocess_batch_results.py +240 -81
- api/batch_processing/postprocessing/render_detection_confusion_matrix.py +625 -0
- api/batch_processing/postprocessing/repeat_detection_elimination/find_repeat_detections.py +71 -23
- api/batch_processing/postprocessing/repeat_detection_elimination/remove_repeat_detections.py +1 -1
- api/batch_processing/postprocessing/repeat_detection_elimination/repeat_detections_core.py +227 -75
- api/batch_processing/postprocessing/subset_json_detector_output.py +132 -5
- api/batch_processing/postprocessing/top_folders_to_bottom.py +1 -1
- api/synchronous/api_core/animal_detection_api/detection/run_detector_batch.py +2 -2
- classification/prepare_classification_script.py +191 -191
- data_management/coco_to_yolo.py +68 -45
- data_management/databases/integrity_check_json_db.py +7 -5
- data_management/generate_crops_from_cct.py +3 -3
- data_management/get_image_sizes.py +8 -6
- data_management/importers/add_timestamps_to_icct.py +79 -0
- data_management/importers/animl_results_to_md_results.py +160 -0
- data_management/importers/auckland_doc_test_to_json.py +4 -4
- data_management/importers/auckland_doc_to_json.py +1 -1
- data_management/importers/awc_to_json.py +5 -5
- data_management/importers/bellevue_to_json.py +5 -5
- data_management/importers/carrizo_shrubfree_2018.py +5 -5
- data_management/importers/carrizo_trail_cam_2017.py +5 -5
- data_management/importers/cct_field_adjustments.py +2 -3
- data_management/importers/channel_islands_to_cct.py +4 -4
- data_management/importers/ena24_to_json.py +5 -5
- data_management/importers/helena_to_cct.py +10 -10
- data_management/importers/idaho-camera-traps.py +12 -12
- data_management/importers/idfg_iwildcam_lila_prep.py +8 -8
- data_management/importers/jb_csv_to_json.py +4 -4
- data_management/importers/missouri_to_json.py +1 -1
- data_management/importers/noaa_seals_2019.py +1 -1
- data_management/importers/pc_to_json.py +5 -5
- data_management/importers/prepare-noaa-fish-data-for-lila.py +4 -4
- data_management/importers/prepare_zsl_imerit.py +5 -5
- data_management/importers/rspb_to_json.py +4 -4
- data_management/importers/save_the_elephants_survey_A.py +5 -5
- data_management/importers/save_the_elephants_survey_B.py +6 -6
- data_management/importers/snapshot_safari_importer.py +9 -9
- data_management/importers/snapshot_serengeti_lila.py +9 -9
- data_management/importers/timelapse_csv_set_to_json.py +5 -7
- data_management/importers/ubc_to_json.py +4 -4
- data_management/importers/umn_to_json.py +4 -4
- data_management/importers/wellington_to_json.py +1 -1
- data_management/importers/wi_to_json.py +2 -2
- data_management/importers/zamba_results_to_md_results.py +181 -0
- data_management/labelme_to_coco.py +35 -7
- data_management/labelme_to_yolo.py +229 -0
- data_management/lila/add_locations_to_island_camera_traps.py +1 -1
- data_management/lila/add_locations_to_nacti.py +147 -0
- data_management/lila/create_lila_blank_set.py +474 -0
- data_management/lila/create_lila_test_set.py +2 -1
- data_management/lila/create_links_to_md_results_files.py +106 -0
- data_management/lila/download_lila_subset.py +46 -21
- data_management/lila/generate_lila_per_image_labels.py +23 -14
- data_management/lila/get_lila_annotation_counts.py +17 -11
- data_management/lila/lila_common.py +14 -11
- data_management/lila/test_lila_metadata_urls.py +116 -0
- data_management/ocr_tools.py +829 -0
- data_management/resize_coco_dataset.py +13 -11
- data_management/yolo_output_to_md_output.py +84 -12
- data_management/yolo_to_coco.py +38 -20
- detection/process_video.py +36 -14
- detection/pytorch_detector.py +23 -8
- detection/run_detector.py +76 -19
- detection/run_detector_batch.py +178 -63
- detection/run_inference_with_yolov5_val.py +326 -57
- detection/run_tiled_inference.py +153 -43
- detection/video_utils.py +34 -8
- md_utils/ct_utils.py +172 -1
- md_utils/md_tests.py +372 -51
- md_utils/path_utils.py +167 -39
- md_utils/process_utils.py +26 -7
- md_utils/split_locations_into_train_val.py +215 -0
- md_utils/string_utils.py +10 -0
- md_utils/url_utils.py +0 -2
- md_utils/write_html_image_list.py +9 -26
- md_visualization/plot_utils.py +12 -8
- md_visualization/visualization_utils.py +106 -7
- md_visualization/visualize_db.py +16 -8
- md_visualization/visualize_detector_output.py +208 -97
- {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/METADATA +3 -6
- {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/RECORD +98 -121
- {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/WHEEL +1 -1
- taxonomy_mapping/map_lila_taxonomy_to_wi_taxonomy.py +1 -1
- taxonomy_mapping/map_new_lila_datasets.py +43 -39
- taxonomy_mapping/prepare_lila_taxonomy_release.py +5 -2
- taxonomy_mapping/preview_lila_taxonomy.py +27 -27
- taxonomy_mapping/species_lookup.py +33 -13
- taxonomy_mapping/taxonomy_csv_checker.py +7 -5
- api/synchronous/api_core/yolov5/detect.py +0 -252
- api/synchronous/api_core/yolov5/export.py +0 -607
- api/synchronous/api_core/yolov5/hubconf.py +0 -146
- api/synchronous/api_core/yolov5/models/__init__.py +0 -0
- api/synchronous/api_core/yolov5/models/common.py +0 -738
- api/synchronous/api_core/yolov5/models/experimental.py +0 -104
- api/synchronous/api_core/yolov5/models/tf.py +0 -574
- api/synchronous/api_core/yolov5/models/yolo.py +0 -338
- api/synchronous/api_core/yolov5/train.py +0 -670
- api/synchronous/api_core/yolov5/utils/__init__.py +0 -36
- api/synchronous/api_core/yolov5/utils/activations.py +0 -103
- api/synchronous/api_core/yolov5/utils/augmentations.py +0 -284
- api/synchronous/api_core/yolov5/utils/autoanchor.py +0 -170
- api/synchronous/api_core/yolov5/utils/autobatch.py +0 -66
- api/synchronous/api_core/yolov5/utils/aws/__init__.py +0 -0
- api/synchronous/api_core/yolov5/utils/aws/resume.py +0 -40
- api/synchronous/api_core/yolov5/utils/benchmarks.py +0 -148
- api/synchronous/api_core/yolov5/utils/callbacks.py +0 -71
- api/synchronous/api_core/yolov5/utils/dataloaders.py +0 -1087
- api/synchronous/api_core/yolov5/utils/downloads.py +0 -178
- api/synchronous/api_core/yolov5/utils/flask_rest_api/example_request.py +0 -19
- api/synchronous/api_core/yolov5/utils/flask_rest_api/restapi.py +0 -46
- api/synchronous/api_core/yolov5/utils/general.py +0 -1018
- api/synchronous/api_core/yolov5/utils/loggers/__init__.py +0 -187
- api/synchronous/api_core/yolov5/utils/loggers/wandb/__init__.py +0 -0
- api/synchronous/api_core/yolov5/utils/loggers/wandb/log_dataset.py +0 -27
- api/synchronous/api_core/yolov5/utils/loggers/wandb/sweep.py +0 -41
- api/synchronous/api_core/yolov5/utils/loggers/wandb/wandb_utils.py +0 -577
- api/synchronous/api_core/yolov5/utils/loss.py +0 -234
- api/synchronous/api_core/yolov5/utils/metrics.py +0 -355
- api/synchronous/api_core/yolov5/utils/plots.py +0 -489
- api/synchronous/api_core/yolov5/utils/torch_utils.py +0 -314
- api/synchronous/api_core/yolov5/val.py +0 -394
- md_utils/matlab_porting_tools.py +0 -97
- {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/LICENSE +0 -0
- {megadetector-5.0.5.dist-info → megadetector-5.0.7.dist-info}/top_level.txt +0 -0
|
@@ -228,7 +228,7 @@ if False:
|
|
|
228
228
|
seq_id_to_annotations,annotations,categories,species_to_category = cct_cache
|
|
229
229
|
|
|
230
230
|
|
|
231
|
-
#%% Take a look at categories
|
|
231
|
+
#%% Take a look at categories
|
|
232
232
|
|
|
233
233
|
if False:
|
|
234
234
|
|
|
@@ -365,7 +365,7 @@ print('\nOf {} images: {} missing, {} corrupt, {} no annotation'.format(len(imag
|
|
|
365
365
|
n_missing, n_corrupt, n_no_annotation))
|
|
366
366
|
|
|
367
367
|
|
|
368
|
-
#%% Print distribution of sequence lengths
|
|
368
|
+
#%% Print distribution of sequence lengths
|
|
369
369
|
|
|
370
370
|
seq_id_to_sequence_length = {}
|
|
371
371
|
|
|
@@ -508,7 +508,7 @@ for iSeason,season_mismatches in enumerate(mismatches_by_season):
|
|
|
508
508
|
print('Size mismatches in season {}: {}'.format(iSeason+1,len(mismatches_by_season[iSeason])))
|
|
509
509
|
|
|
510
510
|
|
|
511
|
-
#%%
|
|
511
|
+
#%% Validate image and annotation uniqueness
|
|
512
512
|
|
|
513
513
|
tmp_img_ids = set()
|
|
514
514
|
tmp_ann_ids = set()
|
|
@@ -852,22 +852,22 @@ for i_season in seasons_to_zip:
|
|
|
852
852
|
# ...for each season
|
|
853
853
|
|
|
854
854
|
|
|
855
|
-
#%%
|
|
855
|
+
#%% Validate .json files
|
|
856
856
|
|
|
857
857
|
# %logstart -o r'E:\snapshot_temp\python.txt'
|
|
858
858
|
|
|
859
|
-
from data_management.databases import
|
|
859
|
+
from data_management.databases import integrity_check_json_db
|
|
860
860
|
|
|
861
861
|
files_to_check = glob.glob(os.path.join(output_base,'*.json'))
|
|
862
862
|
|
|
863
|
-
options =
|
|
863
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
864
864
|
options.baseDir = image_base
|
|
865
865
|
options.bCheckImageSizes = False
|
|
866
866
|
options.bCheckImageExistence = True
|
|
867
867
|
options.bFindUnusedImages = False
|
|
868
868
|
|
|
869
869
|
for fn in files_to_check:
|
|
870
|
-
sortedCategories, data =
|
|
870
|
+
sortedCategories, data = integrity_check_json_db.integrity_check_json_db(fn,options)
|
|
871
871
|
|
|
872
872
|
|
|
873
873
|
#%% Zip up .json and .csv files
|
|
@@ -894,7 +894,7 @@ for fn in tqdm(files_to_zip):
|
|
|
894
894
|
zip_single_file(fn)
|
|
895
895
|
|
|
896
896
|
|
|
897
|
-
#%%
|
|
897
|
+
#%% Validate that S11 info isn't leaking
|
|
898
898
|
|
|
899
899
|
files_to_check = glob.glob(os.path.join(output_base,'*.json'))
|
|
900
900
|
|
|
@@ -992,7 +992,7 @@ viz_options.num_to_visualize = 500
|
|
|
992
992
|
viz_options.trim_to_images_with_bboxes = True
|
|
993
993
|
viz_options.add_search_links = True
|
|
994
994
|
viz_options.sort_by_filename = False
|
|
995
|
-
html_output_file,bbox_db = visualize_db.
|
|
995
|
+
html_output_file,bbox_db = visualize_db.visualize_db(bbox_json_fn,os.path.join(output_base,'preview2'),image_base,viz_options)
|
|
996
996
|
os.startfile(html_output_file)
|
|
997
997
|
|
|
998
998
|
|
|
@@ -24,7 +24,7 @@ import numpy as np
|
|
|
24
24
|
from tqdm import tqdm
|
|
25
25
|
|
|
26
26
|
from md_visualization import visualize_db
|
|
27
|
-
from data_management.databases import
|
|
27
|
+
from data_management.databases import integrity_check_json_db
|
|
28
28
|
from md_utils import path_utils
|
|
29
29
|
|
|
30
30
|
# Text file with relative paths to all files (images and .csv files)
|
|
@@ -84,7 +84,6 @@ for fn in image_files:
|
|
|
84
84
|
print('Found {} image files and {} .csv files ({} non-matching files)'.format(
|
|
85
85
|
len(image_files),len(csv_files),len(non_matching_files)))
|
|
86
86
|
|
|
87
|
-
|
|
88
87
|
|
|
89
88
|
#%% Verify column consistency, create a giant array with all rows from all .csv files
|
|
90
89
|
|
|
@@ -473,10 +472,10 @@ print('Finished writing .json file with {} images, {} annotations, and {} catego
|
|
|
473
472
|
len(images),len(annotations),len(categories)))
|
|
474
473
|
|
|
475
474
|
|
|
476
|
-
#%%
|
|
475
|
+
#%% Validate the database's integrity
|
|
477
476
|
|
|
478
|
-
options =
|
|
479
|
-
sortedCategories,data =
|
|
477
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
478
|
+
sortedCategories,data = integrity_check_json_db.integrity_check_json_db(output_file, options)
|
|
480
479
|
|
|
481
480
|
|
|
482
481
|
#%% Render a bunch of images to make sure the labels got carried along correctly
|
|
@@ -487,6 +486,5 @@ options.parallelize_rendering = True
|
|
|
487
486
|
options.sort_by_filename = False
|
|
488
487
|
options.classes_to_exclude = ['unlabeled','empty','ambiguous']
|
|
489
488
|
|
|
490
|
-
html_output_file,data = visualize_db.
|
|
489
|
+
html_output_file,data = visualize_db.visualize_db(output_file,preview_base,file_base,options)
|
|
491
490
|
os.startfile(html_output_file)
|
|
492
|
-
|
|
@@ -25,7 +25,7 @@ from tqdm import tqdm
|
|
|
25
25
|
from PIL import Image
|
|
26
26
|
|
|
27
27
|
from md_visualization import visualize_db
|
|
28
|
-
from data_management.databases import
|
|
28
|
+
from data_management.databases import integrity_check_json_db
|
|
29
29
|
from md_utils.path_utils import find_images
|
|
30
30
|
|
|
31
31
|
input_base = r'e:\ubc'
|
|
@@ -373,13 +373,13 @@ print('Finished writing .json file with {} images, {} annotations, and {} catego
|
|
|
373
373
|
|
|
374
374
|
#%% Validate output
|
|
375
375
|
|
|
376
|
-
options =
|
|
376
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
377
377
|
options.baseDir = output_base
|
|
378
378
|
options.bCheckImageSizes = False
|
|
379
379
|
options.bCheckImageExistence = False
|
|
380
380
|
options.bFindUnusedImages = True
|
|
381
381
|
|
|
382
|
-
sortedCategories, data, errors =
|
|
382
|
+
sortedCategories, data, errors = integrity_check_json_db.integrity_check_json_db(
|
|
383
383
|
output_json_file, options)
|
|
384
384
|
|
|
385
385
|
|
|
@@ -391,7 +391,7 @@ viz_options.trim_to_images_with_bboxes = False
|
|
|
391
391
|
viz_options.add_search_links = True
|
|
392
392
|
viz_options.sort_by_filename = False
|
|
393
393
|
viz_options.parallelize_rendering = True
|
|
394
|
-
html_output_file, image_db = visualize_db.
|
|
394
|
+
html_output_file, image_db = visualize_db.visualize_db(db_path=output_json_file,
|
|
395
395
|
output_dir=os.path.join(
|
|
396
396
|
output_base, 'preview'),
|
|
397
397
|
image_base_dir=output_base,
|
|
@@ -292,7 +292,7 @@ import uuid
|
|
|
292
292
|
import datetime
|
|
293
293
|
from tqdm import tqdm
|
|
294
294
|
|
|
295
|
-
from data_management.databases import
|
|
295
|
+
from data_management.databases import integrity_check_json_db
|
|
296
296
|
|
|
297
297
|
output_base = 'f:\orinoquia_camera_traps'
|
|
298
298
|
output_image_base = os.path.join(output_base,'images')
|
|
@@ -431,13 +431,13 @@ print('Finished writing json to {}'.format(output_json_filename))
|
|
|
431
431
|
|
|
432
432
|
#%% Validate .json file
|
|
433
433
|
|
|
434
|
-
options =
|
|
434
|
+
options = integrity_check_json_db.IntegrityCheckOptions()
|
|
435
435
|
options.baseDir = output_base
|
|
436
436
|
options.bCheckImageSizes = False
|
|
437
437
|
options.bCheckImageExistence = False
|
|
438
438
|
options.bFindUnusedImages = False
|
|
439
439
|
|
|
440
|
-
_, _, _ =
|
|
440
|
+
_, _, _ = integrity_check_json_db.integrity_check_json_db(output_json_filename, options)
|
|
441
441
|
|
|
442
442
|
|
|
443
443
|
#%% Map relative paths to annotation categories
|
|
@@ -497,7 +497,7 @@ viz_options.parallelize_rendering = True
|
|
|
497
497
|
viz_options.include_filename_links = True
|
|
498
498
|
|
|
499
499
|
# viz_options.classes_to_exclude = ['test']
|
|
500
|
-
html_output_file, _ = visualize_db.
|
|
500
|
+
html_output_file, _ = visualize_db.visualize_db(db_path=output_json_filename,
|
|
501
501
|
output_dir=os.path.join(
|
|
502
502
|
output_base,'preview'),
|
|
503
503
|
image_base_dir=os.path.join(output_image_base,'public'),
|
|
@@ -253,7 +253,7 @@ viz_options.add_search_links = False
|
|
|
253
253
|
viz_options.sort_by_filename = False
|
|
254
254
|
viz_options.parallelize_rendering = True
|
|
255
255
|
viz_options.classes_to_exclude = ['test']
|
|
256
|
-
html_output_file, image_db = visualize_db.
|
|
256
|
+
html_output_file, image_db = visualize_db.visualize_db(db_path=output_file,
|
|
257
257
|
output_dir=os.path.join(
|
|
258
258
|
preview_dir),
|
|
259
259
|
image_base_dir=image_directory,
|
|
@@ -351,7 +351,7 @@ viz_options.sort_by_filename = False
|
|
|
351
351
|
viz_options.parallelize_rendering = True
|
|
352
352
|
viz_options.include_filename_links = True
|
|
353
353
|
|
|
354
|
-
html_output_file, _ = visualize_db.
|
|
354
|
+
html_output_file, _ = visualize_db.visualize_db(db_path=output_json_filename,
|
|
355
355
|
output_dir=preview_base,
|
|
356
356
|
image_base_dir=image_base,
|
|
357
357
|
options=viz_options)
|
|
@@ -426,7 +426,7 @@ if create_ordered_dataset:
|
|
|
426
426
|
viz_options.parallelize_rendering = True
|
|
427
427
|
viz_options.include_filename_links = True
|
|
428
428
|
|
|
429
|
-
html_output_file, _ = visualize_db.
|
|
429
|
+
html_output_file, _ = visualize_db.visualize_db(db_path=ordered_json_filename,
|
|
430
430
|
output_dir=ordered_preview_base,
|
|
431
431
|
image_base_dir=ordered_image_base,
|
|
432
432
|
options=viz_options)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
########
|
|
2
|
+
#
|
|
3
|
+
# zamba_results_to_md_results.py
|
|
4
|
+
#
|
|
5
|
+
# Convert a labels.csv file produced by Zamba Cloud to a MD results file suitable
|
|
6
|
+
# for import into Timelapse.
|
|
7
|
+
#
|
|
8
|
+
# Columns are expected to be:
|
|
9
|
+
#
|
|
10
|
+
# video_uuid (not used)
|
|
11
|
+
# original_filename (assumed to be a relative path name)
|
|
12
|
+
# top_k_label,top_k_probability, for k = 1..N
|
|
13
|
+
# [category name 1],[category name 2],...
|
|
14
|
+
# corrected_label
|
|
15
|
+
#
|
|
16
|
+
# Because the MD results file fundamentally stores detections, what we'll
|
|
17
|
+
# actually do is created bogus detections that fill the entire image. Detection
|
|
18
|
+
# coordinates are not currently used in Timelapse video video anyway.
|
|
19
|
+
#
|
|
20
|
+
# There is no special handling of empty/blank categories; because these results are
|
|
21
|
+
# based on a classifier, rather than a detector (where "blank" would be the absence of
|
|
22
|
+
# all other categories), "blank" can be queried in Timelapse just like any other class.
|
|
23
|
+
#
|
|
24
|
+
########
|
|
25
|
+
|
|
26
|
+
#%% Imports and constants
|
|
27
|
+
|
|
28
|
+
import pandas as pd
|
|
29
|
+
import json
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
#%% Main function
|
|
33
|
+
|
|
34
|
+
def zamba_results_to_md_results(input_file,output_file=None):
|
|
35
|
+
"""
|
|
36
|
+
Converts the .csv file [input_file] to the MD-formatted .json file [output_file].
|
|
37
|
+
|
|
38
|
+
If [output_file] is None, '.json' will be appended to the input file.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
if output_file is None:
|
|
42
|
+
output_file = input_file + '.json'
|
|
43
|
+
|
|
44
|
+
df = pd.read_csv(input_file)
|
|
45
|
+
|
|
46
|
+
expected_columns = ('video_uuid','corrected_label','original_filename')
|
|
47
|
+
for s in expected_columns:
|
|
48
|
+
assert s in df.columns,\
|
|
49
|
+
'Expected column {} not found, are you sure this is a Zamba results .csv file?'.format(
|
|
50
|
+
s)
|
|
51
|
+
|
|
52
|
+
# How many results are included per file?
|
|
53
|
+
assert 'top_1_probability' in df.columns and 'top_1_label' in df.columns
|
|
54
|
+
top_k = 2
|
|
55
|
+
while(True):
|
|
56
|
+
p_string = 'top_' + str(top_k) + '_probability'
|
|
57
|
+
label_string = 'top_' + str(top_k) + '_label'
|
|
58
|
+
|
|
59
|
+
if p_string in df.columns:
|
|
60
|
+
assert label_string in df.columns,\
|
|
61
|
+
'Oops, {} is a column but {} is not'.format(
|
|
62
|
+
p_string,label_string)
|
|
63
|
+
top_k += 1
|
|
64
|
+
continue
|
|
65
|
+
else:
|
|
66
|
+
assert label_string not in df.columns,\
|
|
67
|
+
'Oops, {} is a column but {} is not'.format(
|
|
68
|
+
label_string,p_string)
|
|
69
|
+
top_k -= 1
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
print('Found {} probability column pairs'.format(top_k))
|
|
73
|
+
|
|
74
|
+
# Category names start after the fixed columns and the probability columns
|
|
75
|
+
category_names = []
|
|
76
|
+
column_names = list(df.columns)
|
|
77
|
+
first_category_name_index = 0
|
|
78
|
+
while('top_' in column_names[first_category_name_index] or \
|
|
79
|
+
column_names[first_category_name_index] in expected_columns):
|
|
80
|
+
first_category_name_index += 1
|
|
81
|
+
|
|
82
|
+
i_column = first_category_name_index
|
|
83
|
+
while( (i_column < len(column_names)) and (column_names[i_column] != 'corrected_label') ):
|
|
84
|
+
category_names.append(column_names[i_column])
|
|
85
|
+
i_column += 1
|
|
86
|
+
|
|
87
|
+
print('Found {} categories:\n'.format(len(category_names)))
|
|
88
|
+
|
|
89
|
+
for s in category_names:
|
|
90
|
+
print(s)
|
|
91
|
+
|
|
92
|
+
info = {}
|
|
93
|
+
info['format_version'] = '1.3'
|
|
94
|
+
info['detector'] = 'Zamba Cloud'
|
|
95
|
+
info['classifier'] = 'Zamba Cloud'
|
|
96
|
+
|
|
97
|
+
detection_category_id_to_name = {}
|
|
98
|
+
for category_id,category_name in enumerate(category_names):
|
|
99
|
+
detection_category_id_to_name[str(category_id)] = category_name
|
|
100
|
+
detection_category_name_to_id = {v: k for k, v in detection_category_id_to_name.items()}
|
|
101
|
+
|
|
102
|
+
images = []
|
|
103
|
+
|
|
104
|
+
# i_row = 0; row = df.iloc[i_row]
|
|
105
|
+
for i_row,row in df.iterrows():
|
|
106
|
+
|
|
107
|
+
im = {}
|
|
108
|
+
images.append(im)
|
|
109
|
+
im['file'] = row['original_filename']
|
|
110
|
+
|
|
111
|
+
detections = []
|
|
112
|
+
|
|
113
|
+
# k = 1
|
|
114
|
+
for k in range(1,top_k+1):
|
|
115
|
+
label = row['top_{}_label'.format(k)]
|
|
116
|
+
confidence = row['top_{}_probability'.format(k)]
|
|
117
|
+
det = {}
|
|
118
|
+
det['category'] = detection_category_name_to_id[label]
|
|
119
|
+
det['conf'] = confidence
|
|
120
|
+
det['bbox'] = [0,0,1.0,1.0]
|
|
121
|
+
detections.append(det)
|
|
122
|
+
|
|
123
|
+
im['detections'] = detections
|
|
124
|
+
|
|
125
|
+
# ...for each row
|
|
126
|
+
|
|
127
|
+
results = {}
|
|
128
|
+
results['info'] = info
|
|
129
|
+
results['detection_categories'] = detection_category_id_to_name
|
|
130
|
+
results['images'] = images
|
|
131
|
+
|
|
132
|
+
with open(output_file,'w') as f:
|
|
133
|
+
json.dump(results,f,indent=1)
|
|
134
|
+
|
|
135
|
+
# ...zamba_results_to_md_results(...)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
#%% Interactive driver
|
|
139
|
+
|
|
140
|
+
if False:
|
|
141
|
+
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
#%%
|
|
145
|
+
|
|
146
|
+
input_file = r"G:\temp\labels-job-b95a4b76-e332-4e17-ab40-03469392d36a-2023-11-04_16-28-50.060130.csv"
|
|
147
|
+
output_file = None
|
|
148
|
+
zamba_results_to_md_results(input_file,output_file)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
#%% Command-line driver
|
|
152
|
+
|
|
153
|
+
import sys,argparse
|
|
154
|
+
|
|
155
|
+
def main():
|
|
156
|
+
|
|
157
|
+
parser = argparse.ArgumentParser(
|
|
158
|
+
description='Convert a Zamba-formatted .csv results file to a MD-formatted .json results file')
|
|
159
|
+
|
|
160
|
+
parser.add_argument(
|
|
161
|
+
'input_file',
|
|
162
|
+
type=str,
|
|
163
|
+
help='input .csv file')
|
|
164
|
+
|
|
165
|
+
parser.add_argument(
|
|
166
|
+
'--output_file',
|
|
167
|
+
type=str,
|
|
168
|
+
default=None,
|
|
169
|
+
help='output .json file (defaults to input file appended with ".json")')
|
|
170
|
+
|
|
171
|
+
if len(sys.argv[1:]) == 0:
|
|
172
|
+
parser.print_help()
|
|
173
|
+
parser.exit()
|
|
174
|
+
|
|
175
|
+
args = parser.parse_args()
|
|
176
|
+
|
|
177
|
+
zamba_results_to_md_results(args.input_file,args.output_file)
|
|
178
|
+
|
|
179
|
+
if __name__ == '__main__':
|
|
180
|
+
main()
|
|
181
|
+
|
|
@@ -20,11 +20,19 @@ from tqdm import tqdm
|
|
|
20
20
|
|
|
21
21
|
#%% Functions
|
|
22
22
|
|
|
23
|
-
def labelme_to_coco(input_folder,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
def labelme_to_coco(input_folder,
|
|
24
|
+
output_file=None,
|
|
25
|
+
category_id_to_category_name=None,
|
|
26
|
+
empty_category_name='empty',
|
|
27
|
+
empty_category_id=None,
|
|
28
|
+
info_struct=None,
|
|
29
|
+
relative_paths_to_include=None,
|
|
30
|
+
relative_paths_to_exclude=None,
|
|
31
|
+
use_folders_as_labels=False,
|
|
32
|
+
recursive=True,
|
|
33
|
+
no_json_handling='skip',
|
|
34
|
+
validate_image_sizes=True,
|
|
35
|
+
right_edge_quantization_threshold=None):
|
|
28
36
|
"""
|
|
29
37
|
Find all images in [input_folder] that have corresponding .json files, and convert
|
|
30
38
|
to a COCO .json file.
|
|
@@ -48,7 +56,13 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
|
|
|
48
56
|
|
|
49
57
|
* 'skip': ignore image files with no corresponding .json files
|
|
50
58
|
* 'empty': treat image files with no corresponding .json files as empty
|
|
51
|
-
* 'error': throw an error when an image file has no corresponding .json file
|
|
59
|
+
* 'error': throw an error when an image file has no corresponding .json file
|
|
60
|
+
|
|
61
|
+
right_edge_quantization_threshold is an off-by-default hack to handle cases where
|
|
62
|
+
boxes that really should be running off the right side of the image only extend like 99%
|
|
63
|
+
of the way there, due to what appears to be a slight bias inherent to MD. If a box extends
|
|
64
|
+
within [right_edge_quantization_threshold] (a small number, from 0 to 1, but probably around
|
|
65
|
+
0.02) of the right edge of the image, it will be extended to the far right edge.
|
|
52
66
|
"""
|
|
53
67
|
|
|
54
68
|
if category_id_to_category_name is None:
|
|
@@ -86,6 +100,8 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
|
|
|
86
100
|
images = []
|
|
87
101
|
annotations = []
|
|
88
102
|
|
|
103
|
+
n_edges_quantized = 0
|
|
104
|
+
|
|
89
105
|
# image_fn_relative = image_filenames_relative[0]
|
|
90
106
|
for image_fn_relative in tqdm(image_filenames_relative):
|
|
91
107
|
|
|
@@ -182,6 +198,14 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
|
|
|
182
198
|
x1 = max(p0[0],p1[0])
|
|
183
199
|
y0 = min(p0[1],p1[1])
|
|
184
200
|
y1 = max(p0[1],p1[1])
|
|
201
|
+
|
|
202
|
+
if right_edge_quantization_threshold is not None:
|
|
203
|
+
x1_rel = x1 / (im['width'] - 1)
|
|
204
|
+
right_edge_distance = 1.0 - x1_rel
|
|
205
|
+
if right_edge_distance < right_edge_quantization_threshold:
|
|
206
|
+
n_edges_quantized += 1
|
|
207
|
+
x1 = im['width'] - 1
|
|
208
|
+
|
|
185
209
|
bbox = [x0,y0,abs(x1-x0),abs(y1-y0)]
|
|
186
210
|
ann = {}
|
|
187
211
|
ann['id'] = str(uuid.uuid1())
|
|
@@ -197,6 +221,10 @@ def labelme_to_coco(input_folder,output_file=None,category_id_to_category_name=N
|
|
|
197
221
|
|
|
198
222
|
# ..for each image
|
|
199
223
|
|
|
224
|
+
if n_edges_quantized > 0:
|
|
225
|
+
print('Quantized the right edge in {} of {} images'.format(
|
|
226
|
+
n_edges_quantized,len(image_filenames_relative)))
|
|
227
|
+
|
|
200
228
|
output_dict = {}
|
|
201
229
|
output_dict['images'] = images
|
|
202
230
|
output_dict['annotations'] = annotations
|
|
@@ -324,7 +352,7 @@ if False:
|
|
|
324
352
|
options.viz_size = (900, -1)
|
|
325
353
|
options.num_to_visualize = 5000
|
|
326
354
|
|
|
327
|
-
html_file,_ = visualize_db.
|
|
355
|
+
html_file,_ = visualize_db.visualize_db(output_file,os.path.expanduser('~/tmp/labelme_to_coco_preview'),
|
|
328
356
|
input_folder,options)
|
|
329
357
|
|
|
330
358
|
|