こんにちは、AMDlabの森山です。私は修士課程の研究で画像処理の研究について行っていました。
その中で没になったけど役に立ちそうだな、と思うものがあったので、紹介したいと思います。
OpenCVとは
OpenCVはOpen Source Computer Vision Libraryという正式名称で、Intelで開発されたコンピュータービジョンライブラリです。主に画像や動画処理系のライブラリで、CppやPythonで利用できます。
BSDライセンスによって公開されており、現在はItseezによって開発が進められています。
https://opencv.org/
ARUcoマーカーとは
OpenCV3から、contribの中にARUcoというマーカーが含まれています。検出精度が優れていて、かなり簡単に扱うことができます。
Pythonで扱う場合は
python -m pip install opencv-contrib-python
によって利用することができるようになります。
マーカーの生成
マーカーの生成は以下のコードで行います
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import cv2 # ArUcoのライブラリを導入 aruco = cv2.aruco # 4x4のマーカー dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) def main(): for i in range(4): ar_image = aruco.drawMarker(dictionary, i, 150) fileName = "ar" + str(i).zfill(2) + ".png" cv2.imwrite(fileName, ar_image) if __name__ == "__main__": main() |
これにより以下のようなマーカーが生成されます。
マーカーの検出
上記で検出したマーカーを検出して、コーナーの座標をとってくるようなプログラムを書いてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import cv2 from PIL import Image import numpy as np inputImg = "markers.png" aruco = cv2.aruco dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) outputImg = "result" + inputImg[0:-4]+".png" def getCorner( argInputImg , argOutputImg ): img = cv2.imread( argInputImg ) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) corners, ids, rejectedImgPoints = aruco.detectMarkers(img, dictionary) # IDを書く aruco.drawDetectedMarkers(img, corners, ids, (0,255,0)) for i, corner in enumerate( corners ): points = corner[0].astype(np.int32) # マーカーの輪郭の検出 cv2.polylines(img, [points], True, (255,0,0)) cv2.putText(img, str(points[0]), tuple(points[0]), cv2.FONT_HERSHEY_PLAIN, 1,(0,0,0), 2) cv2.putText(img, str(points[1]), tuple(points[1]), cv2.FONT_HERSHEY_PLAIN, 1,(0,255,0), 2) cv2.putText(img, str(points[2]), tuple(points[2]), cv2.FONT_HERSHEY_PLAIN, 1,(0,0,255), 2) cv2.putText(img, str(points[3]), tuple(points[3]), cv2.FONT_HERSHEY_PLAIN, 1,(255,0,0), 2) img = Image.fromarray(img) img.save( argOutputImg ) getCorner( inputImg , outputImg ) |
画像をマッピングする
検出されたマーカーに画像をマッピングしてみましょう。以下のようなコードでできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
import numpy as np from PIL import Image import cv2 inputImg = "markers.png" mappingImg = "amd_logo.jpg" aruco = cv2.aruco dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) outputImg = "edit07-" + inputImg[0:-4]+".png" aruco_dict = aruco.Dictionary_get(aruco.DICT_4X4_50) parameters = aruco.DetectorParameters_create() def imgMapping(): img = cv2.imread( inputImg ) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) im_src = cv2.imread( mappingImg ) # マッピングする画像 im_src = cv2.cvtColor(im_src, cv2.COLOR_BGR2RGB) corners, ids, _ = aruco.detectMarkers(img, aruco_dict, parameters=parameters) if np.all(ids != None): # 検出されたARマーカーの数だけループする for c in corners : x1 = (c[0][0][0], c[0][0][1]) x2 = (c[0][1][0], c[0][1][1]) x3 = (c[0][2][0], c[0][2][1]) x4 = (c[0][3][0], c[0][3][1]) size = im_src.shape pts_dst = np.array([x1, x2, x3, x4]) pts_src = np.array( [ [0,0], [size[1] - 1, 0], [size[1] - 1, size[0] -1], [0, size[0] - 1 ] ],dtype=float ) h, status = cv2.findHomography(pts_src, pts_dst) temp = cv2.warpPerspective(im_src.copy(), h, (img.shape[1], img.shape[0])) cv2.fillConvexPoly(img, pts_dst.astype(int), 0, 16) img = cv2.add(img , temp) #検出したマーカへのマッピング aruco.drawDetectedMarkers(img, corners) img = Image.fromarray(img) img.save( outputImg ) imgMapping() |
配置したマーカーに大きく画像を貼る
コーナーの座標をとり、画像のマッピングする方法ができているため、ここから配置されたマーカーのそれぞれの四隅の点から、大きな画像を貼る方法について説明します。言葉で説明するとわかりにくいですが、
例えば、建築の図面なんかを見せたいときに、四隅にマーカーを配置することで、簡単にサイズを変えたり、配置場所を変えたりできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
import numpy as np from PIL import Image import cv2 inputImg = "markers1.png" mappingImg = "amd_logo.jpg" aruco = cv2.aruco dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50) outputImg = "result-" + inputImg[0:-4]+".png" aruco_dict = aruco.Dictionary_get(aruco.DICT_4X4_50) parameters = aruco.DetectorParameters_create() def getLargeCorner( argInputImg): large_corners = [] img = cv2.imread( argInputImg ) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) corners, ids, rejectedImgPoints = aruco.detectMarkers(img, dictionary) order = [2,3,1,0] for i, corner in enumerate( corners ): points = corner[0].astype(np.int32) print(points) large_corners.append(points[order[i]]) return large_corners def imgMapping(): img = cv2.imread( inputImg ) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) im_src = cv2.imread( mappingImg ) # マッピングする画像 im_src = cv2.cvtColor(im_src, cv2.COLOR_BGR2RGB) large_corners = getLargeCorner(inputImg) corners, ids, _ = aruco.detectMarkers(img, aruco_dict, parameters=parameters) if np.all(ids != None): size = im_src.shape pts_dst = np.array([large_corners[3], large_corners[2], large_corners[0], large_corners[1]]) pts_src = np.array( [ [0,0], [size[1] - 1, 0], [size[1] - 1, size[0] -1], [0, size[0] - 1 ] ],dtype=float ) h, status = cv2.findHomography(pts_src, pts_dst) temp = cv2.warpPerspective(im_src.copy(), h, (img.shape[1], img.shape[0])) cv2.fillConvexPoly(img, pts_dst.astype(int), 0, 16) img = cv2.add(img , temp) aruco.drawDetectedMarkers(img, corners) img = Image.fromarray(img) img.save( outputImg ) imgMapping() |
これによって、マーカーを四隅に配置することで、大きな画像をマッピングすることができます。
もちろんARマーカーなので、カメラでリアルタイムに検出することも可能です。四枚のマーカーでレイアウトを考えたりすることができるので便利ですね
COMMENTS