# Camera Traps in Potato: Reviewing MegaDetector Output, Camtrap DP and Darwin Core

Source: https://www.potatoannotator.com/docs/guides/camera-traps

**Potato 2.12.0 reviews [camera-trap](https://en.wikipedia.org/wiki/Camera_trap) images after a detector has run over them. You import [MegaDetector](https://github.com/agentmorris/MegaDetector)'s batch output or a COCO Camera Traps file, annotators triage each image and correct its boxes, and the result exports as reviewed MegaDetector JSON, a Camtrap DP data package or Darwin Core occurrences.**

Potato reads the detector's output and does not run the detector. Run MegaDetector, or the classifier you use for species, on your own machine first.

## Import the detector output

```bash
# MegaDetector batch output; images under /data/traps
potato import -i md_output.json --image-dir /data/traps -o review-project/

# The same, with the images hosted elsewhere
potato import -i md_output.json --image-url-prefix https://example.org/traps -o review-project/

# Keep only detections with confidence 0.5 or more
potato import -i md_output.json --image-dir /data/traps --md-threshold 0.5 -o review-project/

# COCO Camera Traps, one item per sequence
potato import -i cct.json --image-dir /data/traps --sequences -o review-project/
```

The format is detected from the content, and `-f megadetector` or `-f coco_camera_traps` chooses explicitly. With `--image-dir`, the generated config sets `media_directory` to that folder, so Potato serves the images from where they already are. With `--image-url-prefix`, the prefix is joined to each file name instead.

Each image is one item with these questions:

| Scheme | Type | Pre-filled with |
|---|---|---|
| `triage` | radio: `empty`, `animal`, `person`, `vehicle` | The category of the most confident detection, or `empty` when no detection reaches the threshold |
| `detections` | image annotation, bounding boxes | Every detection at or above the threshold, labelled with its top species classification when the file has one, otherwise its category |
| `species` | multiselect | The species of those detections, created only when the source names species |

The triage question is a quick first pass: annotators answer it with the keys `1` to `4` and move on, then come back to the boxes of the images that need them. Boxes keep the detector's provenance (`"source": "ai"`, the detector's name and the confidence), and get `"edited": true` when an annotator changes them. The item keeps `datetime`, `location`, `seq_id` and `frame_num` when the source has them.

The MegaDetector importer reads batch-output format 1.x. Its `bbox` is `[x, y, width, height]` as fractions of the image from the top-left corner, which is how Potato stores boxes, so no image size is needed. Images with a `failure` are left out and counted, and so are detections below `--md-threshold` (default 0.2). A file of video results is reviewed at clip level, with each video as one item that has the `triage` and `species` questions.

A COCO file whose images carry `seq_id` is read as COCO Camera Traps, with its categories as the species plus `empty`. With `--sequences`, images that share a `seq_id` become one item, shown as a gallery of the frames in order, with `triage` and `species` but no boxes.

## Review

```bash
python potato/flask_server.py start review-project/config.yaml -p 8000
```

On each image, the annotator checks the triage answer, moves, resizes, relabels or deletes boxes, draws any animal the detector missed, and ticks the species present. Pre-filled answers are stored only when the annotator saves, so an export contains reviewed images only. [Detecting Rubber-Stamped Pre-Labels](/docs/guides/detecting-rubber-stamped-prelabels) covers checking whether reviewers accepted suggestions without looking.

## Export reviewed MegaDetector JSON

```bash
python -m potato.export -c review-project/config.yaml -f megadetector -o export/
```

`megadetector_reviewed.json` uses batch-output format 1.4, with one entry per reviewed image, so it can go back into tools that read MegaDetector results. A box the reviewer drew or changed gets `conf` 1.0, and a detector box left as it was keeps the detector's score. When several people reviewed an image, the first by user ID is written with a warning, and `--option annotator=<user>` picks one person.

## Export a Camtrap DP package

```bash
python -m potato.export -c review-project/config.yaml -f camtrap_dp -o export/ \
    --option timezone=-05:00 --option contributor="Your Name" \
    --option sampling_design=opportunistic --option capture_method=activityDetection
```

The export writes a [Camtrap DP](https://camtrap-dp.tdwg.org/) 1.0 data package: `datapackage.json`, `deployments.csv`, `media.csv` and `observations.csv`. Observations are one per box, one per ticked species without a box, and one `blank` observation for an image triaged `empty`. `classificationMethod` is `machine` for a detector box the reviewer left unchanged, and `human` otherwise. Sequence items give event-level observations.

Camtrap DP requires facts Potato does not have: the coordinates of each deployment, a UTC offset on every timestamp, and package metadata. Pass what you know as options:

| Option | Fills |
|---|---|
| `timezone` | UTC offset added to timestamps that have none, such as `+02:00` or `Z` |
| `title` | `title` and `project.title` (default: `annotation_task_name`) |
| `contributor` | `contributors`, one entry with role `contact` |
| `license` | `licenses`, scope `data` |
| `sampling_design` | `project.samplingDesign` |
| `capture_method` | `project.captureMethod` and `media.captureMethod` (`activityDetection` or `timeLapse`) |

Anything still missing is listed in the export warnings. Fill it in, such as the deployment coordinates in `deployments.csv`, and check the package with a Camtrap DP validator before publishing it.

## Export Darwin Core occurrences

```bash
python -m potato.export -c review-project/config.yaml -f darwin_core -o export/
```

`occurrence.csv` has one [Darwin Core](https://en.wikipedia.org/wiki/Darwin_Core) occurrence per animal observation that has a scientific name. Animals labelled only `animal` are left out, since an occurrence needs a scientific name, and the export says how many. `basisOfRecord` is `MachineObservation` when the identification is the detector's and the reviewer left it unchanged, and `HumanObservation` when a person drew, changed or added it.

A reviewer can answer `empty` and still leave boxes on the image. The exports write the boxes, because deleting a box is the reviewer's decision, and the warnings list each such item and annotator, so fix them in Potato and export again.

## Example

`examples/image/camera-trap-review/` has eight synthetic frames from two cameras (deer, a raccoon at night, a person, a vehicle and empty frames) and the MegaDetector file they were imported from.

```bash
python potato/flask_server.py start examples/image/camera-trap-review/config.yaml -p 8000
```

## Further Reading

- [Bioacoustics](/docs/guides/bioacoustics) - Reviewing BirdNET detections and Raven tables
- [Image Annotation](/docs/annotation-types/image-annotation) - Boxes, polygons and the image tools
- [Maps](/docs/annotation-types/geo-annotation) - Drawing on georeferenced images and GeoTIFFs
- [LLM Pre-Annotation](/docs/guides/llm-pre-annotation) - Reviewing machine suggestions in general

For implementation details, see the [source documentation](https://github.com/davidjurgens/potato/blob/master/docs/guides/camera-traps.md).
