見出し画像

MFCC分析による類似音声検出システム in Python

概要

このツールは、2つのPythonスクリプトで構成されています。

  1. mfcc_based_audio_similarity_analyzer.py
    オーディオファイルのMFCC(Mel-frequency cepstral coefficients)を基にした類似性分析を行います。

  2. wav_volume_based_trimmer_dir.py
    WAVファイルを音量に基づいてトリミングします。

用語説明

  • 参照ファイル: 比較の基準となる既知のオーディオファイル群。これらは reference_wav_files/original ディレクトリに配置します。

  • 対象ファイル: 参照ファイルと比較される、分析対象のオーディオファイル群。これらは target_wav_files/original ディレクトリに配置します。

  • MFCC: 音声信号の特徴を表す係数で、人間の聴覚特性を考慮した音声の特徴量です。

機能

  • WAVファイルからMFCC特徴量を抽出

  • 主成分分析(PCA)を用いた特徴量の次元削減

  • 複数のオーディオファイル間の類似性を比較

  • 音量に基づいてWAVファイルをトリミング

  • ディレクトリ単位でのバッチ処理

必要なライブラリ

  • numpy

  • librosa

  • scipy

  • sklearn

  • os

  • base64

使い方

  • 必要なライブラリをインストールします。

pip install numpy librosa scipy scikit-learn
  • 以下のディレクトリ構造を作成します。

.
├── reference_wav_files
│   ├── original  # 参照ファイルを配置するディレクトリ
│   └── trimmed  # トリミングされたファイルが保存されるディレクトリ
├── target_wav_files
│   ├── original  # 対象ファイルを配置するディレクトリ
│   └── trimmed  # トリミングされたファイルが保存されるディレクトリ
├── mfcc_based_audio_similarity_analyzer.py
└── wav_volume_based_trimmer_dir.py
  • reference_wav_files/original と target_wav_files/original に分析したいWAVファイルを配置します。

  • mfcc_based_audio_similarity_analyzer.py を実行します:

python mfcc_based_audio_similarity_analyzer.py

スクリプトの詳細

1. mfcc_based_audio_similarity_analyzer.py

このスクリプトは、オーディオファイルの類似性分析の中心的な役割を果たします。

import numpy as np
import librosa
import base64
from sklearn.decomposition import PCA
from scipy.spatial.distance import cosine
import os
import wav_volume_based_trimmer_dir

def create_mfcc_features(audio_file):
    y, sr = librosa.load(audio_file, offset=0, duration=1)
    mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=20)
    return mfcc

def apply_pca(features, n_components=10):
    pca = PCA(n_components=n_components)
    pca_features = pca.fit_transform(features.T).T
    return pca_features

def features_to_feature_string(features):
    flattened = features.flatten()
    normalized = ((flattened - flattened.min()) / (flattened.max() - flattened.min()) * 255).astype(np.uint8)
    byte_data = normalized.tobytes()
    base64_str = base64.b64encode(byte_data).decode('utf-8')
    return base64_str

def audio_to_mfcc_pca_feature_string(audio_file):
    mfcc = create_mfcc_features(audio_file)
    pca_features = apply_pca(mfcc)
    feature_string = features_to_feature_string(pca_features)
    return feature_string

def feature_string_to_features(feature_string):
    byte_data = base64.b64decode(feature_string)
    normalized = np.frombuffer(byte_data, dtype=np.uint8)
    features = normalized.astype(float) / 255
    return features

def compare_audio_features(feature_string1, feature_string2, threshold=0.1):
    features1 = feature_string_to_features(feature_string1)
    features2 = feature_string_to_features(feature_string2)
    similarity = 1 - cosine(features1, features2)
    return similarity >= 1 - threshold, similarity

def compare_with_reference_set(reference_files, target_file, threshold=0.1):
    target_feature = audio_to_mfcc_pca_feature_string(target_file)
    
    max_similarity = -1
    most_similar_file = None
    
    for ref_file in reference_files:
        ref_feature = audio_to_mfcc_pca_feature_string(ref_file)
        is_similar, similarity = compare_audio_features(ref_feature, target_feature, threshold)
        
        if similarity > max_similarity:
            max_similarity = similarity
            most_similar_file = ref_file
    
    is_similar = max_similarity >= (1 - threshold)
    return most_similar_file, max_similarity, is_similar

def batch_compare_with_reference_set(reference_dir, target_dir, threshold=0.1):
    reference_files = [os.path.join(reference_dir, f) for f in os.listdir(reference_dir) if f.endswith('.wav')]
    target_files = [os.path.join(target_dir, f) for f in os.listdir(target_dir) if f.endswith('.wav')]
    
    results = []
    
    for target_file in target_files:
        most_similar, similarity, is_similar = compare_with_reference_set(reference_files, target_file, threshold)
        results.append({
            'target_file': target_file,
            'most_similar_reference': most_similar,
            'similarity': similarity,
            'is_similar': is_similar
        })
    
    return results

if __name__ == "__main__":
    reference_dir = "./reference_wav_files"
    target_dir = "./target_wav_files"

    wav_volume_based_trimmer_dir.main(reference_dir)
    wav_volume_based_trimmer_dir.main(target_dir)
    
    trimmed_reference_dir = f"{reference_dir}/trimmed"
    trimmed_target_dir = f"{target_dir}/trimmed"
    
    results = batch_compare_with_reference_set(trimmed_reference_dir, trimmed_target_dir)
    
    if not results:
        print("---")
        print("比較が行われませんでした。両方のディレクトリに有効な.wavファイルがあるか確認してください。")
    else:
        for result in results:
            print("---")
            print(f"対象ファイル: {result['target_file']}")
            print(f"最も類似した参照ファイル: {result['most_similar_reference']}")
            print(f"類似度: {result['similarity']:.4f}")
            print(f"類似判定: {'類似' if result['is_similar'] else '非類似'}")
            

主要な関数の説明:

  • create_mfcc_features(): 音声ファイルからMFCC特徴量を抽出します。

  • apply_pca(): 特徴量にPCAを適用して次元を削減します。

  • features_to_feature_string(): 特徴量を文字列形式に変換します。

  • audio_to_mfcc_pca_feature_string(): 音声ファイルからMFCC特徴量を抽出し、PCAを適用した後、文字列形式に変換します。

  • compare_audio_features(): 2つの特徴量文字列の類似度を計算します。

2. wav_volume_based_trimmer_dir.py

このスクリプトは、WAVファイルを音量に基づいてトリミングする機能を提供します。

import os
import wave
import numpy as np
from scipy.io import wavfile

def trim_audio(input_file, output_file, threshold=0.1, duration=1.0):
    # WAVファイルを読み込む
    try:
        rate, data = wavfile.read(input_file)
    except FileNotFoundError:
        print(f"エラー: 入力ファイル '{input_file}' が見つかりません。")
        return
    except:
        print(f"エラー: 入力ファイル '{input_file}' の読み込み中に問題が発生しました。")
        return

    # データを float32 型に変換し、正規化する
    data = data.astype(np.float32) / np.iinfo(data.dtype).max
    
    # ステレオの場合は、チャンネルの平均を取る
    if len(data.shape) > 1:
        data = np.mean(data, axis=1)
    
    # 閾値を超える最初のインデックスを見つける
    threshold_indices = np.where(np.abs(data) > threshold)[0]
    
    if len(threshold_indices) == 0:
        print(f"警告: 閾値 {threshold} を超える音量が見つかりませんでした。全体の最大音量: {np.max(np.abs(data))}")
        return
    
    threshold_index = threshold_indices[0]
    
    # 切り出し開始位置から指定された長さ分のデータを抽出
    end_index = min(threshold_index + int(rate * duration), len(data))
    trimmed_data = data[threshold_index:end_index]
    
    # 新しいWAVファイルとして保存
    trimmed_data = (trimmed_data * 32767).astype(np.int16)
    try:
        wavfile.write(output_file, rate, trimmed_data)
        print(f"音声を '{input_file}' から '{output_file}' に切り出しました。")
        print(f"切り出し開始位置: {threshold_index / rate:.2f} 秒")
    except:
        print(f"エラー: 出力ファイル '{output_file}' の書き込み中に問題が発生しました。")

def process_directory(input_dir, output_dir, threshold=0.1, duration=1.0):
    # 出力ディレクトリが存在しない場合は作成
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    # 入力ディレクトリ内のすべてのWAVファイルを処理
    for filename in os.listdir(input_dir):
        if filename.lower().endswith('.wav'):
            input_path = os.path.join(input_dir, filename)
            output_filename = f"trimmed_{filename}"
            output_path = os.path.join(output_dir, output_filename)
            
            print(f"処理中: {filename}")
            trim_audio(input_path, output_path, threshold, duration)

def main(dir):
    input_directory = f"{dir}/original"
    output_directory = f"{dir}/trimmed"
    process_directory(input_directory, output_directory, threshold=0.1, duration=1.0)

処理の流れ

  1. wav_volume_based_trimmer_dir.py が呼び出され、参照ファイルと対象ファイルがトリミングされます。

  2. トリミングされたファイルは trimmed サブディレクトリに保存されます。

  3. トリミングされたファイルからMFCC特徴量が抽出され、PCAで次元削減されます。

  4. 各対象ファイルについて、最も類似した参照ファイル、類似度、類似判定結果が出力されます。

出力例

---
対象ファイル: ./target_wav_files/trimmed/trimmed_target1.wav
最も類似した参照ファイル: ./reference_wav_files/trimmed/trimmed_ref2.wav
類似度: 0.9876
類似判定: 類似

カスタマイズ

このツールには、パフォーマンスと結果を微調整するためのいくらかのパラメータがあります。

  1. 類似性判定のしきい値 (threshold)

    • compare_audio_features 関数内の threshold パラメータを調整します。

    • 小さい値にすると厳密な判定に、大きい値にすると寛容な判定になります。

  2. MFCC特徴量の抽出パラメータ

    • create_mfcc_features 関数内の n_mfcc パラメータを調整します。

    • 値を増やすとより詳細な特徴を捉えますが、計算コストが増加します。

  3. PCAの次元数

    • apply_pca 関数内の n_components パラメータを調整します。

    • 値を増やすとより多くの情報を保持しますが、計算コストが増加します。

  4. 音声トリミングパラメータ

    • trim_audio 関数内の threshold と duration パラメータを調整します。

    • threshold: トリミング開始点を決定する音量のしきい値

    • duration: トリミングする音声の長さ(秒)

これらのパラメータを調整することで、様々な種類のオーディオデータや分析目的に合わせてツールの動作を最適化できます。

注意事項

  • 入力ファイルは WAV 形式である必要があります。

  • 処理時間はファイルサイズと数に応じて変動します。

  • 十分なディスク容量があることを確認してください。トリミングされたファイルが追加で生成されます。

  • PCAによる次元削減は、データの一部の情報を失う可能性があります。非常に細かい違いを検出する必要がある場合は、PCAの使用を再検討するか、n_components の値を調整してください。

このツールを使用することで、大量のオーディオファイルの中から類似したものを効率的に見つけ出すことができます。MFCC分析は人間の聴覚特性を考慮しているため、人間の知覚に近い形で音声の類似性を評価することができます。

いいなと思ったら応援しよう!