Contents
OpenCVを使ったARマーカーの認識
1.目的
ARマーカーを使った画像認識をR-CPSで行うために、PythonならびにOpenCVを使った方法を確認する。ここでは、PDHでPyhon+OpenCVで動作させます。
2.PythonのOpenCVのライブラリのインストール
以下のコマンドを使って、OpenCVのライブラリをインストールします。
$ python -m pip install opencv-python opencv-contrib-python
インストールされているライブラリの確認は、以下のコマンドで行います。
$ python –m pip list
結果は、下を参照
3.ARマーカーの生成
ARマーカーの生成は簡単です。以下の3行でファイルに書き出せます。1行目は、ARマーカーの辞書を指定します。2行目でARマーカーを生成します。その際に、辞書とID番号とイメージのサイズを指定します。3行目はファイルへの書出しです。その下に、サンプルプログラムを示します。生成したマーカーの表示も行います。
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
generator = aruco.generateImageMarker(dictionary, ID, size)
cv2.imwrite(fileName, generator)
下に、生成したARマーカーを示します。
次に、ARマーカーを生成するサンプルプログラムを載せます。
# -*- coding: utf-8 -*-
import cv2
from cv2 import aruco
size = 200
ID = 0
fileName = "ar00.png"
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
def arGenerator():
# generate ARmarker and save ARmarker
generator = aruco.generateImageMarker(dictionary, ID, size)
cv2.imwrite(fileName, generator)
# read ARmarker and display it, press any key for closing
img = cv2.imread(fileName)
cv2.imshow('ArMarker',img)
cv2.waitKey(0)
def main():
arGenerator()
if __name__ == "__main__":
main()
4.ARマーカーの認識
前ページを印刷し、カメラで撮った画像を、ARマーカーの認識プログラムで認識させたのが、下の写真です。緑の枠でARマーカーが囲われ、青い文字でID番号が正しく表示されているのが分かります。
プログラムを以下に示します。大きく4つの部分に分かれます。
1)辞書とパラメータの準備。辞書は生成した際に使用したものと同じものです。
2)認識するイメージをリードします。
3)aruco.detectMarkers()を使って、マーカーの認識を行います。
また、aruco.drawDetectedMarkers()で認識結果を合成します。
4)合成したイメージを保存します。
次に、ARマーカーを検出するプログラム例を示します。
# -*- coding: utf-8 -*-
import cv2
from cv2 import aruco
# get dicionary and get parameters
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters = aruco.DetectorParameters()
# read from image
input_file = "/home/pi/Pictures/ArMaker/Armaker.jpeg"
output_file = "IMG_7225-2.png"
input_img = cv2.imread(input_file)
# detect and draw marker's information
corners, ids, rejectedCandidates = aruco.detectMarkers(input_img, dictionary, parameters=parameters)
print(ids)
ar_image = aruco.drawDetectedMarkers(input_img, corners, ids)
cv2.imwrite(output_file, ar_image)
5.Node-REDを使った画像の自動読み取りとARマーカーの認識
以下の様に、5秒おきにPDHに接続したUSBカメラで画像を取得し、指定したIDのARマーカーが存在しているかを検出します。
そして有れば、ダッシュボードのLEDを点灯するプログラムをNode-REDで作成します。検出部分は、Pythonで作成します。
動作のフローを以下に示します。
下に、Node-RED+Pythonで実装した結果を示します。
上がARマーカーを検出した場合、下が検出できなかった場合です。
画像に左側がオリジナルで、右側が検出結果を重ねた画像です。右上の画像には、ID番号が見られます。
5-1.Pythonのプログラム
ARマーカーを検出して、結果のjsonをUDPで送信するプログラムを以下に示します。
# -*- coding: utf-8 -*-
import cv2
from cv2 import aruco
import numpy as np
import socket
import json
dictionary = aruco.getPredefinedDictionary(aruco.DICT_4X4_50)
parameters = aruco.DetectorParameters()
input_file = "/home/pi/Pictures/ArMaker/Armaker.jpeg"
output_file = "/home/pi/Pictures/ArMaker/Dtmaker.jpeg"
target_ids = 7
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def process_result(result):
if isinstance(result, np.ndarray):
if (np.any(result == target_ids)):
message = {"result":"Found target id"}
else:
message = {"result":"Not target id"}
elif isinstance(result, type(None)):
message = {"result":"No AR-Marker"}
else:
message = {"result":"Unknown type."}
print(message)
message = json.dumps(message)
sock.sendto(message.encode(), (UDP_IP, UDP_PORT))
def arDetector():
input_img = cv2.imread(input_file)
corners, ids, rejectedCandidates = aruco.detectMarkers(input_img, dictionary, parameters=parameters)
process_result(ids)
ar_image = aruco.drawDetectedMarkers(input_img, corners, ids)
cv2.imwrite(output_file, ar_image)
def main():
arDetector()
if __name__ == "__main__":
main()
5-2.Pythonのプログラム
ARマーカーを検出して、結果のjsonをUDPで送信するプログラムを以下に示します。このフローのダッシュボードが面が、前に示した検出結果です。
以下に、Node-REDのフローを載せます。
[{"id":"d0e45825f3d36388","type":"tab","label":"ArMarker","disabled":false,"info":"","env":[]},{"id":"2f0bf973e5979310","type":"inject","z":"d0e45825f3d36388","name":"5sec each","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":80,"wires":[["e41e83b9d38c1ecc"]]},{"id":"82c1a17226f699b0","type":"inject","z":"d0e45825f3d36388","name":"toggle","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"control","payload":"toggle","payloadType":"str","x":190,"y":120,"wires":[["e41e83b9d38c1ecc"]]},{"id":"e41e83b9d38c1ecc","type":"gate","z":"d0e45825f3d36388","name":"","controlTopic":"control","defaultState":"closed","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"status","persist":false,"storeName":"memory","x":330,"y":80,"wires":[["e6dd01d27ee3a928"]]},{"id":"e6dd01d27ee3a928","type":"usbcamera","z":"d0e45825f3d36388","filemode":"0","filename":"image01.jpg","filedefpath":"1","filepath":"","fileformat":"jpeg","resolution":"1","name":"","x":470,"y":80,"wires":[["5da81b8de1c88e98","8e1ae3efb6ed64f6"]]},{"id":"5da81b8de1c88e98","type":"template","z":"d0e45825f3d36388","name":"filename","field":"filename","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"/home/pi/Pictures/ArMaker/Armaker.jpeg","output":"str","x":620,"y":120,"wires":[["930107a0abeffea1","f072b11353124591"]]},{"id":"930107a0abeffea1","type":"image","z":"d0e45825f3d36388","name":"","width":"320","data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":820,"y":160,"wires":[]},{"id":"f072b11353124591","type":"file","z":"d0e45825f3d36388","name":"","filename":"filename","filenameType":"msg","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":800,"y":120,"wires":[[]]},{"id":"7882fa09aad5a2f8","type":"watch","z":"d0e45825f3d36388","name":"Armaker.jpeg","files":"/home/pi/Pictures/ArMaker/Armaker.jpeg","recursive":"","x":170,"y":260,"wires":[["3349d2a478e35b2f"]]},{"id":"3349d2a478e35b2f","type":"exec","z":"d0e45825f3d36388","command":"/home/pi/source/python/ArMarker/DetectMarker.bash","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"検出","x":310,"y":260,"wires":[["5d274652f6b61907"],["5d274652f6b61907"],["5d274652f6b61907"]]},{"id":"5d274652f6b61907","type":"debug","z":"d0e45825f3d36388","name":"debug 97","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":460,"y":260,"wires":[]},{"id":"d386d489f74a4808","type":"watch","z":"d0e45825f3d36388","name":"Dtmaker.jpeg","files":"/home/pi/Pictures/ArMaker/Dtmaker.jpeg","recursive":"","x":170,"y":360,"wires":[["57194e6e4971a81a"]]},{"id":"5e44c2d8c281dce4","type":"image","z":"d0e45825f3d36388","name":"","width":"320","data":"payload","dataType":"msg","thumbnail":false,"active":true,"pass":false,"outputs":0,"x":480,"y":360,"wires":[]},{"id":"57194e6e4971a81a","type":"file in","z":"d0e45825f3d36388","name":"","filename":"payload","filenameType":"msg","format":"","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":320,"y":360,"wires":[["5e44c2d8c281dce4","5ca4a16427c5f09a"]]},{"id":"31b8c531c94c1f72","type":"comment","z":"d0e45825f3d36388","name":"Take a picture by USB Camera","info":"","x":210,"y":40,"wires":[]},{"id":"d0558e02d00698e7","type":"comment","z":"d0e45825f3d36388","name":"Detect ArMaker","info":"","x":160,"y":220,"wires":[]},{"id":"1988551584d90790","type":"comment","z":"d0e45825f3d36388","name":"Read Detected ","info":"","x":160,"y":320,"wires":[]},{"id":"8e1ae3efb6ed64f6","type":"base64","z":"d0e45825f3d36388","name":"","action":"","property":"payload","x":620,"y":80,"wires":[["f6ba397c16362620"]]},{"id":"f6ba397c16362620","type":"ui_template","z":"d0e45825f3d36388","group":"0e1754c58bfda985","name":"Raw Picture","order":1,"width":6,"height":6,"format":"<div>\n <img src=\"data:image/jpeg;base64,{{msg.payload}}\">\n</div>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":810,"y":80,"wires":[[]]},{"id":"5ca4a16427c5f09a","type":"base64","z":"d0e45825f3d36388","name":"","action":"","property":"payload","x":460,"y":320,"wires":[["357a72de3db2592d"]]},{"id":"357a72de3db2592d","type":"ui_template","z":"d0e45825f3d36388","group":"0e1754c58bfda985","name":"Detected Picture","order":2,"width":6,"height":6,"format":"<div>\n <img src=\"data:image/jpeg;base64,{{msg.payload}}\">\n</div>","storeOutMessages":true,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":630,"y":320,"wires":[[]]},{"id":"fd59eef37001cdbc","type":"udp in","z":"d0e45825f3d36388","name":"受信","iface":"","port":"5005","ipv":"udp4","multicast":"false","group":"","datatype":"utf8","x":150,"y":680,"wires":[["2fdd49b8ad3cddd6"]]},{"id":"307a4737fde3218c","type":"debug","z":"d0e45825f3d36388","name":"debug 98","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":300,"y":620,"wires":[]},{"id":"2fdd49b8ad3cddd6","type":"json","z":"d0e45825f3d36388","name":"","property":"payload","action":"","pretty":false,"x":270,"y":680,"wires":[["307a4737fde3218c","93ed339aed479f75"]]},{"id":"93ed339aed479f75","type":"switch","z":"d0e45825f3d36388","name":"判定","property":"payload.result","propertyType":"msg","rules":[{"t":"eq","v":"Found target id","vt":"str"},{"t":"neq","v":"Found target id","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":410,"y":680,"wires":[["7b583b78b80e859d"],["d812cebeae05829e"]]},{"id":"59e5fb88f4c3771f","type":"ui_led","z":"d0e45825f3d36388","order":3,"group":"0e1754c58bfda985","width":"4","height":2,"label":"AR Maker","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#808080","value":"false","valueType":"bool"},{"color":"#ff0000","value":"true","valueType":"bool"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":true,"name":"AR Marker","x":670,"y":680,"wires":[]},{"id":"7b583b78b80e859d","type":"change","z":"d0e45825f3d36388","name":"点灯","rules":[{"t":"set","p":"payload","pt":"msg","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":660,"wires":[["59e5fb88f4c3771f"]]},{"id":"d812cebeae05829e","type":"change","z":"d0e45825f3d36388","name":"消灯","rules":[{"t":"set","p":"payload","pt":"msg","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":700,"wires":[["59e5fb88f4c3771f"]]},{"id":"2cbe3b871f702ab1","type":"comment","z":"d0e45825f3d36388","name":"UDP受信+LED制御","info":"","x":190,"y":580,"wires":[]},{"id":"f20b23fd950175dc","type":"ui_spacer","z":"d0e45825f3d36388","name":"spacer","group":"0e1754c58bfda985","order":4,"width":10,"height":1},{"id":"807a540f060a87a1","type":"ui_spacer","z":"d0e45825f3d36388","name":"spacer","group":"0e1754c58bfda985","order":5,"width":10,"height":1},{"id":"0e1754c58bfda985","type":"ui_group","name":"Detect AR-Marker","tab":"dd051dd47928cb4a","order":1,"disp":true,"width":"12","collapse":false,"className":""},{"id":"dd051dd47928cb4a","type":"ui_tab","name":"AR-Marker","icon":"dashboard","disabled":false,"hidden":false}]