Skip to content

Instantly share code, notes, and snippets.

@Wsiegenthaler
Created December 30, 2019 23:41
Show Gist options
  • Save Wsiegenthaler/3678eef368a3c9e128a390f80b112607 to your computer and use it in GitHub Desktop.
Save Wsiegenthaler/3678eef368a3c9e128a390f80b112607 to your computer and use it in GitHub Desktop.
Cleaning voice-activity data with "Mathematical Morphology"
/// Removes noise from voice-activity data resulting in cleaner and fewer timespans
fn clean_vad_data(data: &Vec<bool>, opening_radius: usize, closing_radius: usize) -> Vec<bool> {
// Clone voice-activity buffer and add padding
fn pad(data: &Vec<bool>, radius: usize) -> Vec<bool> {
let orig_len = data.len();
let clone_len = orig_len + radius * 2;
let mut clone = vec![false; clone_len];
clone.truncate(radius);
clone.extend_from_slice(&data);
clone.resize(clone_len, false);
clone
}
// Remove padding
fn unpad(data: &Vec<bool>, radius: usize) -> Vec<bool> {
data[radius .. data.len()-radius].to_vec()
}
let data = data.clone();
// Perform morphological 'closing' operation to fill gaps
let data = if opening_radius > 0 {
let opening_clone = pad(&data, opening_radius);
unpad(&morph_opening(&opening_clone, opening_radius), opening_radius)
} else {
data
};
// Perform morphological 'opening' operation to remove noise
let data = if closing_radius > 0 {
let closing_clone = pad(&data, closing_radius);
unpad(&morph_closing(&closing_clone, closing_radius), closing_radius)
} else {
data
};
data
}
/// The morphological 'opening' operator for 1-d. Used to fill-in
/// small gaps in areas of high activity
fn morph_opening(input: &Vec<bool>, radius: usize) -> Vec<bool> {
let eroded = morph_erosion(input, radius);
let dilated = morph_dilation(&eroded, radius);
dilated
}
/// The morphological 'closing' operator for 1-d. Used to remove
/// small voice segments from areas of low activity
fn morph_closing(input: &Vec<bool>, radius: usize) -> Vec<bool> {
let dilated = morph_dilation(input, radius);
let eroded = morph_erosion(&dilated, radius);
eroded
}
/// The morphological 'dilate' operator for 1-d
fn morph_dilation(input: &Vec<bool>, radius: usize) -> Vec<bool> {
let mut output = input.clone();
let (start, end) = (radius, input.len() - radius);
for i in start .. end {
if !input[i] {
for j in 1 ..= radius {
if input[i-j] || input[i+j] {
output[i] = true;
}
}
}
}
output
}
/// The morphological 'erode' operator for 1-d
fn morph_erosion(input: &Vec<bool>, radius: usize) -> Vec<bool> {
let mut output = input.clone();
let (start, end) = (radius, input.len() - radius);
for i in start .. end {
if input[i] {
for j in 1 ..= radius {
if !(input[i-j] && input[i+j]) {
output[i] = false;
}
}
}
}
output
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment