Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a5363f8
gitignore
max-mauermann Sep 3, 2024
8789dd9
first changes, embeddings get written to db
max-mauermann Sep 12, 2024
011a66a
embeddings are not inserted if an embedding with equal source + offse…
max-mauermann Sep 23, 2024
39d3fbe
added embeddings to gui, still needs translations and validation
max-mauermann Sep 24, 2024
5a1d18a
de/en translations + validation
max-mauermann Sep 25, 2024
f03fb27
rudimentary search script
max-mauermann Sep 25, 2024
c400de7
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Nov 5, 2024
855aeb4
embeddings gui (WIP)
max-mauermann Nov 5, 2024
e83945c
.
max-mauermann Nov 19, 2024
7a345b6
spectrogram shows now
max-mauermann Nov 19, 2024
ae5ed72
show search result spectrograms
max-mauermann Nov 28, 2024
01320a1
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Nov 28, 2024
f1008f3
play buttons
max-mauermann Nov 28, 2024
0dd876a
.
max-mauermann Nov 28, 2024
8374ecb
dynamically create result plots and max_results input
max-mauermann Nov 29, 2024
3c0355b
exporting results + en language
max-mauermann Dec 2, 2024
b5adfa5
toggle all button + progress
max-mauermann Dec 3, 2024
46170ee
correctly closing database + validation
max-mauermann Dec 4, 2024
72dc7e6
results are now on pages + sorting search results
max-mauermann Dec 10, 2024
6d76a81
changed to perch_hoplite repository and updated code
max-mauermann Jan 15, 2025
49acaab
updates
max-mauermann Jan 20, 2025
f6ac488
updates
max-mauermann Jan 21, 2025
8b6865b
updated cli params. score is now written to export file names
max-mauermann Jan 30, 2025
2cedacf
included perch in requirements
max-mauermann Jan 31, 2025
e759752
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Jan 31, 2025
a8e0149
.
max-mauermann Jan 31, 2025
c8495ec
small fixes and german translations
max-mauermann Jan 31, 2025
75b3a4d
added speed and bandpass filter config (at least for scripts, gui sti…
max-mauermann Feb 4, 2025
7ed800c
.
max-mauermann Feb 4, 2025
1aeca4b
spectrograms in gui are now using the speed/bandpass from the setting…
max-mauermann Feb 11, 2025
048757f
.
max-mauermann Feb 11, 2025
d9aea2e
replaced settings file with hoplite metadata
max-mauermann Feb 11, 2025
a228c5b
implemented crop mode for query sample selection.
max-mauermann Feb 12, 2025
7906294
implemented crop mode in gui and adjusted query sample selection
max-mauermann Feb 12, 2025
b9f75dd
german/english language
max-mauermann Feb 12, 2025
c8de379
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Feb 17, 2025
ba1ae3b
changed embeddings stuff to new structure
max-mauermann Feb 17, 2025
c083e1f
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Feb 17, 2025
a99304c
some smaller fixes
max-mauermann Feb 18, 2025
581e3a6
added embeddings to dependencies
max-mauermann Feb 19, 2025
e7680cf
Merge branch 'main' into embeddings-with-hoplite
max-mauermann Feb 19, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions birdnet_analyzer/analyze/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ def combine_raven_tables(saved_results: list[str]):

# skip header and add to file
f_name = lines[1].split("\t")[10]
f_duration = audio.get_audio_file_Length(f_name)
f_duration = audio.get_audio_file_length(f_name)

audiofiles.append(f_name)

Expand Down Expand Up @@ -614,7 +614,7 @@ def analyze_file(item):
print(f"Analyzing {fpath}", flush=True)

try:
fileLengthSeconds = int(audio.get_audio_file_Length(fpath) / cfg.AUDIO_SPEED)
fileLengthSeconds = int(audio.get_audio_file_length(fpath) / cfg.AUDIO_SPEED)
except Exception as ex:
# Write error log
print(f"Error: Cannot analyze audio file {fpath}. File corrupt?\n", flush=True)
Expand Down
2 changes: 1 addition & 1 deletion birdnet_analyzer/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def open_audio_file(path: str, sample_rate=48000, offset=0.0, duration=None, fmi
return sig, rate


def get_audio_file_Length(path):
def get_audio_file_length(path):
"""
Get the length of an audio file in seconds.

Expand Down
89 changes: 87 additions & 2 deletions birdnet_analyzer/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,22 @@ def bs_args():

return p

def db_args():
"""
Creates an arguments parser for the database path.
Returns:
argparse.ArgumentParser: An argument parser with a database size argument.
The parser includes the following argument:
-db, --database: Path to the database folder.
"""
p = argparse.ArgumentParser(add_help=False)
p.add_argument(
"-db",
"--database",
help="Path to the database folder.",
)

return p

def analyzer_parser():
"""
Expand Down Expand Up @@ -360,21 +376,90 @@ def embeddings_parser():
Creates and returns an argument parser for extracting feature embeddings with BirdNET.

The parser includes arguments from the following parent parsers:
- io_args(): Handles input/output arguments.
- db_args(): Handles database arguments.
- bandpass_args(): Handles bandpass filter arguments.
- audio_speed_args(): Handles audio speed arguments.
- overlap_args(): Handles overlap arguments.
- threads_args(): Handles threading arguments.
- bs_args(): Handles batch size arguments.

Returns:
argparse.ArgumentParser: Configured argument parser for extracting feature embeddings.
"""

parents = [
db_args(),
bandpass_args(),
audio_speed_args(),
overlap_args(),
threads_args(),
bs_args()
]

parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
parents=[io_args(), bandpass_args(), overlap_args(), threads_args(), bs_args()],
parents=parents,
)

parser.add_argument(
"-i",
"--input",
help="Path to input file or folder.",
)

return parser

def search_parser():
"""
Creates and returns an argument parser for searching BirdNET embeddings.

The parser includes the following arguments:
- -q, --queryfile: Path to the query file.
- -o, --output: Path to the output folder.
- --n_results: Number of results to return.
- --score_function: Scoring function to use. Choose 'cosine', 'euclidean' or 'dot'. Defaults to 'cosine'.
- --crop_mode: Crop mode for the query sample. Can be 'center', 'first' or 'segments'.

The parser also includes arguments from the following parent parsers:
- overlap_args(): Handles overlap arguments if segments is selected as crop mode.
- db_args(): Handles database arguments.
"""

parents = [overlap_args(), db_args()]

parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
parents=parents
)
parser.add_argument(
"-q",
"--queryfile",
help="Path to the query file."
)
parser.add_argument(
"-o",
"--output",
help="Path to the output folder."
)
parser.add_argument(
"--n_results",
default=10,
help="Number of results to return."
)

# TODO: use choice argument.
parser.add_argument(
"--score_function",
default="cosine",
help="Scoring function to use. Choose 'cosine', 'euclidean' or 'dot'. Defaults to 'cosine'."
)
parser.add_argument(
"--crop_mode",
default=cfg.SAMPLE_CROP_MODE,
help="Crop mode for the query sample. Can be 'center', 'first' or 'segments'.",
)

return parser

def client_parser():
"""
Expand Down
60 changes: 2 additions & 58 deletions birdnet_analyzer/embeddings/__init__.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,8 @@
def main():
import os
from multiprocessing import Pool

import birdnet_analyzer.config as cfg
import birdnet_analyzer.utils as utils
import birdnet_analyzer.cli as cli

parser = cli.embeddings_parser()

args = parser.parse_args()

from birdnet_analyzer.embeddings.utils import analyze_file # noqa: E402

### Make sure to comment out appropriately if you are not using args. ###

# 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)
else:
cfg.FILE_LIST = [cfg.INPUT_PATH]

# Set overlap
cfg.SIG_OVERLAP = args.overlap

# Set bandpass frequency range
cfg.BANDPASS_FMIN = args.fmin
cfg.BANDPASS_FMAX = args.fmax

# 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]
from birdnet_analyzer.embeddings.utils import run # noqa: E402

# Analyze files
if cfg.CPU_THREADS < 2:
for entry in flist:
analyze_file(entry)
else:
with Pool(cfg.CPU_THREADS) as p:
p.map(analyze_file, flist)
run(args.input, args.database, args.overlap, args.audio_speed, args.fmin, args.fmax, args.threads, args.batchsize)
Loading