よく使うもの
- hippie-expand (M-/)
- completion-at-point (C-M-i)
- company
デフォルトだとC-M-/ にdabbrev-completionがバインドされているけど、それほど使わない。
よく使うもの
デフォルトだとC-M-/ にdabbrev-completionがバインドされているけど、それほど使わない。
表題の通り。
今回も外部パッケージの力を借りてLSB置換法に基づくステガノグラフィを試してみた。
参考にしたのは以下のリポジトリである(Steganography/stego_lsb)。
リトルエンディアン環境で正常に動作するよう、バグを修正したPythonコードを以下に置いた。
https://gist.github.com/tam17aki/fa084a9e698ffd255791750b923cdc8c
下記の内容が書かれたテキストファイルをまるごと、waveデータに埋め込んでみた(utf-8)。
A01 あらゆる 現実を すべて 自分の ほうへ ねじ曲げたのだ。 A02 一週間ばかり ニューヨークを 取材した。 A03 テレビゲームや パソコンで ゲームを して 遊ぶ。 A04 物価の 変動を 考慮して 給付水準を 決める 必要がある。 A05 救急車が 十分に 動けず 救助作業が 遅れている。 A06 言論の 自由は 一歩 譲れば 百歩も 千歩も 攻めこまれる。 A07 会場の 周辺には 原宿駅や 代々木駅も あるし ちょっと 歩けば 新宿御苑駅も ある。 A08 老人ホームの 場合は 健康器具や ひざ掛けだ。 A09 ちょっと 遅い 昼食を とるため ファミリーレストランに 入ったのです。 A10 嬉しいはずが ゆっくり 寝ても いられない。 出典:http://research.nii.ac.jp/src/ATR503.html
結果は次の通り。元の音声(host.wav)とメッセージが埋め込まれた音声(stego_lsb.wav) (初回はロードが入り冒頭の音が欠けるので再生は2回目以降)。
メッセージが埋め込まれることによる音質の劣化は確認できないので、優れた手法のように思える。しかしながら、この手法は「攻撃」に弱いのが欠点である。
表題の通りのまさに備忘録。
音声波形をヒルベルト変換して包絡および瞬時位相を計算し、そこから元の音声波形を再構成するスクリプトをPythonで書いた話。SPTKに付属のdata.shortをwavに変換して用いた。発話内容は「青い植木鉢」である。
処理の核となるのは以下の通りである。ヒルベルト変換を計算した結果は複素数値の「解析信号」であり、絶対値を取ることで音声波形の包絡線が得られる。位相は瞬時位相と呼ばれる。これら振幅と位相の情報から元の音声波形が再構成される。
scipyのsignalパッケージを使うと上記の処理が本質的に3行で済んでしまうので、scipy最高〜〜、というわけである。
import numpy as np import matplotlib.pyplot as plt import scipy.signal as signal # wave_dataは音声データ envelop = np.abs(signal.hilbert(wave_data)) # 包絡 angle = np.unwrap(np.angle(signal.hilbert(wave_data))) # 瞬時位相 reconst = envelop * np.cos(angle) # 再構成
元の波形と再構成後の波形、そして再構成誤差を図1に示す。誤差は完全に0にはならないことがわかる。
使ったプログラムは以下の通り。
東京大学の小山先生が、フーリエ級数展開のデモンストレーションをMATLABでお書きになった。
講義でフーリエ変換というかフーリエ級数展開の説明用に作った動画をせっかくなのでここに置いておく。。 pic.twitter.com/2wm4ecjdty
— Shoichi Koyama (@sh01) 2020年5月1日
この素晴らしいアニメーションをPythonで再現するスクリプトを書いても良いのではないかと思い、今回の表題に至るわけである。
ちなみに再現したアニメーションは以下の通りである。グラフの軸ラベルがずっと固定であったり、描画範囲が微妙に異なるので完全再現ではないが、それなりに再現できていると思われる。
ノコギリ波のアニメの向きを修正して再アップ pic.twitter.com/RuOil5QG0N
— mat (@ballforest) 2020年5月2日
小山先生のMATLABスクリプトを参考に、以下のPythonスクリプトを書いた。
https://gist.github.com/tam17aki/4dc145b3f7d128fdb15ebf0e9137cd9b
基本的にはオリジナルのMATLABスクリプトを逐次Pythonに翻訳していく方針である。配列操作にはnumpy、またグラフの描画とアニメーション作成にはmatplotlibというライブラリを用いた。
アニメーションを作成する以前に、まず複数のグラフを一枚のキャンバスに重ね描きしないといけない。matplotlibはデフォルトで重ね描きが有効になっているので、MATLABのようにhold onとhold offを切り替える必要はない。
キャンバスを用意するにはまず以下を書く。
import matplotlib.pyplot as plt fig = plt.figure(figsize=[8.0, 8.0]) # 800 x 800
これで図の外枠ができ上がるので、add_axes関数により実際のグラフ描画枠を配置していく。描画位置を指定するsubplotをより細かく制御する働きをしていると考えればよい。
ax1 = fig.add_axes([0.04, 0.85, 0.14, 0.14]) ax2 = fig.add_axes([0.24, 0.85, 0.74, 0.14]) ax3 = fig.add_axes([0.04, 0.65, 0.14, 0.14]) ax4 = fig.add_axes([0.24, 0.65, 0.74, 0.14]) ...
add_axesの引数は「x軸の開始位置, y軸の開始位置, x軸の長さ, y軸の長さ」を、全体に対する比率で書いて与える。詳細な仕様は公式マニュアルを参考にしたほうが良い(URL)。
グラフのプロットは各描画枠(axes)ごとに行うことができる。例えば
ax2.plot(time_axis, sig, linestyle="-", color="b", linewidth=1.5) ax4.plot(time_axis, coef[0] * numpy.sin(phi[:, 0]), linestyle="-", color="b", linewidth=1.5)
のような形である。
重ね描きは各axesごとにplotを並べるだけで実現できる。例えば以下のようにする。
ax3.plot(coef[0] * numpy.cos(ANGLE), coef[0] * numpy.sin(ANGLE), color="k", linewidth=1.5) ax3.plot([0, circ[0, 0]], [0, circ[1, 0]], linestyle="-", color="b", marker="o", markerfacecolor="b", markersize=4) ax3.plot([circ[0, 0], 0.6], [circ[1, 0], circ[1, 0]], linestyle=":", color="b", marker="o", markersize=4, markerfacecolor="b", linewidth=1)
以上の要素を用いることで、アニメーションの1コマに相当するグラフを描くことができるので、あとはそれらをくっつければ動画にすることができる。アニメーションの作成にはmatplotlibのanimationモジュールを用いた。
import matplotlib.animation as animation
1コマに相当する各プロットのグラフを集めて、それをリストに追加していくのが基本的な使い方である。ちなみにplotの戻り値は描画内容を格納する特殊なリストになっているので、「+=」で次々と追加していくことができる(URL)。
images = [] # アニメーションの総プロットを格納するリスト ... for t0 in range(TIME_NUM): ... im = ax1.plot(coef[0] * numpy.cos(ANGLE), coef[0] * numpy.sin(ANGLE), color="k", linewidth=1.5) im += ax1.plot(coef[1] * numpy.cos(ANGLE) + circ[0, 0], coef[1] * numpy.sin(ANGLE) + circ[1, 0], color="k", linewidth=1.5) ... im += ax2.plot(time_axis, sig, linestyle="-", color="b", linewidth=1.5) ... images.append(im) # 1コマ分の全プロットを集めたものをリストに追加
最終的に、以下のArtistAnimation関数を用いてアニメを作成し、save関数でmp4に書き出すことができる。
ANIME = animation.ArtistAnimation(fig, images, interval=40) ANIME.save("plot_sawtooth.mp4", writer="ffmpeg", dpi=300)
ArtistAnimation関数の引数intervalには各フレーム間の遅延をmsecで与える。save関数の引数dpiには解像度を与える。今回はあまり高解像度にする必要はないだろう。mp4作成にあたって、事前にffmpegをインストールしておく必要がある。
今回はmatplotlibの優秀さを実感した。アニメーション作成がやや重たいのが課題である。FuncAnimation関数を用いたとき、軽くなるかを一度検証してみる必要がある。
フーリエ級数展開はいいぞ。
1. 2chproxy.plをダウンロードして、適切な場所に置く
https://github.com/yama-natuki/2chproxy.pl
2. bash_profileに以下を追記
/path/to/2chproxy.pl -d
navi2ch起動前に2chproxy.plをバックグラウンドで起動しておくという主旨である。バックグラウンドでの実行ができれば、他の手段で構わないと思う。
3. navi2chをインストール
melpaからインストール可能。https://melpa.org/#/navi2ch
4. 以下の設定を使う
(eval-when-compile (require 'navi2ch)) (autoload 'navi2ch "navi2ch" "Navigator for 2ch for Emacs" t) (with-eval-after-load "navi2ch" (setq navi2ch-list-bbstable-url "http://menu.5ch.net/bbsmenu.html") (setq navi2ch-list-valid-host-regexp (concat "\\(" (regexp-opt '(".5ch.net" ".2ch.net")) "\\)\\'")) (setq navi2ch-net-http-proxy "localhost:8080"))
5. Emacsを立ち上げる
6. M-x navi2ch で起動する
ステガノグラフィとは、秘密のメッセージを「ばれないように、こっそりと」隠す技術である。画像メディアに対するステガノグラフィのPythonパッケージは見つかるのだが、音メディア系はちょっと見当たらなかったので、試しにPythonで書いてみたということ。
今回の実装はステガノグラフィ技術の中でも一番簡単なLSB置換法に基づくものである。LSBとは最下位ビットのことを指す。音の各サンプル点における振幅値(整数)の最下位ビットは相対的に重要度が低いと考えられるので、ここに情報を埋め込む、すなわち振幅値のLSBをメッセージのビットで置き換えるわけである。
1. ステガノグラフィのPythonパッケージsteganoをインストール
pip install stegano
2. soundfile, numpy, scipyをインストール
3. メッセージを隠したいwavを用意
今回は秘密のメッセージを文字列として与えることにした(『Hello, World!』)。以下のコードではwavの入力まわりのつくりがまだ甘いが。隠したメッセージはきちんと復元できるのがポイントである。
$ python stegano_lsb.py Hidden message is "Hello, World!"