Created
December 30, 2019 23:41
-
-
Save Wsiegenthaler/3678eef368a3c9e128a390f80b112607 to your computer and use it in GitHub Desktop.
Cleaning voice-activity data with "Mathematical Morphology"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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