見出し画像

スペクトログラムベースの特徴量を文字列で抽出する音声処理Pythonスクリプト

概要

このドキュメントは、音声ファイルを処理してスペクトログラムベースの特徴量を抽出するPythonプログラムの解説書です。プログラムは主に2つのスクリプトから構成されています。

  1. spectrogram_based_audio_to_text.py: スペクトログラムベースの特徴量抽出

  2. wav_volume_based_trimmer.py: 音量ベースの音声トリミング

1. スペクトログラムベースの特徴量抽出 (spectrogram_based_audio_to_text.py)

スペクトログラムベースの特徴量抽出について

スペクトログラムは、音声信号の時間-周波数表現です。これは、音声の時間的変化と周波数成分を同時に可視化する強力なツールです。

特徴

  • 横軸が時間、縦軸が周波数を表します。

  • 色や濃淡で信号の強度(振幅)を表現します。

  • 音声の時間的変化と周波数特性を同時に観察できます。

利点

  1. 時間情報と周波数情報の統合:音声の時間的変化と周波数特性を同時に捉えることができます。

  2. 豊富な情報量:調波構造、フォルマント、ノイズ成分など、音声の詳細な特徴を視覚化できます。

  3. 柔軟性:異なる時間スケールや周波数帯域に焦点を当てることができます。

  4. ノイズ耐性:時間-周波数表現により、特定の種類のノイズを識別し、フィルタリングしやすくなります。

  5. パターン認識との親和性:機械学習アルゴリズムとの相性が良く、音声認識や話者識別などのタスクに適しています。

欠点

  1. 高次元データ:生のスペクトログラムは高次元になりがちで、そのまま特徴量として使用すると計算コストが高くなる可能性があります。

  2. 位相情報の損失:通常のスペクトログラムでは振幅情報のみを使用するため、位相情報が失われます。

  3. 時間-周波数分解能のトレードオフ:時間分解能を上げると周波数分解能が下がり、その逆も発生します(不確定性原理)。

  4. 背景ノイズの影響:静的な背景ノイズがスペクトログラム全体に影響を与える可能性があります。

  5. 解釈の複雑さ:生のスペクトログラムは専門知識なしで直接解釈するのが難しい場合があります。

主な機能

  • 音声ファイルからメルスペクトログラムを生成

  • 主成分分析(PCA)を適用して特徴量の次元を削減

  • 特徴量を文字列(Base64エンコード)に変換

重要な関数

  1. create_spectrogram_features(audio_file, n_mels=128, n_fft=2048, hop_length=512)

    • 音声ファイルからメルスペクトログラムを生成します。

  2. apply_pca(features, n_components=10)

    • 特徴量に主成分分析を適用して次元を削減します。

  3. features_to_feature_string(features)

    • 特徴量を Base64 エンコードされた文字列に変換します。

  4. audio_to_spectrogram_pca_feature_string(audio_file)

    • 音声ファイルを処理して特徴量文字列を生成する主要な関数です。

設定可能なパラメータ

  1. create_spectrogram_features 関数のパラメータ:

    • n_mels (デフォルト: 128): メルフィルタバンクの数。値を増やすと周波数分解能が向上しますが、計算コストが増加します。

    • n_fft (デフォルト: 2048): FFTウィンドウサイズ。大きい値はより細かい周波数分解能を提供しますが、時間分解能が低下します。

    • hop_length (デフォルト: 512): 連続するフレーム間のサンプル数。小さい値は時間分解能を向上させますが、計算コストが増加します。

  2. apply_pca 関数のパラメータ:

    • n_components (デフォルト: 10): PCAで保持する主成分の数。より多くの成分を保持すると情報量は増えますが、次元削減の効果が減少します。

  3. メイン処理部分:

    • audio_file (デフォルト: "input_audio.wav"): 処理する入力音声ファイルのパス。

    • threshold (wav_volume_based_trimmerへの引数、デフォルト: 0.1): 音声トリミングの閾値。

    • duration (wav_volume_based_trimmerへの引数、デフォルト: 1.0): トリミングする音声の長さ(秒)。

スクリプト

import numpy as np
import librosa
import base64
from pydub import AudioSegment
from sklearn.decomposition import PCA
import wav_volume_based_trimmer
import os

def create_spectrogram_features(audio_file, n_mels=128, n_fft=2048, hop_length=512):
    try:
        # 音声ファイルの読み込み (1秒間)
        y, sr = librosa.load(audio_file, offset=0, duration=1)
    except FileNotFoundError:
        print(f"エラー: 音声ファイル '{audio_file}' が見つかりません。")
        return None
    except Exception as e:
        print(f"エラー: 音声ファイルの読み込み中に問題が発生しました: {str(e)}")
        return None
    
    # メルスペクトログラムの計算
    spectrogram = librosa.feature.melspectrogram(y=y, sr=sr, n_mels=n_mels, n_fft=n_fft, hop_length=hop_length)
    
    # デシベルスケールに変換
    spectrogram_db = librosa.power_to_db(spectrogram, ref=np.max)
    
    return spectrogram_db

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

def features_to_feature_string(features):
    # 特徴量を1次元配列に変換
    flattened = features.flatten()
    
    # 値を0-255の範囲に正規化
    normalized = ((flattened - flattened.min()) / (flattened.max() - flattened.min()) * 255).astype(np.uint8)
    
    # バイト列に変換
    byte_data = normalized.tobytes()
    
    # Base64エンコード
    base64_str = base64.b64encode(byte_data).decode('utf-8')
    
    return base64_str

def audio_to_spectrogram_pca_feature_string(audio_file):
    # スペクトログラムの特徴を抽出
    spectrogram = create_spectrogram_features(audio_file)
    if spectrogram is None:
        return None
    
    # PCAを適用して次元削減
    pca_features = apply_pca(spectrogram)
    
    # 特徴を文字列に変換
    feature_string = features_to_feature_string(pca_features)
    
    return feature_string

if __name__ == "__main__":
    audio_file = "input_audio.wav"  # 入力音声ファイル

    if not os.path.exists(audio_file):
        print(f"エラー: 入力音声ファイル '{audio_file}' が見つかりません。")
    else:
        try:
            wav_volume_based_trimmer.main(audio_file)
        except Exception as e:
            print(f"エラー: 音声トリミング中に問題が発生しました: {str(e)}")
        else:
            trimmed_file = f"trimmed_{audio_file}"
            if not os.path.exists(trimmed_file):
                print(f"警告: トリミングされたファイル '{trimmed_file}' が見つかりません。元のファイルを使用します。")
                trimmed_file = audio_file

            result = audio_to_spectrogram_pca_feature_string(trimmed_file)
            if result:
                print("スペクトログラム-PCA特徴文字列:")
                print(result[:100] + "...")  # 最初の100文字のみ表示
                print(f"特徴文字列の長さ: {len(result)}")
                print("変換プロセスが完了しました。")
            else:
                print("変換プロセスが失敗しました。")

2. 音量ベースの音声トリミング (wav_volume_based_trimmer.py)

主な機能

  • WAVファイルから音声データを読み込む

  • 指定された閾値を超える最初の位置を見つける

  • その位置から指定された長さ分の音声を切り出す

重要な関数

  1. trim_audio(input_file, output_file, threshold=0.1, duration=1.0)

    • 音声ファイルをトリミングする主要な関数です。

  2. main(audio_file)

    • トリミング処理を実行するメイン関数です。

設定可能なパラメータ

  1. trim_audio 関数のパラメータ:

    • input_file: 入力音声ファイルのパス。

    • output_file: 出力(トリミングされた)音声ファイルのパス。

    • threshold (デフォルト: 0.1): 音量閾値。この値を超える最初の位置からトリミングを開始します。値の範囲は0.0から1.0で、小さい値ほど感度が高くなります。

    • duration (デフォルト: 1.0): トリミングする音声の長さ(秒)。

  2. main 関数のパラメータ:

    • file: 処理する音声ファイルのパス。

スクリプト

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 main(audio_file):
    input_file = audio_file
    output_file = f"trimmed_{audio_file}"
    trim_audio(input_file, output_file, threshold=0.1, duration=1.0)

使用方法

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

pip install numpy librosa scipy pydub scikit-learn

入力音声ファイル(例:input_audio.wav)を準備します。

スクリプトを実行します。

python spectrogram_based_audio_to_text.py

実行結果

音声を 'input_audio.wav' から 'trimmed_input_audio.wav' に切り出しました。
切り出し開始位置: 0.97 秒
スペクトログラム-PCA特徴文字列:
ka/Xz6tcLBgKAAcfQnqov/D/+/GtZyEXJRkREiVLg6zI5+3dm1U2IAsLMD/fsjYML1hvd5nEyM7Ap6SnpIxTIAUXPzwXMGysx6uQ...
特徴文字列の長さ: 588
変換プロセスが完了しました。

注意点

  1. 入力音声ファイルが存在することを確認してください。

  2. パラメータ調整により処理時間と結果の質が変化する可能性があります。目的に応じて適切に調整してください。

  3. スペクトログラムベースの特徴量抽出は計算コストが高くなる可能性があるため、大量の音声データを処理する場合はハードウェアリソースに注意してください。

  4. 位相情報の損失により、スペクトログラムから元の音声を完全に再構築することは困難です。

  5. 背景ノイズの多い環境での録音に対しては、前処理でのノイズ削減が有効な場合があります。

エラーハンドリング

両スクリプトとも、ファイルが見つからない場合や処理中にエラーが発生した場合のエラーメッセージを提供します。

まとめ

このスクリプトセットは、スペクトログラムベースの特徴量抽出を中心とした音声処理ツールです。スペクトログラムの利点(豊富な情報量、時間-周波数情報の統合)を活かしつつ、PCAによる次元削減で計算効率を向上させています。音声認識、話者識別、音楽ジャンル分類など、様々な音声解析タスクの前処理として活用できます。ただし、位相情報の損失や背景ノイズの影響には注意が必要です。パラメータを適切に調整することで、様々な音声入力や用途に対応できる柔軟性を持っています。

この記事が気に入ったらサポートをしてみませんか?