OpenCVとMatplotlibでAR(拡張現実)できるか挑戦してみた
去年のアドベントカレンダーでは100行で作るARと題して、できるだけシンプルにARを実装する挑戦をしました。
今年は、MatplotlibでARを実装する挑戦をしました。
OpenCVで3Dデータを用いたARにはOpenGLを使うことがよくあると思いますが、OpenGLを使用せずMatplotlibの3DグラフでARができないか挑戦しました。
完成デモ
完成したものはこちらです。ARで描画しているのはMatplotlibの3Dグラフです。ARマーカーの傾きに応じグラフの見え方も変わっているのがわかるでしょうか。
ここから作り方について紹介します。
環境
Windows11(カメラ付き)でPython3.10を使用しました。
PS C:\> python --version
Python 3.10.8
コードはgithubにあります
コード類はgithubに格納しました。
環境の準備
Windows環境の準備
PowerShellで以下のコマンドを実行しPythonの必要モジュールをインストールします。
最初にvenv環境を作り、作成したvenv環境OpenCVMatplotlibAR
を起動します。
mkdir .venv
cd .venv
python -m venv OpenCVMatplotlibAR
PS C:\Users\hoge> .venv\OpenCVMatplotlibAR\Scripts\Activate.ps1
(OpenCVMatplotlibAR) PS C:\Users\hoge>
venv環境 OpenCVMatplotlibAR
に必要モジュールをインストールします。
モジュールのインストールは本コードをまとめたgithubのrequirementsファイルを使用します。
(OpenCVMatplotlibAR) PS C:\Users\hoge> cd repo
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo> git clone https://github.com/zgw426/AugmentedReality_with_OpenCV_Matplotlib.git
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo> cd AugmentedReality_with_OpenCV_Matplotlib
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> pip install -r requirements_fixed-version.txt
これでWindows環境の準備は完了です。
ARマーカーの準備
ARマーカーの作成は、こちらの記事を参考に0
番と1
番の画像を作成します。
これでARマーカーの準備は完了です。
実行してみる
実際にコードを実行してみます。
Step01.2DのMatplotlibグラフでARする
スクリプトが動作するかの確認です。元画像sample.png
に対しARを実行し、その結果をout-sample.png
として出力します。
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> python 01_matplot2d_not-camera.py
DONE :
inputfile is sample.png
outputfile is out-sample.png
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib>
以下は、元画像sample.png
と出力画像out-sample.png
です。
このように、ARマーカーにグラフが描画されれば成功です。
Step02.カメラ映像と2DのMatplotlibグラフでARする
Windows搭載のカメラからの映像にMatplotlibグラフをARで描画します。以下を実行するとウィンドウが開きカメラ映像が表示されます。ARマーカーを映すと2Dグラフが描画されます。
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> python 02_matplot2d_no-transparency.py
この動画のように2Dグラフが表示されれば成功です。
開いたウィンドうは q
キーで終了します。
Step03.3DのMatplotlibグラフでARする
次は3DグラフでARします。
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> python 03_matplot3d_no-transparency.py
この動画のように3Dグラフが表示されれば成功です。
開いたウィンドうは q
キーで終了します。
Step04.3Dの透過処理を追加してMatplotlibグラフでARする
Step03では白い背景色のため立体物を描画してる感じがしないので背景を透過します。またグラフの軸や目盛も不要なので消しました。
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> python 04_matplot3d_transparency.py
この動画のように3Dグラフが表示されれば成功です。
開いたウィンドうは q
キーで終了します。
※Step04は冒頭で紹介したデモと同じです。
補足
3DグラフでAR(Step03, Step04)の仕組みを簡単に説明します。
要はARマーカーの傾きにあわせて3Dグラフも傾けています。
- Step03の処理フロー概要
- (1) ARマーカーを検出した際にARマーカーの傾きを算出
- (2) 算出した傾きをもとに3Dグラフの傾ける
- (3) 3Dグラフの画像を生成
- (4) 生成した画像をARマーカーにマッピング
3Dグラフの作成と画像生成は以下の関数で実施しています。引数のroll_elev
,pitch_azim
がARマーカーの傾きから算出した値です。
def graph_3d(roll_elev, pitch_azim):
t = np.linspace(0, np.pi * 4, 50)
x = np.cos(t)
y = np.sin(t)
z = np.linspace(0,1,50)
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.view_init(elev=roll_elev, azim=pitch_azim)
plt.cla()
ax.plot(x, y, z, marker='o', markersize=5, color='blue')
fig.canvas.draw()
img_array = np.array(fig.canvas.renderer.buffer_rgba())
img_return = cv2.cvtColor(img_array, cv2.COLOR_RGBA2BGR)
# メモリ解放
plt.clf()
plt.close()
return img_return
Step04は、Step03の処理フロー(4)にて透過処理を追加で行います。
透過処理の関数はこちらです。
def putSprite_npwhere(back, front4, pos):
"""透過処理"""
x, y = pos
fh, fw = front4.shape[:2]
bh, bw = back.shape[:2]
x1, y1 = max(x, 0), max(y, 0)
x2, y2 = min(x+fw, bw), min(y+fh, bh)
if not ((-fw < x < bw) and (-fh < y < bh)) :
return back
front3 = front4[:, :, :3]
front_roi = front3[y1-y:y2-y, x1-x:x2-x]
roi = back[y1:y2, x1:x2]
tmp = np.where((front_roi==(255,255,255))|(front_roi==(0,0,0)), roi, front_roi) # 255x3:黒, 0x3:白
back[y1:y2, x1:x2] = tmp
return back
今回は以上です。
起動したvenv環境OpenCVMatplotlibAR
はdeactivate
コマンドで終了します。
(OpenCVMatplotlibAR) PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib> deactivate
PS C:\Users\hoge\repo\AugmentedReality_with_OpenCV_Matplotlib>
今後もOpenCVでARを挑戦していきます
今回はMatplotlibでしたが、他の画像生成系のモジュールでもに同様のことができそうに思いました。他のモジュールでも挑戦しようかと思います。
自己紹介
OpenCVで壁に穴をあけたりしています。こちらのデモは2枚の壁に穴をあけています。いつか高層ビルの1階から屋上まで穴をあけたいと思っています。