見出し画像

あつ森研究日誌(流れ星を捕まえたい①)

※まだまだ研究中(勉強中)の技術を使って、素人なりの作業のログを残しているだけです。6月27日現在未完成ですのでそこのところよろしくです。

「あつ森」を中心に知的好奇心の向かうところにがむしゃらに突っ込んでいる今日この頃、ロボ作ったりアレしたりコレしたりしているやつの最近の進捗報告です。まだまだ形になってはいませんが、いちおうこんなところまでやってるよ。というやつですね。

やりたいこと

流れ星が発生したことを検知->できれば1秒以内に空を見上げ(JoyCon↓方向入力)ー>Aボタンを押す

というイベント駆動な機構を作成したいのです。

後半の空を見上げてAボタン動作は、既にメカニカルなロボが制作されているほか、将来的には

このあたりの技術を使ってコントローラーをエミュレーションすることも考えています。(めっちゃ大変そうなんですけど!><)

とりあえず、ロボ系の動作部分はあとでなんとかするとして、今は「検出」系に的を絞ってやっていきます。

二種類の検出系

この2パターンの検出がすぐ思いつきますね。

①音で抽出
②画像から検出

どちらも、流れ星の特徴を絵か音かのどちらかでとらえようというものです。

画像認識もやろうとしていたのですが、その予備実験中に

↑ただの興味からよくわからない方向に突き進んだ挙句、うまくいかなくて諦めるの図

こんなかんじで意味もなく別の壁にぶち当たってしまったのでいったん停止w

その方向を攻めるのはまたの機会に。とおいといて、音を検出する方向で今回挑戦してみようとおもいます(またこちらも諦めるかもですがw まあ、いけるところまでw)

流れ星の音とは

画像1

↑だいたいこんな感じの音が最初の1秒。

流れ星が流れるシーンを録画したものから、音のデータを取り出し、いろいろごにょごにょして(この部分もけっこう大変だったのでいつか記事にするかも?)、なんとか流れ星のきらーんという音を取り出したのがこちらになります。

BGMや波の音とかをカットするの大変だったんですよぉ。

さて、なんとか取り出せたデータを、いつものPythonで読み込ませていろいろやるわけですが、このあたりもなかなか難儀しましたので、以下に作業メモを残しておきますです。


Pythonでオーディオ解析

参考URL: https://jorublog.site/python-voice-analysis/

※これ以降はPython3.7でやってます。

準備

最初に、必要なモジュールをインストールします。

$ pip install numpy
$ pip install librosa
$ pip install matplotlib
$ pip install scipy 

音声データの表示

音声データの中身をそのまま表示してみます。

参考サイトのソースそのままでやってみると

import sys
import scipy.io.wavfile
import numpy as np
import matplotlib.pyplot as plt

#音声ファイル読み込み
#args = sys.argv
#wav_filename = args[1]
#rate, data = scipy.io.wavfile.read("star0_R2_m.wav") # bad data
rate, data = scipy.io.wavfile.read("Interphone.wav") # Good data

print(rate)
print(type(data))

##### 音声データをそのまま表示する #####
#縦軸(振幅)の配列を作成   #16bitの音声ファイルのデータを-1から1に正規化
data = data / 32768
#横軸(時間)の配列を作成  #np.arange(初項, 等差数列の終点, 等差)
time = np.arange(0, data.shape[0]/rate, 1/rate)  
#データプロット
plt.plot(time, data)
plt.show()

サイトにあるWavファイル(GoodData)では

画像2

このような表示になりますが、こちらで用意した流れ星のwavデータでは

画像3

こんな感じでエラーになっちゃうんですわー。

色々調べて、GoodDataのWav形式の

画像4

この形式そのままにしてもダメ。

悩んだ挙句、仕方がないのでエラーを出している scipy.io.wavfile を使うのを諦めて、 import wave をして、wavデータをファイルから愚直に取得することにします。

取得後、np.frombufferでnumpy 形式に変更すれば、きっと、scipy.io.wavfile 風の操作できるでしょう、きっと。たぶん。おそらく。

参考:https://deepage.net/features/numpy-frombuffer.html

import wave
   
#wave_file = "/path/to/wave/file"
wf = wave.open("star0_R2.wav")
channels = wf.getnchannels()
print(wf.getparams())

chunk_size = wf.getnframes()
print(chunk_size)

#data = wf.readframes(wf.getnframes())
data = wf.readframes(chunk_size) # まずは読み取ったファイルの全てを格納する。

wf.close()

data2 = np.frombuffer(data, dtype = 'int16')


#rate = 16000
rate = wf.getframerate()

print(rate)
print(type(data))

##### 音声データをそのまま表示する #####
#縦軸(振幅)の配列を作成   #16bitの音声ファイルのデータを-1から1に正規化
data2 = data2 / 32768
#横軸(時間)の配列を作成  #np.arange(初項, 等差数列の終点, 等差)
time = np.arange(0, data2.shape[0]/rate, 1/rate)  
#データプロット
plt.plot(time, data2)
plt.show()

画像5

お、でたでた。これですよこれ☆

特徴を取り出すため、

周波数成分を表示

フーリエ変換して周波数成分を表示させます。

##### 周波数成分を表示する #####
#縦軸:dataを高速フーリエ変換する(時間領域から周波数領域に変換する)
fft_data = np.abs(np.fft.fft(data2))
#横軸:周波数の取得  #np.fft.fftfreq(データ点数, サンプリング周期)
freqList = np.fft.fftfreq(data2.shape[0], d=1.0/rate)
#データプロット
plt.plot(freqList, fft_data)
plt.xlim(3500, 8000) #3500~8000Hzまで表示
plt.show()

フーリエ変換なにそれおいしいの? って人は

画像6

↑このあたりの本おすすめです。(( ゚д゚)ハッ! よく見たらこれトランスナショナル カレッジ オブ レックス編!? レックス君の学校でしたか 歓喜!!(いやきっと違う))
この本の紹介も例によって「らせんの本棚①」に書いていますが、これまた例によってG+消滅のためネットの海からは消えてしまっています。残念!><

さて、上記の結果は

画像7

こんなかんじ。

大小あわせて6本のスパイクが出ています。このスパイクが特徴的な周波数成分というわけ。

それぞれを取り分けてみてみます。

## 特徴点を抜き出してみる

plt.plot(freqList, fft_data)
plt.xlim(3700, 3800)
plt.show()

plt.plot(freqList, fft_data)
plt.xlim(4000, 4500)
plt.show()

plt.plot(freqList, fft_data)
plt.xlim(4500, 5000)
plt.show()

plt.plot(freqList, fft_data)
plt.xlim(5500, 6000)
plt.show()

plt.plot(freqList, fft_data)
plt.xlim(6000, 6500)
plt.show()

plt.plot(freqList, fft_data)
plt.xlim(7000, 7500)
plt.show()

画像8

画像9

画像10

↑この6つの山を見張っていて、これらが同時に立つ瞬間があったら、流れ星が来た! と判定するプログラムを書けばいいわけですね。

というところまでで以下次号!

オマケ

せっかくなのでスペクトル解析表示もやってみます。

音楽解析ライブラリlibrosaを使ってこんなプログラムをかくだけで

import librosa.display

# フレーム長
fft_size = 1024                 
# フレームシフト長 
hop_length = int(fft_size / 4)  


# 短時間フーリエ変換実行
amplitude = np.abs(librosa.core.stft(data2, n_fft=fft_size, hop_length=hop_length))

# 振幅をデシベル単位に変換
log_power = librosa.core.amplitude_to_db(amplitude)

# グラフ表示
librosa.display.specshow(log_power, sr=rate, hop_length=hop_length, x_axis='time', y_axis='hz', cmap='magma')
plt.colorbar(format='%+2.0f dB')  
plt.show()            

画像11

↑こんな表示できちゃうのですね。

冒頭で抽出した流れ星の音ファイルのスペクトラム表示そのままがだせました。(∩´∀`)∩☆

オマケのオマケ

今回 JupyterNotebook という奴を使ってみました。

GitHubで共有できちゃうみたいなので↑で共有しておきます。

よろしければサポートお願いします!いただいたサポートはクリエイターとしての活動費にさせていただきます!感謝!,,Ծ‸Ծ,,