【问题标题】:What I do wrong with algorithm to compare samples?我对比较样本的算法做错了什么?
【发布时间】:2014-06-02 16:31:01
【问题描述】:

我想比较和识别两个声音流。我创建了自己的算法,但它并没有像我想要的那样工作。例如,我尝试将几个字母“A,B,C”与“D,E,F”或单词“facebook”与“音乐”进行比较,算法为这种比较提供了真正的价值,但这些不是同一个词.我的算法太不精确了,还是导致使用笔记本电脑的麦克风录制的声音质量不佳?

我的比较算法概念: 例如,我从一个流中提取 100 个样本(它可以在轨道中间),并以指定的方式循环检查第二个流的每个片段:前 0-99 个样本、1-100、2-101 等。 我的程序几乎没有轨道可以与一个输入轨道进行比较,因此我的算法可以从每个轨道中获得最佳解决方案(轨道中最相似的样本)不幸的是它得到了错误的结果。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using Controller.Annotations;
using NAudio.Wave;


namespace Controller.Models
{
    class DecompositionOfSound
    {
        private int _numberOfSimilarSamples;
        private String _stream;
    public string Stream
    {
        get { return _stream; }
        set { _stream = value; }
    }

    public int IloscPodobnychProbek
    {
        get { return _numberOfSimilarSamples; }
        set { _numberOfSimilarSamples = value; }
    }

    public DecompositionOfSound(string stream)
    {
        _stream = stream;
        SaveSamples(stream);
    }

    private void SaveSamples(string stream)
    {
        var wave = new WaveChannel32(new WaveFileReader(stream));
        Samples = new byte[wave.Length];
        wave.Read(Samples, 0, (int) wave.Length);
    }

    private byte[] _samples;
    public byte[] Samples
    {
        get { return _samples; }
        set { _samples = value; }
    }
}

class Sample: INotifyPropertyChanged
{
    #region Cechy
    private IList<DecompositionOfSound> _listoOfSoundSamples = new ObservableCollection<DecompositionOfSound>();
    private string[] _filePaths;
    #endregion

    #region Property
    public string[] FilePaths
    {
        get { return _filePaths; }
        set { _filePaths = value; }
    }
    public IList<DecompositionOfSound> ListaSciezekDzwiekowych
    {
        get { return _listoOfSoundSamples; }
        set { _listoOfSoundSamples = value; }
    }
    #endregion

    #region Metody
    public Sample()
    {
        LoadSamples(); // przy każdym nowym nagraniu należy zaktualizować !!!
    }
    public void DisplayMatchingOfSamples()
    {
        foreach (var decompositionOfSound in ListaSciezekDzwiekowych)
        {
            MessageBox.Show(decompositionOfSound.IloscPodobnychProbek.ToString());
        }
    }
    public DecompositionOfSound BestMatchingOfSamples()
    {
        int max=0;
        DecompositionOfSound referenceToObject = null;
        foreach (var numberOfMatching in _listoOfSoundSamples)
        {
            if (numberOfMatching.IloscPodobnychProbek > max)
            {
                max = numberOfMatching.IloscPodobnychProbek;
                referenceToObject = numberOfMatching;
            }
        }
        return referenceToObject;

    }
    public void LoadSamples()
    {
        int i = 0;

        _filePaths = Directory.GetFiles(@"Samples","*.wav");
        while (i < _filePaths.Length)
        {
            ListaSciezekDzwiekowych.Add(new DecompositionOfSound(_filePaths[i]));
            i++;
        }
    }
    public void CheckMatchingOfWord(byte[] inputSound,double eps)
    {            
        foreach (var probka in _listoOfSoundSamples)
        {
            CompareBufforsOfSamples(inputSound, probka, eps);
        }
    }
    public void CheckMatchingOfWord(String inputSound,int iloscProbek, double eps)
    {

        var wave = new WaveChannel32(new WaveFileReader(inputSound));
        var samples = new byte[wave.Length];
        wave.Read(samples, 0, (int)wave.Length);
        var licznik = 0;
        var samplesTmp = new byte[iloscProbek];
        while (licznik < iloscProbek)
        {
            samplesTmp[licznik] = samples[licznik + (wave.Length >> 1)];
            licznik++;
        }
        foreach (var probka in _listoOfSoundSamples)
        {
            CompareBufforsOfSamples(samplesTmp, probka, eps);
        }
    }
    private void CompareBufforsOfSamples(byte[] inputSound, DecompositionOfSound samples, double eps)
    {
        int max = 0;
        for (int i = 0; i < (samples.Samples.Length - inputSound.Length); i++)
        {
            int counter = 0;
            for (int j = 0; j < inputSound.Length; j++)
            {
                if (inputSound[j] * eps <= samples.Samples[i + j] && 
                (inputSound[j] + inputSound[j] *(1 - eps)) >= samples.Samples[i + j])
                {
                    counter++;
                }
            }
            if (counter > max) max = counter;
        }
        samples.IloscPodobnychProbek = max;
    }   
    #endregion

    #region INotifyPropertyChange
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

在比较所有声音样本时,算法会找到匹配样本数最多的音轨,但记录不正确。我对这两条记录的比较是否有意义,以及我如何修复它以获得预期的结果。你愿意帮我找到这个问题的解决方案吗?对不起我的英语。

亲切的问候

【问题讨论】:

  • 除非两个声音样本是由完全相同的设备在完全相同的环境中录制的,并且录音与声源精确同步,并且完全消除了所有可能的环境干扰,否则它们不会匹配样本对样本.即使在一个完美控制的工作室里,由于许多不同的原因,他们仍然可能不会。比较声音样本的等效/相似性更多的是比较随时间变化的频率内容、包络和其他塑造声音的因素。逐个样本的比较几乎不会有用。

标签: naudio


【解决方案1】:

您根本无法对录音进行样本级别的比较来确定您的匹配。即使在同一台计算机上对同一个人所说的同一个词进行两次录音 - 即:每个细节都完全相同 - 记录的样本也会有所不同。数字音频就是这样。听起来可能一样,但实际录制的样本会不匹配。

Speech To Text 并不简单,语音识别也不简单(即:通过声音检查一个人的身份)。

您需要检查录音的频率曲线,而不是样本。自然语音中的各种声音具有不同的频率分布。咝咝声 - s 声音 - 例如,具有较高频率的广泛分布,因此很容易发现 - 这就是为什么他们过去常常在电话系统上对旧的 yes/no 响应检测使用咝咝声检测。

您可以通过对样本块使用快速傅里叶变换来获得波形的频率分布。遍历音频流并执行一系列 FFT 以获得波形频率的 2D 映射,然后寻找有趣的东西,例如咝咝声(高频很多,低频很少)。

当然,您可以只使用其中一种基于 Web 的 Speech to Text API。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多