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