任意の画像をスペクトログラムとして読み込み音声を生成する(i2s2w)

概要

指定した画像をスペクトログラムとして持つような音声を作る.

デモ

右肩上がりの直線を与えると

時間に比例して周波数の高くなるTSP信号(もどき)の音声を返す.

文字も埋め込める.

写真などの濃淡のはっきりしていない画像では,広い周波数域に同程度のパワーを持つためノイズっぽくなってしまう.

@i2s2wで動かしていているのでお試しください. ただTwitter bot 作成の知見が薄いので稼働が不安定かも知れません.

スペクトログラムについてざっくりと

音声信号の特徴を知りたいときはフーリエ変換を行ってどのように周波数が含まれているか調べる.

f:id:gifunogi:20170323160117p:plain

しかし,発話音声や音楽信号などの時間的な変化の大きい信号では全体の周波数的特徴が分かってもそのときどきの実用的な特徴がわからない.

f:id:gifunogi:20170323160106p:plain

このとき,時間方向に細かく分割した周波数分析(短時間フーリエ変換)を行ったスペクトログラムの表示から特徴を知ることが多い.

f:id:gifunogi:20170323225107p:plain

スペクトログラムは縦軸を周波数,横軸を時間,色でパワーを示す擬似的な3次元のグラフと見ることができる.

スペクトログラムから音声への逆変換

スペクトログラムを時間方向に分割し,逆フーリエ変換を行えばその時間における音声波形を復号することができる. (これは半分嘘で,一般的にスペクトログラム表示では位相情報が失われるため完全な復号はできない.) (実際に完全な復号をやっている研究もあるらしいのですが資料を読んでいません.)

つまり,任意の画像を読み込み,1列1列をフーリエ変換結果として考えて逆フーリエ変換を行えば,その画像をスペクトログラムとしてもつ音声波形を生成できる.

ソースコード(Python3)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import numpy as np
import scipy.io.wavfile as scw
from PIL import Image
from scipy.fftpack import ifft

img_path = "spectrogram_image.png"   # 読み込む画像の名前

# 読み込んだ画像のリサイズ設定
# 生成される音声の信号時間は height * width * 2 / fs [sec]
height = 1024      # 大きいほど時間分解能が高く
width = 64         # 大きいほど周波数分解能が高く

raw_input_img = Image.open(img_path).convert("L") # グレースケールで読み込み
input_img = raw_input_img.resize((height, width))
img_data = np.array(input_img, dtype="uint8")
img_data = np.rot90(img_data, 3)                   # 画像の回転(スペクトログラム表示のときの方向調整)
img_data = 255 - img_data                          # 黒がパワー大,白がパワー小となるようにネガポジ反転

# 時間方向で画像を分割し,1行を短時間周波数結果と見る
# 1行ごとに逆フーリエ変換(ifft)を行うことで波形を生成できる
wav_data = np.zeros((height, width * 2))
for i, spectral in enumerate(img_data):
    wav_data[i] = ifft(spectral, n=width*2).real

wav_data = np.reshape(wav_data, height * width * 2)        # 1行の行列データに整形
wav_data = (2 ** 15 * wav_data) // max(abs(wav_data))   # 最大が 2**15 になるように正規化
wav_data = np.array(wav_data, dtype="int16")         # data type を int16に(wav書き出しのため)

t = str(time.time()).replace(".", "")
wav_path = "./out{0}.wav".format(t)       # 保存するwav音声の名前
fs = 16000                             # サンプリング周波数
scw.write(wav_path, fs, wav_data)       # wav書き出し

モチベーション

これから3年間音響の勉強をしなければならないらしい.

Visual Studio Code の統合ターミナルでも cmder の alias コマンドを使いたい

環境変数を設定してバッチファイルを起動させればOK

@echo off
    
REM cmder のパスを指定
SET CMDER_ROOT=C:\cmder
REM ConEmu のパスを指定
REM cmder を Download full でダウンロードしているなら
REM [%CMDER_ROOT%\vendor\conemu-maximus5] のはず
SET ConEmuDir=C:\cmder\vendor\conemu-maximus5

C:\Windows\sysnative\cmd.exe /k "C:\cmder\vendor\init.bat"
  1. 以上の内容のバッチファイルを作成.
  2. バッチファイルを適当な名前(mycmd.batなど)で適当なディレクトリ(C:\ など)に保存.
  3. VSCode 上で[Ctrl + P] -> [Preferences: Open User Settings]を選択.
  4. User Settings に次の1行を追加.
"terminal.integrated.shell.windows": "C:/mycmd.bat",

はい

f:id:gifunogi:20170220160458g:plain

bat だと動作が微妙なら exe に書き出したりして下さい

Atmel Studio 7 でC言語コンパイル時に「recipe for target 'main.o' failed」のエラーでハマった

備忘録

  1. メニューから[Tool] -> [Option]を選択.[Builder]を選択.
  2. [ShellUtils Packages:]のタブを[Custom]に変更.
  3. GNU Make For Windowsで配布されている make.exe をダウンロード.適当なディレクトリ(C:\GnuWin32\bin\make.exeなど)に置く.
  4. [Path to make:]で参照されている make.exe を のパスをさっきダウンロードしたディレクトリに変更. f:id:gifunogi:20170220150530p:plain
  5. [OK].

なんなの

TDUCTF 2015 に参加した.

connpass.com

参加しました.WriteUpのようなものと感想です.

続きを読む

TDU CTF 2014 Satellite in Conoha に参加した.

ホンモノのCTF初経験,ホンモノの初心者として参加しました.

Write Up 書ける程解けていてないのであくまで感想です.

connpass.com

続きを読む

hoge

人の真似をしてブログを書く.

恐らく次のエントリになっているであろう,「TDU CTF 2014 Satellite in Conoha」がきっかけです.