CamTrapTools 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. camtraptools-0.6.0/.github/workflows/ci.yml +35 -0
  2. camtraptools-0.6.0/.github/workflows/publish.yml +23 -0
  3. camtraptools-0.6.0/.gitignore +11 -0
  4. camtraptools-0.6.0/CHANGELOG.md +270 -0
  5. camtraptools-0.6.0/CITATION.cff +19 -0
  6. camtraptools-0.6.0/LICENSE +21 -0
  7. camtraptools-0.6.0/PKG-INFO +302 -0
  8. camtraptools-0.6.0/README.md +265 -0
  9. camtraptools-0.6.0/docs/adapted-examples.jpg +0 -0
  10. camtraptools-0.6.0/docs/case-study-kgalagadi.md +285 -0
  11. camtraptools-0.6.0/docs/report.png +0 -0
  12. camtraptools-0.6.0/docs/review.jpg +0 -0
  13. camtraptools-0.6.0/docs/user-guide.md +819 -0
  14. camtraptools-0.6.0/examples/kgalagadi/prepare.py +129 -0
  15. camtraptools-0.6.0/examples/kgalagadi/sensitivity.py +173 -0
  16. camtraptools-0.6.0/pyproject.toml +60 -0
  17. camtraptools-0.6.0/src/camtraptools/__init__.py +3 -0
  18. camtraptools-0.6.0/src/camtraptools/activity.py +255 -0
  19. camtraptools-0.6.0/src/camtraptools/adapt.py +453 -0
  20. camtraptools-0.6.0/src/camtraptools/check.py +232 -0
  21. camtraptools-0.6.0/src/camtraptools/cli.py +887 -0
  22. camtraptools-0.6.0/src/camtraptools/compare.py +189 -0
  23. camtraptools-0.6.0/src/camtraptools/crops.py +191 -0
  24. camtraptools-0.6.0/src/camtraptools/detect.py +319 -0
  25. camtraptools-0.6.0/src/camtraptools/ecology.py +372 -0
  26. camtraptools-0.6.0/src/camtraptools/evaluate.py +267 -0
  27. camtraptools-0.6.0/src/camtraptools/events.py +104 -0
  28. camtraptools-0.6.0/src/camtraptools/export.py +159 -0
  29. camtraptools-0.6.0/src/camtraptools/importer.py +116 -0
  30. camtraptools-0.6.0/src/camtraptools/ingest.py +376 -0
  31. camtraptools-0.6.0/src/camtraptools/labels.py +297 -0
  32. camtraptools-0.6.0/src/camtraptools/report.py +315 -0
  33. camtraptools-0.6.0/src/camtraptools/review.py +155 -0
  34. camtraptools-0.6.0/src/camtraptools/reviews.py +192 -0
  35. camtraptools-0.6.0/src/camtraptools/templates/evaluation.html +115 -0
  36. camtraptools-0.6.0/src/camtraptools/templates/event.html +148 -0
  37. camtraptools-0.6.0/src/camtraptools/templates/events.html +48 -0
  38. camtraptools-0.6.0/tests/conftest.py +31 -0
  39. camtraptools-0.6.0/tests/test_activity.py +125 -0
  40. camtraptools-0.6.0/tests/test_adapt.py +301 -0
  41. camtraptools-0.6.0/tests/test_check.py +233 -0
  42. camtraptools-0.6.0/tests/test_cli.py +754 -0
  43. camtraptools-0.6.0/tests/test_compare.py +113 -0
  44. camtraptools-0.6.0/tests/test_crops.py +152 -0
  45. camtraptools-0.6.0/tests/test_deployments.py +42 -0
  46. camtraptools-0.6.0/tests/test_detect.py +275 -0
  47. camtraptools-0.6.0/tests/test_ecology.py +229 -0
  48. camtraptools-0.6.0/tests/test_evaluate.py +255 -0
  49. camtraptools-0.6.0/tests/test_events.py +169 -0
  50. camtraptools-0.6.0/tests/test_export.py +208 -0
  51. camtraptools-0.6.0/tests/test_field_sheet.py +183 -0
  52. camtraptools-0.6.0/tests/test_importer.py +146 -0
  53. camtraptools-0.6.0/tests/test_ingest.py +38 -0
  54. camtraptools-0.6.0/tests/test_labels.py +187 -0
  55. camtraptools-0.6.0/tests/test_media.py +99 -0
  56. camtraptools-0.6.0/tests/test_recorded_periods.py +152 -0
  57. camtraptools-0.6.0/tests/test_report.py +108 -0
  58. camtraptools-0.6.0/tests/test_review.py +250 -0
  59. camtraptools-0.6.0/tests/test_reviews.py +163 -0
  60. camtraptools-0.6.0/uv.lock +3936 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ test:
13
+ name: Python ${{ matrix.python }} on ${{ matrix.os }}
14
+ runs-on: ${{ matrix.os }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest]
19
+ python: ["3.11", "3.12", "3.13", "3.14"]
20
+ include:
21
+ - os: windows-latest
22
+ python: "3.14"
23
+ - os: macos-latest
24
+ python: "3.14"
25
+ steps:
26
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
28
+ with:
29
+ python-version: ${{ matrix.python }}
30
+ - name: Install dependencies
31
+ run: uv sync --locked
32
+ - name: Lint
33
+ run: uv run ruff check src tests
34
+ - name: Test
35
+ run: uv run pytest
@@ -0,0 +1,23 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ publish:
12
+ name: Build and publish
13
+ runs-on: ubuntu-latest
14
+ environment: pypi
15
+ permissions:
16
+ id-token: write
17
+ steps:
18
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
19
+ - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
20
+ - name: Build
21
+ run: uv build
22
+ - name: Publish
23
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
4
+ .pytest_cache/
5
+ dist/
6
+ # Camera-trap images are large: never commit them
7
+ data/
8
+ *.JPG
9
+ *.jpg
10
+ # except small figures for the documentation
11
+ !docs/*.jpg
@@ -0,0 +1,270 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.6.0] - 2026-10-20
10
+
11
+ Ready for real surveys: large surveys and interrupted runs, other folder layouts,
12
+ camera clock correction, importing existing labels, the relative abundance index, a
13
+ user guide, and packaging for PyPI.
14
+
15
+ ### Added
16
+
17
+ - `labels` command: imports existing image labels from a Camtrap DP package (human
18
+ classifications first; event-level observations label every image in the event), a
19
+ Wildlife Insights `images.csv` export (with its taxonomy), a Timelapse CSV export or
20
+ any CSV (`--species-column`, `--path-column`, `--file-column`, `--folder-column`), and
21
+ writes a truth file for `evaluate`, `crops` and `compare`. Images are matched by path,
22
+ without leading folders, then by unique file name; common names are turned into
23
+ scientific names with SpeciesNet's taxonomy when its model is downloaded, or with a
24
+ `--names` mapping; blank labels are recognised, and unmatched, ambiguous and
25
+ unrecognised labels are reported.
26
+ - Clock correction: optional `cameraTime` and `actualTime` field-sheet columns (what a
27
+ camera's clock showed and the real time at that moment) make `ingest` shift all of
28
+ that deployment's image times by the difference before deployment periods are
29
+ derived, keep each image's original camera time in `mediaComments`, and report the
30
+ correction. `check` suggests these columns when it finds a wrong clock.
31
+ - Relative abundance index in `ecology`: independent events per 100 camera-days for
32
+ each species, in `occupancy.csv` and the printed table, and per site and species in
33
+ `rai.csv`.
34
+ - `detect` saves SpeciesNet's progress every 10 minutes and continues an interrupted
35
+ run when the same command is run again, discarding saved progress from a run with
36
+ other settings; it shows SpeciesNet's progress bars.
37
+ - `ingest --folder-depth` reads deployments from deeper folder levels, such as
38
+ `site/camera/` (deployment `site_camera`).
39
+ - `ingest` reports the files it skipped by type, such as videos, and JPEG images
40
+ outside any deployment folder.
41
+ - User guide (`docs/user-guide.md`): installation, preparing images and field sheets,
42
+ every step from `ingest` to `export` with example output and how to read it, choosing
43
+ a workflow, the files in a package, troubleshooting and a command reference.
44
+
45
+ - Packaging for PyPI: project links, keywords and classifiers, a workflow that
46
+ publishes to PyPI with trusted publishing when a GitHub release is published, and a
47
+ `CITATION.cff` file for citing the toolkit.
48
+
49
+ ### Changed
50
+
51
+ - The README's images and links are absolute, so they also work on PyPI.
52
+ - The message for a missing `detect` extra gives the `pip` command as well.
53
+ - `events` summarises all events at once: 100,000 images now take about a second
54
+ instead of more than ten minutes, with identical results.
55
+ - Activity curves of species with many events are computed from one-minute bins with
56
+ a fast Fourier transform, so `ecology` handles thousands of events per species in
57
+ seconds; smaller samples are computed exactly as before.
58
+
59
+ ### Fixed
60
+
61
+ - An event whose images all had a classifier probability of 0 got no confidence; its
62
+ species is now chosen by the number of images.
63
+
64
+ ## [0.5.0] - 2026-10-20
65
+
66
+ Ecology: detection histories, occupancy corrected for imperfect detection, daily
67
+ activity and overlap between species, and a comparison of how AI mistakes, review and
68
+ adaptation change these results.
69
+
70
+ ### Added
71
+
72
+ - `ecology` command: writes a detection history per species (sites by sampling
73
+ occasions of `--occasion-days`, default 7, with 1 for recorded, 0 for not recorded and
74
+ empty when no camera was running), the camera days per site and occasion
75
+ (`effort.csv`) and naive occupancy per species (`occupancy.csv`): events, sites
76
+ recorded out of sites surveyed, and the share of surveyed occasions with a record at
77
+ those sites. Sites are camera locations, reviewed decisions replace the AI's, and
78
+ events identified only to a higher taxon are left out and listed unless `--all-taxa`
79
+ or `--taxon` is given.
80
+ - Occupancy model in `ecology`: for each species recorded at three or more sites, the
81
+ single-season occupancy model (MacKenzie et al. 2002) estimates the probability that
82
+ a site is occupied, with a 95% profile-likelihood interval, from a daily detection
83
+ probability applied to each occasion's camera days. `occupancy.csv` and the printed
84
+ table add the chance of recording the species in a full occasion and of missing it
85
+ over the whole survey at an occupied site, with a warning when detection is too rare
86
+ to estimate occupancy or the interval is wider than 0.5.
87
+ - Activity patterns in `ecology`: for each species with at least
88
+ `--min-activity-events` events (default 20), a daily activity curve from the start
89
+ times of its independent events, as a von Mises kernel density with the bandwidth of
90
+ Taylor (2008) estimated from trigonometric moments up to order 3, and its busiest
91
+ time of day. The overlap coefficient between every pair of species (Δ₁, or Δ₄ when
92
+ both have 75 or more events; Ridout & Linkie 2009) comes with a 95% percentile
93
+ bootstrap interval from 999 resamples. Writes `activity.csv`, `overlap.csv` and an
94
+ `activity.svg` chart of the six most recorded species.
95
+ - `compare` command: runs the ecology analyses on every labelling of a survey (the
96
+ machine's labels alone, with reviews, ground truth from `--truth`, and other packages
97
+ with `--other NAME=FOLDER`) and compares them with the reference (truth if given,
98
+ otherwise the reviews): species and species-at-site records missed or added, mean
99
+ naive and modelled occupancy error, the difference between each species' activity
100
+ curves (1 − Δ) and the error in overlaps between species. Writes each source's
101
+ ecology results, `scores.csv`, `comparison.csv` and `overlap_comparison.csv`.
102
+ - Ecological consequences in the case study, with `examples/kgalagadi/sensitivity.py`,
103
+ which builds labellings with cross-fitted adapted layers and with simulated review of
104
+ the least confident 5% to 50% of events, and compares them with the volunteer labels.
105
+ - `examples/kgalagadi/prepare.py` also writes a field sheet with each camera's season,
106
+ from its first and last capture including blank ones.
107
+
108
+ ## [0.4.0] - 2026-10-19
109
+
110
+ Evaluation and regional adaptation: measure the AI against ground truth, build crop
111
+ datasets split by camera, adapt SpeciesNet to a region and use the adapted layer in
112
+ `detect`, with a case study on Snapshot Kgalagadi.
113
+
114
+ ### Added
115
+
116
+ - `evaluate` command: compares the AI's event-level decisions with ground truth, either
117
+ the package's reviews or a CSV of image labels (`--truth`, with `filePath` and
118
+ `scientificName` and optional `genus`, `family`, `order` and `class` columns). Each
119
+ event is correct, correct only above species level (verified against the true
120
+ taxon's ancestry), unverified, or wrong. The command prints per-label precision and
121
+ recall and every event that was not correct, and writes `evaluation.csv`.
122
+ - Confidence thresholds: `evaluate` prints, for each label the AI used, the lowest event
123
+ confidence at which its answers reach a target precision (`--target-precision`,
124
+ default 0.95) and how many answers that keeps. Labels with fewer than ten answers are
125
+ flagged as unreliable, and `evaluation.csv` includes each event's confidence.
126
+ - Failure report: `evaluate --report report.html --images DIR` writes a self-contained
127
+ HTML page with the outcomes, precision and recall, thresholds and every event the AI
128
+ did not get exactly right, with its images and bounding boxes.
129
+ - `crops` command: saves a JPEG crop of every animal detection with a known true label
130
+ (from `--truth` or the reviews) in `train/`, `val/` and `test/` folders with one
131
+ subfolder per label, and lists them in `crops.csv`. Each camera location (its
132
+ `locationID`, `locationName` or deployment) goes to a single split, so evaluation uses
133
+ unseen backgrounds; target shares are set with `--val` and `--test`. Boxes are padded
134
+ (`--padding`), crops under 32 pixels and detections whose true label is blank are
135
+ skipped, the padding is recorded, and the command warns about labels with no or few
136
+ training crops.
137
+ - `adapt` command: trains a new final layer for SpeciesNet on the crops from `crops`,
138
+ for only the labels in the training split, on frozen SpeciesNet features. Labels
139
+ SpeciesNet knows start from its own weights, the layer from the epoch with the lowest
140
+ validation loss is kept (`--epochs`, `--learning-rate`, `--seed`, `--device`), and
141
+ `--balanced` weights classes by their number of crops. The command saves the layer as `adapted.pt`, every crop's prediction
142
+ in `predictions.csv` and the crops' SpeciesNet features in `features.npz`, which later
143
+ runs reuse. It prints accuracy per split and per label for SpeciesNet as run by
144
+ `detect`, SpeciesNet limited to the training labels and the adapted layer, and the
145
+ held-out labels it cannot name. Requires the optional `detect` extra.
146
+ - `adapt` chooses a confidence threshold on the validation crops: the lowest at which
147
+ the adapted layer is as precise as SpeciesNet's species-level answers. It is saved in
148
+ `adapted.pt` with the crop padding.
149
+ - `detect --adapted MODEL_DIR` classifies every animal detection with an adapted layer,
150
+ cropped like the training crops, and uses its answer at or above the layer's threshold
151
+ (or `--adapted-threshold`), except where SpeciesNet named a species the layer was not
152
+ trained on. Answers are saved in `adapted.csv`, observations record the adapted layer
153
+ in `classifiedBy`, and the command prints how many of SpeciesNet's answers changed.
154
+ - `evaluate --deployment` compares only events from the given deployments, such as
155
+ cameras held out from training.
156
+ - Case study (`docs/case-study-kgalagadi.md`): adapting SpeciesNet on Snapshot
157
+ Kgalagadi Season 1 raised correct events on seven held-out cameras from 72 to 92 of
158
+ 104. `examples/kgalagadi/prepare.py` downloads the data and writes the truth file to
159
+ reproduce it.
160
+
161
+ ### Changed
162
+
163
+ - Per-label precision counts answers that are correct above species level (such as
164
+ *Bovidae* for a gemsbok) as right; recall still requires the exact taxon.
165
+
166
+ ### Fixed
167
+
168
+ - The review app screenshot in the README was missing from the repository.
169
+
170
+ ## [0.3.0] - 2026-10-19
171
+
172
+ Human review: a local web app that shows the AI's least confident decisions first and
173
+ records corrections as human observations.
174
+
175
+ ### Added
176
+
177
+ - `review` command: a local web app (on 127.0.0.1 only) that shows each event's images
178
+ with the AI's bounding boxes, labels and confidences, the event-level decision with its
179
+ vote share and common name, and previous/next navigation with the arrow keys. Only
180
+ images listed in the package can be served.
181
+ - Review decisions: each event page has a form, pre-filled with the AI's decision, to
182
+ accept or correct the type, scientific name and count. Decisions are stored in
183
+ `reviews.csv` with the reviewer's name (`--reviewer`) and time, and written to
184
+ `observations.csv` as event-level observations with `classificationMethod` `human`,
185
+ next to the machine's. Saving moves to the next event. `events` re-applies reviews,
186
+ `export` uses the human decision for reviewed events, and forms are protected by a
187
+ per-session token.
188
+ - The review app shows events least confident first (`--order uncertainty`, the default,
189
+ or `--order time`), scoring each event by its vote share and best classifier
190
+ probability, with animals not identified to species capped at 0.5. It starts at the
191
+ least confident unreviewed event and, after saving, moves to the next unreviewed one.
192
+ - Review progress on every page, an "all events" page with confidence and review status,
193
+ and keyboard shortcuts: Enter or A to save, B for blank, 1–9 for the count, S for the
194
+ species field and the arrow keys to move between events.
195
+ - `review` uses another port when the requested one is in use, and says so.
196
+ - `review-stats` command: reviewed events, agreement with the AI, each correction (AI →
197
+ reviewer), changes per AI confidence band and review speed (pauses over ten minutes
198
+ count as breaks).
199
+
200
+ ## [0.2.0] - 2026-10-19
201
+
202
+ AI detection and species identification, independent events, importing other tools'
203
+ results and validated Camtrap DP export.
204
+
205
+ ### Added
206
+
207
+ - `detect` command: runs SpeciesNet on every ingested image. SpeciesNet uses
208
+ MegaDetector v5a to find animals, people and vehicles, classifies each animal and
209
+ applies geofencing (`--country`, `--admin1-region`) and taxonomic rollup. Results are
210
+ saved as `speciesnet.json`, and the command prints the images per category and per
211
+ species for each deployment. Requires the optional `detect` extra; SpeciesNet is
212
+ Apache-2.0 and its MegaDetector inference code is GPL-licensed.
213
+ - `detect` writes `observations.csv` with Camtrap DP media-level observations: one per
214
+ detection at or above `--threshold` (default 0.2) with bounding box, `scientificName`
215
+ (species, or a higher taxon such as *Bovidae* when SpeciesNet rolls up), classifier
216
+ probability and model version; `blank` for empty images, `unknown` when SpeciesNet
217
+ cannot tell, and `unclassified` for images it could not process.
218
+ - `detect` reuses existing results for the same model and country, so trying another
219
+ `--threshold` is instant; `--rerun` runs SpeciesNet again, and `--images` is only
220
+ needed when it runs.
221
+ - `events` command: groups consecutive images at each deployment into independent
222
+ events (a new event after more than `--gap` minutes without images, default 30),
223
+ fills in `eventID` on media-level observations and adds one event-level observation
224
+ per event. The event's species is chosen by summed classifier probability across its
225
+ images, its count is the largest number of individuals in any single image, and the
226
+ command prints independent animal events per taxon and deployment. Rerunning
227
+ replaces earlier event-level observations.
228
+ - `import` command: reads results in the MegaDetector batch format (MegaDetector,
229
+ AddaxAI, Timelapse, run_md_and_speciesnet) or SpeciesNet's format, matches their
230
+ image paths to the package even when they are relative to another folder, and writes
231
+ them as `speciesnet.json` and `observations.csv`, so `events` and later steps work
232
+ unchanged. Classification taxonomy is kept when it is in SpeciesNet's format; the
233
+ command reports how many images matched, were ignored or have no results, and
234
+ images without results are recorded as `unclassified`.
235
+ - `export` command: writes a complete Camtrap DP 1.0.2 data package (`datapackage.json`,
236
+ `deployments.csv`, `media.csv`, `observations.csv`) to a separate folder, with every
237
+ standard column, time zones on all timestamps (`--timezone`, e.g.
238
+ `Africa/Johannesburg`, including daylight saving), spatial, temporal and taxonomic
239
+ coverage, contributors, project details (`--sampling-design`) and data and media
240
+ licenses. Images without a timestamp and non-standard deployment columns are left out
241
+ and reported. Exported packages pass Frictionless validation against the Camtrap DP
242
+ profile, which is checked in the test suite.
243
+ - `detect` records when SpeciesNet ran with the computer's UTC offset.
244
+
245
+ ## [0.1.0] - 2026-10-15
246
+
247
+ First release: ingest, quality checks and an HTML health report.
248
+
249
+ ### Added
250
+
251
+ - `ingest` command: scans one folder per camera deployment, reads capture times from
252
+ EXIF and writes `media.csv` and `deployments.csv` in Camtrap DP format.
253
+ - Optional CSV or Excel field sheets with coordinates, camera details and recorded
254
+ deployment periods, which take priority over image dates.
255
+ - Field-sheet validation: duplicate IDs, impossible coordinates, unreadable or reversed
256
+ dates, images outside the recorded period, and deployment IDs that do not match image
257
+ folders, with suggestions for near matches.
258
+ - `check` command: missing timestamps, reset or wrongly set clocks, time going
259
+ backwards, long gaps (`--max-gap-days`), days with excessive triggers and cameras
260
+ without night or day images, with key numbers for each deployment.
261
+ - `report` command: a self-contained HTML report with an interactive timeline, a
262
+ summary table and all issues, in light and dark mode.
263
+ - Continuous integration on Python 3.11–3.14 (Linux) and on Windows and macOS.
264
+
265
+ [0.6.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.6.0
266
+ [0.5.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.5.0
267
+ [0.4.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.4.0
268
+ [0.3.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.3.0
269
+ [0.2.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.2.0
270
+ [0.1.0]: https://github.com/ivanposavecwildlife/CamTrapTools/releases/tag/v0.1.0
@@ -0,0 +1,19 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use CamTrapTools in your work, please cite it as below."
3
+ title: "CamTrapTools: open-source toolkit for camera-trap projects, from SD card to ecological answers"
4
+ type: software
5
+ authors:
6
+ - family-names: Posavec
7
+ given-names: Ivan
8
+ repository-code: "https://github.com/ivanposavecwildlife/CamTrapTools"
9
+ url: "https://github.com/ivanposavecwildlife/CamTrapTools"
10
+ license: MIT
11
+ version: "0.6.0"
12
+ date-released: "2026-10-20"
13
+ keywords:
14
+ - camera traps
15
+ - wildlife monitoring
16
+ - ecology
17
+ - Camtrap DP
18
+ - SpeciesNet
19
+ - occupancy
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ivan Posavec
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.