さて、今回はAR技術についてです。
ポケモンGoやドラクエウォークなど、ARを使ってキャラクターを現実世界に表示させるアプリがありますが、
ARってどうやって作ればいいんだろう??🤔と思い、調べてみました。
ARマーカー作成と表示にあたりPythonでOpenCVを用いたいと思います。
Pythonのバージョンは"3.7.4"を用います。
独学プログラマー Python言語の基本から仕事のやり方まで 新品価格 |
■環境構築
OpenCVにてARマーカーの作成や読み込みを行うにあたり、
"aruco"ライブラリが用意されているとのこと!!
早速、
import cv2 aruco = cv2.aruco ~~~
を実行してみたところ、
AttributeError: module 'cv2.cv2' has no attribute 'aruco'
といったエラーが発生!!
どうやら、opencv-pythonと"opencv-contrib-python"が必要なようです!!
opencv-contrib-python入れてないや😅
ということで、
pip install opencv-contrib-python
を実行!!
インストール成功!!👍
こちらを実現したところ問題なく通った!!
import cv2 aruco = cv2.aruco ~~~
■ARマーカー作成
マーカー作成のソースコードはこちら。
ちょっと欲張って10枚のマーカー作成させ、
それらを5×5に配置して1枚の画像として出力させてみました。
※もちろんそれぞれ単体のマーカー生成も行っております。
import cv2.aruco import numpy as np aruco = cv2.aruco dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) SIZE = 150 ImgList1 = [] ImgList2 = [] WiteList = [] def arGenerator(): img_white = np.ones((SIZE,SIZE, 3),np.uint8)*255 for i in range(1,6): fileName = "ar_" + str(i) + ".png" generator = aruco.drawMarker(dictionary, i, SIZE) cv2.imwrite(fileName, generator) ImgList1.append(cv2.imread(fileName)) ImgList1.append(img_white) WiteList.append(img_white) WiteList.append(img_white) convImg1 = cv2.hconcat(ImgList1) convWhite = cv2.hconcat(WiteList) for i in range(6,11): fileName = "ar_" + str(i) + ".png" generator = aruco.drawMarker(dictionary, i, SIZE) cv2.imwrite(fileName, generator) ImgList2.append(cv2.imread(fileName)) ImgList2.append(img_white) convImg2 = cv2.hconcat(ImgList2) TestList = [convImg1, convWhite, convImg2] convImg3 = cv2.vconcat(TestList) cv2.imshow('ArMarker1',convImg3) cv2.imwrite("Result.jpg", convImg3) cv2.waitKey(0) arGenerator()
こちらでARマーカーの形状や形式??を定義。
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
そして、実際にARマーカーを生成している箇所はこちら。
generator = aruco.drawMarker(dictionary, i, SIZE)
後はimwriteでpng画像にした後にそれらの情報をリスト化して5×5に置き換えているのみなので割愛しますが、
cv2.hconcat()
が渡されたリスト情報を元に1枚ずつ横に画像を並べ、
cv2.vconcat()
が縦に画像を並べます。
生成されるARマーカーはこんな感じになります。
■ARマーカー読み取り
ARマーカーを読み取り、ARマーカー上に画像を表示するコードはこちら。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import cv2 aruco = cv2.aruco #arucoライブラリ dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) img1 = cv2.imread("makewani.png") img2 = cv2.imread("hamstar.png") img3 = cv2.imread("mogura.png") def ConvImg(corners, i, img, convimg): x=int(corners[i][0][0][0]) y=int(corners[i][0][0][1]) w=int(corners[i][0][2][0]) - int(corners[i][0][0][0]) h=int(corners[i][0][2][1]) - int(corners[i][0][0][1]) if w > 0 and h > 0: convimg = cv2.resize(convimg,(w,h)) img[y:y+h,x:x+w] = convimg return img def arReader(): cap = cv2.VideoCapture(0) #ビデオキャプチャの開始 while True: ret, frame = cap.read() #ビデオキャプチャから画像を取得 Height, Width = frame.shape[:2] #sizeを取得 img = cv2.resize(frame,(int(Width),int(Height))) corners, ids, rejectedImgPoints = aruco.detectMarkers(img, dictionary) #マーカを検出 aruco.drawDetectedMarkers(img, corners, ids, (0,255,0)) #検出したマーカに描画する try: if corners != []: for i in range(len(ids)): if ids[i] == 10: img = ConvImg(corners, i, img, img1) if ids[i] == 5: img = ConvImg(corners, i, img, img2) if ids[i] == 3: img = ConvImg(corners, i, img, img3) cv2.imshow('drawDetectedMarkers', img) #マーカが描画された画像を表示 cv2.waitKey(1) #キーボード入力の受付 except: print("error") cap.release() #ビデオキャプチャのメモリ解放 cv2.destroyAllWindows() #すべてのウィンドウを閉じる arReader()
処理としては大きく分けて、
・ARマーカー読み取り
・読み取ったARマーカー上に画像を表示
の2つです。
まず、ARマーカー読み取り
まずはいつもの。
ret, frame = cap.read() #ビデオキャプチャから画像を取得 Height, Width = frame.shape[:2] #sizeを取得 img = cv2.resize(frame,(int(Width),int(Height)))
カメラからキャプチャ画像を取得。
そして取得したキャプチャ画像に対して、
corners, ids, rejectedImgPoints = aruco.detectMarkers(img, dictionary) #マーカを検出
によりARマーカを読み取り。
返り値ですが、
・corners:マーカーの4角の座標情報
・ids:登録されているid値
となります。
デバッグも兼ねて、
aruco.drawDetectedMarkers(img, corners, ids, (0,255,0)) #検出したマーカに描画する
を入れております。
こちらは、読み取ったARマーカーの領域やid値をキャプチャ画像に重ね合わせる処理を行っております。
次にARマーカー上に画像重ね合わせです。
def ConvImg(corners, i, img, convimg): x=int(corners[i][0][0][0]) y=int(corners[i][0][0][1]) w=int(corners[i][0][2][0]) - int(corners[i][0][0][0]) h=int(corners[i][0][2][1]) - int(corners[i][0][0][1]) if w > 0 and h > 0: convimg = cv2.resize(convimg,(w,h)) img[y:y+h,x:x+w] = convimg return img
にて重ね合わせ処理を実行しております。
cornersですが、4次元配列で情報が保存されております。
1次元目にARマーカーの各角x座標、y座標が格納。
2次元目にARマーカーの各角番号が格納されています。
角番号の割り振りですが、時計回りに0~3で格納されております。
そして、4次元目に読み取ったマーカー番号が格納されています。
と言っても文字だけだとわかりにくいので図で表すとこんな感じです。
この図を例に1番目のマーカーの左上のx座標を取得したい場合には、
X = corners[1][0][0][0]
となります。
右下のy座標の場合には、
Y = corners[1][0][2][1]
ですね。
実際に動かしてみるとこんな感じになりました。
なかなかですね😅
■最後に
ARでの画像表示するだけなら結構簡単に行えるんだな!!と思いました。
だけど、、、
最近のARで表示される画像って3次元なんですね。。。
ARマーカーを読み取った際の向きや角度も検出できるようなので、それを用いて切り替えるのかな?🤔
https://sgrsn1711.hatenablog.com/entry/2018/02/15/224615
3次元画像をどうやって表示させるか?はまだ調べなければ、、
う~~ん。奥が深いです。