Skip to content

Commit

Permalink
Add new documentation + rework CLI args (#564)
Browse files Browse the repository at this point in the history
  • Loading branch information
Josef-Haupt authored Feb 11, 2025
1 parent 0d77701 commit 34aa833
Show file tree
Hide file tree
Showing 83 changed files with 2,572 additions and 4,424 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/documentation.yml
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ foo*
# Apple :/
.DS_Store

# Documentation
_build

# Installers
installers/
desktop.ini
Expand Down
379 changes: 19 additions & 360 deletions LICENSE

Large diffs are not rendered by default.

850 changes: 0 additions & 850 deletions README.adoc

This file was deleted.

89 changes: 89 additions & 0 deletions README.md
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">

[![License](https://badgen.net/badge/License/CC-BY-NC-SA%204.0/green)](http://creativecommons.org/licenses/by-nc-sa/4.0/)
![OS](https://badgen.net/badge/OS/Linux%2C%20Windows%2C%20macOS/blue)
[![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
![Species](https://badgen.net/badge/Species/6512/blue)
![Downloads](https://www-user.tu-chemnitz.de/~johau/birdnet_total_downloads_badge.php)
[![Docker](https://github.com/kahst/BirdNET-Analyzer/actions/workflows/docker-build.yml/badge.svg)](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!

![Logos of all partners](https://tuc.cloud/index.php/s/KSdWfX5CnSRpRgQ/download/box_logos.png)
Empty file.
161 changes: 161 additions & 0 deletions birdnet_analyzer/analyze/__main__.py
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))
Loading

0 comments on commit 34aa833

Please sign in to comment.