cleanup privacy filter, also make sure a human chunk their neighbour is also overwritten (#475)

This commit is contained in:
Nachtzuster
2025-09-27 13:41:33 +02:00
committed by GitHub
parent 786348d815
commit 59e378791c
+63 -33
View File
@@ -1,4 +1,3 @@
import datetime
import logging
import math
import operator
@@ -25,7 +24,7 @@ userDir = os.path.expanduser('~')
INTERPRETER, M_INTERPRETER, INCLUDE_LIST, EXCLUDE_LIST = (None, None, None, None)
PREDICTED_SPECIES_LIST = []
WEEK = None
model, priv_thresh, sf_thresh = (None, None, None)
model, sf_thresh = (None, None)
mdata, mdata_params = (None, None)
@@ -222,17 +221,7 @@ def predict(sample, sensitivity):
# Sort by score
p_sorted = sorted(p_labels.items(), key=operator.itemgetter(1), reverse=True)
human_cutoff = max(10, int(len(p_sorted) * priv_thresh / 100.0))
log.debug("DATABASE SIZE: %d", len(p_sorted))
log.debug("HUMAN-CUTOFF AT: %d", human_cutoff)
for i in range(min(10, len(p_sorted))):
if p_sorted[i][0] == 'Human_Human':
with open(userDir + '/BirdNET-Pi/HUMAN.txt', 'a') as rfile:
rfile.write(str(datetime.datetime.now()) + str(p_sorted[i]) + ' ' + str(human_cutoff) + '\n')
return p_sorted[:human_cutoff]
return p_sorted
def analyzeAudioData(chunks, lat, lon, week, sens, overlap,):
@@ -240,7 +229,7 @@ def analyzeAudioData(chunks, lat, lon, week, sens, overlap,):
sensitivity = max(0.5, min(1.0 - (sens - 1.0), 1.5))
detections = {}
detections = []
start = time.time()
log.info('ANALYZING AUDIO...')
@@ -252,35 +241,77 @@ def analyzeAudioData(chunks, lat, lon, week, sens, overlap,):
mdata = get_metadata(lat, lon, week)
# Parse every chunk
pred_start = 0.0
for c in chunks:
# Prepare as input signal
sig = np.expand_dims(c, 0)
# Make prediction
p = predict([sig, mdata], sensitivity)
# print("PPPPP",p)
HUMAN_DETECTED = False
log.debug("PPPPP: %s", p)
detections.append(p)
# Catch if Human is recognized
for x in range(len(p)):
if "Human" in p[x][0]:
HUMAN_DETECTED = True
# Save result and timestamp
labeled = {}
pred_start = 0.0
for p in filter_humans(detections):
# Save timestamp and result
pred_end = pred_start + 3.0
# If human detected set all detections to human to make sure voices are not saved
if HUMAN_DETECTED is True:
p = [('Human_Human', 0.0)] * 10
detections[str(pred_start) + ';' + str(pred_end)] = p
labeled[str(pred_start) + ';' + str(pred_end)] = p
pred_start = pred_end - overlap
log.info('DONE! Time %.2f SECONDS', time.time() - start)
return detections
return labeled
def filter_humans(detections):
conf = get_settings()
priv_thresh = conf.getfloat('PRIVACY_THRESHOLD')
human_cutoff = max(10, int(len(detections[0]) * priv_thresh / 100.0))
log.debug("DATABASE SIZE: %d", len(detections[0]))
log.debug("HUMAN-CUTOFF AT: %d", human_cutoff)
censored_detections = []
for detection in detections:
p = detection[:human_cutoff]
human_detected = False
# Catch if Human is recognized in any of the predictions
for x in p:
if 'Human' in x[0]:
human_detected = True
# If human detected set detection to human to make sure voices are not saved
if human_detected is True:
p = [('Human_Human', 0.0)]
else:
p = p[:10]
censored_detections.append(p)
# now overwrite detections that have a human neighbour too
try:
extraction_length = conf.getint('EXTRACTION_LENGTH')
except ValueError:
extraction_length = 6
if extraction_length > 9:
log.warning("EXTRACTION_LENGTH is set to %d. Privacy filter might miss human sound, "
"if you care about privacy, set EXTRACTION_LENGTH to below 9 or leave empty.", extraction_length)
human_neighbour_mask = [False] * len(censored_detections)
for i, detection in enumerate(censored_detections):
if i != 0:
if censored_detections[i - 1][0][0] == 'Human_Human':
human_neighbour_mask[i] = True
if i != len(censored_detections) - 1:
if censored_detections[i + 1][0][0] == 'Human_Human':
human_neighbour_mask[i] = True
clean_detections = []
for i, (has_human_neighbour, detection) in enumerate(zip(human_neighbour_mask, censored_detections)):
if has_human_neighbour and detection[0][0] != 'Human_Human':
log.debug('Overwriting detection %d %s - Has Human neighbour', i + 1, detection[0])
detection = [('Human_Human', 0.0)]
clean_detections.append(detection)
return clean_detections
def get_metadata(lat, lon, week):
@@ -296,10 +327,9 @@ def get_metadata(lat, lon, week):
def load_global_model():
global INTERPRETER
global model, priv_thresh, sf_thresh
global model, sf_thresh
conf = get_settings()
model = conf['MODEL']
priv_thresh = conf.getfloat('PRIVACY_THRESHOLD')
sf_thresh = conf.getfloat('SF_THRESH')
INTERPRETER = loadModel()