postprocessing package

This subpackage contains modules for working with MegaDetector batch processing results.

Subpackages

Submodules

postprocessing.analyze_classification_results module

analyze_classification_results.py

Given a results file in MD format, and a ground truth file in COCO Camera Traps format, both containing classification results, perform various analyses, including:

  • Precision/recall analysis

  • Confusion matrix with links to visualization pages

Only analyzes image-level correctness, i.e., box locations are ignored in both the predictions and the ground truth.

class megadetector.postprocessing.analyze_classification_results.AnalysisResults[source]

Bases: object

Results returned by analyze_classification_results().

active_categories

Ordered list of category names corresponding to matrix rows/columns

confusion_matrix

The confusion matrix as a 2D numpy array

html_output_file

Path to the output HTML file (if generated)

per_category_results

Dictionary mapping category names to dicts, where each item has at least the keys “precision”, “recall”, “f1”, “n_ground_truth”, “n_predicted”

class megadetector.postprocessing.analyze_classification_results.ClassificationAnalysisOptions[source]

Bases: object

Options used to parameterize analyze_classification_results().

apply_detection_category_mapping_when_classifications_are_present

When this is True (default), we trust detection categories regardless of classifications. I.e., a detection category of “person” with a classification of “elk” will be treated as a classification of “person”.

When this is False, we trust classifications, if present. This is generally used when I’m simulating Wildlife Insights ensemble behavior, where “classifications” at this point really represent the output of the entire WI ensemble.

categories_to_ignore

List of category names to completely exclude from the analysis, whether they appear in ground truth or predictions. Checked after detection category remapping (e.g. person -> human).

classification_confidence_threshold

Confidence threshold to apply to classification (not detection) results

detection_category_mapping

A dict mapping detection category names to classification category names, for categories we want to handle specially. Any detection in a matching category with an above-threshold confidence value is treated as if it had a classification with the corresponding (mapped) classification category, with a confidence of 1.0, whether or not that category exists in the ground truth.

For example, by default a detection with category “person” with confidence 0.4 should be treated as a classification of category “human” with confidence 1.0.

Defaults to detection_category_mapping.

detection_threshold

Ignore all detections below this confidence threshold

If this is None, a confidence threshold is selected based on the detector version.

gt_category_name_mappings

Before processing, optionally map a subset of GT classification categories to alternative names. Typically used to reconcile category names across predictions/GT.

If not None, should be a str –> str dict.

gt_file

Ground truth file in COCO Camera Traps format

html_output_dir

Folder to which we should write html output page

image_base_dir

Folder where images live; filenames in [results_file] and [gt_file] should be relative to this path. Only required if html_output_dir is not None.

max_classifications_per_detection

Only review this many classifications per detection

max_images_per_cell

Try to sample this many images to render per confusion matrix cell. Only relevant if html_output_dir is not None. Total number is still capped by max_total_images.

max_images_per_html_file

Maximum number of images to include in any HTML page, generally only relevant when calling render_misprediction_pages(…).

max_total_images

Approximate maximum number of total images to render. May be exceeded slightly if required to make sure that at least one image is rendered per non-empty cell in the confusion matrix. Only relevant if html_output_dir is not None.

n_mispredictions_for_table

Number of top misprediction categories to show in the per-category statistics table (for both “mispredicted as this” and “this was mispredicted as” columns).

output_image_width

Width of rendered output images (-1 to preserve original size)

overwrite

Should we over-write images that already exist?

predicted_category_name_mappings

Before processing, optionally map a subset of predicted classification categories to alternative names. Typically used to reconcile category names across predictions/GT.

If not None, should be a str –> str dict.

random_seed

Random seed to be used if image sampling is necessary

rendering_pool_type

Should we use threads (“threads”) or processes (“processes”) for rendering?

Only relevant if rendering_workers is > 1.

rendering_workers

Number of workers to use when rendering images

results_file

MD-formatted results file to analyze

sequence_level_analysis

If True, the entire analysis will be performed at the sequence level, rather than the image level.

single_label_per_image

If True, collapse each image’s (or sequence’s) ground truth to a single category. For image-level analyses, ties are broken alphabetically. For sequence-level analyses, ties are broken by count (how many images in the sequence have that category), then alphabetically.

single_prediction_per_image

If True, collapse each image’s (or sequence’s) predictions to a single category. The winner is chosen by the number of above- threshold classifications for that category, with max classification confidence as a tie-breaker. For sequence-level analyses, collapsing happens at the sequence level (counts are summed across images in the sequence), not per-image.

megadetector.postprocessing.analyze_classification_results.analyze_classification_results(options)[source]

Perform precision-recall analysis on classification results.

Parameters:

options (ClassificationAnalysisOptions) – options object defining filenames and analysis parameters.

Returns:

results of the classification analysis

Return type:

AnalysisResults

megadetector.postprocessing.analyze_classification_results.render_misprediction_pages(options, cells_to_render)[source]

Render detailed HTML pages for specific misprediction cells, typically with a large number of images (e.g. 2000) for deep-dive analysis.

Uses the same data-loading and preparation logic as analyze_classification_results.

Parameters:
  • options (ClassificationAnalysisOptions) – options object; needs results_file, gt_file, image_base_dir, html_output_dir. max_images_per_cell controls page length (e.g. set to 2000 for deep dives).

  • cells_to_render (list) –

    list of (true_cat, pred_cat, mode) tuples where mode is one of:

    • ’standard’: entities where true_cat is in GT, pred_cat is in predictions, true_cat != pred_cat, and the off-diagonal skip condition is not met.

    • ’strict_fp’: entities where pred_cat is among the predictions and pred_cat is NOT in the ground truth, and true_cat is in GT. (The “mispredicted as this category” criterion.)

    • ’strict_fn’: entities where true_cat is in GT and true_cat is NOT among the predictions, and pred_cat is in predictions. (The “mispredicted as” criterion.)

Returns:

paths to the generated HTML files

Return type:

list

analyze_classification_results - CLI interface

Analyze classification results against ground truth, computing precision/recall/F1 and generating an HTML report.

analyze_classification_results [-h] [--image_base_dir IMAGE_BASE_DIR]
                               [--html_output_dir HTML_OUTPUT_DIR]
                               [--detection_threshold DETECTION_THRESHOLD]
                               [--classification_confidence_threshold CLASSIFICATION_CONFIDENCE_THRESHOLD]
                               [--max_total_images MAX_TOTAL_IMAGES]
                               [--max_images_per_cell MAX_IMAGES_PER_CELL]
                               [--random_seed RANDOM_SEED] [--sequence_level]
                               [--rendering_workers RENDERING_WORKERS]
                               [--rendering_pool_type {threads,processes}]
                               [--output_image_width OUTPUT_IMAGE_WIDTH]
                               [--n_mispredictions_for_table N_MISPREDICTIONS_FOR_TABLE]
                               [--categories_to_ignore CATEGORIES_TO_IGNORE]
                               [--single_prediction_per_image] [--single_label_per_image]
                               results_file gt_file

analyze_classification_results positional arguments

  • results_file - MD-formatted results file (.json)

  • gt_file - Ground truth file in COCO Camera Traps format (.json)

analyze_classification_results options

postprocessing.categorize_detections_by_size module

categorize_detections_by_size.py

Given a MegaDetector .json file, creates a separate category for bounding boxes above one or more size thresholds.

class megadetector.postprocessing.categorize_detections_by_size.SizeCategorizationOptions[source]

Bases: object

Options used to parameterize categorize_detections_by_size().

categories_to_separate

List of category numbers to use in separation; uses all categories if None

default_category_is_smallest

Is the default category above the largest threshold in size_thresholds, or below the smallest? By default we are separating large detections into a new category, so the default is smaller than the smallest threshold

measurement

Dimension to use for thresholding; can be “size”, “width”, or “height”

size_category_names

Categories to assign to thresholded ranges; should have the same length as “size_thresholds”.

size_thresholds

Thresholds to use for separation, as a fraction of the image size.

Will get sorted by categorize_detections_by_size, so the order doesn’t matter, as long as the order matches size_category_names.

megadetector.postprocessing.categorize_detections_by_size.categorize_detections_by_size(input_file, output_file=None, options=None)[source]

Given a MegaDetector .json file, creates a separate category for bounding boxes above one or more size thresholds, optionally writing results to [output_file].

Parameters:
  • input_file (str) – file to process

  • output_file (str, optional) – optional output file

  • options (SizeCategorizationOptions, optional) – categorization parameters

Returns:

data loaded from [input_file], with the new size-based categories. Identical to what’s written to [output_file], if [output_file] is not None.

Return type:

dict

postprocessing.create_crop_folder module

create_crop_folder.py

Given a MegaDetector .json file and a folder of images, creates a new folder of images representing all above-threshold crops from the original folder.

class megadetector.postprocessing.create_crop_folder.CreateCropFolderOptions[source]

Bases: object

Options used to parameterize create_crop_folder().

category_names_to_include

Include only these categories, or None to include all

options.category_names_to_include = [‘animal’]

confidence_threshold

Confidence threshold determining which detections get written

expansion

Number of pixels to expand each crop

n_workers

Number of concurrent workers

overwrite

Whether to overwrite existing images

pool_type

Whether to use processes (‘process’) or threads (‘thread’) for parallelization

quality

JPEG quality to use for saving crops (None for default)

megadetector.postprocessing.create_crop_folder.create_crop_folder(input_file, input_folder, output_folder, output_file=None, crops_output_file=None, options=None)[source]

Given a MegaDetector .json file and a folder of images, creates a new folder of images representing all above-threshold crops from the original folder.

Optionally writes a new .json file that attaches unique IDs to each detection.

Parameters:
  • input_file (str) – MD-formatted .json file to process

  • input_folder (str) – Input image folder

  • output_folder (str) – Output (cropped) image folder

  • output_file (str, optional) – new .json file that attaches unique IDs to each detection.

  • crops_output_file (str, optional) – new .json file that includes whole-image detections for each of the crops, using confidence values from the original results

  • options (CreateCropFolderOptions, optional) – crop parameters

megadetector.postprocessing.create_crop_folder.crop_results_to_image_results(image_results_file_with_crop_ids, crop_results_file, output_file, delete_crop_information=True, require_identical_detection_categories=True, restrict_to_top_n=-1, crop_results_prefix=None, detections_without_classification_handling='error')[source]

This function is intended to be run after you have:

  1. Run MegaDetector on a folder

  2. Generated a crop folder using create_crop_folder

  3. Run a species classifier on those crops

This function will take the crop-level results and transform them back to the original images. Classification categories, if available, are taken from [crop_results_file].

Parameters:
  • image_results_file_with_crop_ids (str) – results file for the original images, containing crop IDs, likely generated via create_crop_folder. All non-standard fields in this file will be passed along to [output_file].

  • crop_results_file (str) – results file for the crop folder

  • output_file (str) – output .json file, containing crop-level classifications mapped back to the image level.

  • delete_crop_information (bool, optional) – whether to delete the “crop_id” and “crop_filename_relative” fields from each detection, if present.

  • require_identical_detection_categories (bool, optional) – if True, error if the image-level and crop-level detection categories are different. If False, ignore the crop-level detection categories.

  • restrict_to_top_n (int, optional) – If >0, removes all but the top N classification results for each detection.

  • crop_results_prefix (str, optional) – if not None, removes this prefix from crop results filenames. Intended to support the case where the crop results use absolute paths.

  • detections_without_classification_handling (str, optional) – what to do when we encounter a crop that doesn’t appear in classification results: ‘error’, or ‘include’ (“include” means “leave the detection alone, without classifications”

create_crop_folder - CLI interface

Create a folder of crops from MegaDetector results

create_crop_folder [-h] [--output_file OUTPUT_FILE] [--crops_output_file CROPS_OUTPUT_FILE]
                   [--confidence_threshold CONFIDENCE_THRESHOLD] [--expansion EXPANSION]
                   [--quality QUALITY] [--overwrite {true,false}] [--n_workers N_WORKERS]
                   [--pool_type {thread,process}] [--category_names CATEGORY_NAMES]
                   input_file input_folder output_folder

create_crop_folder positional arguments

  • input_file - Path to the MegaDetector .json results file

  • input_folder - Path to the folder containing the original images

  • output_folder - Path to the folder where cropped images will be saved

create_crop_folder options

  • -h, --help - show this help message and exit

  • --output_file OUTPUT_FILE - Path to save the modified MegaDetector .json file (with crop IDs and filenames)

  • --crops_output_file CROPS_OUTPUT_FILE - Path to save a new .json file for the crops themselves (with full-image detections for each crop)

  • --confidence_threshold CONFIDENCE_THRESHOLD - Confidence threshold for detections to be cropped (default: 0.1)

  • --expansion EXPANSION - Number of pixels to expand each crop (default: 0)

  • --quality QUALITY - JPEG quality for saving crops (default: 95)

  • --overwrite OVERWRITE - Overwrite existing crop images (default: 'true')

  • --n_workers N_WORKERS - Number of concurrent workers (default: 8)

  • --pool_type POOL_TYPE - Type of parallelism to use ('thread' or 'process', default: 'thread')

  • --category_names CATEGORY_NAMES - Comma-separated list of category names to include (e.g., 'animal,person'). If None (default), all categories are included.

postprocessing.classification_postprocessing module

classification_postprocessing.py

Functions for postprocessing species classification results, particularly:

  • Smoothing results within an image (an image with 700 cows and one deer is really just 701 cows)

  • Smoothing results within a sequence (a sequence that looks like deer/deer/deer/elk/deer/deer is really just a deer)

class megadetector.postprocessing.classification_postprocessing.ClassificationSmoothingOptions[source]

Bases: object

Options used to parameterize smooth_classification_results_image_level() and smooth_classification_results_sequence_level()

add_pre_smoothing_description

Should we record information about the state of labels prior to smoothing?

break_at_image

Enable additional debug output for a particular image

classification_confidence_threshold

We’re not even going to mess around with classifications below this threshold.

We won’t count them, we won’t over-write them, they don’t exist during the within-image smoothing step.

detection_category_names_to_smooth

Only include these categories in the smoothing process (None to use all categories)

detection_confidence_threshold

We’re not even going to mess around with detections below this threshold.

We won’t count them, we won’t over-write them, they don’t exist during the within-image smoothing step.

max_detections_nondominant_class

Even if we have a dominant class, if a non-dominant class has at least this many classifications in an image, leave them alone.

If this is <= 1, we won’t replace non-dominant, non-other classes with the dominant class, even if there are 900 cows and 1 deer.

max_detections_nondominant_class_same_family

If we have this many classifications of a nondominant category, we won’t do same-family overwrites. <= 1 means “even if there are a million deer, if there are two million moose, call all the deer moose”. This option doesn’t mean anything if min_detections_to_overwrite_secondary_same_family <= 0.

min_detections_to_overwrite_other

If the dominant class has at least this many classifications, overwrite “other” classifications with the dominant class

min_detections_to_overwrite_secondary

How many detections do we need in a dominant category to overwrite non-dominant classifications? This is irrelevant if max_detections_nondominant_class <= 1.

min_detections_to_overwrite_secondary_same_family

How many detections do we need in a dominant category to overwrite non-dominant classifications in the same family? If this is <= 0, we’ll skip this step. This option doesn’t mean anything if max_detections_nondominant_class_same_family <= 1.

modify_in_place

When a dict (rather than a file) is passed to either smoothing function, if this is True, we’ll make a copy of the input dict before modifying.

other_category_names

Names to treat as “other” categories; can’t be None, but can be empty

“Other” classifications will be changed to the dominant category, regardless of confidence, as long as there are at least min_detections_to_overwrite_other examples of the dominant class. For example, cow/other will remain unchanged, but cow/cow/other will become cow/cow/cow.

propagate_classifications_through_taxonomy

If classification descriptions are present and appear to represent taxonomic information, should we propagate classifications when lower-level taxa are more common in an image? For example, if we see “carnivore/fox/fox/deer”, should we make that “fox/fox/fox/deer”?

taxonomy_propagation_count_weight

When propagating classifications down through taxonomy levels, we have to decide whether we prefer more frequent categories or more specific categories. taxonomy_propagation_level_weight and taxonomy_propagation_count_weight balance levels against counts in this process.

With a very low default value, this just breaks ties.

taxonomy_propagation_level_weight

When propagating classifications down through taxonomy levels, we have to decide whether we prefer more frequent categories or more specific categories. taxonomy_propagation_level_weight and taxonomy_propagation_count_weight balance levels against counts in this process.

megadetector.postprocessing.classification_postprocessing.combine_redundant_classification_categories(input_file, output_file=None, classification_threshold=0.5)[source]

If [input_file] contains multiple categories with the same category name, merges each equivalence class into a single category, optionally writing the results to [output_file].

Parameters:
  • input_file (str or dict) – .json file to read, in MD format (or an already-loaded dict)

  • output_file (str) – .json file to write, in MD format

  • classification_threshold (float, optional) – only used when sorting descriptions by count

Returns:

remapped MD-formatted dict

Return type:

dict

megadetector.postprocessing.classification_postprocessing.count_detections_by_classification_category(detections, options=None)[source]

Count the number of instances of each classification category in the detections list [detections] that have an above-threshold detection. Sort results in descending order by count. Returns a dict mapping category ID –> count. If no detections are above threshold, returns an empty dict.

Only processes the top classification for each detection.

Parameters:
Returns:

dict mapping above-threshold category IDs to counts

megadetector.postprocessing.classification_postprocessing.get_classification_description_string(category_to_count, classification_descriptions)[source]

Return a string summarizing the image content according to [category_to_count].

Parameters:
  • category_to_count (dict) – a dict mapping category IDs to counts

  • classification_descriptions (dict) – a dict mapping category IDs to description strings

Returns:

a description of this image’s content, e.g. “rabbit (4), human (1)”

Return type:

string

megadetector.postprocessing.classification_postprocessing.merge_classification_categories(target_file, source_file, output_file=None)[source]

Modify the classification categories in [source file] to be compatible with the categories in [target_file], optionally writing a new file. Uses only category names, does not use category descriptions to decide whether to merge categories. Behavior is undefined if multiple source categories have the same name. Does not look at detection categories at all. If neither file has classification categories, just re-writes the source file. Errors if exactly one file has classification categories.

Parameters:
  • target_file (str or dict) – target .json file, in MD format (or an already-loaded dict)

  • source_file (str) – .json file to modify, in MD format (or an already-loaded dict)

  • output_file (str, optional) – .json file to which we should write a modified version of [source_file]

Returns:

remapped MD-formatted dict

Return type:

dict

megadetector.postprocessing.classification_postprocessing.remove_classifications_from_non_animal_detections(input_file, output_file, animal_category_names=None)[source]

Remove classifications from non-animal detections in a MD .json file, optionally writing the results to a new .json file

Parameters:
  • input_file (str) – the MD-formatted .json file to process

  • output_file (str, optional) – the output file to write the modified results

  • animal_category_names (list, optional) – the detection category names that should be treated as animals (defaults to just ‘animal’).

Returns:

the modified results

Return type:

dict

megadetector.postprocessing.classification_postprocessing.restrict_to_taxa_list(taxa_list, speciesnet_taxonomy_file, input_file, output_file, allow_walk_down=False, add_pre_filtering_description=True, add_post_filtering_description=True, allow_redundant_latin_names=True, protected_common_names=None, use_original_common_names_if_available=True, verbose=True, classification_threshold=None, combine_redundant_categories=True)[source]

Given a prediction file in MD .json format, likely without having had a geofence applied, apply a custom taxa list.

Parameters:
  • taxa_list (str) – .csv file with at least the columns “latin” and “common”

  • speciesnet_taxonomy_file (str) – taxonomy filename, in the same format used for model release (with 7-token taxonomy entries)

  • input_file (str) – .json file to read, in MD format. This can be None, in which case this function just validates [taxa_list].

  • output_file (str) – .json file to write, in MD format

  • allow_walk_down (bool, optional) – should we walk down the taxonomy tree when making mappings if a parent has only a single allowable child? For example, if only a single felid species is allowed, should other felid predictions be mapped to that species, as opposed to being mapped to the family?

  • add_pre_filtering_description (bool, optional) – should we add a new metadata field that summarizes each image’s classifications prior to taxonomic restriction?

  • add_post_filtering_description (bool, optional) – should we add a new metadata field that summarizes each image’s classifications after taxonomic restriction?

  • allow_redundant_latin_names (bool, optional) – if False, we’ll raise an Exception if the same latin name appears twice in the taxonomy list; if True, we’ll just print a warning and ignore all entries other than the first for this latin name

  • protected_common_names (list, optional) – these categories should be unmodified, even if they aren’t used, or have the same taxonomic description as other categories

  • use_original_common_names_if_available (bool, optional) – if an “original_common” column is present in [taxa_list], use those common names instead of the ones in the taxonomy file

  • verbose (bool, optional) – enable additional debug output

  • classification_threshold (float, optional) – only relevant for the pre/post filtering descriptions

  • combine_redundant_categories (bool, optional) – whether to combine categories with the same common name

megadetector.postprocessing.classification_postprocessing.smooth_classification_results_image_level(input_file, output_file=None, options=None)[source]

Smooth classifications at the image level for all results in the MD-formatted results file [input_file], optionally writing a new set of results to [output_file].

This function generally expresses the notion that an image with 700 cows and one deer is really just 701 cows.

Only count detections with a classification confidence threshold above [options.classification_confidence_threshold], which in practice means we’re only looking at one category per detection.

If an image has at least [options.min_detections_to_overwrite_secondary] such detections in the most common category, and no more than [options.max_detections_nondominant_class] in the second-most-common category, flip all detections to the most common category.

Optionally treat some classes as particularly unreliable, typically used to overwrite an “other” class.

This function also removes everything but the non-dominant classification for each detection.

Parameters:
  • input_file (str) – MegaDetector-formatted classification results file to smooth. Can also be an already-loaded results dict.

  • output_file (str, optional) – .json file to write smoothed results

  • options (ClassificationSmoothingOptions, optional) – see ClassificationSmoothingOptions for details.

Returns:

MegaDetector-results-formatted dict, identical to what’s written to [output_file] if [output_file] is not None.

Return type:

dict

megadetector.postprocessing.classification_postprocessing.smooth_classification_results_sequence_level(input_file, cct_sequence_information, output_file=None, options=None)[source]

Smooth classifications at the sequence level for all results in the MD-formatted results file [md_results_file], optionally writing a new set of results to [output_file].

This function generally expresses the notion that a sequence that looks like deer/deer/deer/elk/deer/deer/deer/deer is really just a deer.

Parameters:
  • input_file (str or dict) – MegaDetector-formatted classification results file to smooth (or already-loaded results). If you supply a dict, it’s copied by default, but in-place modification is supported via options.modify_in_place.

  • cct_sequence_information (str, dict, or list) – COCO Camera Traps file containing sequence IDs for each image (or an already-loaded CCT-formatted dict, or just the ‘images’ list from a CCT dict).

  • output_file (str, optional) – .json file to write smoothed results

  • options (ClassificationSmoothingOptions, optional) – see ClassificationSmoothingOptions for details.

Returns:

MegaDetector-results-formatted dict, identical to what’s written to [output_file] if [output_file] is not None.

Return type:

dict

postprocessing.combine_batch_outputs module

combine_batch_outputs.py

Merges two or more .json files in MD output format, optionally writing the results to another .json file.

  • Concatenates image lists, erroring if images are not unique.

  • Errors if class lists are conflicting; errors on unrecognized fields.

  • Checks compatibility in info structs, within reason.

File format:

https://github.com/agentmorris/MegaDetector/tree/main/megadetector/api/batch_processing#batch-processing-api-output-format

Command-line use:

combine_batch_outputs input1.json input2.json … inputN.json output.json

This does no checking for redundancy; if you are looking to ensemble the results of multiple model versions, see merge_detections.py.

megadetector.postprocessing.combine_batch_outputs.combine_batch_output_dictionaries(input_dicts, require_uniqueness=True)[source]

Merges the list of MD results dictionaries [input_dicts] into a single dict. See module header comment for details on merge rules.

Parameters:
  • input_dicts (list of dicts) – list of dicts in which each dict represents the contents of a MD output file

  • require_uniqueness (bool, optional) – whether to require that the images in each input dict be unique; if this is True and image filenames are not unique, an error is raised.

Returns:

merged MD results

Return type:

dict

megadetector.postprocessing.combine_batch_outputs.combine_batch_output_files(input_files, output_file=None, require_uniqueness=True, verbose=True)[source]

Merges the list of MD results files [input_files] into a single dictionary, optionally writing the result to [output_file].

Always overwrites [output_file] if it exists.

Parameters:
  • input_files (list of str) – paths to JSON detection files

  • output_file (str, optional) – path to write merged JSON

  • require_uniqueness (bool, optional) – whether to require that the images in each list of images be unique

  • verbose (bool, optional) – enable additional debug output

Returns:

merged dictionaries loaded from [input_files], identical to what’s written to [output_file] if [output_file] is not None

Return type:

dict

combine_batch_outputs - CLI interface

combine_batch_outputs [-h] input_paths [input_paths ...] output_path

combine_batch_outputs positional arguments

combine_batch_outputs options

  • -h, --help - show this help message and exit

postprocessing.compare_batch_results module

compare_batch_results.py

Compare sets of batch results; typically used to compare:

  • Results from different MegaDetector versions

  • Results before/after RDE

  • Results with/without augmentation

Makes pairwise comparisons between sets of results, but can take lists of results files (will perform all pairwise comparisons). Results are written to an HTML page that shows the number and nature of disagreements (in the sense of each image being a detection or non-detection), with sample images for each category.

Operates in one of three modes, depending on whether ground truth labels/boxes are available:

  • The most common mode assumes no ground truth, just finds agreement/disagreement between results files, or class discrepancies.

  • If image-level ground truth is available, finds image-level agreements on TPs/TNs/FPs/FNs, but also finds image-level TPs/TNs/FPs/FNs that are unique to each set of results (at the specified confidence threshold).

  • If box-level ground truth is available, finds box-level agreements on TPs/TNs/FPs/FNs, but also finds image-level TPs/TNs/FPs/FNs that are unique to each set of results (at the specified confidence threshold).

class megadetector.postprocessing.compare_batch_results.BatchComparisonOptions[source]

Bases: object

Defines the options for a set of (possibly many) pairwise comparisons.

category_names_to_include

List of category names to include in the comparison, or None to use all categories

class_agnostic_comparison

Compare only detections/non-detections, ignore categories (still renders categories)

colormap_a

Colormap to use for detections in file A (maps detection categories to colors)

colormap_b

Colormap to use for detections in file B (maps detection categories to colors)

error_on_non_matching_lists

The expectation is that all results sets being compared will refer to the same images; if this is True (default), we’ll error if that’s not the case, otherwise non-matching lists will just be a warning.

filenames_to_include

List of filenames to include in the comparison, or None to use all files

fn_to_display_fn

When rendering to the output table, optionally write alternative strings to describe images

ground_truth_file

Ground truth .json file in COCO Camera Traps format, or an already-loaded COCO dictionary

gt_empty_categories

Category names that refer to empty images when image-level ground truth is provided

gt_iou_threshold

IoU threshold to use when comparing to ground truth with boxes

image_folder

Base folder for images (which are specified as relative files)

include_clean_categories

Separate out the “clean TP” and “clean TN” categories, only relevant when GT is available

include_toc

Should we include a TOC? TOC is always omitted if <=2 comparisons are performed.

job_name

Job name to use in the HTML output file

max_images_per_category

Maximum number of images to render for each category, where a “category” here is “detections_a_only”, “detections_b_only”, etc., or None to render all images.

max_images_per_page

Maximum number of images per HTML page (paginates if a category page goes beyond this), or None to disable pagination.

n_rendering_workers

Number of workers to use for rendering, or <=1 to disable parallelization

output_folder

Folder to which we should write HTML output

pairwise_options

List of PairwiseBatchComparisonOptions that defines the comparisons we’ll render

parallelize_rendering_with_threads

Whether to render images with threads (True) or processes (False)

Should we run urllib.parse.quote() on paths before using them as links in the output page?

random_seed

Random seed for image sampling (not used if max_images_per_category is None)

required_token

Only process images whose file names contain this token

This can also be a pointer to a function that takes a string (filename) and returns a bool (if the function returns True, the image will be included in the comparison).

return_images_by_category

Should we return the mapping from categories (e.g. “common detections”) to image pairs? Makes the return dict much larger, but allows post-hoc exploration.

show_category_names_on_detected_boxes

Should we show category names (instead of numbers) on detected boxes?

show_category_names_on_gt_boxes

Should we show category names (instead of numbers) on GT boxes?

show_classification_categories

Should we show classification categories if present?

show_labels_for_image_level_gt

Should we show image-level labels as text on each image when boxes are not available?

sort_by_confidence

Whether to sort results by confidence; if this is False, sorts by filename

target_width

Width of images to render in the output HTML (None to use original size)

verbose

Enable additional debug output

class megadetector.postprocessing.compare_batch_results.BatchComparisonResults[source]

Bases: object

The results from a set of pairwise comparisons

html_output_file

Filename containing HTML output

pairwise_results

A list of PairwiseBatchComparisonResults

class megadetector.postprocessing.compare_batch_results.PairwiseBatchComparisonOptions[source]

Bases: object

Defines the options used for a single pairwise comparison; a list of these pairwise options sets is stored in the BatchComparisonsOptions class.

classification_confidence_threshold_a

Classification threshold to use for filename A, only relevant if classifications are present

classification_confidence_threshold_b

Classification threshold to use for filename B, only relevant if classifications are present

detection_thresholds_a

Per-class detection thresholds to use for filename A (including a ‘default’ threshold)

detection_thresholds_b

Per-class detection thresholds to use for filename B (including a ‘default’ threshold)

rendering_confidence_threshold_a

Rendering threshold to use for all categories for filename A

rendering_confidence_threshold_b

Rendering threshold to use for all categories for filename B

results_description_a

Description to use in the output HTML for filename A

results_description_b

Description to use in the output HTML for filename B

results_filename_a

First filename to compare

results_filename_b

Second filename to compare

class megadetector.postprocessing.compare_batch_results.PairwiseBatchComparisonResults[source]

Bases: object

The results from a single pairwise comparison.

categories_to_image_pairs

Values are dicts with fields ‘im_a’, ‘im_b’, ‘sort_conf’, and ‘im_gt’

comparison_friendly_name

Friendly identifier for this comparison

comparison_short_name

Short identifier for this comparison

html_content

String of HTML content suitable for rendering to an HTML file

pairwise_options

Possibly-modified version of the PairwiseBatchComparisonOptions supplied as input

megadetector.postprocessing.compare_batch_results.compare_batch_results(options)[source]

The main entry point for this module. Runs one or more batch results comparisons, writing results to an html page. Most of the work is deferred to _pairwise_compare_batch_results().

Parameters:

options (BatchComparisonOptions) – job options to use for this comparison task, including the list of specific pairswise comparisons to make (in the pairwise_options field)

Returns:

the results of this comparison task

Return type:

BatchComparisonResults

megadetector.postprocessing.compare_batch_results.find_equivalent_threshold(results_a, results_b, threshold_a=0.2, category_names=None, verbose=False)[source]

Given two sets of detector results, finds the confidence threshold for results_b that produces the same fraction of images with detections as threshold_a does for results_a. Uses all categories.

Parameters:
  • results_a (str or dict) – the first set of results, either a .json filename or a results dict

  • results_b (str or dict) – the second set of results, either a .json filename or a results dict

  • threshold_a (float, optional) – the threshold used to determine the target number of detections in results_a

  • category_names (list or str, optional) – the list of category names to consider (defaults to using all categories), or the name of a single category.

  • verbose (bool, optional) – enable additional debug output

Returns:

the threshold that - when applied to results_b - produces the same number of image-level detections that results from applying threshold_a to results_a

Return type:

float

megadetector.postprocessing.compare_batch_results.find_image_level_detections_above_threshold(results, threshold=0.2, category_names=None)[source]

Returns images in the set of MD results [results] with detections above a threshold confidence level, optionally only counting certain categories.

Parameters:
  • results (str or dict) – the set of results, either a .json filename or a results dict

  • threshold (float, optional) – the threshold used to determine the target number of detections in [results]

  • category_names (list or str, optional) – the list of category names to consider (defaults to using all categories), or the name of a single category.

Returns:

the images with above-threshold detections

Return type:

list

megadetector.postprocessing.compare_batch_results.n_way_comparison(filenames, options, detection_thresholds=None, rendering_thresholds=None, model_names=None)[source]

Performs N pairwise comparisons for the list of results files in [filenames], by generating sets of pairwise options and calling compare_batch_results.

Parameters:
  • filenames (list) – list of MD results filenames to compare

  • options (BatchComparisonOptions) – task options set in which pairwise_options is still empty; that will get populated from [filenames]

  • detection_thresholds (list, optional) – list of detection thresholds with the same length as [filenames], or None to use sensible defaults

  • rendering_thresholds (list, optional) – list of rendering thresholds with the same length as [filenames], or None to use sensible defaults

  • model_names (list, optional) – list of model names to use the output HTML file, with the same length as [filenames], or None to use sensible defaults

Returns:

the results of this comparison task

Return type:

BatchComparisonResults

compare_batch_results - CLI interface

compare_batch_results [-h] [--detection_thresholds [DETECTION_THRESHOLDS ...]]
                      [--rendering_thresholds [RENDERING_THRESHOLDS ...]]
                      [--max_images_per_category MAX_IMAGES_PER_CATEGORY]
                      [--target_width TARGET_WIDTH] [--use_processes] [--open_results]
                      [--n_rendering_workers N_RENDERING_WORKERS]
                      output_folder image_folder [results_files ...]

compare_batch_results positional arguments

compare_batch_results options

  • -h, --help - show this help message and exit

  • --detection_thresholds DETECTION_THRESHOLDS - list of detection thresholds, same length as the number of .json files, defaults to 0.15 for all files

  • --rendering_thresholds RENDERING_THRESHOLDS - list of rendering thresholds, same length as the number of .json files, defaults to 0.10 for all files

  • --max_images_per_category MAX_IMAGES_PER_CATEGORY - number of images to sample for each agreement category (common detections, etc.)

  • --target_width TARGET_WIDTH - output image width, defaults to 800

  • --use_processes - use processes rather than threads for parallelization

  • --open_results - open the output html file when done

  • --n_rendering_workers N_RENDERING_WORKERS - number of workers for parallel rendering, defaults to 10

Example:

python compare_batch_results.py output_folder image_folder mdv5a.json mdv5b.json mdv4.json --detection_thresholds 0.15 0.15 0.7

postprocessing.validate_batch_results module

validate_batch_results.py

Given a .json file containing MD results, validate that it’s compliant with the format spec:

https://lila.science/megadetector-output-format

class megadetector.postprocessing.validate_batch_results.ValidateBatchResultsOptions[source]

Bases: object

Options controlling the behavior of validate_batch_results()

check_image_existence

Should we verify that images exist? If this is True, and the .json file contains relative paths, relative_path_base needs to be specified.

raise_errors

Should we raise errors immediately (vs. just catching and reporting)?

relative_path_base

If check_image_existence is True, where do the images live?

If None, assumes absolute paths.

return_data

Should we return the loaded data, or just the validation results?

verbose

Enable additional debug output

megadetector.postprocessing.validate_batch_results.validate_batch_results(json_filename, options=None)[source]

Verify that [json_filename] is a valid MD output file. Currently errors on invalid files.

Parameters:
  • json_filename (str or dict) – the filename to validate, or an already loaded results dict

  • options (ValidateBatchResultsOptions, optional) – all the parameters used to control this process, see ValidateBatchResultsOptions for details

Returns:

a dict with a field called “validation_results”, which is itself a dict. The reason it’s a dict inside a dict is that if return_data is True, the outer dict also contains all the loaded data. The “validation_results” dict contains fields called “errors”, “warnings”, and “filename”. “errors” and “warnings” are lists of strings, although “errors” will never be longer than N=1, since validation fails at the first error.

Return type:

dict

validate_batch_results - CLI interface

validate_batch_results [-h] [--check_image_existence]
                       [--relative_path_base RELATIVE_PATH_BASE]
                       json_filename

validate_batch_results positional arguments

  • json_filename - path to .json file containing MegaDetector results

validate_batch_results options

  • -h, --help - show this help message and exit

  • --check_image_existence - check that all images referred to in the results file exist

  • --relative_path_base RELATIVE_PATH_BASE - if –check_image_existence is specified and paths are relative, use this as the base folder

postprocessing.detector_calibration module

detector_calibration.py

Tools for comparing/calibrating confidence values from detectors, particularly different versions of MegaDetector.

class megadetector.postprocessing.detector_calibration.CalibrationMatchColumns(value)[source]

Bases: IntEnum

Enumeration defining columns in the calibration_matches list we’ll assemble below.

COLUMN_CATEGORY_ID = 4
COLUMN_CONF_A = 0
COLUMN_CONF_B = 1
COLUMN_IOU = 2
COLUMN_I_IMAGE = 3
COLUMN_MATCHES_GT = 5
class megadetector.postprocessing.detector_calibration.CalibrationOptions[source]

Bases: object

Options controlling comparison/calibration behavior.

categories_to_plot

List of category IDs to use for plotting comparisons, or None to plot all categories.

category_id_to_name

Optionally map category ID to name in plot labels

confidence_threshold

Minimum confidence threshold to consider for calibration (should be lower than the lowest value you would use in realistic situations)

iou_threshold

IoU threshold used for determining whether two detections are the same

When multiple detections match, we will only use the highest-matching IoU.

max_samples_per_category

Maximum number of samples to use for plotting or calibration per category, or None to use all paired values. If separate_plots_by_category is False, this is the overall number of points sampled.

model_name_a

Model name to use in printouts and plots for result set A

model_name_b

Model name to use in printouts and plots for result set B

return_data

Should we populate the data_a and data_b fields in the return value?

separate_plots_by_category

Should we make separate plots for each category? Mutually exclusive with separate_plots_by_correctness.

separate_plots_by_correctness

Should we make separate plots for TPs/FPs? Mutually exclusive with separate_plots_by_category.

verbose

Enable additional debug output

class megadetector.postprocessing.detector_calibration.CalibrationResults[source]

Bases: object

Results of a model-to-model comparison.

calibration_matches

[conf_a, conf_b, iou, i_image, category_id, matches_gt]

If ground truth is supplied, [matches_gt] is a bool indicating whether either of the detected boxes matches a ground truth box of the same category. If ground truth is not supplied, [matches_gt] is None.

Type:

List of tuples

data_a

Populated with the data loaded from json_filename_a if options.return_data is True

data_b

Populated with the data loaded from json_filename_b if options.return_data is True

megadetector.postprocessing.detector_calibration.compare_model_confidence_values(json_filename_a, json_filename_b, json_filename_gt=None, options=None)[source]

Compare confidence values across two .json results files. Compares only detections that can be matched by IoU, i.e., does not do anything with detections that only appear in one file.

Parameters:
  • json_filename_a (str or dict) – filename containing results from the first model to be compared; should refer to the same images as [json_filename_b]. Can also be a loaded results dict.

  • json_filename_b (str or dict) – filename containing results from the second model to be compared; should refer to the same images as [json_filename_a]. Can also be a loaded results dict.

  • json_filename_gt (str or dict, optional) – filename containing ground truth; should refer to the same images as [json_filename_a] and [json_filename_b]. Can also be a loaded results dict. Should be in COCO format.

  • options (CalibrationOptions, optional) – all the parameters used to control this process, see CalibrationOptions for details

Returns:

description of the comparison results

Return type:

CalibrationResults

megadetector.postprocessing.detector_calibration.plot_matched_confidence_values(calibration_results, output_filename, options=None)[source]

Given a set of paired confidence values for matching detections (from compare_model_confidence_values), plot histograms of those pairs for each detection category.

Parameters:
  • calibration_results (CalibrationResults) – output from a call to compare_model_confidence_values, containing paired confidence values for two sets of detection results.

  • output_filename (str) – filename to write the plot (.png or .jpg)

  • options (CalibrationOptions, optional) – plotting options, see CalibrationOptions for details.

postprocessing.convert_output_format module

convert_output_format.py

Converts between file .json and .csv representations of MD output. The .csv format is largely obsolete, don’t use it unless you’re super-duper sure you need it.

megadetector.postprocessing.convert_output_format.convert_csv_to_json(input_path, output_path=None, overwrite=True)[source]

Convert .csv to .json. If output_path is None, will convert x.csv to x.json. This supports a largely obsolete .csv format, there’s almost no reason you want to do this.

Parameters:
  • input_path (str) – .csv filename to convert to .json

  • output_path (str, optional) – the output .json file to generate; if this is None, uses [input_path].json

  • overwrite (bool, optional) – whether to overwrite an existing .json file; if this is False and the output file exists, no-ops and returns

megadetector.postprocessing.convert_output_format.convert_json_to_csv(input_path, output_path=None, min_confidence=None, omit_bounding_boxes=False, output_encoding=None, overwrite=True, verbose=False)[source]

Converts a MD results .json file to a totally non-standard .csv format.

If [output_path] is None, will convert x.json to x.csv.

Parameters:
  • input_path (str) – the input .json file to convert

  • output_path (str, optional) – the output .csv file to generate; if this is None, uses [input_path].csv

  • min_confidence (float, optional) – the minimum-confidence detection we should include in the “detections” column; has no impact on the other columns

  • omit_bounding_boxes (bool, optional) – whether to leave out the json-formatted bounding boxes that make up the “detections” column, which are not generally useful for someone who wants to consume this data as a .csv file

  • output_encoding (str, optional) – encoding to use for the .csv file

  • overwrite (bool, optional) – whether to overwrite an existing .csv file; if this is False and the output file exists, no-ops and returns

  • verbose (bool, optional) – enable additional debug output

convert_output_format - CLI interface

convert_output_format [-h] [--output_path OUTPUT_PATH] [--omit_bounding_boxes] input_path

convert_output_format positional arguments

  • input_path - Input filename ending in .json or .csv

convert_output_format options

  • -h, --help - show this help message and exit

  • --output_path OUTPUT_PATH - Output filename ending in .json or .csv (defaults to input file, with .json/.csv replaced by .csv/.json)

  • --omit_bounding_boxes - Omit bounding box text from .csv output (large and usually not useful)

postprocessing.md_to_coco module

md_to_coco.py

“Converts” MegaDetector output files to COCO format. “Converts” is in quotes because this is an opinionated transformation that requires a confidence threshold for most applications.

Does not currently handle classification information.

megadetector.postprocessing.md_to_coco.md_to_coco(md_results_file, coco_output_file=None, image_folder=None, confidence_threshold=0.15, validate_image_sizes=False, info=None, preserve_nonstandard_metadata=True, include_failed_images=True, include_annotations_without_bounding_boxes=True, empty_category_id='0', overwrite_behavior='skip', verbose=True, image_filename_to_size=None, unrecognized_category_handling='error', precision=3)[source]

“Converts” MegaDetector output files to COCO format. “Converts” is in quotes because this is an opinionated transformation that typically requires a confidence threshold.

The default confidence threshold is not 0; the assumption is that by default, you are going to treat the resulting COCO file as a set of labels. If you are using the resulting COCO file to evaluate a detector, rather than as a set of labels, you likely want a confidence threshold of 0. Confidence values will be written to the semi-standard “score” field for each image (regardless of the threshold) if preserve_nonstandard_metadata is True.

A folder of images is required if width and height information are not available in the MD results file.

Parameters:
  • md_results_file (str) – MD results .json file to convert to COCO format

  • coco_output_file (str, optional) – COCO .json file to write; if this is None, we’ll return a COCO-formatted dict, but won’t write it to disk. If this is ‘auto’, we’ll write to [md_results_file_without_extension].coco.json.

  • image_folder (str, optional) – folder of images, required if ‘width’ and ‘height’ are not present in the MD results file (they are not required by the format)

  • confidence_threshold (float, optional) – boxes below this confidence threshold will not be included in the output data

  • validate_image_sizes (bool, optional) – if this is True, we’ll check the image sizes regardless of whether “width” and “height” are present in the MD results file.

  • info (dict, optional) – arbitrary metadata to include in an “info” field in the COCO-formatted output

  • preserve_nonstandard_metadata (bool, optional) – if this is True, confidence will be preserved in a non-standard “score” field in each annotation, and any random fields present in each image’s data (e.g. EXIF metadata) will be propagated to COCO output

  • include_failed_images (bool, optional) – if this is True, failed images will be propagated to COCO output with a non-empty “failure” field and no other fields, otherwise failed images will be skipped.

  • include_annotations_without_bounding_boxes (bool, optional) – the only time we end up with annotations without bounding boxes is when a detection has the category [empty_category_id]; this determines whether those annotations are included in the output.

  • empty_category_id (str, optional) – category ID reserved for the ‘empty’ class, should not be attached to any bounding boxes

  • overwrite_behavior (str, optional) – determines behavior if the output file exists (‘skip’ to skip conversion, ‘overwrite’ to overwrite the existing file, ‘error’ to raise an error, ‘skip_if_valid’ to skip conversion if the .json file appears to be intact (does not verify COCO formatting, just intact-.json-ness))

  • verbose (bool, optional) – enable debug output, including the progress bar,

  • image_filename_to_size (dict, optional) – dictionary mapping relative image paths to (w,h) tuples. Reading image sizes is the slowest step, so if you need to convert many results files at once for the same set of images, things will be gobs faster if you read the image sizes in advance and pass them in via this argument. The format used here is the same format output by parallel_get_image_sizes().

  • unrecognized_category_handling (str or float, optional) – specifies what to do when encountering category IDs not in the category mapping. Can be “error”, “ignore”, or “warning”. Can also be a float, in which case an error is thrown if an unrecognized category has a confidence value higher than this value.

  • precision (int, optional) – round box coordinates to this many decimal places, or None to bypass rounding.

Returns:

the COCO data dict, identical to what’s written to [coco_output_file] if [coco_output_file] is not None.

Return type:

dict

md_to_coco - CLI interface

“Convert” MD output to COCO format, in quotes because this is an opinionated transformation that requires a confidence threshold

md_to_coco [-h] [--image_folder IMAGE_FOLDER] [--preserve_nonstandard_metadata]
           [--include_failed_images]
           md_results_file coco_output_file confidence_threshold

md_to_coco positional arguments

md_to_coco options

  • -h, --help - show this help message and exit

  • --image_folder IMAGE_FOLDER - Image folder, only required if we will need to access image sizes

  • --preserve_nonstandard_metadata - Preserve metadata that isn’t normally included in COCO-formatted data (e.g. EXIF metadata, confidence values)

  • --include_failed_images - Keep a record of corrupted images in the output; may not be completely COCO-compliant

postprocessing.md_to_labelme module

md_to_labelme.py

“Converts” a MegaDetector output .json file to labelme format (one .json per image file). “Convert” is in quotes because this is an opinionated transformation that requires a confidence threshold.

TODO: # noqa

  • support variable confidence thresholds across classes

  • support classification data

megadetector.postprocessing.md_to_labelme.get_labelme_dict_for_image(im, image_base_name=None, category_id_to_name=None, info=None, confidence_threshold=None)[source]

For the given image struct in MD results format, reformat the detections into labelme format.

Parameters:
  • im (dict) – MegaDetector-formatted results dict, must include ‘height’ and ‘width’ fields

  • image_base_name (str, optional) – written directly to the ‘imagePath’ field in the output; defaults to os.path.basename(im[‘file’]).

  • category_id_to_name (dict, optional) – maps string-int category IDs to category names, defaults to the standard MD categories

  • info (dict, optional) – arbitrary metadata to write to the “detector_info” field in the output dict

  • confidence_threshold (float, optional) – only detections at or above this confidence threshold will be included in the output dict

Returns:

labelme-formatted dictionary, suitable for writing directly to a labelme-formatted .json file

Return type:

dict

megadetector.postprocessing.md_to_labelme.md_to_labelme(results_file, image_base, confidence_threshold=None, overwrite=False, extension_prefix='', n_workers=1, use_threads=False, bypass_image_size_read=False, verbose=False)[source]

For all the images in [results_file], write a .json file in labelme format alongside the corresponding relative path within image_base.

Parameters:
  • results_file (str) – MD results .json file to convert to Labelme format

  • image_base (str) – folder of images; filenames in [results_file] should be relative to this folder

  • confidence_threshold (float, optional) – only detections at or above this confidence threshold will be included in the output dict. If None, no threshold will be applied.

  • overwrite (bool, optional) – whether to overwrite existing output files; if this is False and the output file for an image exists, we’ll skip that image

  • extension_prefix (str, optional) – if non-empty, “extension_prefix” will be inserted before the .json extension (typically used to generate multiple copies of labelme files representing different MD thresholds)

  • n_workers (int, optional) – enables multiprocessing if > 1

  • use_threads (bool, optional) – if [n_workers] > 1, determines whether we parallelize via threads (True) or processes (False)

  • bypass_image_size_read (bool, optional) – if True, skips reading image sizes and trusts whatever is in the MD results file (don’t set this to “True” if your MD results file doesn’t contain image sizes)

  • verbose (bool, optional) – enables additionald ebug output

md_to_labelme - CLI interface

Convert MD output to labelme annotation format

md_to_labelme [-h] [--confidence_threshold CONFIDENCE_THRESHOLD] [--overwrite]
              results_file image_base

md_to_labelme positional arguments

md_to_labelme options

postprocessing.md_to_wi module

md_to_wi.py

Converts the MD .json format to the WI predictions.json format.

md_to_wi - CLI interface

md_to_wi [-h] [--base_folder BASE_FOLDER] md_results_file predictions_json_file

md_to_wi positional arguments

md_to_wi options

  • -h, --help - show this help message and exit

  • --base_folder BASE_FOLDER - folder name to prepend to each path in md_results_file, to convert relative paths to absolute paths.

postprocessing.merge_detections module

merge_detections.py

Merge high-confidence detections from one or more results files into another file. Typically used to combine results from MDv5b and/or MDv4 and/or MDv5a into a “primary” results file from MDv5a or MDv1000-redwood.

Detection categories must be the same in both files; if you want to first remap one file’s category mapping to be the same as another’s, see remap_detection_categories.

If you want to literally merge two .json files, see combine_batch_outputs.py.

class megadetector.postprocessing.merge_detections.MergeDetectionsOptions[source]

Bases: object

Class defining options for merge_detections().

categories_to_exclude

If you want to merge only certain categories, specify one (but not both) of these. These are category IDs, not names.

categories_to_include

If you want to merge only certain categories, specify one (but not both) of these. These are category IDs, not names.

iou_threshold

IoU threshold above which two detections are considered the same

mark_copied_detections

Add a ‘merged’ field (value True) to all merged detections.

Only used for debugging.

max_detection_size

Maximum detection size to include in the merged output

merge_empty_only

Only merge detections into images that have no above-threshold detections in the target results file.

min_detection_size

Minimum detection size to include in the merged output

overwrite

Error if this is False and the output file exists

source_confidence_thresholds

Exclude detections whose confidence in the source file(s) is less than this. Should have the same length as the number of source files.

target_confidence_threshold

Don’t bother merging into target images if there is a similar detection above this threshold (or if there is any detection above this threshold, and merge_empty_only is True)

megadetector.postprocessing.merge_detections.merge_detections(source_files, target_file, output_file=None, options=None)[source]

Merge high-confidence detections from one or more results files into another file. Typically used to combine results from, e.g., MDv5a and/or MDv5b into a “primary” results file from MDv1000-redwood.

[source_files] (a list of files or a single filename) specifies the set of results files that will be merged into [target_file]. The difference between a “source file” and the “target file” is that if no merging is necessary, either because two boxes are nearly identical or because merge_only_empty is True and the target file already has above-threshold detection for an image+category, the output file gets the results of the “target” file. I.e., the “target” file wins all ties.

Merges classification categories based on category names (ignoring descriptions).

The results are written to [output_file].

Parameters:
  • source_files (list of str) – list of files to merge into the results in [target_file]

  • target_file (str) – filename that is treated as the primary source of results

  • output_file (str, optional) – file to which we should write merged results

  • options (MergeDetectionsOptions, optional) – see MergeDetectionsOptions

Returns:

dict in MegaDetector format, containing merged results

merge_detections - CLI interface

Merge detections from one or more MegaDetector results files into an existing results file

merge_detections [-h] [--max_detection_size MAX_DETECTION_SIZE]
                 [--min_detection_size MIN_DETECTION_SIZE]
                 [--source_confidence_thresholds SOURCE_CONFIDENCE_THRESHOLDS [SOURCE_CONFIDENCE_THRESHOLDS ...]]
                 [--target_confidence_threshold TARGET_CONFIDENCE_THRESHOLD]
                 [--categories_to_include CATEGORIES_TO_INCLUDE [CATEGORIES_TO_INCLUDE ...]]
                 [--categories_to_exclude CATEGORIES_TO_EXCLUDE [CATEGORIES_TO_EXCLUDE ...]]
                 [--merge_empty_only] [--iou_threshold IOU_THRESHOLD]
                 source_files [source_files ...] target_file output_file

merge_detections positional arguments

merge_detections options

  • -h, --help - show this help message and exit

  • --max_detection_size MAX_DETECTION_SIZE - Ignore detections with an area larger than this (as a fraction of image size) (default 1.01)

  • --min_detection_size MIN_DETECTION_SIZE - Ignore detections with an area smaller than this (as a fraction of image size) (default 0)

  • --source_confidence_thresholds SOURCE_CONFIDENCE_THRESHOLDS - List of thresholds for each source file (default [0.05]). Merge only if the source file’s detection confidence is higher than its corresponding threshold. Should be the same length as the number of source files.

  • --target_confidence_threshold TARGET_CONFIDENCE_THRESHOLD - Do not merge if target file detection confidence is already higher than this (default 0.2)

  • --categories_to_include CATEGORIES_TO_INCLUDE - List of numeric detection category IDs to include

  • --categories_to_exclude CATEGORIES_TO_EXCLUDE - List of numeric detection categories to exclude

  • --merge_empty_only - Ignore individual detections and only merge images for which the target file contains no detections

  • --iou_threshold IOU_THRESHOLD - Sets the minimum IoU for a source detection to be considered the same as a target detection (default 0.65)

postprocessing.postprocess_batch_results module

postprocess_batch_results.py

Given a .json or .csv file containing MD results, do one or more of the following:

  • Sample detections/non-detections and render to HTML (when ground truth isn’t available) (this is 99.9% of what this module is for)

  • Evaluate detector precision/recall, optionally rendering results (requires ground truth)

  • Sample true/false positives/negatives and render to HTML (requires ground truth)

Ground truth, if available, must be in COCO Camera Traps format:

https://github.com/agentmorris/MegaDetector/blob/main/megadetector/data_management/README.md#coco-camera-traps-format

class megadetector.postprocessing.postprocess_batch_results.PostProcessingOptions[source]

Bases: object

Options used to parameterize process_batch_results().

additional_image_fields_to_display

Additional image fields to display in image headers. If this is a list, we’ll include those fields; if this is a dict, we’ll use that dict to choose alternative display names for each field.

almost_detection_confidence_threshold

Only a float is supported here (unlike the “confidence_threshold” parameter, which can be a dict).

api_detection_results

Allow bypassing API output loading when operating on previously-loaded results. If present, this is a Pandas DataFrame. Almost never useful.

api_other_fields

Allow bypassing API output loading when operating on previously-loaded results. If present, this is a str –> obj dict. Almost never useful.

api_output_filename_replacements

Optionally replace one or more strings in filenames with other strings; useful for taking a set of results generated for one folder structure and applying them to a slightly different folder structure.

box_expansion

Box expansion (in pixels) for rendering detections

category_name_to_sort_weight

When classification results are present, use this dictionary to push some categories to the bottom of the list. Larger numbers == later groups. Default sort weight is zero. Line breaks will separate equal sort weights. Sort weights must be integers.

In practice this is used to push generic categories like “blank”, “animal”, and “unreliable” to the bottom of the list, like:

options.category_name_to_sort_weight =

{‘animal’:1,’blank’:1,’unknown’:1,’unreliable’:1,’mammal’:1,’no cv result’:1}

classification_confidence_threshold

Confidence threshold to apply to classification (not detection) results

Only a float is supported here (unlike the “confidence_threshold” parameter, which can be a dict).

confidence_threshold

If this is None, a confidence threshold is selected based on the detector version.

This can either be a float or a dictionary mapping category names (not IDs) to thresholds. The category “default” can be used to specify thresholds for other categories. Currently the use of a dict here is not supported when ground truth is supplied.

ground_truth_filename_replacements

Optionally replace one or more strings in filenames with other strings; useful for taking a set of results generated for one folder structure and applying them to a slightly different folder structure.

ground_truth_json_file

Optional .json file containing ground truth information

html_sort_order

Sort order for the output, should be one of “filename”, “confidence”, or “random”

image_base_dir

Folder where images live (filenames in [md_results_file] should be relative to this folder)

Can be ‘’ if [md_results_file] uses absolute paths.

include_almost_detections

Should we also split out a separate report about the detections that were just below our main confidence threshold?

Currently only supported when ground truth is unavailable.

include_category_descriptions_with_global_counts

The category/count summary typically only includes category names, this flag includes descriptions (typically taxonomic strings) as well.

include_classification_category_report

If classification results are present, should we include a summary of classification categories?

include_size_range

Display the min/max normalized size of above-threshold detections for each image

job_name_string

Job name to include in big letters in the output HTML

line_thickness

Line width (in pixels) for rendering detections

If True, images in the output HTML will be links back to the original images

max_figures_per_html_file

Should we split individual pages up into smaller pages if there are more than N images?

md_results_file

MD results .json file to process

model_version_string

Model version string to include in the output HTML

negative_classes

List of classes we’ll treat as negative (defaults to “empty”, typically includes classes like “blank”, “misfire”, etc.).

Include the token “#NO_LABELS#” to indicate that an image with no annotations should be considered empty.

num_images_to_sample

Number of images to sample, -1 for “all images”

output_dir

Folder to which we should write HTML output

output_html_encoding

Character encoding to use when writing the index HTML html

parallelize_rendering

Enable/disable rendering parallelization

parallelize_rendering_n_cores

Number of threads/processes to use for rendering parallelization

parallelize_rendering_with_threads

Whether to use threads (True) or processes (False) for rendering parallelization

rendering_bypass_sets

List of output sets that we should count, but not render images for.

Typically used to preview sets with lots of empties, where you don’t want to subset but also don’t want to render 100,000 empty images.

Example strings that are valid for this option:

detections, non_detections detections_animal, detections_person, detections_vehicle tn, tp, fn, fp

sample_seed

Random seed for sampling, or None

separate_detections_by_category

Optionally separate detections into categories (animal/vehicle/human)

Currently only supported when ground truth is unavailable

sort_classification_results_by_count

When classification results are present, should be sort alphabetically by class name (False) or in descending order by frequency (True)?

target_recall

Used for summary statistics only

unlabeled_classes

List of classes we’ll treat as neither positive nor negative (defaults to “unknown”, typically includes classes like “unidentifiable”).

viz_target_width

Image width for images in the HTML output

class megadetector.postprocessing.postprocess_batch_results.PostProcessingResults[source]

Bases: object

Return format from process_batch_results

api_detection_results

Pandas Dataframe containing detection results

api_other_fields

str –> obj dictionary containing other information loaded from the results file

output_html_file

HTML file to which preview information was written

megadetector.postprocessing.postprocess_batch_results.process_batch_results(options)[source]

Given a .json or .csv file containing MD results, do one or more of the following:

  • Sample detections/non-detections and render to HTML (when ground truth isn’t available) (this is 99.9% of what this module is for)

  • Evaluate detector precision/recall, optionally rendering results (requires ground truth)

  • Sample true/false positives/negatives and render to HTML (requires ground truth)

Ground truth, if available, must be in COCO Camera Traps format:

https://github.com/agentmorris/MegaDetector/blob/main/megadetector/data_management/README.md#coco-camera-traps-format

Parameters:

options (PostProcessingOptions) – everything we need to render a preview/analysis for this set of results; see the PostProcessingOptions class for details.

Returns:

information about the results/preview, most importantly the HTML filename of the output. See the PostProcessingResults class for details.

Return type:

PostProcessingResults

postprocess_batch_results - CLI interface

postprocess_batch_results [-h] [--image_base_dir IMAGE_BASE_DIR]
                          [--ground_truth_json_file GROUND_TRUTH_JSON_FILE]
                          [--confidence_threshold CONFIDENCE_THRESHOLD]
                          [--almost_detection_confidence_threshold ALMOST_DETECTION_CONFIDENCE_THRESHOLD]
                          [--target_recall TARGET_RECALL]
                          [--num_images_to_sample NUM_IMAGES_TO_SAMPLE]
                          [--viz_target_width VIZ_TARGET_WIDTH] [--include_almost_detections]
                          [--html_sort_order HTML_SORT_ORDER] [--sort_by_confidence]
                          [--n_cores N_CORES] [--parallelize_rendering_with_processes]
                          [--no_separate_detections_by_category] [--open_output_file]
                          [--max_figures_per_html_file MAX_FIGURES_PER_HTML_FILE]
                          md_results_file output_dir

postprocess_batch_results positional arguments

postprocess_batch_results options

postprocessing.remap_detection_categories module

remap_detection_categories.py

Given a MegaDetector results file, remap the category IDs according to a specified dictionary, writing the results to a new file.

Currently only supports remapping detection categories, not classification categories.

megadetector.postprocessing.remap_detection_categories.remap_detection_categories(input_file, output_file, target_category_map, input_category_name_to_output_category_name, overwrite=False, invalid_category_handling='unknown')[source]

Given a MegaDetector results file [input_file], remap the category IDs according to the dictionary [target_category_map], writing the results to [output_file]. The remapped dictionary needs to have the same category names as the input file’s detection_categories dictionary.

Typically used to map, e.g., a variety of species to the class “mammal” or the class “animal”.

Currently only supports remapping detection categories, not classification categories.

Parameters:
  • input_file (str) – the MD .json results file to remap

  • output_file (str) – the remapped .json file to write

  • target_category_map (dict) – the category mapping that should be used in the output file, mapping string-ints to class names. This can also be a MD results file, in which case we’ll use that file’s detection_categories dictionary.

  • input_category_name_to_output_category_name (dict) – str->str, the specific category mapping that should be used, otherwise will determine from target class names

  • overwrite (bool, optional) – whether to overwrite [output_file] if it exists; if this is True and [output_file] exists, this function is a no-op

  • invalid_category_handling (str, optional) – what to do about categories that are not in the input file’s category list (‘error’ or ‘unknown’), if ‘unknown’, creates a new “unknown” category

postprocessing.render_detection_confusion_matrix module

render_detection_confusion_matrix.py

Given a CCT-formatted ground truth file and a MegaDetector-formatted results file, render an HTML confusion matrix. Typically used for multi-class detectors. Currently assumes a single class per image.

megadetector.postprocessing.render_detection_confusion_matrix.render_detection_confusion_matrix(ground_truth_file, results_file, image_folder, preview_folder, force_render_images=False, confidence_thresholds=None, rendering_confidence_thresholds=None, target_image_size=(1280, -1), parallelize_rendering=True, parallelize_rendering_n_cores=None, parallelize_rendering_with_threads=False, job_name='unknown', model_file=None, empty_category_name='empty', html_image_list_options=None)[source]

Given a CCT-formatted ground truth file and a MegaDetector-formatted results file, render an HTML confusion matrix in [preview_folder. Typically used for multi-class detectors. Currently assumes a single class per image.

confidence_thresholds and rendering_confidence_thresholds are dictionaries mapping class names to thresholds. “default” is a special token that will be used for all classes not otherwise assigned thresholds.

Parameters:
  • ground_truth_file (str) – the CCT-formatted .json file with ground truth information

  • results_file (str) – the MegaDetector results .json file

  • image_folder (str) – the folder where images live; filenames in [ground_truth_file] and [results_file] should be relative to this folder.

  • preview_folder (str) – the output folder, i.e. the folder in which we’ll create our nifty HTML stuff.

  • force_render_images (bool, optional) – if False, skips images that already exist

  • confidence_thresholds (dict, optional) – a dictionary mapping class names to thresholds; all classes not explicitly named here will use the threshold for the “default” category.

  • rendering_confidence_thresholds (dict, optional) – a dictionary mapping class names to thresholds; all classes not explicitly named here will use the threshold for the “default” category.

  • target_image_size (tuple, optional) – output image size, as a pair of ints (width,height). If one value is -1 and the other is not, aspect ratio is preserved. If both are -1, the original image sizes are preserved.

  • parallelize_rendering (bool, optional) – enable (default) or disable parallelization when rendering

  • parallelize_rendering_n_cores (int, optional) – number of threads or processes to use for rendering, only used if parallelize_rendering is True

  • parallelize_rendering_with_threads (bool, optional) – whether to use threads (True) or processes (False) when rendering, only used if parallelize_rendering is True

  • job_name (str, optional) – job name to include in big letters in the output file

  • model_file (str, optional) – model filename to include in HTML output

  • empty_category_name (str, optional) – special category name that we should treat as empty, typically “empty”

  • html_image_list_options (dict, optional) – options listed passed along to write_html_image_list; see write_html_image_list for documentation.

Returns:

confusion matrix information, containing at least the key “html_file”

Return type:

dict

postprocessing.separate_detections_into_folders module

separate_detections_into_folders.py

Overview

Given a .json file with batch processing results, separate the files in that set of results into folders that contain animals/people/vehicles/nothing, according to per-class thresholds.

Image files are copied, not moved.

Output structure

Preserves relative paths within each of those folders; cannot be used with .json files that have absolute paths in them.

For example, if your .json file has these images:

  • a/b/c/1.jpg

  • a/b/d/2.jpg

  • a/b/e/3.jpg

  • a/b/f/4.jpg

  • a/x/y/5.jpg

And let’s say:

  • The results say that the first three images are empty/person/vehicle, respectively

  • The fourth image is above threshold for “animal” and “person”

  • The fifth image contains an animal

  • You specify an output base folder of c:/out

You will get the following files:

  • c:/out/empty/a/b/c/1.jpg

  • c:/out/people/a/b/d/2.jpg

  • c:/out/vehicles/a/b/e/3.jpg

  • c:/out/animal_person/a/b/f/4.jpg

  • c:/out/animals/a/x/y/5.jpg

Rendering bounding boxes

By default, images are just copied to the target output folder. If you specify –render_boxes, bounding boxes will be rendered on the output images. Because this is no longer strictly a copy operation, this may result in the loss of metadata. More accurately, this may result in the loss of some EXIF metadata; this will result in the loss of IPTC/XMP metadata.

Rendering boxes also makes this script a lot slower.

Classification-based separation

If you have a results file with classification data, you can also specify classes to put in their own folders, within the “animals” folder, like this:

--classification_thresholds "deer=0.75,cow=0.75"

So, e.g., you might get:

c:/out/animals/deer/a/x/y/5.jpg

In this scenario, the folders within “animals” will be:

deer, cow, multiple, unclassified

“multiple” in this case only means “deer and cow”; if an image is classified as containing a bird and a bear, that would end up in “unclassified”, since the folder separation is based only on the categories you provide at the command line.

No classification-based separation is done within the animal_person, animal_vehicle, or animal_person_vehicle folders.

class megadetector.postprocessing.separate_detections_into_folders.SeparateDetectionsIntoFoldersOptions(threshold=None)[source]

Bases: object

Options used to parameterize separate_detections_into_folders()

allow_existing_directory

By default, this function errors if you try to output to an existing folder

allow_missing_files

By default, this function errors if any of the images specified in the results file don’t exist in the source folder.

base_input_folder

The folder containing source images; filenames in [results_file] should be relative to this folder.

base_output_folder

The folder to which we should write output images; see the module header comment for information about how that folder will be structured.

box_expansion

Box expansion in pixels; only relevant if [render_boxes] is True

category_id_to_category_name

Do not set explicitly; this gets loaded from [results_file]

category_name_to_folder

Do not set explicitly; this gets created based on [results_file]

Dictionary mapping categories (plus combinations of categories, and ‘empty’) to output folders

category_name_to_threshold

Dict mapping category names to thresholds; for example, an image with only a detection of class “animal” whose confidence is greater than or equal to category_name_to_threshold[‘animal’] will be put in the “animal” folder.

category_names_to_blur

List of category names for which we should blur detections, most commonly [‘person’]

Can also be a comma-separated list.

classification_categories

Do not set explicitly; populated from data when using classification results

classification_category_id_to_name

Do not set explicitly; populated from data when using classification results

classification_thresholds

Originally specified as a string that looks like this:

deer=0.75,cow=0.75

String, converted internally to a dict mapping name:threshold

debug_max_images

Used to test this script; sets a limit on the number of images to process.

line_thickness

Line thickness in pixels; only relevant if [render_boxes] is True

move_images

Should we move rather than copy?

n_threads

Number of workers to use, set to <= 1 to disable parallelization

overwrite

Whether to overwrite images that already exist in the target folder; only relevant if [allow_existing_directory] is True

remove_empty_folders

Remove all empty folders from the target folder at the end of the process, whether or not they were created by this script

render_boxes

Should we render boxes on the output images? Makes everything a lot slower.

results_file

The MD results .json file to process

skip_empty_images

Whether to skip empty images; if this is False, empty images (i.e., images with no detections above the corresponding threshold) will be copied to an “empty” folder.

threshold

Default threshold for categories not specified in category_name_to_threshold

megadetector.postprocessing.separate_detections_into_folders.separate_detections_into_folders(options)[source]

Given a .json file with batch processing results, separate the files in that set of results into folders that contain animals/people/vehicles/nothing, according to per-class thresholds. See the header comment of this module for more details about the output folder structure.

Parameters:

separate_detections_into_folders - CLI interface

separate_detections_into_folders [-h] [--threshold THRESHOLD]
                                 [--animal_threshold ANIMAL_THRESHOLD]
                                 [--human_threshold HUMAN_THRESHOLD]
                                 [--vehicle_threshold VEHICLE_THRESHOLD]
                                 [--classification_thresholds CLASSIFICATION_THRESHOLDS]
                                 [--n_threads N_THREADS] [--allow_existing_directory]
                                 [--no_overwrite] [--skip_empty_images] [--move_images]
                                 [--render_boxes] [--line_thickness LINE_THICKNESS]
                                 [--box_expansion BOX_EXPANSION]
                                 [--category_names_to_blur CATEGORY_NAMES_TO_BLUR]
                                 [--remove_empty_folders]
                                 results_file base_input_folder base_output_folder

separate_detections_into_folders positional arguments

separate_detections_into_folders options

  • -h, --help - show this help message and exit

  • --threshold THRESHOLD - Default confidence threshold for all categories (defaults to selection based on model version, other options may override this for specific categories)

  • --animal_threshold ANIMAL_THRESHOLD - Confidence threshold for the animal category

  • --human_threshold HUMAN_THRESHOLD - Confidence threshold for the human category

  • --vehicle_threshold VEHICLE_THRESHOLD - Confidence threshold for vehicle category

  • --classification_thresholds CLASSIFICATION_THRESHOLDS - List of classification thresholds to use for species-based folder separation, formatted as, e.g., "deer=0.75,cow=0.75"

  • --n_threads N_THREADS - Number of threads to use for parallel operation (default=1)

  • --allow_existing_directory - Proceed even if the target directory exists and is not empty

  • --no_overwrite - Skip images that already exist in the target folder, must also specify –allow_existing_directory

  • --skip_empty_images - Do not copy empty images to the output folder

  • --move_images - Move images (rather than copying) (not recommended this if you have not backed up your data!)

  • --render_boxes - Render bounding boxes on output images; may result in some metadata not being transferred

  • --line_thickness LINE_THICKNESS - Line thickness (in pixels) for rendering, only meaningful if using render_boxes (defaults to 8)

  • --box_expansion BOX_EXPANSION - Box expansion (in pixels) for rendering, only meaningful if using render_boxes (defaults to 3)

  • --category_names_to_blur CATEGORY_NAMES_TO_BLUR - Comma-separated list of category names to blur (or a single category name, e.g. "person")

  • --remove_empty_folders - Remove all empty folders from the target folder at the end of the process, whether or not they were created by this script

postprocessing.subset_json_detector_output module

subset_json_detector_output.py

Creates one or more subsets of a detector results file (.json), doing either or both of the following (if both are requested, they happen in this order):

  1. Retrieve all elements where filenames contain a specified query string, optionally replacing that query with a replacement token. If the query is blank, can also be used to prepend content to all filenames.

    Does not support regex’s, but supports a special case of ^string to indicate “must start with to match”.

  2. Create separate .jsons for each unique path, optionally making the filenames in those .json’s relative paths. In this case, you specify an output directory, rather than an output path. All images in the folder blah/foo/bar will end up in a .json file called blah_foo_bar.json.

Can also apply a confidence threshold.

Can also subset by categories above a threshold (programmatic invocation only, this is not supported at the command line yet).

To subset a COCO Camera Traps .json database, see subset_json_db.py

Sample invocation (splitting into multiple json’s)

Read from “1800_idfg_statewide_wolf_detections_w_classifications.json”, split up into individual .jsons in ‘d:/temp/idfg/output’, making filenames relative to their individual folders:

python subset_json_detector_output.py ^

“d:/temp/idfg/1800_idfg_statewide_wolf_detections_w_classifications.json” “d:/temp/idfg/output” ^ –split_folders –make_folder_relative

Now do the same thing, but instead of writing .json’s to d:/temp/idfg/output, write them to subfolders corresponding to the subfolders for each .json file.

python subset_json_detector_output.py ^

“d:/temp/idfg/1800_detections_S2.json” “d:/temp/idfg/output_to_folders” ^ –split_folders –make_folder_relative –copy_jsons_to_folders

Sample invocation (creating a single subset matching a query)

Read from “1800_detections.json”, write to “1800_detections_2017.json”

Include only images matching “2017”, and change “2017” to “blah”

python subset_json_detector_output.py “d:/temp/1800_detections.json” “d:/temp/1800_detections_2017_blah.json” ^

–query 2017 –replacement blah

Include all images, prepend with “prefix/”

python subset_json_detector_output.py “d:/temp/1800_detections.json” “d:/temp/1800_detections_prefix.json” ^

–replacement “prefix/”

class megadetector.postprocessing.subset_json_detector_output.SubsetJsonDetectorOutputOptions[source]

Bases: object

Options used to parameterize subset_json_detector_output()

categories_to_keep

Either a list of category IDs (as string-ints) (not names), or a dictionary mapping category IDs (as string-ints) (not names) to thresholds. Removes non-matching detections, does not remove images. Not technically mutually exclusize with category_names_to_keep, but it’s an esoteric scenario indeed where you would want to specify both.

category_names_to_keep

Either a list of category names (not IDs), or a dictionary mapping category names (not IDs) to thresholds. Removes non-matching detections, does not remove images. Not technically mutually exclusize with category_ids_to_keep, but it’s an esoteric scenario indeed where you would want to specify both.

confidence_threshold

Optional confidence threshold; if not None, detections below this confidence won’t be included in the output.

copy_jsons_to_folders

if not None, will copy .json files to their corresponding output directories, relative to output_filename

Type:

Only meaningful if split_folders and make_folder_relative are True

copy_jsons_to_folders_directories_must_exist

If copy_jsons_to_folders is true, do we require that directories already exist?

debug_max_images

Set to >0 during testing to limit the number of images that get processed.

keep_files_in_list

Assumes that the input .json file contains relative paths when comparing to a folder.

make_folder_relative

should we convert pathnames to be relative the folder for each .json file?

Type:

Only meaningful if split_folders is True

maximum_detection_size

Remove detections above a threshold size (as a fraction of the image size)

minimum_detection_size

Remove detections below a threshold size (as a fraction of the image size)

overwrite_json_files

Should we over-write .json files?

query

Only process files containing the token ‘query’

Does not support general regexes, but supports ^ as a special case regex-like notation for “starts with”

remove_classification_categories_below_count

Remove classification with <= N instances. Does not re-map categories to be contiguous. Set to 1 to remove empty categories only.

remove_failed_images

Should we remove failed images?

replacement

Replace ‘query’ with ‘replacement’ if ‘replacement’ is not None. If ‘query’ is None, prepend ‘replacement’

split_folder_mode

Folder level to use for splitting [‘bottom’,’n_from_bottom’,’n_from_top’,’dict’]

‘dict’ requires ‘split_folder_param’ to be a dictionary mapping each filename to a token.

split_folder_param

When using the ‘n_from_bottom’ parameter to define folder splitting, this defines the number of directories from the bottom. ‘n_from_bottom’ with a parameter of zero is the same as ‘bottom’.

Same story with ‘n_from_top’.

When ‘split_folder_mode’ is ‘dict’, this should be a dictionary mapping each filename to a token.

split_folders

Should we split output into individual .json files for each folder?

megadetector.postprocessing.subset_json_detector_output.remove_classification_categories_below_count(data, options)[source]

Removes all classification categories below a threshold count. Does not re-map classification category IDs.

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.remove_failed_images(data, options)[source]

Removed failed images from [data]

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output(input_filename, output_filename, options, data=None)[source]

Main entry point; creates one or more subsets of a detector results file. See the module header comment for more information about the available subsetting approaches.

Makes a copy of [data] before modifying if a data dictionary is supplied.

Parameters:
  • input_filename (str) – filename to load and subset; can be None if [data] is supplied

  • output_filename (str) – file or folder name (depending on [options]) to which we should write subset results.

  • options (SubsetJsonDetectorOutputOptions) – parameters for .json splitting/subsetting; see SubsetJsonDetectorOutputOptions for details.

  • data (dict, optional) – data loaded from a .json file; if this is not None, [input_filename] will be ignored. If supplied, this will be copied before it’s modified.

Returns:

Results that are either loaded from [input_filename] and processed, or copied from [data] and processed.

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output_by_categories(data, options)[source]

Removes all detections without detections above a threshold for specific categories.

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output_by_confidence(data, options)[source]

Removes all detections below options.confidence_threshold.

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output_by_list(data, options)[source]

Keeps only files in options.keep_files_in_list, which can be a .json results file or a folder. Assumes that the input .json file contains relative paths when comparing to a folder.

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output_by_query(data, options)[source]

Subsets to images whose filename matches options.query; replace all instances of options.query with options.replacement. No-op if options.query_string is None or ‘’.

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

megadetector.postprocessing.subset_json_detector_output.subset_json_detector_output_by_size(data, options)[source]

Remove detections above or below threshold sizes (as a fraction of the image size).

Parameters:
Returns:

Possibly-modified version of [data] (also modifies in place)

Return type:

dict

subset_json_detector_output - CLI interface

subset_json_detector_output [-h] [--query QUERY] [--replacement REPLACEMENT]
                            [--confidence_threshold CONFIDENCE_THRESHOLD]
                            [--maximum_detection_size MAXIMUM_DETECTION_SIZE]
                            [--minimum_detection_size MINIMUM_DETECTION_SIZE]
                            [--keep_files_in_list KEEP_FILES_IN_LIST] [--split_folders]
                            [--split_folder_param SPLIT_FOLDER_PARAM]
                            [--split_folder_mode SPLIT_FOLDER_MODE] [--make_folder_relative]
                            [--overwrite_json_files] [--copy_jsons_to_folders]
                            [--create_folders]
                            [--remove_classification_categories_below_count REMOVE_CLASSIFICATION_CATEGORIES_BELOW_COUNT]
                            input_file output_file

subset_json_detector_output positional arguments

subset_json_detector_output options

  • -h, --help - show this help message and exit

  • --query QUERY - Query string to search for (omitting this matches all)

  • --replacement REPLACEMENT - Replace [query] with this

  • --confidence_threshold CONFIDENCE_THRESHOLD - Remove detections below this confidence level

  • --maximum_detection_size MAXIMUM_DETECTION_SIZE - Remove detections above this size (as a fraction of the image size)

  • --minimum_detection_size MINIMUM_DETECTION_SIZE - Remove detections below this size (as a fraction of the image size)

  • --keep_files_in_list KEEP_FILES_IN_LIST - Keep only files in this list, which can be a .json results file or a folder. Assumes that the input .json file contains relative paths when comparing to a folder.

  • --split_folders - Split .json files by leaf-node folder

  • --split_folder_param SPLIT_FOLDER_PARAM - Directory level count for n_from_bottom and n_from_top splitting

  • --split_folder_mode SPLIT_FOLDER_MODE - Folder level to use for splitting ("bottom", "n_from_bottom", or "n_from_top")

  • --make_folder_relative - Make image paths relative to their containing folder (only meaningful with split_folders)

  • --overwrite_json_files - Overwrite output files

  • --copy_jsons_to_folders - When using split_folders and make_folder_relative, copy jsons to their corresponding folders (relative to output_file)

  • --create_folders - When using copy_jsons_to_folders, create folders that dont exist

  • --remove_classification_categories_below_count REMOVE_CLASSIFICATION_CATEGORIES_BELOW_COUNT - Remove classification categories with less than this many instances (no removal by default)

postprocessing.top_folders_to_bottom module

top_folders_to_bottom.py

Given a base folder with files like:

  • A/1/2/a.jpg

  • B/3/4/b.jpg

…moves the top-level folders to the bottom in a new output folder, i.e., creates:

  • 1/2/A/a.jpg

  • 3/4/B/b.jpg

In practice, this is used to make this:

animal/camera01/image01.jpg

…look like:

camera01/animal/image01.jpg

class megadetector.postprocessing.top_folders_to_bottom.TopFoldersToBottomOptions(input_folder, output_folder, copy=True, n_threads=1, overwrite=False)[source]

Bases: object

Options used to parameterize top_folders_to_bottom()

copy

Whether to copy (True) vs. move (False) false when re-organizing

input_folder

Input folder

n_threads

Number of worker threads to use, or <1 to disable parallelization

output_folder

Output folder

overwrite

If this is False and an output file exists, throw an error

megadetector.postprocessing.top_folders_to_bottom.top_folders_to_bottom(options)[source]

top_folders_to_bottom.py

Given a base folder with files like:

  • A/1/2/a.jpg

  • B/3/4/b.jpg

…moves the top-level folders to the bottom in a new output folder, i.e., creates:

  • 1/2/A/a.jpg

  • 3/4/B/b.jpg

In practice, this is used to make this:

animal/camera01/image01.jpg

…look like:

camera01/animal/image01.jpg

Parameters:

options (TopFoldersToBottomOptions) – See TopFoldersToBottomOptions for parameter details.

top_folders_to_bottom - CLI interface

top_folders_to_bottom [-h] [--copy] [--overwrite] [--n_threads N_THREADS]
                      input_folder output_folder

top_folders_to_bottom positional arguments

top_folders_to_bottom options

  • -h, --help - show this help message and exit

  • --copy - Copy images, instead of moving (moving is the default)

  • --overwrite - Allow image overwrite (default=False)

  • --n_threads N_THREADS - Number of threads to use for parallel operation (default=1)

postprocessing.generate_csv_report module

generate_csv_report.py

Generates a .csv report from a MD-formatted .json file with the following columns:

  • filename

  • datetime (if images or EXIF information is supplied)

  • detection_category

  • max_detection_confidence

  • classification_category

  • max_classification_confidence

  • count

One row is generated per category pair per image. For example, these would be unique rows:

image0001.jpg,animal,deer,4 image0001.jpg,animal,lion,4 image0001.jpg,animal,[none],4 image0001.jpg,person,[none],2

Images with no above-threshold detections will have a single row:

image0001.jpg,empty,[none],-1

Images with processing errors will have a single row:

image0001.jpg,error,error_string,-1

megadetector.postprocessing.generate_csv_report.generate_csv_report(md_results_file, output_file=None, datetime_source=None, folder_level_columns=None, detection_confidence_threshold=None, classification_confidence_threshold=None, verbose=True)[source]

Generates a .csv report from a MD-formatted .json file

Parameters:
  • md_results_file (str) – MD results .json file for which we should generate a report

  • output_file (str, optional) – .csv file to write; if this is None, we’ll use md_results_file.csv

  • datetime_source (str, optional) – if datetime information is required, this should point to a folder of images, a MD results .json file (can be the same as the input file), or an exif_info.json file created with read_exif().

  • folder_level_columns (list of int, optional) – list of folder levels (where zero is the top-level folder in a path name) for which we should create separate columns. Should be zero-indexed ints, or a comma-delimited list of zero-indexed int-strings.

  • detection_confidence_threshold (float, optional) – detections below this confidence threshold will not be included in the output data. Defaults to the recommended value based on the .json file.

  • classification_confidence_threshold (float, optional) – classifications below this confidence threshold will not be included in the output data (i.e., detections will be considered “animal”).

  • verbose (bool, optional) – enable debug output, including the progress bar,

Returns:

the output .csv filename

Return type:

str

generate_csv_report - CLI interface

Generates a .csv report from a MD-formatted .json file

generate_csv_report [-h] [--output_file OUTPUT_FILE] [--datetime_source DATETIME_SOURCE]
                    [--folder_level_columns FOLDER_LEVEL_COLUMNS]
                    [--detection_confidence_threshold DETECTION_CONFIDENCE_THRESHOLD]
                    [--classification_confidence_threshold CLASSIFICATION_CONFIDENCE_THRESHOLD]
                    [--verbose]
                    md_results_file

generate_csv_report positional arguments

generate_csv_report options

  • -h, --help - show this help message and exit

  • --output_file OUTPUT_FILE - Output filename (.csv) (if omitted, will append .csv to the input file)

  • --datetime_source DATETIME_SOURCE - Image folder, exif_info.json file, or MD results file from which we should read datetime information

  • --folder_level_columns FOLDER_LEVEL_COLUMNS - Comma-separated list of zero-indexed folder levels that should become columns in the output file

  • --detection_confidence_threshold DETECTION_CONFIDENCE_THRESHOLD - Detection threshold (if omitted, chooses a reasonable default based on the .json file)

  • --classification_confidence_threshold CLASSIFICATION_CONFIDENCE_THRESHOLD - Classification threshold (default 0.3)

  • --verbose - Enable additional debug output