This value is used by the model to constrain the list of possible species that it will try to detect, given the minimum occurence frequency. A 0.05 threshold means that the species is seen on average at least 5% of the time, from historically collected data for your lat/lon. If you'd like to tinker with this value and see the species list output, you can run the following command:
This model comes from BirdNET-Lite, with bird sound recognition for more than 6,000 species worldwide. This is the default option and will generally work very well for most use cases.
diff --git a/scripts/install_config.sh b/scripts/install_config.sh
index ba08c46..a592407 100755
--- a/scripts/install_config.sh
+++ b/scripts/install_config.sh
@@ -32,6 +32,7 @@ LONGITUDE=$(curl -s4 ifconfig.co/json | jq .longitude)
#______________________used for detecting bird audio.__________________________#
MODEL=BirdNET_6K_GLOBAL_MODEL
+SF_THRESH=0.5
#--------------------- BirdWeather Station Information -----------------------#
#_____________The variable below can be set to have your BirdNET-Pi____________#
diff --git a/scripts/species.py b/scripts/species.py
new file mode 100644
index 0000000..3426f61
--- /dev/null
+++ b/scripts/species.py
@@ -0,0 +1,139 @@
+from pathlib import Path
+from tzlocal import get_localzone
+import datetime
+import sqlite3
+import requests
+import json
+import time
+import math
+import numpy as np
+import librosa
+import operator
+import socket
+import threading
+import os
+import sys
+import argparse
+import datetime
+
+try:
+ import tflite_runtime.interpreter as tflite
+except BaseException:
+ from tensorflow import lite as tflite
+
+
+
+def loadMetaModel():
+
+ global M_INTERPRETER
+ global M_INPUT_LAYER_INDEX
+ global M_OUTPUT_LAYER_INDEX
+ global CLASSES
+
+ # Load TFLite model and allocate tensors.
+ M_INTERPRETER = tflite.Interpreter(model_path=userDir + '/BirdNET-Pi/model/BirdNET_GLOBAL_3K_V2.2_MData_Model_FP16.tflite')
+ M_INTERPRETER.allocate_tensors()
+
+ # Get input and output tensors.
+ input_details = M_INTERPRETER.get_input_details()
+ output_details = M_INTERPRETER.get_output_details()
+
+ # Get input tensor index
+ M_INPUT_LAYER_INDEX = input_details[0]['index']
+ M_OUTPUT_LAYER_INDEX = output_details[0]['index']
+
+ # Load labels
+ CLASSES = []
+ labelspath = userDir + '/BirdNET-Pi/model/labels.txt'
+ with open(labelspath, 'r') as lfile:
+ for line in lfile.readlines():
+ CLASSES.append(line.replace('\n', ''))
+
+ print("loaded META model")
+
+def predictFilter(lat, lon, week):
+
+ global M_INTERPRETER
+
+ # Does interpreter exist?
+ try:
+ if M_INTERPRETER == None:
+ loadMetaModel()
+ except Exception as e:
+ loadMetaModel()
+
+ # Prepare mdata as sample
+ sample = np.expand_dims(np.array([lat, lon, week], dtype='float32'), 0)
+
+ # Run inference
+ M_INTERPRETER.set_tensor(M_INPUT_LAYER_INDEX, sample)
+ M_INTERPRETER.invoke()
+
+ return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0]
+
+def explore(lat, lon, week):
+
+ # Make filter prediction
+ l_filter = predictFilter(lat, lon, week)
+
+ # Apply threshold
+ l_filter = np.where(l_filter >= 0.03, l_filter, 0)
+
+ # Zip with labels
+ l_filter = list(zip(l_filter, CLASSES))
+
+ # Sort by filter value
+ l_filter = sorted(l_filter, key=lambda x: x[0], reverse=True)
+
+ return l_filter
+
+def getSpeciesList(lat, lon, week, threshold=0.05, sort=False):
+
+ print('Getting species list for {}/{}, Week {}...'.format(lat, lon, week), end='', flush=True)
+
+ # Extract species from model
+ pred = explore(lat, lon, week)
+
+ # Make species list
+ slist = []
+ for p in pred:
+ if p[0] >= threshold:
+ slist.append([p[1],p[0]])
+
+ return slist
+
+
+userDir = os.path.expanduser('~')
+DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db'
+with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f:
+
+ this_run = f.readlines()
+ lat = str(str(str([i for i in this_run if i.startswith('LATITUDE')]).split('=')[1]).split('\\')[0])
+ lon = str(str(str([i for i in this_run if i.startswith('LONGITUDE')]).split('=')[1]).split('\\')[0])
+
+weekofyear = datetime.datetime.today().isocalendar()[1]
+if __name__ == '__main__':
+
+ # Parse arguments
+ parser = argparse.ArgumentParser(description='Get list of species for a given location with BirdNET. Sorted by occurrence frequency.')
+ #parser.add_argument('--o', default='/home/pi/BirdNET-Pi/include_species_list.txt', help='Path to output file or folder. If this is a folder, file will be named \'species_list.txt\'.')
+ #parser.add_argument('--lat', type=float, default=##, help='Recording location latitude. Set -1 to ignore.')
+ #parser.add_argument('--lon', type=float, default=##, help='Recording location longitude. Set -1 to ignore.')
+ #parser.add_argument('--week', type=int, default=dayofweek, help='Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 for year-round species list.')
+ parser.add_argument('--threshold', type=float, default=0.05, help='Occurrence frequency threshold. Defaults to 0.05.')
+ #parser.add_argument('--sortby', default='freq', help='Sort species by occurrence frequency or alphabetically. Values in [\'freq\', \'alpha\']. Defaults to \'freq\'.')
+
+ args = parser.parse_args()
+
+ LOCATION_FILTER_THRESHOLD = args.threshold
+
+ # Get species list
+ species_list = getSpeciesList(lat, lon, weekofyear, LOCATION_FILTER_THRESHOLD, False)
+ for x in range(len(species_list)):
+ print(species_list[x][0] + " - "+ str(species_list[x][1]))
+
+ print("\nThe above species list describes all of the species that have been historically observed at the specified lat/long ("+lat+", "+lon+") for this week of the year. The frequency threshold is the percentage of submitted eBird checklists that the species appeared on, meaning a higher threshold means that the species is more common.")
+ print("\nNOTE: no actual changes to your BirdNET-Pi species list were made by running this command. To set your desired frequency threshold, do it through the BirdNET-Pi web interface (Tools -> Settings -> Model)")
+
+
+
diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh
index 9efac14..9e69411 100755
--- a/scripts/update_birdnet_snippets.sh
+++ b/scripts/update_birdnet_snippets.sh
@@ -147,6 +147,9 @@ fi
if ! grep MODEL /etc/birdnet/birdnet.conf &>/dev/null;then
sudo -u$USER echo "MODEL=BirdNET_6K_GLOBAL_MODEL" >> /etc/birdnet/birdnet.conf
fi
+if ! grep SF_THRESH /etc/birdnet/birdnet.conf &>/dev/null;then
+ sudo -u$USER echo "SF_THRESH=0.5" >> /etc/birdnet/birdnet.conf
+fi
sudo systemctl daemon-reload
restart_services.sh