OpenCVとARCoreで作るスタンプAR
ARコンテンツ作成勉強会 in 宮崎
自己紹介
氏名:吉永崇(Takashi Yoshinaga)
所属:九州先端科学技術研究所(ISIT)
専門:ARを用いた医療支援や運動計測
コミュニティ:ARコンテンツ作成勉強会 主催
AR×医療支援:超音波診断
https://youtu.be/dClP0NsKUVM
ウェアラブル・モーションキャプチャの開発
https://youtu.be/Po-orPCgi4E
趣味開発: Volumetric Video
複数のKinectで取得したPoint Cloudを統合し、HoloLens等のARデバイスで表示
https://youtu.be/_oeUjRSS8ug
ARコンテンツ作成勉強会の紹介
 2013年5月に勉強会をスタートし
 ARコンテンツの作り方をハンズオン形式で学ぶ
 人数は5~10名程度の少人数で実施
 参加条件はAR/VRに興味がある人(知識不要)
 各地で開催 (福岡、熊本、宮崎、長崎、大分、 鹿児島、山口、広島、関東、北海道)
Twitterと勉強会ページで情報を発信しています
#AR_Fukuoka Googleで「AR勉強会」で検索
#AR_Miyazaki
今日のハッシュタグ
Special Thanks
永井 ひろかず 株式会社まなびと
今日のゴール
https://youtu.be/a8o1ieL01_w
ARCore (GooglePlay開発者サービス(AR))
Googleが提供する次世代ARプラットフォーム。普通のスマホでマーカーレスARを実現。
【主要機能】
(1) 自己位置推定 (Motion Tracking)
(2) 平面認識 (Environmental Understanding)
(3) 明るさ推定 (Light Estimation)
(4) マーカー認識 (Augmented Image)
(5) 空間共有 (Cloud Anchor)
(6) 顔認識 (Augmented Faces)
(1) 自己位置推定 (Motion Tracking)
OpenCV Plus Unity
 画像処理ライブラリの定番としてお馴染みのOpenCVのUnity版
 C#版のOpenCVSharpをベースにUnityに対応させたアセット
 Windows/Mac/Android/iOSに対応。しかも無料!
処理手順
二値化
capture
色の変更
アルファ値
の追加
2D→3DGOAL!
もろもろのダウンロード
①演習用素材 (sample.zip)
http://arfukuoka.lolipop.jp/stampar/Sample.zip
②ARCoreSDK 1.11.0.1 (unitypackage)
https://github.com/google-ar/arcore-unity-
sdk/releases/tag/v1.11.0.1
まずはUnityの操作の基本
プロジェクトを作成
New
プロジェクトを作成
最後にCreate Project
プロジェクト名
保存場所
Unityの操作画面(概要)
ゲーム空間の設計画面
ゲーム空間にCGを追加しよう
①右クリック
②3D Object
③Quad
実行してみよう
クリックして実行
クリックして終了
カメラから見た空間
Scene(設計画面)の視点を変えよう
[←] [→]で左右移動
[↑][↓]でズームイン/アウト
[Alt]+ドラッグで回転
+ドラッグで上下左右
オブジェクトの位置・向き・サイズを調整
クリックして選択
移動 回転 拡大・縮小
数値を用いた位置・姿勢・サイズの指定
 オブジェクトの詳細の確認・追加・変更はInspectorで行う
 例えば、TransformのPositionを変更すると位置が変わる
②Inspector
① Quad
数値を用いた位置・姿勢・サイズの指定
各値を初期状態に戻す
Position 0 0 0
Rotation 0 0 0
Scale 1 1 1
座標系
Y
ZX
Unityでは横はX、奥行方向がZ、そして地面に対して垂直がY
色情報の設定:テクスチャを指定
既存の3Dモデルにテクスチャ画像を貼り付けて見た目を変更
色情報の設定:マテリアルの作成
①Assets
②空白を右クリック
色情報の設定:マテリアルの作成
①Create
②Material
色情報の設定:マテリアルの適用
①Quadをクリック
②Materialsを開く
※▼をクリック
色情報の設定:マテリアルの適用
①NewMaterialに注目
②MaterialsのElement0
にドラッグ&ドロップ
色情報の設定:マテリアルの適用
①Quadをクリック
②NewMaterialを開く
※▼をクリック
色情報の設定:マテリアルの適用
ここをクリック
色情報の設定:マテリアルの適用
①Unlit
②Transparent
色情報の設定:マテリアルの適用
Quadの詳細情報として
テクスチャを登録する
色情報の設定:画像のインポート
①Assets
②ImportNewAsset...
色情報の設定:画像のインポート
①Sampleフォルダ
②logo.pngを選択
③Import
色情報の設定:テクスチャの貼り付け
①Quadをクリック
色情報の設定:テクスチャの貼り付け
①logoに注目
②テクスチャ指定領域に
ドラッグ&ドロップ
色情報の設定:テクスチャの貼り付け
ポイント&アイディア
【ポイント】
3Dオブジェクトにテクスチャを貼るというマテリアルを一度設定。
その後は画像を関連付けるだけで見た目を変えることが可能。
【アイディア】
 カメラ画像を着色領域(黒)と透過領域(白)に分ける
 黒画素の領域をスクリプトで操作して色を変更
 画像の白画素の領域を透明にした画像を作成
 透過画像を貼り付けたQuadを空中に出現させる
一旦、現状を保存
①File
②Save Scene as...
(Unity2018はSave As)
現状を保存:Sceneの保存
①適当に名前を付ける
(例:StampAR)
②保存
以降はCtrl/Command + Sで現状を保存
ARCore SDKの導入
①Assets
②Import Package
③Custom Packageから下記を開く
arcore-unity-sdk-v1.XX.0.unitypackage
ARCore SDKの導入
Import
ARCore SDKの導入
GoogleARCoreが追加される
AR用カメラの設定
Main Cameraを削除
※右クリック→Delete
AR用カメラの設定
Assets→GoogleARCore→Prefabs
AR用カメラの設定
①ARCore Device
②Hierarchyにドラッグ&ドロップ
AR用カメラの設定
①ARCore Device
②DefaultSessionConfig
をダブルクリック
AR用カメラの設定
Camera Focus ModeをAutoに変更
オブジェクト表示位置の調整
Quadをクリック
表示オブジェクトの設定
Position: 0, 0, 0.5
Scale: 全て0.1
オブジェクト表示位置の調整
Quadをダブルクリック
保存
Ctrl + S
または
Command + S
ビルド設定
①File
②Build Settings...
ビルド設定
①Android
②Switch Platform
ビルド設定
①Internal
②Player Settings
ビルド設定
①Resolution and Presentation
②Default OrientationをPortraitに変更
ビルド設定
①Other Settings
②Multithreaded Renderingをオフ
ビルド設定
①PackageNameを設定
例)com.fukuoka.test
②Minimum API Level
をAndrid 7.0に変更
OpenCVの利用設定(Unity2018のみ)
Allow unsafe Codeをオン
ARCoreの利用設定
①XR Settings
②ARCore Supportedをオン
Ctrl/Command+Sで現状を保存
実機インストール
①File
②Build & Run
実機インストール
①インストーラ(.apk)の名前を付ける
②保存
動作確認
画像処理を始める準備
OpenCV Plus Unityの導入
①Window
②Asset Store
OpenCV Plus Unityの導入
OpenCV Plusで検索
OpenCV Plus Unityの導入
OpenCV Plus Unityをクリック
OpenCV Plus Unityの導入
ダウンロード
OpenCV Plus Unityの導入
インポート
OpenCV Plus Unityの導入
Import
OpenCV Plus Unityの導入
OpenCV + Unity
が追加されていればOK
UnityEditorの画面設定
Game
UnityEditorの画面設定
①Free Aspectをクリック
②+をクリック
UnityEditorの画面設定
①名前を付ける
②800 × 1280
UIのインポート
②Import Package
①Assets
③Custom Package...
UIのインポート
②開く
①StampUI.unitypackage
UIのインポート
Import
UIのインポート
Scene
UIのインポート
①Assets
②Canvasが追加
されていることを確認
UIのインポート
①Canvas
②Hierarchyにドラッグ&ドロップ
UIのインポート
UIが追加されているはず
UIのインポート
①Canvasをダブルクリック
②UIの全体が見える
UIのインポート
①xやzをクリック
②UIを正面に向ける
UIの役割
キャプチャ開始
色変更
空間に貼り付け
キャプチャや画像処理
結果の可視化
画像表示部分の設定
①Canvasを開く
②Assetsを開く
画像表示部分の設定
①RawImage
②Materialに注目
画像表示部分の設定
①NewMaterialに注目
②Materialに
ドラッグ&ドロップ
画像表示部分の設定
確認用の領域に透過画像を
表示できるようになった
画像処理スクリプト記述の準備
空白を右クリック
画像処理スクリプト記述の準備
Create Empty
画像処理スクリプト記述の準備
①Game Object
②Add Component
画像処理スクリプト記述の準備
①New Script
②スクリプト名を決める
(例:StampScript)
③Create and Add
画像処理スクリプト記述の準備
①Game Object
②StampScript
が追加されていればOK
画像処理スクリプト記述の準備
ダブルクリック
OpenCV等のインポート
using UnityEngine;
using UnityEngine.UI;
using OpenCvSharp;
using OpenCvSharp.Demo;
public class StampScript : MonoBehaviour {
// Start関数は初期化のために一度だけ実行される
void Start () {
cg = GameObject.Find ("Robot Kyle");
}
// Update関数は毎フレーム実行される
void Update () {
}
}
canvas
変数の用意
//UIが張り付けられたCanvas
public GameObject canvas;
//プレビュー領域
public RawImage preview;
//キャプチャ領域を保持
UnityEngine.Rect capRect;
//キャプチャ画像を保持
Texture2D capTexture;
void Start () {
}
void Update () {
}
preview
UIと変数の関連付け
①GameObjectをクリック
②CanvasとPreview
が追加されていればOK
UIと変数の関連付け
Canvasに注目
StampScriptの
Canvasにドラッグ&ドロップ
UIと変数の関連付け
RawImageに注目
StampScriptの
Previewにドラッグ&ドロップ
処理手順
二値化
capture
色の変更
アルファ値
の追加
2D→3DGOAL!
処理手順
二値化 色の変更
アルファ値
の追加
2D→3DGOAL!
capture
準備:まずは画面全体をキャプチャしてみる
//UIが張り付けられたCanvas
public GameObject canvas;
//プレビュー領域
public RawImage preview;
//キャプチャ領域を保持
UnityEngine.Rect capRect;
//キャプチャ画像を保持
Texture2D capTexture;
void Start () {
int w = Screen.width;
int h = Screen.height;
//原点(0,0)から画面の縦横の長さまでをキャプチャ領域とする
capRect = new UnityEngine.Rect(0, 0, w, h);
//画面サイズの空画像を作成
capTexture =
new Texture2D(w, h, TextureFormat.RGBA32, false);
//capTextureをプレビュー領域に貼り付け
preview.material.mainTexture = capTexture;
}
width
height
(0,0)
画像処理用の関数
void Start () {
/*省略:前ページで記述した初期化*/
}
IEnumerator ImageProcessing()
{
canvas.SetActive(false);//Canvas上のUIを一時的に消す
yield return new WaitForEndOfFrame();//フレーム終了を待つ
capTexture.ReadPixels(capRect, 0, 0);//キャプチャ開始
capTexture.Apply();//各画素の色をテクスチャに反映
canvas.SetActive(true);//Canvas上のUIを再表示
}
public void StartCV()
{
StartCoroutine(ImageProcessing());//コルーチンの実行
}
ここに記述
StartCV()を呼び出す
①CaptureBtnをクリック
②Buttonを探す
③OnClick()の
下方にある+をクリック
StartCV()を呼び出す
GameObjectに注目
OnClick()内のNoneと
書かれた箇所にドラッグ&ドロップ
StartCV()を呼び出す
①No Functionをクリック
②StampScript
StartCV()を呼び出す
StartCV()
Build & Run!
動作確認
キャプチャ画像が表示される
Capture
コードを整理(1/2)
IEnumerator ImageProcessing()
{
canvas.SetActive(false);
yield return new WaitForEndOfFrame();
capTexture.ReadPixels(capRect, 0, 0);
capTexture.Apply();
canvas.SetActive(true);
}
void CreateImages() {
/*ここに画像生成コードを移す*/
}
画像の生成
このあと、画像生成のコードが増えるため関数にまとめて整理しておく
コードを整理(2/2)
このあと、画像生成のコードが増えるため関数にまとめて整理しておく
IEnumerator ImageProcessing()
{
canvas.SetActive(false);//Canvas上のUIを一時的に消す
yield return new WaitForEndOfFrame();
CreateImages(); //画像の生成
canvas.SetActive(true);//Canvas上のUIを再表示
}
void CreateImages()
{
capTexture.ReadPixels(capRect, 0, 0);
capTexture.Apply();
}
処理手順
二値化 色の変更
アルファ値
の追加
2D→3DGOAL!
capture
ここからOpenCV!
capture
処理手順
色の変更
アルファ値
の追加
2D→3DGOAL!
二値化
グレースケール画像の二値化
0 255
0 255
0~255の輝度値を、ある値(しきい値)以上か未満かで分離することを二値化と呼ぶ。
画像処理すべき領域か否かをはっきり分けることができるため非常に重要なテクニック。
OpenCVで画像を扱う準備
//スクショ領域を保持
UnityEngine.Rect capRect;
//スクショ画像を保持
Texture2D capTexture;
//OpenCVで扱う画像を保持
Mat bgraMat, binMat;
void Start () {
int w = Screen.width;
int h = Screen.height;
//原点(0,0)から画面の縦横の長さまでをキャプチャ領域とする
capRect = new UnityEngine.Rect(0, 0, w, h);
//画面サイズの空画像を作成
capTexture =
new Texture2D(w, h, TextureFormat.RGBA32, false);
//capTextureをプレビュー領域に貼り付け
preview.material.mainTexture = capTexture;
}
二値化
void CreateImages()
{
capTexture.ReadPixels(capRect, 0, 0);
capTexture.Apply();
//Texure2DをMatに変換
bgraMat = OpenCvSharp.Unity.TextureToMat(capTexture);
//カラー画像をグレースケール(濃淡)画像に変換
binMat = bgraMat.CvtColor(ColorConversionCodes.BGRA2GRAY);
//大津の方法で二値化。結果を白黒反転
binMat = binMat.Threshold(100, 255, ThresholdTypes.Otsu);
//あとで色を変えられるようにカラー(BGR)に変換
bgraMat = binMat.CvtColor(ColorConversionCodes.GRAY2BGRA);
}
bgraMat binMat(GrayScale) binMat (Binarized) bgraMat (B=G=R)
二値化結果の表示
IEnumerator ImageProcessing()
{
canvas.SetActive(false);
yield return new WaitForEndOfFrame();
CreateImages();//画像を生成
SetColor(capTexture);//テクスチャに色をセット
canvas.SetActive(true);
}
//bgraMatが保持する色をテクスチャにセットする
void SetColor(Texture2D texture)
{
OpenCvSharp.Unity.MatToTexture(bgraMat, texture);
}
動作確認
①Capture ②二値化結果
Matに関するメモリの開放
IEnumerator ImageProcessing()
{
canvas.SetActive(false);
//Mat用に確保したメモリを解放
if (bgraMat != null) { bgraMat.Release(); }
if (binMat != null) { binMat.Release(); }
yield return new WaitForEndOfFrame();
CreateImages();
SetColor(capTexture);
canvas.SetActive(true);
}
capture
処理手順
色の変更
アルファ値
の追加
2D→3DGOAL!
二値化
capture
処理手順
アルファ値
の追加
2D→3DGOAL!
二値化 色の変更
黒画素に色を付ける (1/2)
void SetColor(Texture2D texture)
{
//Matが初期化されていない場合は何もしない
if (bgraMat == null || binMat == null) { return; }
unsafe
{
//各Matのピクセル情報の配列(ポインタ)を取得
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
//全ピクセル数を算出
int pixelCount = binMat.Width * binMat.Height;
//各ピクセルを参照して黒画素なら色を塗る
for (int i = 0; i < pixelCount; i++)
{
}
}
OpenCvSharp.Unity.MatToTexture(bgraMat, texture);
}
後ほど処理を記述
ポインタと各ピクセルの色情報
 どちらの画像も左上から横方向スキャンし、それを全段で行った
場合の各画素の色情報を1次元配列に格納している。
 binPtr(白黒画像) :
 bgraPtr(カラー画像+アルファ):
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
・・・
・・・
binPtr bgraPtr
0th pixel 1st 2nd
全要素数 n (=width*height)
全要素数 n*4
この次の作業
void SetColor(Texture2D texture)
{
//Matが初期化されていない場合は何もしない
if (bgraMat == null || binMat == null) { return; }
unsafe
{
//各Matのピクセル情報の配列(ポインタ)を取得
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
//全ピクセル数を算出
int pixelCount = binMat.Width * binMat.Height;
//各ピクセルを参照して黒画素なら色を塗る
for (int i = 0; i < pixelCount; i++)
{
}
}
OpenCvSharp.Unity.MatToTexture(bgraMat, texture);
}
これから処理を記述
黒画素に色を付ける (2/2)
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
int pixelCount = binMat.Width * binMat.Height;
for (int i = 0; i < pixelCount; i++)
{
//白黒画像のi番目に相当するBGRAのデータの位置
int bgraPos = i * 4;
//白かったら無視(あとで透過させる)
if (binPtr[i] == 255)
{
}
//黒かったら色を塗る
else
{
bgraPtr[bgraPos] = 255; //B
bgraPtr[bgraPos+1] = 0; //G
bgraPtr[bgraPos+2] = 0; //R
}
}
動作確認
色の配列を作成
//14色の色情報
byte[,] colors = { { 255, 255, 255 },{ 18, 0, 230 },
{ 0, 152, 243 }, { 0, 241, 255 }, { 31, 195, 143 },
{ 68, 153, 0 }, { 150, 158, 0 }, { 233, 160, 0 },
{ 183, 104, 0 }, { 136, 32, 29 }, { 131, 7, 146 },
{ 127, 0, 228 }, { 79, 0, 229 }, { 0, 0, 0 } };
//何番目の色かを表す変数 (colNo=0~13)
int colorNo = 0;
void Start()
{
int w = Screen.width;
int h = Screen.height;
/*資料のスペースの都合により省略*/
}
①color.txtからコピペ
②自分で書く
黒画素の色の切り替え(1/3)
void SetColor(Texture2D texture)
{
//Matが初期化されていない場合は何もしない
if (bgraMat == null || binMat == null) { return; }
unsafe
{
//各Matのピクセル情報の配列(ポインタ)を取得
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
//全ピクセル数を算出
int pixelCount = binMat.Width * binMat.Height;
//各ピクセルをチェックして黒かったら色を付ける
for (int i = 0; i < pixelCount; i++)
{
}
}
OpenCvSharp.Unity.MatToTexture(bgraMat, texture);
}
ここで色を指定 (次のページで解説)
黒画素の色の切り替え(2/3)
for (int i = 0; i < pixelCount; i++)
{
//白黒画像のi番目に相当するBGRAのデータの位置
int bgraPos = i * 4;
//白かったら無視(あとで透過にする)
if (binPtr[i] == 255)
{
}
//黒かったら色を付ける
else
{
bgraPtr[bgraPos] = colors[colorNo, 0]; //B
bgraPtr[bgraPos + 1] = colors[colorNo, 1]; //G
bgraPtr[bgraPos + 2] = colors[colorNo, 2]; //R
}
}
黒画素の色の切り替え(3/3)
public void ChangeColor()
{
colorNo++;
colorNo %= colors.Length / 3;
SetColor(capTexture);
}
//色を変更する関数
void SetColor(Texture2D texture)
{
//Matが初期化されていない場合は何もしない
if (bgraMat == null || binMat == null) { return; }
unsafe
{
//各Matのピクセル情報の配列(ポインタ)を取得
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
/*資料のスペースの都合により以下省略*/
ChangeColor()を呼び出す
①ColorBtnをクリック
②Buttonを探す
③OnClick()の
下方にある+をクリック
ChangeColor()を呼び出す
GameObjectに注目
OnClick()内のNoneと
書かれた箇所にドラッグ&ドロップ
ChangeColor()を呼び出す
①No Functionをクリック
②StampScript
ChangeColor()を呼び出す
ChangeColor()
動作確認
Capture Color Color
capture
処理手順
アルファ値
の追加
2D→3DGOAL!
二値化 色の変更
capture
処理手順
2D→3DGOAL!
二値化 色の変更
アルファ値
の追加
白画素を透過させる(1/2)
void SetColor(Texture2D texture)
{
//Matが初期化されていない場合は何もしない
if (bgraMat == null || binMat == null) { return; }
unsafe
{
//各Matのピクセル情報の配列(ポインタ)を取得
byte* bgraPtr = bgraMat.DataPointer;
byte* binPtr = binMat.DataPointer;
//全ピクセル数を算出
int pixelCount = binMat.Width * binMat.Height;
//各ピクセルに対して透過/非透過の処理を行う
for (int i = 0; i < pixelCount; i++)
{
}
}
OpenCvSharp.Unity.MatToTexture(bgraMat, texture);
}
ここで色を指定 (次のページで解説)
白画素を透過させる(2/2)
for (int i = 0; i < pixelCount; i++)
{
//白黒画像のi番目に相当するBGRAのデータの位置
int bgraPos = i * 4;
//白かったら透過
if (binPtr[i] == 255)
{
bgraPtr[bgraPos + 3] = 0;
}
//黒かったら非透過
else
{
bgraPtr[bgraPos] = colors[colorNo, 0]; //B
bgraPtr[bgraPos + 1] = colors[colorNo, 1]; //G
bgraPtr[bgraPos + 2] = colors[colorNo, 2]; //R
bgraPtr[bgraPos + 3] = 255;
}
}
動作確認
①Capture
②透過画像
プレビュー表示の最大化
①RawImage
クリック
プレビュー表示の最大化
全体を選択
プレビュー表示の最大化
Left,Top,Right,Bottom
をすべて0に変更
プレビュー表示の最大化
RawImageをオフ
プレビューの表示
IEnumerator ImageProcessing()
{
canvas.SetActive(false);
//Mat用に確保したメモリを解放
if (bgraMat != null) { bgraMat.Release(); }
if (binMat != null) { binMat.Release(); }
yield return new WaitForEndOfFrame();
CreateImages();
SetColor(capTexture);
canvas.SetActive(true);
//プレビューを表示する
preview.enabled = true;
}
動作確認
Capture
capture
処理手順
2D→3DGOAL!
二値化 色の変更
アルファ値
の追加
capture
処理手順
二値化 色の変更
アルファ値
の追加
2D→3DGOAL!
テクスチャ付きのQuadをPrefab化
Quadをクリック
②QuadをAssetsに
ドラッグ&ドロップ
テクスチャ付きのQuadをPrefab化
Quadを削除
空間にスタンプを固定
//スタンプのテンプレートオブジェクト(テクスチャ付きのQuad)
public GameObject original;
void Start()
{
int w = Screen.width;
int h = Screen.height;
capRect = new UnityEngine.Rect(0, 0, w, h);
capTexture =
new Texture2D(w, h, TextureFormat.RGBA32, false);
preview.material.mainTexture = capTexture;
}
//スタンプを空間に置くための関数
public void PutObject()
{
}
次のページからコードを記載
スタンプの実サイズを計算
//カメラの情報を取得
Camera cam = Camera.main;
//画面左下のxy座標を3次元に変換(0.6m手前に置くとする)
Vector3 v1 =
cam.ViewportToWorldPoint(new Vector3(0, 0, 0.6f));
//画面右上のxy座標を3次元に変換
Vector3 v2 =
cam.ViewportToWorldPoint(new Vector3(1, 1, 0.6f));
//画面左上のxy座標を3次元に変換
Vector3 v3 =
cam.ViewportToWorldPoint(new Vector3(0, 1, 0.6f));
//キャプチャ領域の実空間でのサイズを計算
float w = Vector3.Distance(v2, v3);
float h = Vector3.Distance(v1, v3);
/*次のページに続く*/
(0,0)
(1,1)
(0,1)
v1
v2
v3
空間にスタンプを固定
/*前のページに記述したコードからの続き*/
GameObject stamp = GameObject.Instantiate(original);
//オブジェクトの生成とカメラに対する位置・向き・サイズを設定
stamp.transform.parent = cam.transform;
stamp.transform.localPosition = new Vector3(0, 0, 0.6f);
stamp.transform.localRotation = Quaternion.identity;
stamp.transform.localScale = new Vector3(w, h, 1);
//上記で作ったオブジェクトに貼るテクスチャを作成
Texture2D stampTexture =
new Texture2D(capTexture.width, capTexture.height);
//色を塗り、そのあとテクスチャとして貼り付ける
SetColor(stampTexture);
stamp.GetComponent<Renderer>().material.mainTexture
= stampTexture;
//スタンプの原点をカメラではなくワールドに変更
stamp.transform.parent = null;
preview.enabled = false;
オブジェクトと変数の関連付け
GameObject
オブジェクトと変数の関連付け
Quadに注目
オブジェクトと変数の関連付け
Originalにドラッグ&ドロップ
PutObject()を呼び出す
①StampBtnをクリック
②Buttonを探す
③OnClick()の
下方にある+をクリック
PutObject()を呼び出す
GameObjectに注目
OnClick()内のNoneと
書かれた箇所にドラッグ&ドロップ
PutObject()を呼び出す
①No Functionをクリック
②StampScript
PutObject()を呼び出す
PutObject()
動作確認
描画できるスタンプ数に制限を設ける
//スタンプのテンプレートオブジェクト(テクスチャ付きのQuad)
public GameObject original;
//生成されたスタンプを覚えておくListを作成
List<GameObject> stampList = new List<GameObject>();
void Start()
{
int w = Screen.width;
int h = Screen.height;
capRect = new UnityEngine.Rect(0, 0, w, h);
capTexture =
new Texture2D(w, h, TextureFormat.RGBA32, false);
preview.material.mainTexture = capTexture;
}
描画できるスタンプ数に制限を設ける
public void PutObject()
{
/*資料のスペースの都合により省略*/
stamp.transform.parent = null;
//以下、生成したスタンプの記録と削除
stampList.Add(stamp);
if (stampList.Count == 10)
{
DestroyImmediate(stampList[0].
GetComponent<Renderer>().material.mainTexture);
DestroyImmediate(stampList[0]);
stampList.RemoveAt(0);
}
preview.enabled = false;
}
完成!
関連資料
• ノンプログラミングで始めるAR
https://www.slideshare.net/ssuserc0d7fb/a
r-173415869
• はじめようARCore
https://www.slideshare.net/ssuserc0d7fb/a
rcore-in
• OpenCVとUnityでつくる塗り絵AR
https://www.slideshare.net/ssuserc0d7fb/o
pencvarcoreunityar

OpenCVとARCoreで作るスタンプAR in 宮崎