Processing 3.3 と NyARToolkit 5.0.5 で AR の練習

More than 1 year has passed since last update.


動機

長らく、Processing 1.5.1 と NyARToolkit で AR を楽しんできました。

少し自由な時間ができたので… さすがにもう、最新の環境に乗り移ろうと決心しました。最新の NyARToolkit は 3.0.2 以降、従来のマーカに加えて、NFT(Natural Feature Tracking; 自然特徴点追跡)もできるので、そのあたりも練習してみました。


環境


やったこと


  • ビデオキャプチャのテスト

  • 最もシンプルな AR

  • OBJ 形式の 3DCG モデルで AR

  • マルチ NFT(自然特徴点追跡)による AR


コード

解説は主にコード中のコメントのみで恐縮です。


ビデオキャプチャのテスト

まずは、Processing 標準の video ライブラリでビデオキャプチャのテストです。

Processing 3 では、video ライブラリは自分でインストールするようです。Processing IDE の「ライブラリの追加...」で The Processing Foundation の video ライブラリをインストールしました。

Processing 1.5.1 時代に比べて(特に Windows 環境では)とても容易になりました。


cam_test.pde

// cam_test.pde

// Install "video" library via "Add Library" tool of Processing IDE.
// Connect a Web camera to your PC.
// Run this sketch once.
// Find a camera device number with "size=640x480,fps=30" from the list.
// * Rewrite "x" with the device number you use.
// Run this sketch again, and confirm the video is shown.
// Coded by Mitsuteru Kokubun, 2017/02/20

import processing.video.*; // using "video" library

Capture cam; // declaration of Capture object

// setup() function is executed once
void setup() {
size(640, 480); // setting size of window
String[] cameras = Capture.list(); // getting available camera devices
printArray(cameras); // listing available camera devices
cam = new Capture(this, cameras[12]); // * Rewrite [x] with the device number you use.
cam.start(); // starting capture
}

// draw() function is exectuted repeatedly
void draw() {
if(cam.available() == false) { // if camera is not available
return; // do nothing and return
}
cam.read(); // capturing image
image(cam, 0, 0); // displaying captured image
}



最もシンプルな AR

NyARToolkit for Processing の GitHub リポジトリの指示通りに、nyar4psg ライブラリをインストールしました。

カメラのキャリブレーションパラメータもデフォルトの "camera_para.dat" を使いました。

また、NyID マーカを使っています(こちらのサイトで作成)。

実質20行くらいでできました。

ar_box.JPG


ar_box.pde

// ar_box.pde

// A simple AR demo using NyARToolkit and Proceccing 3.
// Install "video" library via "Add Library" tool of Processing IDE.
// Install "nyar4psg" library according to the URL below.
// -> https://github.com/nyatla/NyARToolkit-for-Processing/
// Connect a Web camera to your PC.
// * Rewrite "x" with the camera device number you use.
// Place "camera_para.dat" in "data" folder of this sketch.
// - "camera_para.dat" is included within ./libraries/nyar4psg/data
// Print NyID markers on paper. ("NyId_000-005.pdf")
// Run this sketch, and check that an orange transparent box is superimposed on the marker.
// Coded by Mitsuteru Kokubun, 2017/02/20

import processing.video.*; // using "video" library
import jp.nyatla.nyar4psg.*; // using "nyar4psg" library

Capture cam; // declaration of Capture object
MultiMarker mm; // declaration of MultiMarker object

void setup() {
// window and camera settings
size(640, 480, P3D); // setting size of window with P3D mode
String[] cameras = Capture.list(); // getting available camera devices
printArray(cameras); // listing available camera devices
cam = new Capture(this, cameras[12]); // * Rewrite [x] with the device number you use.
cam.start(); // starting capture
// NyARToolkit settings
mm = new MultiMarker(this, // initial settings of NyARToolkit
width, // width of the input image
height, // height of the input image
"camera_para.dat", // camera calibration parameter file
NyAR4PsgConfig.CONFIG_PSG); // configuration for Processing
mm.addNyIdMarker(0, 80); // adding NyId marker(ID, marker_width[mm])
}

void draw() {
// video capture
if(cam.available() == false) { // if camera is not available
return; // do nothing and return
}
cam.read(); // capturing image
// Start of AR process
mm.detect(cam); // detecting marker within captured image
mm.drawBackground(cam); // drawing captured image on background
if(mm.isExist(0) == false) { // if marker[0] is not exist within the image
return; // do nothing and return
}
mm.beginTransform(0); // starting coordinate projection based on marker[0]
translate(0, 0, 40); // move the origin 40 mm in the Z axis direction
fill(255, 165, 0, 127); // fill color(R, G, B, opacity)
box(80); // draw a 80 mm square box
mm.endTransform(); // ending coordinate projection
// End of AR process
}



OBJ 形式の 3DCG モデルで AR

3DCG のモデルを読むには、Processing 1.5.1 時代は、saitoobjloaderMQOLoader などを使わせていただいてきました。

今回、saitoobjloader を試したところ、Processing 3.3 では動きませんでした。

少し調べたら、Processing 標準の PShape で OBJ 形式のモデルが読めることが分かったので、試したら、簡単にできました。実質30行くらいです。

OBJ 形式の 3DCG モデル(rocket.obj, rocket.mtl, rocket.png)は、Processing のサンプル「LoadDisplayObj.pde」で使われているものを使いました。Processing 本体のフォルダ内の、modes\java\examples\Basics\Shape\LoadDisplayOBJ\data の中にあります。

ar_obj.JPG


ar_obj.pde

// ar_obj.pde

// A 3DCG (*.obj) AR demo using NyARToolkit and Proceccing 3.
// Install "video" library via "Add Library" tool of the Processing IDE.
// Install "nyar4psg" library according to the URL below.
// Connect a Web camera to your PC.
// * Rewrite "x" with the camera device number you use.
// Place "camera_para.dat" in "data" folder of this sketch.
// - "camera_para.dat" is included within ./libraries/nyar4psg/data
// Place "rocket.obj", "rocket.mtl", and "rocket.png" in "data" folder of this sketch.
// - "rocket.*" are included within ./Processing_3.x.x/
// modes/java/exmples/Basics/Shape/LoadDisplayOBJ/data
// Print NyID markers on paper. ("NyId_000-005.pdf")
// Run this sketch, and check that a rocket of 3DCG is superimposed on the marker.
// Coded by Mitsuteru Kokubun, 2017/02/20

import processing.video.*; // using "video" library
import jp.nyatla.nyar4psg.*; // using "nyar4psg" library

Capture cam; // declaration of Capture object
MultiMarker mm; // declaration of MultiMarker object
PShape obj; // declaration of PShape object
float ry; // variable for rotation of 3DCG model

void setup() {
// window and camera settings
size(640, 480, P3D); // setting size of window with P3D mode
String[] cameras = Capture.list(); // getting available camera devices
printArray(cameras); // listing available camera devices
cam = new Capture(this, cameras[12]); // * Rewrite [x] with the device number you use.
cam.start(); // starting capture
// NyARToolkit settings
mm = new MultiMarker(this, // initial settings of NyARToolkit
width, // width of the input image
height, // height of the input image
"camera_para.dat", // camera calibration parameter file
NyAR4PsgConfig.CONFIG_PSG); // configuration for Processing
mm.addNyIdMarker(0, 80); // adding NyId marker(ID, marker_width[mm])
// PShape setting
obj = loadShape("rocket.obj"); // loading a 3DCG model named "rocket.obj"
}

void draw() {
// video capture
if(cam.available() == false) { // if camera is not available
return; // do nothing and return
}
cam.read(); // capturing image
// Start of AR process
mm.detect(cam); // detecting marker within captured image
mm.drawBackground(cam); // drawing captured image on background
if(mm.isExist(0) == false) { // if marker[0] is not exist within the image
return; // do nothing and return
}
mm.beginTransform(0); // starting coordinate projection based on marker[0]
lights(); // adding lights in the 3D scene
scale(0.3); // adjusting the size of the 3DCG model
translate(0, 0, 80); // adjusting the position of the 3DCG model
rotateX(PI/2); // rotating the 3DCG model 90 degrees around the X axis
rotateY(ry); // rotating the 3DCG model ry radians around the Y axis
shape(obj); // displaying the 3DCG model
mm.endTransform(); // ending coordinate projection
// End of AR process
ry += 0.1; // changing rotation angle
}



マルチ NFT(自然特徴点追跡)による AR

最後に NFT も練習してみましした。せっかくなので、適当に写真を撮ってそれを NFT のターゲットに、重畳表示させる CG モデルも Blender を使って自作しました。

以下はターゲット用に撮影した写真です。

IMG_0177.JPG

NyARToolkit のサンプルとして付属する NftFileGenerator を使って画像から特徴点を抽出し、特徴点ファイル(*.fset, *.fset3, *.iset の三つのファイル)を出力します。

nftgen_savefeatureset.PNG

Blender で適当に CG を作りました。

blender_time.PNG

完成です。

nft_clock.JPG


ar_nft.pde

// ar_nft.pde

// An NFT(Natural Feature Tracking) AR demo using NyARToolkit and Proceccing 3.
// Install "video" library via "Add Library" tool of the Processing IDE.
// Install "nyar4psg" library according to the URL below.
// Connect a Web camera to your PC.
// * Rewrite "x" with the device number you use.
// Place "camera_para.dat" in "data" folder of this sketch.
// - "camera_para.dat" is included within ./libraries/nyar4psg/data
// Place "drop.{obj, mtl}" and "time.{obj, mtl}" in "data" folder of this sketch.
// - These obj models are made by using some modeling software, e.g. Blender.
// Place "faucet.{fset,fset3, iset}" and "time.{fset,fset3, iset}" in "data" folder of this sketch.
// Print "faucet.jpg" and "clock.jpg" on paper.
// Run this sketch, and check that the 3DCGs are superimposed on the marker.
// Coded by Mitsuteru Kokubun, 2017/02/20

import processing.video.*; // using "video" library
import jp.nyatla.nyar4psg.*; // using "nyar4psg" library

Capture cam; // declaration of Capture object
MultiNft nft; // declaration of MultiNft object
PShape[] obj; // declaration of PShape array object

void setup() {
// window and camera settings
size(640, 480, P3D); // setting size of window with P3D mode
String[] cameras = Capture.list(); // getting available camera devices
printArray(cameras); // listing available camera devices
cam = new Capture(this, cameras[0]); // * Rewrite [x] with the device number you use.
cam.start(); // starting capture
// NyARToolkit settings
nft = new MultiNft(this, // initial settings of NyARToolkit
width, // width of the input image
height, // height of the input image
"camera_para.dat", // camera calibration parameter file
NyAR4PsgConfig.CONFIG_PSG); // configuration for Processing
nft.addNftTarget("faucet", 160); // adding NFT target[0] (name, target_width[mm])
nft.addNftTarget("clock", 160); // adding NFT target[1] (name, target_width[mm])
// PShape setting
obj = new PShape[2];
obj[0] = loadShape("drop.obj"); // loading a 3DCG model named "drop.obj"
obj[1] = loadShape("time.obj"); // loading a 3DCG model named "time.obj"
}

void draw() {
// video capture
if(cam.available() == false) { // if camera is not available
return; // do nothing and return
}
cam.read(); // capturing image
// Start of AR process
nft.detect(cam); // detecting marker within captured image
nft.drawBackground(cam); // drawing captured image on background
for (int i=0; i<2; i++) { // repeating for two NFT targets
if(nft.isExist(i) == false) { // if target[i] is not exist within the image
continue; // do nothing and find next target
}
nft.beginTransform(i); // starting coordinate projection based on target[i]
lights(); // adding lights in the 3D scene
translate(-80, 40, 0); // adjusting the position of the 3DCG model
rotateY(PI); // rotating the 3DCG model 180 degrees around the Y axis
shape(obj[i]); // displaying the 3DCG model
nft.endTransform(); // ending coordinate projection
}
// End of AR process
}



所感と今後

移行して大正解でした。

たいていの私の用途は初期のプロトタイピングのため、通常のマーカーを使っていてもなんの問題もないのですが、NFT のほうがやっぱり楽しいですね。

引き続きいろいろ遊んでみたいと思います。