mirror of
https://github.com/macaodha/batdetect2.git
synced 2025-06-29 14:41:58 +02:00
126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
import numpy as np
|
|
|
|
|
|
def convert_int_to_freq(spec_ind, spec_height, min_freq, max_freq):
|
|
spec_ind = spec_height - spec_ind
|
|
return round((spec_ind / float(spec_height)) * (max_freq - min_freq) + min_freq, 2)
|
|
|
|
|
|
def extract_spec_slices(spec, pred_nms, params):
|
|
"""
|
|
Extracts spectrogram slices from spectrogram based on detected call locations.
|
|
"""
|
|
|
|
x_pos = pred_nms["x_pos"]
|
|
y_pos = pred_nms["y_pos"]
|
|
bb_width = pred_nms["bb_width"]
|
|
bb_height = pred_nms["bb_height"]
|
|
slices = []
|
|
|
|
# add 20% padding either side of call
|
|
pad = bb_width * 0.2
|
|
x_pos_pad = x_pos - pad
|
|
bb_width_pad = bb_width + 2 * pad
|
|
|
|
for ff in range(len(pred_nms["det_probs"])):
|
|
x_start = int(np.maximum(0, x_pos_pad[ff]))
|
|
x_end = int(
|
|
np.minimum(spec.shape[1] - 1, np.round(x_pos_pad[ff] + bb_width_pad[ff]))
|
|
)
|
|
slices.append(spec[:, x_start:x_end].astype(np.float16))
|
|
return slices
|
|
|
|
|
|
def get_feature_names():
|
|
feature_names = [
|
|
"duration",
|
|
"low_freq_bb",
|
|
"high_freq_bb",
|
|
"bandwidth",
|
|
"max_power_bb",
|
|
"max_power",
|
|
"max_power_first",
|
|
"max_power_second",
|
|
"call_interval",
|
|
]
|
|
return feature_names
|
|
|
|
|
|
def get_feats(spec, pred_nms, params):
|
|
"""
|
|
Extracts features from spectrogram based on detected call locations.
|
|
Condsider re-extracting spectrogram for this to get better temporal resolution.
|
|
|
|
For more possible features check out:
|
|
https://github.com/YvesBas/Tadarida-D/blob/master/Manual_Tadarida-D.odt
|
|
"""
|
|
|
|
x_pos = pred_nms["x_pos"]
|
|
y_pos = pred_nms["y_pos"]
|
|
bb_width = pred_nms["bb_width"]
|
|
bb_height = pred_nms["bb_height"]
|
|
|
|
feature_names = get_feature_names()
|
|
num_detections = len(pred_nms["det_probs"])
|
|
features = np.ones((num_detections, len(feature_names)), dtype=np.float32) * -1
|
|
|
|
for ff in range(num_detections):
|
|
x_start = int(np.maximum(0, x_pos[ff]))
|
|
x_end = int(np.minimum(spec.shape[1] - 1, np.round(x_pos[ff] + bb_width[ff])))
|
|
# y low is the lowest freq but it will have a higher value due to array starting at 0 at top
|
|
y_low = int(np.minimum(spec.shape[0] - 1, y_pos[ff]))
|
|
y_high = int(np.maximum(0, np.round(y_pos[ff] - bb_height[ff])))
|
|
spec_slice = spec[:, x_start:x_end]
|
|
|
|
if spec_slice.shape[1] > 1:
|
|
features[ff, 0] = round(
|
|
pred_nms["end_times"][ff] - pred_nms["start_times"][ff], 5
|
|
)
|
|
features[ff, 1] = int(pred_nms["low_freqs"][ff])
|
|
features[ff, 2] = int(pred_nms["high_freqs"][ff])
|
|
features[ff, 3] = int(
|
|
pred_nms["high_freqs"][ff] - pred_nms["low_freqs"][ff]
|
|
)
|
|
features[ff, 4] = int(
|
|
convert_int_to_freq(
|
|
y_high + spec_slice[y_high:y_low, :].sum(1).argmax(),
|
|
spec.shape[0],
|
|
params["min_freq"],
|
|
params["max_freq"],
|
|
)
|
|
)
|
|
features[ff, 5] = int(
|
|
convert_int_to_freq(
|
|
spec_slice.sum(1).argmax(),
|
|
spec.shape[0],
|
|
params["min_freq"],
|
|
params["max_freq"],
|
|
)
|
|
)
|
|
hlf_val = spec_slice.shape[1] // 2
|
|
|
|
features[ff, 6] = int(
|
|
convert_int_to_freq(
|
|
spec_slice[:, :hlf_val].sum(1).argmax(),
|
|
spec.shape[0],
|
|
params["min_freq"],
|
|
params["max_freq"],
|
|
)
|
|
)
|
|
features[ff, 7] = int(
|
|
convert_int_to_freq(
|
|
spec_slice[:, hlf_val:].sum(1).argmax(),
|
|
spec.shape[0],
|
|
params["min_freq"],
|
|
params["max_freq"],
|
|
)
|
|
)
|
|
|
|
if ff > 0:
|
|
features[ff, 8] = round(
|
|
pred_nms["start_times"][ff] - pred_nms["start_times"][ff - 1],
|
|
5,
|
|
)
|
|
|
|
return features
|