Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PyConJP2026_wat_Python × Signal Processing: How...

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.
Avatar for wat wat
August 21, 2026

PyConJP2026_wat_Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art

Slides from my talk at PyCon JP 2026, “Python × Signal Processing: How to Draw Pictures with Sound Using Spectrogram Art.”

Avatar for wat

wat

August 21, 2026

Other Decks in Programming

Transcript

  1. /33 PyCon JP 2026 Python × 信号処理入門! 音で絵を描く スペクトログラムアートのつくりかた Drawing

    Pictures with Sound: Spectrogram Art with Python and Signal Processing 2026.8.22(Day2) 10:30-11:00 wat @watlablog
  2. 自己紹介 お前誰よ? ⚫ 名前:wat (Kenta WATANABE) ⚫ 職業:電機メーカーのメカエンジニア 音振動、 熱流体関連のシミュレーションや実験

    ⚫ 趣味: • Python (2019年〜) • ピアノ (独学) • 囲碁 (アマ五段くらい) ⚫ 活動: • Python系技術ブログ「WATLAB」運営 https://watlab-blog.com/ • 技術ツール制作 https://watlab-tools.com/ • 著書「いきなりプログラミングPython(翔泳社)」 https://www.shoeisha.co.jp/book/detail/9784798184869 1 /33 @watlablog
  3. このトークについて ⚫ このトークで話すこと ・スペクトログラムの読み方と歴史 ・画像を音に変換する仕組み ⚫ このトークで話さないこと ・Pythonの環境構築 ・詳しい数式の導出 ・完成コードの逐次解説

    ・スペクトログラムそのものの描き方 2 /33 スペクトログラムを作成するPythonコードは PyConJP2025の資料を参照してください https://github.com/watlablog/pyconjp2025-wat 今回のスライドで紹介しているデモコードは こちらのGitHubリンクから参照してください https://github.com/watlablog/pyconjp2026-wat ⚫ このトークで持ち帰れるもの ・音と画像を繋ぐPythonの使い方 →信号処理と画像処理の面白い部分をちょっとだけ知ることができる
  4. 3.人が音と絵を行き来してきた歴史 1930前後 1940 1941 1946 1957 1958 10 /33 図形を光学音声へ変換するグラフィカル・サウンドの実験が広く実施された

    〜 例)Norman McLaren, Drawn sound[1] 録音ではなく、最初から図形や縞模様をフィルムに描く ↓ 模様の濃淡・幅の変化が通る光の量を変える ↓ Film 光を電気信号へ変換 ↓ スピーカーから出力 1999 2016 Sound pattern Pen Drawn soundのイメージ図 音づくりが「録音するもの」から「目で見て描いて設計するもの」に変わった [1]An introduction to the hand-drawn sounds of NORMAN McLAREN, https://www.nfb.ca/film/pen_point_percussion/
  5. 3.人が音と絵を行き来してきた歴史 1930前後 1940 1941 1946 1957 1958 11 /33 音のエネルギー分布を時間×周波数の画像として記録

    〜 例)Bell研究所のKoenig, Dunn, LacyがSound Spectrograph[2]を発表 約2.4[s]の音を磁気テープへ録音 ↓ 同じ音を繰り返し再生 ↓ 狭い帯域のアナログフィルタで 周波数を順番に走査 ↓ 出力の強さを紙の濃淡として記録 1999 2016 Sound Spectrographのイメージ図 音を「聴いて消えるもの」から「見て読み解けるもの」へ ※FFTやデジタル信号処理は使っていないが、考え方は現代のスペクトログラム [2] W. Koenig, H. K. Dunn, and L. Y. Lacy, “The Sound Spectrograph,” JASA, Vol. 18, No. 1, pp. 19–49, 1946.
  6. 3.人が音と絵を行き来してきた歴史 1930前後 1940 1941 1946 1957 1958 〜 1999 12

    /33 目で見えた音をそのまま機械へ渡す技術 例)ANS Synthesizer[3]の誕生 黒く塗られたガラスをスクラッチして 音を描く ※横方向時間、縦方向音の高さ ↓ 黒いガラスの裏から光を当てる ↓ 受光素子が光を電気信号へ変換 ↓ 予め用意された720個の純音を合成して鳴らす 2016 ANSのイメージ図 音を「読み解く」から、時間と周波数に「配置する」へ変えた [3] Stanislav Kreichi, “The ANS Synthesizer: Composing on a Photoelectronic Instrument” Leonardo, Vol. 28, No. 1, 1995, pp. 59–62
  7. 3.人が音と絵を行き来してきた歴史 1930前後 1940 1941 1946 13 /33 完成した音楽の中へ絵(意味)を隠すスペクトログラムアートの技術 例)1999:Aphex Twin

    2001:Venetian Snares 2007:Nine Inch Nails 2016:DOOM 音を分析した人しか見ることができない、 隠し要素(イースターエッグ)、アートとして の表現をする人が増えてきた 1957 1958 〜 1999 2016 作曲者の顔 ネコ デジタル音楽制作環境や信号処理技術の普及によって スペクトログラムはアートとして楽しめるようになった 手
  8. 目次 1. スペクトログラムを読んでみよう 2. スペクトログラムアートとは 3. 人が音と絵を行き来してきた歴史 4. 画像をスペクトログラムに変換してみよう 4.1.画像を読み込む

    4.2.画像の輝度を振幅に変換する 4.3.位相を設定する 5. Pythonで絵を鳴らしてみよう 6. 画像や音声を改善しよう 7. まとめ 16 /33
  9. 4.1.画像を読み込む 17 /33 ⚫ png画像はx, y方向の各ピクセルにRGBAの輝度値(0-255)を持つ 画像処理プログラミングはまず画像を数値に変換するところからはじまる x Red pip

    install pillow from PIL import Image import numpy as np y Green with Image.open("cat.png") as image: input_image = np.array(image.convert("RGBA")) NumPy行列に変換 RGBAに変換 Blue Alpha cat.png https://github.com/watlablog/pyconjp2026-wat/blob/main/src/00_img2spectrogram.py
  10. 4.2.画像の輝度を振幅に変換する 18 /33 ⚫ RGBAの数値を一つの行列にまとめるために、グレースケールに変換 今回は白背景+透明度が存在するpng画像を対象とするため、 黒に近いほど高輝度にし、さらに透明度の影響も反映されるようにした。 def image_to_magnitude(image): """暗い画素ほど振幅が大きい0〜1の行列を作る。"""

    →グレースケールへ変換 rgba = image.convert("RGBA") grayscale = np.array(rgba.convert("L"), dtype=np.float64) / 255.0 alpha = np.array(rgba.getchannel("A"), dtype=np.float64) / 255.0 →アルファ値の取得 # 黒を1、白を0にして、透明度を振幅へ反映する。 magnitude = (1.0 - grayscale) * alpha →反転グレースケールへ変換し、透明度をかける magnitude /= magnitude.max() return magnitude グレースケール変換 https://github.com/watlablog/pyconjp2026-wat/blob/main/src/00_img2spectrogram.py
  11. 4.2.画像の輝度を振幅に変換する 19 /33 ⚫ スペクトログラムの描画ルールから画像をマッピングするサイズを決める スペクトログラムはSTFT(Short-Time Fourier Transform)で描画する。 予め決めた分析条件を想定して、時間軸範囲と周波数軸範囲を決定する。 Nf

    個 ・サンプリング周波数 ・フレームサイズ ・ホップサイズ(オーバーラップ率) ・全時間長 ・時間軸サンプル数 ・周波数軸サンプル数 Nt 個 STFT処理のイメージ図 STFTの資料やコードはこちら https://github.com/watlablog/pyconjp2025-wat
  12. 4.2.画像の輝度を振幅に変換する 20 /33 ⚫ スペクトログラムの描画ルールから画像をマッピングするサイズを決める 複雑なSTFT計算はSciPyの.signal.ShortTimeFFTにお任せ。 Nf 個=len(frequencies) stft =

    signal.ShortTimeFFT.from_window( "hann", 窓関数=ハニング窓 SAMPLE_RATE, サンプリング周波数 nperseg=FRAME_SIZE, フレームサイズ noverlap=FRAME_SIZE - HOP_SIZE, オーバーラップ symmetric_win=False, 周期窓 fft_mode="onesided2X", 正の周波数だけを残し補正 mfft=FRAME_SIZE, FFT点数 scale_to="magnitude", 振幅スペクトルとして補正 ) times = stft.t(SAMPLE_COUNT) frequencies = stft.f Nt 個=len(times) 画像をマッピングするサイズはこの変数で決まる 窓関数や負の周波数領域って? https://watlab-blog.com/2019/04/21/python-fft/
  13. 4.2.画像の輝度を振幅に変換する 21 /33 ⚫ グレースケール画像をリサイズして時間×周波数の2次元配列に変換する 用意したキャンバスに座標系を合わせ、画像をリサイズでマッピングする。 Nf 個 上下反転(座標合わせ) frequency_oriented_image

    = np.flipud(image_magnitude) target_magnitude = np.array( Image.fromarray(frequency_oriented_image.astype (np.float32)).resize( (times.size, frequencies.size), Image.Resampling.BILINEAR, ), dtype=np.float64, ) .resize() リサイズ np.flipud() .resize() Nt 個 ターゲットの振幅スペクトログラム https://github.com/watlablog/pyconjp2026-wat/blob/main/src/00_img2spectrogram.py
  14. 4.3.位相を設定する 22 /33 ⚫ ランダム位相をマッピングする 振幅スペクトログラムと同じサイズで位相を設定する ランダム(-π〜π) random_phase = np.random.default_rng(PHASE_SEED).uniform(

    -np.pi, np.pi, size=target_magnitude.shape, ) 振幅(Amplitude) 振幅が同じでも位相(Phase) が異なる波の例 振幅スペクトログラム 位相スペクトログラム [s] 画像から求めた振幅だけでは音はつくれない 位相情報を設定することが必要 https://github.com/watlablog/pyconjp2026-wat/blob/main/src/00_img2spectrogram.py
  15. 5.Pythonで絵を鳴らしてみよう 24 /33 ⚫ スペクトログラムを実際の音にするには、逆STFTが必要 複雑な逆STFTはSciPyの.istftにお任せ 振幅A 復元された時間波形 位相φ (scipy.ioのwavfileで保存)

    逆STFTのイメージ図 複素スペクトログラム target_spectrogram = target_magnitude * np.exp(1j * random_phase) output_samples = stft.istft(target_spectrogram, k1=SAMPLE_COUNT) 複素スペクトログラム 逆STFT https://github.com/watlablog/pyconjp2026-wat/blob/main/src/00_img2spectrogram.py
  16. 目次 1. スペクトログラムを読んでみよう 2. スペクトログラムアートとは 3. 人が音と絵を行き来してきた歴史 4. 画像をスペクトログラムに変換してみよう 5.

    Pythonで絵を鳴らしてみよう 6. 画像や音声を改善しよう 6.1.位相を最適化する 6.2.耳の特性を考慮する 6.3.画像処理でアート表現を高める 7. まとめ 26 /33
  17. 6.1.位相を最適化する 27 /33 ⚫ Griffin-Lim法[4] 振幅だけが決まっている状態で、時間波形として整合する位相を反復的に推定する方法 初期位相=ランダム 反復 位相を更新 元の振幅を使用

    元振幅=ターゲット [4] Griffin, D. W. & Lim, J. S. (1984), “Signal Estimation from Modified Short-Time Fourier Transform,” IEEE TASSP, 32(2), 236–243.
  18. 6.1.位相を最適化する 28 /33 ⚫ Griffin-Lim法[4] 位相を改善することで元画像の再現度が向上する。 for iteration in range(1,

    GRIFFIN_LIM_ITERATIONS + 1): spectrogram = target_magnitude * np.exp(1j * phase) output_samples = stft.istft(spectrogram, k1=SAMPLE_COUNT) estimated_spectrogram = stft.stft(output_samples) phase = np.angle(estimated_spectrogram) ランダム位相の場合 Griffin-Lim法による推定位相の場合 (反復回数=10) 複素スペクトログラムを構成 逆STFT STFT 更新するための位相スペクトログラム 画像の再現度は向上したが、 音は聞くに耐えない電子音 →少し改善を試みる https://github.com/watlablog/pyconjp2026-wat/blob/main/src/01_img2spectrogram_griffinlim.py
  19. 6.3.画像処理でアート表現を高める 31 /33 ⚫ 様々な画像処理を組み合わせることで、よりスペクトログラム向きの絵に変換する グレースケール画像 x A:ポスタリゼーション B:Blur +

    Sobelフィルタ import cv2 cv2.GaussianBlur() cv2.Sobel() cv2.hypot() 色の階調を落とすことで ベタ塗り感を出す技術 A+B(輝度値調整) pip install opencv-python ぼかし処理で細かい毛をまとめ、 Sobelフィルタでエッジを際立たせる https://github.com/watlablog/pyconjp2026-wat/blob/main/src/02_img2spectrogram_imgprocessing.py