-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new documentation + rework CLI args (#564)
- Loading branch information
1 parent
0d77701
commit 34aa833
Showing
83 changed files
with
2,572 additions
and
4,424 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
name: documentation | ||
|
||
on: [push, pull_request, workflow_dispatch] | ||
|
||
permissions: | ||
contents: write | ||
|
||
jobs: | ||
docs: | ||
runs-on: ubuntu-latest | ||
env: | ||
IS_GITHUB_RUNNER: "true" | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.11' | ||
- name: Install dependencies | ||
run: | | ||
pip install sphinx sphinx_rtd_theme sphinx-argparse sphinx-autobuild | ||
- name: Sphinx build | ||
run: | | ||
sphinx-build docs _build | ||
- name: Deploy to GitHub Pages | ||
uses: peaceiris/actions-gh-pages@v3 | ||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} | ||
with: | ||
publish_branch: gh-pages | ||
github_token: ${{ secrets.GITHUB_TOKEN }} | ||
publish_dir: _build/ | ||
force_orphan: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,9 @@ foo* | |
# Apple :/ | ||
.DS_Store | ||
|
||
# Documentation | ||
_build | ||
|
||
# Installers | ||
installers/ | ||
desktop.ini | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
<div align="center"> | ||
<h1>BirdNET-Analyzer</h1> | ||
<a href="https://kahst.github.io/BirdNET-Analyzer/"> | ||
<img src="https://tuc.cloud/index.php/s/xwKqoCmRDKzBCDZ/download/logo_box_birdnet.png" width="500px" alt="BirdNET-Logo" /> | ||
</a> | ||
</div> | ||
<br> | ||
<div align="center"> | ||
|
||
[](http://creativecommons.org/licenses/by-nc-sa/4.0/) | ||
 | ||
[](https://www.python.org/downloads/release/python-3110/) | ||
 | ||
 | ||
[](https://github.com/kahst/BirdNET-Analyzer/actions/workflows/docker-build.yml) | ||
|
||
</div> | ||
|
||
This repo contains BirdNET models and scripts for processing large amounts of audio data or single audio files. | ||
This is the most advanced version of BirdNET for acoustic analyses and we will keep this repository up-to-date with new models and improved interfaces to enable scientists with no CS background to run the analysis. | ||
|
||
Feel free to use BirdNET for your acoustic analyses and research. | ||
If you do, please cite as: | ||
|
||
```bibtex | ||
@article{kahl2021birdnet, | ||
title={BirdNET: A deep learning solution for avian diversity monitoring}, | ||
author={Kahl, Stefan and Wood, Connor M and Eibl, Maximilian and Klinck, Holger}, | ||
journal={Ecological Informatics}, | ||
volume={61}, | ||
pages={101236}, | ||
year={2021}, | ||
publisher={Elsevier} | ||
} | ||
``` | ||
|
||
This work is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-nc-sa/4.0/). | ||
|
||
## Documentation | ||
|
||
The documentation and further information will be listed [here](https://kahst.github.io/BirdNET-Analyzer/) | ||
|
||
## About | ||
|
||
Developed by the [K. Lisa Yang Center for Conservation Bioacoustics](https://www.birds.cornell.edu/ccb/) at the [Cornell Lab of Ornithology](https://www.birds.cornell.edu/home) in collaboration with [Chemnitz University of Technology](https://www.tu-chemnitz.de/index.html.en). | ||
|
||
Go to https://birdnet.cornell.edu to learn more about the project. | ||
|
||
Want to use BirdNET to analyze a large dataset? Don't hesitate to contact us: [email protected] | ||
|
||
**Have a question, remark, or feature request? Please start a new issue thread to let us know. Feel free to submit a pull request.** | ||
|
||
## License | ||
|
||
- **Source Code**: The source code for this project is licensed under the [MIT License](https://opensource.org/licenses/MIT). | ||
- **Models**: The models used in this project are licensed under the [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc-sa/4.0/). | ||
|
||
Please ensure you review and adhere to the specific license terms provided with each model. Note that educational and research purposes are considered non-commercial use cases. | ||
|
||
## Usage guide | ||
|
||
This document provides instructions for downloading and installing the GUI, and conducting some of the most common types of analyses. Within the document, a link is provided to download example sound files that can be used for practice. | ||
|
||
Download the PDF here: [BirdNET-Analyzer Usage Guide](https://zenodo.org/records/8357176) | ||
|
||
Watch our presentation on how to use BirdNET-Analyzer to train your own models: [BirdNET - BioacousTalks at YouTube](https://youtu.be/HuEZGIPeyq0) | ||
|
||
## Projects map | ||
|
||
We have created an interactive map of projects that use BirdNET. If you are working on a project that uses BirdNET, please let us know [here](https://github.com/kahst/BirdNET-Analyzer/issues/221) and we can add it to the map. | ||
|
||
You can access the map here: [Open projects map](https://kahst.github.io/BirdNET-Analyzer/projects.html) | ||
|
||
## Funding | ||
|
||
This project is supported by Jake Holshuh (Cornell class of ´69) and The Arthur Vining Davis Foundations. | ||
Our work in the K. Lisa Yang Center for Conservation Bioacoustics is made possible by the generosity of K. Lisa Yang to advance innovative conservation technologies to inspire and inform the conservation of wildlife and habitats. | ||
|
||
The development of BirdNET is supported by the German Federal Ministry of Education and Research through the project “BirdNET+” (FKZ 01|S22072). | ||
The German Federal Ministry for the Environment, Nature Conservation and Nuclear Safety contributes through the “DeepBirdDetect” project (FKZ 67KI31040E). | ||
In addition, the Deutsche Bundesstiftung Umwelt supports BirdNET through the project “RangerSound” (project 39263/01). | ||
|
||
## Partners | ||
|
||
BirdNET is a joint effort of partners from academia and industry. | ||
Without these partnerships, this project would not have been possible. | ||
Thank you! | ||
|
||
 |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
import os | ||
from multiprocessing import Pool, freeze_support | ||
|
||
import birdnet_analyzer.cli as cli | ||
import birdnet_analyzer.config as cfg | ||
import birdnet_analyzer.utils as utils | ||
|
||
# Freeze support for executable | ||
freeze_support() | ||
|
||
parser = cli.analyzer_parser() | ||
|
||
args = parser.parse_args() | ||
|
||
try: | ||
if os.get_terminal_size().columns >= 64: | ||
print(cli.ASCII_LOGO, flush=True) | ||
except Exception: | ||
pass | ||
|
||
import birdnet_analyzer.species.utils as species # noqa: E402 | ||
from birdnet_analyzer.analyze.utils import analyze_file, combine_results, load_codes, save_analysis_params # noqa: E402 | ||
|
||
# Load eBird codes, labels | ||
cfg.CODES = load_codes() | ||
cfg.LABELS = utils.read_lines(cfg.LABELS_FILE) | ||
|
||
cfg.SKIP_EXISTING_RESULTS = args.skip_existing_results | ||
|
||
# Set custom classifier? | ||
if args.classifier is not None: | ||
cfg.CUSTOM_CLASSIFIER = args.classifier # we treat this as absolute path, so no need to join with dirname | ||
|
||
if args.classifier.endswith(".tflite"): | ||
cfg.LABELS_FILE = args.classifier.replace(".tflite", "_Labels.txt") # same for labels file | ||
|
||
if not os.path.isfile(cfg.LABELS_FILE): | ||
cfg.LABELS_FILE = args.classifier.replace("Model_FP32.tflite", "Labels.txt") | ||
|
||
cfg.LABELS = utils.read_lines(cfg.LABELS_FILE) | ||
else: | ||
cfg.APPLY_SIGMOID = False | ||
cfg.LABELS_FILE = os.path.join(args.classifier, "labels", "label_names.csv") | ||
cfg.LABELS = [line.split(",")[1] for line in utils.read_lines(cfg.LABELS_FILE)] | ||
|
||
args.lat = -1 | ||
args.lon = -1 | ||
args.locale = "en" | ||
|
||
# Load translated labels | ||
lfile = os.path.join( | ||
cfg.TRANSLATED_LABELS_PATH, os.path.basename(cfg.LABELS_FILE).replace(".txt", "_{}.txt".format(args.locale)) | ||
) | ||
|
||
if args.locale not in ["en"] and os.path.isfile(lfile): | ||
cfg.TRANSLATED_LABELS = utils.read_lines(lfile) | ||
else: | ||
cfg.TRANSLATED_LABELS = cfg.LABELS | ||
|
||
### Make sure to comment out appropriately if you are not using args. ### | ||
|
||
# Load species list from location filter or provided list | ||
cfg.LATITUDE, cfg.LONGITUDE, cfg.WEEK = args.lat, args.lon, args.week | ||
cfg.LOCATION_FILTER_THRESHOLD = args.sf_thresh | ||
|
||
if cfg.LATITUDE == -1 and cfg.LONGITUDE == -1: | ||
if not args.slist: | ||
cfg.SPECIES_LIST_FILE = None | ||
else: | ||
cfg.SPECIES_LIST_FILE = args.slist | ||
|
||
if os.path.isdir(cfg.SPECIES_LIST_FILE): | ||
cfg.SPECIES_LIST_FILE = os.path.join(cfg.SPECIES_LIST_FILE, "species_list.txt") | ||
|
||
cfg.SPECIES_LIST = utils.read_lines(cfg.SPECIES_LIST_FILE) | ||
else: | ||
cfg.SPECIES_LIST_FILE = None | ||
cfg.SPECIES_LIST = species.get_species_list(cfg.LATITUDE, cfg.LONGITUDE, cfg.WEEK, cfg.LOCATION_FILTER_THRESHOLD) | ||
|
||
if not cfg.SPECIES_LIST: | ||
print(f"Species list contains {len(cfg.LABELS)} species") | ||
else: | ||
print(f"Species list contains {len(cfg.SPECIES_LIST)} species") | ||
|
||
# Set input and output path | ||
cfg.INPUT_PATH = args.input | ||
|
||
if not args.output: | ||
if os.path.isfile(cfg.INPUT_PATH): | ||
cfg.OUTPUT_PATH = os.path.dirname(cfg.INPUT_PATH) | ||
else: | ||
cfg.OUTPUT_PATH = cfg.INPUT_PATH | ||
else: | ||
cfg.OUTPUT_PATH = args.output | ||
|
||
# Parse input files | ||
if os.path.isdir(cfg.INPUT_PATH): | ||
cfg.FILE_LIST = utils.collect_audio_files(cfg.INPUT_PATH) | ||
print(f"Found {len(cfg.FILE_LIST)} files to analyze") | ||
else: | ||
cfg.FILE_LIST = [cfg.INPUT_PATH] | ||
|
||
# Set confidence threshold | ||
cfg.MIN_CONFIDENCE = args.min_conf | ||
|
||
# Set sensitivity | ||
cfg.SIGMOID_SENSITIVITY = args.sensitivity | ||
|
||
# Set overlap | ||
cfg.SIG_OVERLAP = args.overlap | ||
|
||
# Set bandpass frequency range | ||
cfg.BANDPASS_FMIN = args.fmin | ||
cfg.BANDPASS_FMAX = args.fmax | ||
|
||
# Set audio speed | ||
cfg.AUDIO_SPEED = args.audio_speed | ||
|
||
# Set result type | ||
cfg.RESULT_TYPES = args.rtype | ||
|
||
# Set output file | ||
cfg.COMBINE_RESULTS = args.combine_results | ||
|
||
# Set number of threads | ||
if os.path.isdir(cfg.INPUT_PATH): | ||
cfg.CPU_THREADS = args.threads | ||
cfg.TFLITE_THREADS = 1 | ||
else: | ||
cfg.CPU_THREADS = 1 | ||
cfg.TFLITE_THREADS = args.threads | ||
|
||
# Set batch size | ||
cfg.BATCH_SIZE = args.batchsize | ||
|
||
# Add config items to each file list entry. | ||
# We have to do this for Windows which does not | ||
# support fork() and thus each process has to | ||
# have its own config. USE LINUX! | ||
flist = [(f, cfg.get_config()) for f in cfg.FILE_LIST] | ||
result_files = [] | ||
|
||
# Analyze files | ||
if cfg.CPU_THREADS < 2 or len(flist) < 2: | ||
for entry in flist: | ||
result_files.append(analyze_file(entry)) | ||
else: | ||
with Pool(cfg.CPU_THREADS) as p: | ||
# Map analyzeFile function to each entry in flist | ||
results = p.map_async(analyze_file, flist) | ||
# Wait for all tasks to complete | ||
results.wait() | ||
result_files = results.get() | ||
|
||
# Combine results? | ||
if cfg.COMBINE_RESULTS: | ||
print(f"Combining results, writing to {cfg.OUTPUT_PATH}...", end="", flush=True) | ||
combine_results(result_files) | ||
print("done!", flush=True) | ||
|
||
save_analysis_params(os.path.join(cfg.OUTPUT_PATH, cfg.ANALYSIS_PARAMS_FILENAME)) |
Oops, something went wrong.