Merge branch 'new_model'
This commit is contained in:
@@ -6,6 +6,12 @@
|
||||
|
||||
SITE_NAME=""
|
||||
|
||||
#--------------------------------- Model --------------------------------------#
|
||||
#_____________The variable below configures which BirdNET model is_____________#
|
||||
#______________________used for detecting bird audio.__________________________#
|
||||
|
||||
MODEL=BirdNET_6K_GLOBAL_MODEL
|
||||
SF_THRESH=0.03
|
||||
|
||||
#--------------------- Required: Latitude, and Longitude ----------------------#
|
||||
|
||||
|
||||
@@ -812,4 +812,8 @@ pre#timer.bash {
|
||||
line-height:5px;
|
||||
padding:3px;
|
||||
background-color:#9fe29b
|
||||
}
|
||||
|
||||
#ddnewline::before {
|
||||
content: none;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -34,6 +34,8 @@ if(isset($_GET["latitude"])){
|
||||
$flickr_filter_email = $_GET["flickr_filter_email"];
|
||||
$language = $_GET["language"];
|
||||
$timezone = $_GET["timezone"];
|
||||
$model = $_GET["model"];
|
||||
$sf_thresh = $_GET["sf_thresh"];
|
||||
|
||||
if(isset($_GET['apprise_notify_each_detection'])) {
|
||||
$apprise_notify_each_detection = 1;
|
||||
@@ -100,6 +102,23 @@ if(isset($_GET["latitude"])){
|
||||
syslog(LOG_INFO, "Successfully changed language to '$language'");
|
||||
}
|
||||
|
||||
if ($model != $lang_config['MODEL']){
|
||||
$user = trim(shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"));
|
||||
$home = trim(shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"));
|
||||
|
||||
// Archive old language file
|
||||
syslog_shell_exec("cp -f $home/BirdNET-Pi/model/labels.txt $home/BirdNET-Pi/model/labels.txt.old", $user);
|
||||
|
||||
if($model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16"){
|
||||
// Install new language label file
|
||||
syslog_shell_exec("sudo chmod +x $home/BirdNET-Pi/scripts/install_language_label_nm.sh && $home/BirdNET-Pi/scripts/install_language_label_nm.sh -l $language", $user);
|
||||
} else {
|
||||
syslog_shell_exec("$home/BirdNET-Pi/scripts/install_language_label.sh -l $language", $user);
|
||||
}
|
||||
|
||||
syslog(LOG_INFO, "Successfully changed language to '$language'");
|
||||
}
|
||||
|
||||
|
||||
$contents = file_get_contents("/etc/birdnet/birdnet.conf");
|
||||
$contents = preg_replace("/SITE_NAME=.*/", "SITE_NAME=\"$site_name\"", $contents);
|
||||
@@ -116,6 +135,8 @@ if(isset($_GET["latitude"])){
|
||||
$contents = preg_replace("/DATABASE_LANG=.*/", "DATABASE_LANG=$language", $contents);
|
||||
$contents = preg_replace("/FLICKR_FILTER_EMAIL=.*/", "FLICKR_FILTER_EMAIL=$flickr_filter_email", $contents);
|
||||
$contents = preg_replace("/APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=.*/", "APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=$minimum_time_limit", $contents);
|
||||
$contents = preg_replace("/MODEL=.*/", "MODEL=$model", $contents);
|
||||
$contents = preg_replace("/SF_THRESH=.*/", "SF_THRESH=$sf_thresh", $contents);
|
||||
|
||||
$contents2 = file_get_contents("./scripts/thisrun.txt");
|
||||
$contents2 = preg_replace("/SITE_NAME=.*/", "SITE_NAME=\"$site_name\"", $contents2);
|
||||
@@ -132,6 +153,9 @@ if(isset($_GET["latitude"])){
|
||||
$contents2 = preg_replace("/DATABASE_LANG=.*/", "DATABASE_LANG=$language", $contents2);
|
||||
$contents2 = preg_replace("/FLICKR_FILTER_EMAIL=.*/", "FLICKR_FILTER_EMAIL=$flickr_filter_email", $contents2);
|
||||
$contents2 = preg_replace("/APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=.*/", "APPRISE_MINIMUM_SECONDS_BETWEEN_NOTIFICATIONS_PER_SPECIES=$minimum_time_limit", $contents2);
|
||||
$contents2 = preg_replace("/MODEL=.*/", "MODEL=$model", $contents2);
|
||||
$contents2 = preg_replace("/SF_THRESH=.*/", "SF_THRESH=$sf_thresh", $contents2);
|
||||
|
||||
|
||||
|
||||
if($site_name != $config["SITE_NAME"]) {
|
||||
@@ -285,6 +309,15 @@ if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
?>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
document.getElementById('modelsel').addEventListener('change', function() {
|
||||
if(this.value == "BirdNET_GLOBAL_3K_V2.2_Model_FP16"){
|
||||
document.getElementById("soft").style.display="unset";
|
||||
} else {
|
||||
document.getElementById("soft").style.display="none";
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
function sendTestNotification(e) {
|
||||
document.getElementById("testsuccessmsg").innerHTML = "";
|
||||
e.classList.add("disabled");
|
||||
@@ -304,6 +337,37 @@ function sendTestNotification(e) {
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
</script>
|
||||
<table class="settingstable"><tr><td>
|
||||
<h2>Model</h2>
|
||||
|
||||
<label for="model">Select a Model: </label>
|
||||
<select id="modelsel" name="model">
|
||||
<?php
|
||||
$models = array("BirdNET_6K_GLOBAL_MODEL", "BirdNET_GLOBAL_3K_V2.2_Model_FP16");
|
||||
foreach($models as $modelName){
|
||||
$isSelected = "";
|
||||
if($config['MODEL'] == $modelName){
|
||||
$isSelected = 'selected="selected"';
|
||||
}
|
||||
|
||||
echo "<option value='{$modelName}' $isSelected>$modelName</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<span <?php if($config['MODEL'] == "BirdNET_6K_GLOBAL_MODEL") { ?>style="display: none"<?php } ?> id="soft">
|
||||
<label for="sf_thresh">Species Occurence Frequency Threshold [0.0005, 0.99]: </label>
|
||||
<input name="sf_thresh" type="number" max="0.99" min="0.0005" step="any" value="<?php print($config['SF_THRESH']);?>"/> <span onclick="document.getElementById('sfhelp').style.display='unset'" style="text-decoration:underline;cursor:pointer">[?]</span><br>
|
||||
<p id="sfhelp" style='display:none'>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.03 threshold means that for a species to be included in this list, it needs to, on average, be seen on at least 3% of historically submitted eBird checklists for your given lat/lon/current week of year. So, the lower the threshold, the rarer the species it will include.<br>If you'd like to tinker with this threshold value and see which species make it onto the list, you can run the following command <?php if($config['MODEL'] == "BirdNET_6K_GLOBAL_MODEL"){ ?>AFTER clicking 'Update Settings' at the very bottom of this page to install the appropriate labels file<?php } ?>: <b>~/BirdNET-Pi/birdnet/bin/python3 ~/BirdNET-Pi/scripts/species.py --threshold 0.03</b></p>
|
||||
</span>
|
||||
|
||||
<dl>
|
||||
<dt>BirdNET_6K_GLOBAL_MODEL (2020)</dt><br>
|
||||
<dd id="ddnewline">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.</dd>
|
||||
<dt>BirdNET_GLOBAL_3K_V2.2_Model_FP16 (2022)</dt><br>
|
||||
<dd id="ddnewline">This model comes from BirdNET-Analyzer, a newer work-in-progress project with aims to improve on the old model. Currently it only supports about 3,500 species worldwide, so for users in North America, this model is generally much more accurate than the above model, but elsewhere it will be less accurate and possibly useless.</dd>
|
||||
</dl>
|
||||
</td></tr></table><br>
|
||||
|
||||
<table class="settingstable"><tr><td>
|
||||
<h2>Location</h2>
|
||||
|
||||
@@ -27,6 +27,13 @@ SITE_NAME="$HOSTNAME"
|
||||
LATITUDE=$(curl -s4 ifconfig.co/json | jq .latitude)
|
||||
LONGITUDE=$(curl -s4 ifconfig.co/json | jq .longitude)
|
||||
|
||||
#--------------------------------- Model --------------------------------------#
|
||||
#_____________The variable below configures which BirdNET model is_____________#
|
||||
#______________________used for detecting bird audio.__________________________#
|
||||
|
||||
MODEL=BirdNET_6K_GLOBAL_MODEL
|
||||
SF_THRESH=0.03
|
||||
|
||||
#--------------------- BirdWeather Station Information -----------------------#
|
||||
#_____________The variable below can be set to have your BirdNET-Pi____________#
|
||||
#__________________also act as a BirdWeather listening station_________________#
|
||||
|
||||
@@ -23,4 +23,11 @@ unzip -o $HOME/BirdNET-Pi/model/labels_l18n.zip $label_file_name \
|
||||
&& mv -f $HOME/BirdNET-Pi/model/$label_file_name $HOME/BirdNET-Pi/model/labels.txt \
|
||||
&& logger "[$0] Changed language label file to '$label_file_name'";
|
||||
|
||||
label_file_name_flickr="labels_en.txt"
|
||||
|
||||
unzip -o $HOME/BirdNET-Pi/model/labels_l18n.zip $label_file_name_flickr \
|
||||
-d $HOME/BirdNET-Pi/model \
|
||||
&& mv -f $HOME/BirdNET-Pi/model/$label_file_name_flickr $HOME/BirdNET-Pi/model/labels_flickr.txt \
|
||||
&& logger "[$0] Set Flickr labels '$label_file_name_flickr'";
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
usage() { echo "Usage: $0 -l <language i18n id>" 1>&2; exit 1; }
|
||||
|
||||
while getopts "l:" o; do
|
||||
case "${o}" in
|
||||
l)
|
||||
lang=${OPTARG}
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
HOME=$(awk -F: '/1000/ {print $6}' /etc/passwd)
|
||||
|
||||
label_file_name="labels_${lang}.txt"
|
||||
|
||||
unzip -o $HOME/BirdNET-Pi/model/labels_nm.zip $label_file_name \
|
||||
-d $HOME/BirdNET-Pi/model \
|
||||
&& mv -f $HOME/BirdNET-Pi/model/$label_file_name $HOME/BirdNET-Pi/model/labels.txt \
|
||||
&& logger "[$0] Changed language label file to '$label_file_name'";
|
||||
|
||||
label_file_name_flickr="labels_en.txt"
|
||||
|
||||
unzip -o $HOME/BirdNET-Pi/model/labels_nm.zip $label_file_name_flickr \
|
||||
-d $HOME/BirdNET-Pi/model \
|
||||
&& mv -f $HOME/BirdNET-Pi/model/$label_file_name_flickr $HOME/BirdNET-Pi/model/labels_flickr.txt \
|
||||
&& logger "[$0] Set Flickr labels '$label_file_name_flickr'";
|
||||
|
||||
exit 0
|
||||
+94
-11
@@ -35,6 +35,7 @@ DISCONNECT_MESSAGE = "!DISCONNECT"
|
||||
userDir = os.path.expanduser('~')
|
||||
DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db'
|
||||
|
||||
PREDICTED_SPECIES_LIST = []
|
||||
|
||||
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
@@ -51,7 +52,12 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f:
|
||||
this_run = f.readlines()
|
||||
audiofmt = "." + str(str(str([i for i in this_run if i.startswith('AUDIOFMT')]).split('=')[1]).split('\\')[0])
|
||||
priv_thresh = float("." + str(str(str([i for i in this_run if i.startswith('PRIVACY_THRESHOLD')]).split('=')[1]).split('\\')[0])) / 10
|
||||
|
||||
try:
|
||||
model = str(str(str([i for i in this_run if i.startswith('MODEL')]).split('=')[1]).split('\\')[0])
|
||||
sf_thresh = str(str(str([i for i in this_run if i.startswith('SF_THRESH')]).split('=')[1]).split('\\')[0])
|
||||
except Exception as e:
|
||||
model = "BirdNET_6K_GLOBAL_MODEL"
|
||||
sf_thresh = 0.5
|
||||
|
||||
def loadModel():
|
||||
|
||||
@@ -63,7 +69,8 @@ def loadModel():
|
||||
print('LOADING TF LITE MODEL...', end=' ')
|
||||
|
||||
# Load TFLite model and allocate tensors.
|
||||
modelpath = userDir + '/BirdNET-Pi/model/BirdNET_6K_GLOBAL_MODEL.tflite'
|
||||
# model will either be BirdNET_GLOBAL_3K_V2.2_Model_FP16 (new) or BirdNET_6K_GLOBAL_MODEL (old)
|
||||
modelpath = userDir + '/BirdNET-Pi/model/'+model+'.tflite'
|
||||
myinterpreter = tflite.Interpreter(model_path=modelpath, num_threads=2)
|
||||
myinterpreter.allocate_tensors()
|
||||
|
||||
@@ -73,7 +80,8 @@ def loadModel():
|
||||
|
||||
# Get input tensor index
|
||||
INPUT_LAYER_INDEX = input_details[0]['index']
|
||||
MDATA_INPUT_INDEX = input_details[1]['index']
|
||||
if model == "BirdNET_6K_GLOBAL_MODEL":
|
||||
MDATA_INPUT_INDEX = input_details[1]['index']
|
||||
OUTPUT_LAYER_INDEX = output_details[0]['index']
|
||||
|
||||
# Load labels
|
||||
@@ -87,6 +95,70 @@ def loadModel():
|
||||
|
||||
return myinterpreter
|
||||
|
||||
def loadMetaModel():
|
||||
|
||||
global M_INTERPRETER
|
||||
global M_INPUT_LAYER_INDEX
|
||||
global M_OUTPUT_LAYER_INDEX
|
||||
|
||||
# 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']
|
||||
|
||||
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 >= float(sf_thresh), 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 predictSpeciesList(lat, lon, week):
|
||||
|
||||
l_filter = explore(lat, lon, week)
|
||||
for s in l_filter:
|
||||
if s[0] >= float(sf_thresh):
|
||||
#if there's a custom user-made include list, we only want to use the species in that
|
||||
if(len(INCLUDE_LIST) == 0):
|
||||
PREDICTED_SPECIES_LIST.append(s[1])
|
||||
|
||||
def loadCustomSpeciesList(path):
|
||||
|
||||
@@ -162,7 +234,8 @@ def predict(sample, sensitivity):
|
||||
global INTERPRETER
|
||||
# Make a prediction
|
||||
INTERPRETER.set_tensor(INPUT_LAYER_INDEX, np.array(sample[0], dtype='float32'))
|
||||
INTERPRETER.set_tensor(MDATA_INPUT_INDEX, np.array(sample[1], dtype='float32'))
|
||||
if model == "BirdNET_6K_GLOBAL_MODEL":
|
||||
INTERPRETER.set_tensor(MDATA_INPUT_INDEX, np.array(sample[1], dtype='float32'))
|
||||
INTERPRETER.invoke()
|
||||
prediction = INTERPRETER.get_tensor(OUTPUT_LAYER_INDEX)[0]
|
||||
|
||||
@@ -197,6 +270,11 @@ def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap,):
|
||||
start = time.time()
|
||||
print('ANALYZING AUDIO...', end=' ', flush=True)
|
||||
|
||||
if model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16":
|
||||
if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0:
|
||||
predictSpeciesList(lat,lon,week)
|
||||
|
||||
|
||||
# Convert and prepare metadata
|
||||
mdata = convertMetadata(np.array([lat, lon, week]))
|
||||
mdata = np.expand_dims(mdata, 0)
|
||||
@@ -242,8 +320,8 @@ def writeResultsToFile(detections, min_conf, path):
|
||||
rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n')
|
||||
for d in detections:
|
||||
for entry in detections[d]:
|
||||
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)):
|
||||
rfile.write(d + ';' + entry[0].replace('_', ';') + ';' + str(entry[1]) + '\n')
|
||||
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ):
|
||||
rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n')
|
||||
rcnt += 1
|
||||
print('DONE! WROTE', rcnt, 'RESULTS.')
|
||||
return
|
||||
@@ -364,16 +442,16 @@ def handle_client(conn, addr):
|
||||
species_apprised_this_run = []
|
||||
for entry in detections[d]:
|
||||
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0)
|
||||
and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)):
|
||||
and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ):
|
||||
# Write to text file.
|
||||
rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';') + ';'
|
||||
rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';').split("/")[0] + ';'
|
||||
+ str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';'
|
||||
+ str(args.sensitivity) + ';' + str(args.overlap) + '\n')
|
||||
|
||||
# Write to database
|
||||
Date = str(current_date)
|
||||
Time = str(current_time)
|
||||
species = entry[0]
|
||||
species = entry[0].split("/")[0]
|
||||
Sci_Name, Com_Name = species.split('_')
|
||||
score = entry[1]
|
||||
Confidence = str(round(score * 100))
|
||||
@@ -475,9 +553,14 @@ def handle_client(conn, addr):
|
||||
post_soundscape_id = "\"soundscapeId\": " + str(soundscape_id) + ","
|
||||
post_soundscape_start_time = "\"soundscapeStartTime\": " + start_time + ","
|
||||
post_soundscape_end_time = "\"soundscapeEndTime\": " + end_time + ","
|
||||
post_commonName = "\"commonName\": \"" + entry[0].split('_')[1] + "\","
|
||||
post_commonName = "\"commonName\": \"" + entry[0].split('_')[1].split("/")[0] + "\","
|
||||
post_scientificName = "\"scientificName\": \"" + entry[0].split('_')[0] + "\","
|
||||
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
|
||||
|
||||
if model == "BirdNET_GLOBAL_3K_V2.2_Model_FP16":
|
||||
post_algorithm = "\"algorithm\": " + "\"2p2\"" + ","
|
||||
else:
|
||||
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
|
||||
|
||||
post_confidence = "\"confidence\": " + str(entry[1])
|
||||
post_end = " }"
|
||||
|
||||
|
||||
@@ -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, threshold):
|
||||
|
||||
# Make filter prediction
|
||||
l_filter = predictFilter(lat, lon, week)
|
||||
|
||||
# Apply threshold
|
||||
l_filter = np.where(l_filter >= threshold, 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, threshold)
|
||||
|
||||
# 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)")
|
||||
|
||||
|
||||
|
||||
@@ -144,5 +144,13 @@ if ! grep HEARTBEAT_URL /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||
sudo -u$USER echo "HEARTBEAT_URL=" >> /etc/birdnet/birdnet.conf
|
||||
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.03" >> /etc/birdnet/birdnet.conf
|
||||
fi
|
||||
sudo chmod +x ~/BirdNET-Pi/scripts/install_language_label_nm.sh
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
restart_services.sh
|
||||
|
||||
Reference in New Issue
Block a user