batdetect2 / bat_detect /detector /compute_features.py
Oisin Mac Aodha
added bat code
9ace58a
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