megadetector 10.0.15__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.
- 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 +701 -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 +563 -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 +192 -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 +665 -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 +984 -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 +2172 -0
- megadetector/detection/run_inference_with_yolov5_val.py +1314 -0
- megadetector/detection/run_md_and_speciesnet.py +1604 -0
- megadetector/detection/run_tiled_inference.py +1044 -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 +1943 -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 +2140 -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 +211 -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 +231 -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 +2872 -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 +1766 -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 +1973 -0
- megadetector/visualization/visualize_db.py +630 -0
- megadetector/visualization/visualize_detector_output.py +498 -0
- megadetector/visualization/visualize_video_output.py +705 -0
- megadetector-10.0.15.dist-info/METADATA +115 -0
- megadetector-10.0.15.dist-info/RECORD +147 -0
- megadetector-10.0.15.dist-info/WHEEL +5 -0
- megadetector-10.0.15.dist-info/licenses/LICENSE +19 -0
- megadetector-10.0.15.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
add_width_and_height_to_db.py
|
|
4
|
+
|
|
5
|
+
Grabs width and height from actual image files for a .json database that is missing w/h.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
#%% Imports and constants
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import sys
|
|
13
|
+
import json
|
|
14
|
+
import argparse
|
|
15
|
+
|
|
16
|
+
from tqdm import tqdm
|
|
17
|
+
from PIL import Image
|
|
18
|
+
|
|
19
|
+
from megadetector.utils import ct_utils
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
#%% Main resizing function
|
|
23
|
+
|
|
24
|
+
def add_width_and_height_to_db(input_file,output_file,image_base_folder):
|
|
25
|
+
"""
|
|
26
|
+
Add width and height to images in the COCO db [input_file]
|
|
27
|
+
that don't have non-None w/h values. Does not verify correctness
|
|
28
|
+
for images that already have non-None w/h values. Ignores files that
|
|
29
|
+
fail to open.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
input_file (str): the COCO .json file to process
|
|
33
|
+
output_file (str): the COCO .json file to write
|
|
34
|
+
image_base_folder (str): image filenames in [input_file] should be relative
|
|
35
|
+
to this folder
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
list: the list of image dicts that were modified
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
with open(input_file,'r') as f:
|
|
42
|
+
d = json.load(f)
|
|
43
|
+
|
|
44
|
+
to_return = []
|
|
45
|
+
|
|
46
|
+
for im in tqdm(d['images']):
|
|
47
|
+
|
|
48
|
+
if ('height' not in im) or ('width' not in im) or \
|
|
49
|
+
(im['height'] is None) or (im['width'] is None) or \
|
|
50
|
+
(im['height'] <= 0) or (im['width'] <= 0):
|
|
51
|
+
|
|
52
|
+
fn_relative = im['file_name']
|
|
53
|
+
fn_abs = os.path.join(image_base_folder,fn_relative)
|
|
54
|
+
|
|
55
|
+
if not os.path.isfile(fn_abs):
|
|
56
|
+
print('Could not find image file {}'.format(fn_abs))
|
|
57
|
+
continue
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
im_w, im_h = Image.open(fn_abs).size
|
|
61
|
+
except Exception as e:
|
|
62
|
+
print('Error opening file {}: {}'.format(fn_abs,str(e)))
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
assert isinstance(im_w,int) and isinstance(im_h,int) and \
|
|
66
|
+
im_w > 0 and im_h > 0, \
|
|
67
|
+
'Illegal size retrieved for {}'.format(fn_abs)
|
|
68
|
+
|
|
69
|
+
im['height'] = im_h
|
|
70
|
+
im['width'] = im_w
|
|
71
|
+
to_return.append(im)
|
|
72
|
+
|
|
73
|
+
# ...if we need to add width and/or height to this image
|
|
74
|
+
|
|
75
|
+
# ...for each image
|
|
76
|
+
|
|
77
|
+
ct_utils.write_json(output_file, d)
|
|
78
|
+
|
|
79
|
+
print('Added size information to {} of {} images'.format(
|
|
80
|
+
len(to_return), len(d['images'])))
|
|
81
|
+
|
|
82
|
+
return to_return
|
|
83
|
+
|
|
84
|
+
# ...def add_width_and_height_to_db(...)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
#%% Command-line driver
|
|
88
|
+
|
|
89
|
+
if __name__ == '__main__':
|
|
90
|
+
|
|
91
|
+
parser = argparse.ArgumentParser()
|
|
92
|
+
parser.add_argument('input_file', type=str,
|
|
93
|
+
help='Input COCO-formatted .json file')
|
|
94
|
+
parser.add_argument('output_file', type=str,
|
|
95
|
+
help='Output COCO-formatted .json file')
|
|
96
|
+
parser.add_argument('image_base_folder', type=str,
|
|
97
|
+
help='Base directory for images')
|
|
98
|
+
|
|
99
|
+
if len(sys.argv[1:]) == 0:
|
|
100
|
+
parser.print_help()
|
|
101
|
+
parser.exit()
|
|
102
|
+
|
|
103
|
+
args = parser.parse_args()
|
|
104
|
+
|
|
105
|
+
add_width_and_height_to_db(args.input_file,
|
|
106
|
+
args.output_file,
|
|
107
|
+
args.image_base_folder)
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
combine_coco_camera_traps_files.py
|
|
4
|
+
|
|
5
|
+
Merges two or more .json files in COCO Camera Traps format, optionally
|
|
6
|
+
writing the results to another .json file.
|
|
7
|
+
|
|
8
|
+
- Concatenates image lists, erroring if images are not unique.
|
|
9
|
+
- Errors on unrecognized fields.
|
|
10
|
+
- Checks compatibility in info structs, within reason.
|
|
11
|
+
|
|
12
|
+
*Example command-line invocation*
|
|
13
|
+
|
|
14
|
+
combine_coco_camera_traps_files input1.json input2.json ... inputN.json output.json
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
#%% Constants and imports
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
from megadetector.utils import ct_utils
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
#%% Merge functions
|
|
27
|
+
|
|
28
|
+
def combine_cct_files(input_files,
|
|
29
|
+
output_file=None,
|
|
30
|
+
require_uniqueness=True,
|
|
31
|
+
filename_prefixes=None):
|
|
32
|
+
"""
|
|
33
|
+
Merges the list of COCO Camera Traps files [input_files] into a single
|
|
34
|
+
dictionary, optionally writing the result to [output_file].
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
input_files (list): paths to CCT .json files
|
|
38
|
+
output_file (str, optional): path to write merged .json file
|
|
39
|
+
require_uniqueness (bool, optional): whether to require that the images in
|
|
40
|
+
each input_dict be unique
|
|
41
|
+
filename_prefixes (dict, optional): dict mapping input filenames to strings
|
|
42
|
+
that should be prepended to image filenames from that source
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
dict: the merged COCO-formatted .json dict
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
input_dicts = []
|
|
49
|
+
print('Loading input files')
|
|
50
|
+
for fn in input_files:
|
|
51
|
+
with open(fn, 'r', encoding='utf-8') as f:
|
|
52
|
+
d = json.load(f)
|
|
53
|
+
if filename_prefixes is not None:
|
|
54
|
+
assert fn in filename_prefixes
|
|
55
|
+
d['filename_prefix'] = filename_prefixes[fn]
|
|
56
|
+
input_dicts.append(d)
|
|
57
|
+
|
|
58
|
+
print('Merging results')
|
|
59
|
+
merged_dict = combine_cct_dictionaries(
|
|
60
|
+
input_dicts, require_uniqueness=require_uniqueness)
|
|
61
|
+
|
|
62
|
+
print('Writing output')
|
|
63
|
+
if output_file is not None:
|
|
64
|
+
ct_utils.write_json(output_file, merged_dict)
|
|
65
|
+
|
|
66
|
+
return merged_dict
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def combine_cct_dictionaries(input_dicts, require_uniqueness=True):
|
|
70
|
+
"""
|
|
71
|
+
Merges the list of COCO Camera Traps dictionaries [input_dicts]. See module header
|
|
72
|
+
comment for details on merge rules.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
input_dicts (list of dict): list of CCT dicts
|
|
76
|
+
require_uniqueness (bool, optional): whether to require that the images in
|
|
77
|
+
each input_dict be unique
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
dict: the merged COCO-formatted .json dict
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
filename_to_image = {}
|
|
84
|
+
all_annotations = []
|
|
85
|
+
info = None
|
|
86
|
+
|
|
87
|
+
category_name_to_id = {}
|
|
88
|
+
category_name_to_id['empty'] = 0
|
|
89
|
+
next_category_id = 1
|
|
90
|
+
|
|
91
|
+
known_fields = ['info', 'categories', 'annotations','images','filename_prefix']
|
|
92
|
+
|
|
93
|
+
# i_input_dict = 0; input_dict = input_dicts[i_input_dict]
|
|
94
|
+
for i_input_dict,input_dict in enumerate(input_dicts):
|
|
95
|
+
|
|
96
|
+
filename_prefix = ''
|
|
97
|
+
if ('filename_prefix' in input_dict.keys()):
|
|
98
|
+
filename_prefix = input_dict['filename_prefix']
|
|
99
|
+
|
|
100
|
+
for k in input_dict.keys():
|
|
101
|
+
if k not in known_fields:
|
|
102
|
+
raise ValueError(f'Unrecognized CCT field: {k}')
|
|
103
|
+
|
|
104
|
+
# We will prepend an index to every ID to guarantee uniqueness
|
|
105
|
+
index_string = 'ds' + str(i_input_dict).zfill(3) + '_'
|
|
106
|
+
|
|
107
|
+
old_cat_id_to_new_cat_id = {}
|
|
108
|
+
|
|
109
|
+
# Map detection categories from the original data set into the merged data set
|
|
110
|
+
for original_category in input_dict['categories']:
|
|
111
|
+
|
|
112
|
+
original_cat_id = original_category['id']
|
|
113
|
+
cat_name = original_category['name']
|
|
114
|
+
if cat_name in category_name_to_id:
|
|
115
|
+
new_cat_id = category_name_to_id[cat_name]
|
|
116
|
+
else:
|
|
117
|
+
new_cat_id = next_category_id
|
|
118
|
+
next_category_id += 1
|
|
119
|
+
category_name_to_id[cat_name] = new_cat_id
|
|
120
|
+
|
|
121
|
+
if original_cat_id in old_cat_id_to_new_cat_id:
|
|
122
|
+
assert old_cat_id_to_new_cat_id[original_cat_id] == new_cat_id
|
|
123
|
+
else:
|
|
124
|
+
old_cat_id_to_new_cat_id[original_cat_id] = new_cat_id
|
|
125
|
+
|
|
126
|
+
# ...for each category
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# Merge original image list into the merged data set
|
|
130
|
+
for im in input_dict['images']:
|
|
131
|
+
|
|
132
|
+
if 'seq_id' in im:
|
|
133
|
+
im['seq_id'] = index_string + str(im['seq_id'])
|
|
134
|
+
if 'location' in im:
|
|
135
|
+
im['location'] = index_string + im['location']
|
|
136
|
+
|
|
137
|
+
im_file = filename_prefix + im['file_name']
|
|
138
|
+
im['file_name'] = im_file
|
|
139
|
+
if require_uniqueness:
|
|
140
|
+
assert im_file not in filename_to_image, f'Duplicate image: {im_file}'
|
|
141
|
+
else:
|
|
142
|
+
if im_file in filename_to_image:
|
|
143
|
+
print('Redundant image {}'.format(im_file))
|
|
144
|
+
|
|
145
|
+
# Create a unique ID
|
|
146
|
+
im['id'] = index_string + str(im['id'])
|
|
147
|
+
filename_to_image[im_file] = im
|
|
148
|
+
|
|
149
|
+
# ...for each image
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Same for annotations
|
|
153
|
+
for ann in input_dict['annotations']:
|
|
154
|
+
|
|
155
|
+
ann['image_id'] = index_string + str(ann['image_id'])
|
|
156
|
+
ann['id'] = index_string + str(ann['id'])
|
|
157
|
+
assert ann['category_id'] in old_cat_id_to_new_cat_id
|
|
158
|
+
ann['category_id'] = old_cat_id_to_new_cat_id[ann['category_id']]
|
|
159
|
+
|
|
160
|
+
# ...for each annotation
|
|
161
|
+
|
|
162
|
+
all_annotations.extend(input_dict['annotations'])
|
|
163
|
+
|
|
164
|
+
# Merge info dicts, don't check completion time fields
|
|
165
|
+
if info is None:
|
|
166
|
+
import copy
|
|
167
|
+
info = copy.deepcopy(input_dict['info'])
|
|
168
|
+
info['original_info'] = [input_dict['info']]
|
|
169
|
+
else:
|
|
170
|
+
info['original_info'].append(input_dict['info'])
|
|
171
|
+
|
|
172
|
+
# ...for each dictionary
|
|
173
|
+
|
|
174
|
+
# Convert merged image dictionaries to a sorted list
|
|
175
|
+
sorted_images = sorted(filename_to_image.values(), key=lambda im: im['file_name'])
|
|
176
|
+
|
|
177
|
+
all_categories = [{'id':category_name_to_id[cat_name],'name':cat_name} for\
|
|
178
|
+
cat_name in category_name_to_id.keys()]
|
|
179
|
+
|
|
180
|
+
merged_dict = {'info': info,
|
|
181
|
+
'categories': all_categories,
|
|
182
|
+
'images': sorted_images,
|
|
183
|
+
'annotations': all_annotations}
|
|
184
|
+
|
|
185
|
+
return merged_dict
|
|
186
|
+
|
|
187
|
+
# ...combine_cct_dictionaries(...)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
#%% Command-line driver
|
|
191
|
+
|
|
192
|
+
def main(): # noqa
|
|
193
|
+
|
|
194
|
+
parser = argparse.ArgumentParser()
|
|
195
|
+
parser.add_argument(
|
|
196
|
+
'input_paths', nargs='+',
|
|
197
|
+
help='List of input .json files')
|
|
198
|
+
parser.add_argument(
|
|
199
|
+
'output_path',
|
|
200
|
+
help='Output .json file')
|
|
201
|
+
|
|
202
|
+
if len(sys.argv[1:]) == 0:
|
|
203
|
+
parser.print_help()
|
|
204
|
+
parser.exit()
|
|
205
|
+
|
|
206
|
+
args = parser.parse_args()
|
|
207
|
+
combine_cct_files(args.input_paths, args.output_path)
|
|
208
|
+
|
|
209
|
+
if __name__ == '__main__':
|
|
210
|
+
main()
|