4
Help us understand the problem. What are the problem?

posted at

updated at

ImmersalのREST APIでマップ作成

はじめに

前回の記事でImmersalのサンプルをレビューしました。今回はImmersalのREST APIを話します。最近の携帯のカメラで写ったが画像はかなりすごいです。そのせいで、写った画像のサイズもかなり大きいです。一枚画像には3~10Mbまではかかりそう。自分のデータプランは最小の3Gb/月なので、アップロードが大変。アップロードスピードも携帯ネットワークを使用すれば遅いと思います。この記事でAPI叩きでマッピング方法を纏めます。

前回の記事
https://qiita.com/brocolly/items/d97f406aa18440d291a3

参考
https://immersal.gitbook.io/sdk/unity/unity-sample-project
https://immersal.gitbook.io/sdk/cloud-service/rest-api

準備

  • Unity 2019.4
  • AR Foundation 4
  • ARCoreかARKitをサポートされる携帯デバイス
  • Immersal Developerアカウント

この記事ではARCoreサポートされたAndroid携帯、Xiaomi Redmi Note 7を利用します。

手順

手順を話す前に、基本の流れを説明します。

  1. Androidアプリで撮影
  2. 画像とPoseからJSON作成、読み込む
  3. REST APIでアップロード (Python)
  4. モデル作成
  5. Server LocalizationとVPSデモ

Androidアプリで撮影

SampleアプリのMappingシーンをベースとして、画像をアップロードしないように、新しスクリプトを作ります。

ImmersalRestExt.cs
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http;
using System.IO;
using System.Text;
using UnityEngine;

namespace Immersal.REST
{
    [Serializable]
    public struct SDKImageRequestExt
    {
    //コード入れる
    }

    public class JobCaptureExtAsync : JobAsync
    {
    //コード入れる
    }
}

まずはJSONスキームを作成します。Assets/ImmersalSDK/Core/Scripts/Rest.csと言うスクリプトを開けて、SDKImageRequestを検索します。これが元のJSONスキームです。新しいのJSONスキームで、endpointの編集を削除します。新しコードは下になります。このコードは上のImmersalRestExt.csに入れます。

...
[Serializable]
public struct SDKImageRequestExt
{
    public string token;
    public int run;
    public int index;
    public bool anchor;
    public double px;
    public double py;
    public double pz;
    public double r00;
    public double r01;
    public double r02;
    public double r10;
    public double r11;
    public double r12;
    public double r20;
    public double r21;
    public double r22;
    public double fx;
    public double fy;
    public double ox;
    public double oy;
    public double latitude;
    public double longitude;
    public double altitude;
    public string b64;
}
...

次は画像アップロードの機能をJSON作成に変更します。ベースコードはAssets/ImmersalSDK/Core/Scripts/RestJobAsync.csであります。このコードでImmersalのアップロード機能を新しいコードで削除します。新しコードは下になります。このコードは上のImmersalRestExt.csに入れます。

...
public class JobCaptureExtAsync : JobAsync
{
    public int run;
    public int index;
    public bool anchor;
    public Vector4 intrinsics;
    public Matrix4x4 rotation;
    public Vector3 position;
    public double latitude;
    public double longitude;
    public double altitude;
    public string encodedImage;
    public string imagePath;
    public Action<SDKImageResult> OnResult;

    public override async Task RunJobAsync()
    {
        Debug.Log("*************************** JobCaptureAsync ***************************");
        this.OnStart?.Invoke();

        SDKImageRequestExt r = new SDKImageRequestExt();
        r.token = "自分のtokenを入れてください";
        r.run = this.run;
        r.index = this.index;
        r.anchor = this.anchor;
        r.px = position.x;
        r.py = position.y;
        r.pz = position.z;
        r.r00 = rotation.m00;
        r.r01 = rotation.m01;
        r.r02 = rotation.m02;
        r.r10 = rotation.m10;
        r.r11 = rotation.m11;
        r.r12 = rotation.m12;
        r.r20 = rotation.m20;
        r.r21 = rotation.m21;
        r.r22 = rotation.m22;
        r.fx = intrinsics.x;
        r.fy = intrinsics.y;
        r.ox = intrinsics.z;
        r.oy = intrinsics.w;
        r.latitude = latitude;
        r.longitude = longitude;
        r.altitude = altitude;
        byte[] image = File.ReadAllBytes(imagePath);
        r.b64 = System.Convert.ToBase64String(image);

        //JSON作成とアプリのデータパスに保存します。
        string jsonData = JsonUtility.ToJson(r);
        var pathJSON = Application.persistentDataPath + "/Capture_"+ this.index.ToString() +".json";
        StreamWriter writer = new StreamWriter(pathJSON, false);
        writer.WriteLine(jsonData);
        writer.Close();   

    }
}
...

これでアップロード機能JSON作成に変更します。次はAssets/ImmersalSDK/Samples/Scripts/Mapping/Mapper.csを編集します。protected override async void Capture(bool anchor)の下にJobCaptureAsyncからJobCaptureExtAsyncに変更します。

JobCaptureExtAsync j = new JobCaptureExtAsync();
//JobCaptureAsync j = new JobCaptureAsync();

これでコード編集は終わり、アプリをビルドします。ビルドする時PlayerSettingsでPackage Nameを覚えてください。
image.png

これでは実験します。Sample通り複数の画像を取ってください。撮影した時、画像の数はここに更新してないので、ご注意。

drawing

画像とPoseからJSON作成、読み込む

JSONファイルはこれで保存しました。Androidをパソコンで繋がって、データを読み込みます。保存したデータのパスはAndroid/data/「packagename」/filesです。「packagename」は、先ほど説明した、PlayerSettingsでビルドする前です。「Capture_~」ファイルは全て画像とPoseのJSONデータです。

image.png

そのファイルを全てパソコンの同じフォルダーで移動してください。

REST APIでアップロード (Python)

まずはワークスペースをリセットしよう。

参考
https://immersal.gitbook.io/sdk/cloud-service/rest-api/python-examples#clear-the-workspace-image-bank

clear-workspace.py
import requests
import json

user_token = "自分のtoken"


def ClearWorkspace(url, token, deleteAnchorImage):
    complete_url = url + '/clear'

    data = {
        "token" : token,
        "bank" : 0, # default workspace/image bank
        "anchor" : deleteAnchorImage
    }

    json_data = json.dumps(data)

    r = requests.post(complete_url, data=json_data)
    print(r.text)

ClearWorkspace('https://api.immersal.com', user_token, True)

コードを実行して、ワークスペースがリセットになる。次は画像アップロードをします。
参考
https://immersal.gitbook.io/sdk/cloud-service/rest-api/python-examples#submit-an-image-to-workspace-image-bank

submit-image.py
import requests
import json
import base64
import os

folder_data = "OfficeLocker" #集まったデータのフォルダ名


user_token = "自分のtoken"

def SubmitImage(url, token, dataPath):
    complete_url = url + '/captureb64'
    f = open(dataPath, "r")
    data = json.load(f)
    data["run"] = 0;
    json_data = json.dumps(data)
    # print(json_data)

    r = requests.post(complete_url, data=json_data)
    print(r.text)


for subdirs, dirs, files in os.walk(folder_data):
    for file in files:
        if file.endswith((".json")):
            dataPath = os.path.join(subdirs, file)
            SubmitImage('https://api.immersal.com', user_token, dataPath)

print("================================")
print("Upload Complete")

コードを実行して、画像のアップロードします。アップロード時間は画像の数によって異なります。
画像アップロードが完了した場合は、次のマップ作成をします。

マップとモデル作成

13枚の画像でマップとモデルを作成します。作成したマップはポータルで見られる。

参考
https://immersal.gitbook.io/sdk/cloud-service/rest-api/python-examples#start-map-construction

create-map.py
import requests
import json
import base64
import os

map_name = "OfficeLocker" #マップ/モデル名

user_token = "自分のtoken"

def StartMapConstruction(url, token, mapName, windowSize):
    complete_url = url + '/construct'

    data = {
        "token": token,
        "bank": 0,
        "name": mapName,
        "window_size" : windowSize,
        "featureCount": 1024,
        "preservePoses": False
    }

    json_data = json.dumps(data)

    r = requests.post(complete_url, data=json_data)
    print(r.text)

StartMapConstruction('https://api.immersal.com', user_token, map_name, 0)

image.png

drawing

Server LocalizationとVPSデモ

まずはREST APIでServer Localizationを試します。まず、さっきのロッカーの画像を撮影しました。
参考
https://immersal.gitbook.io/sdk/cloud-service/rest-api/python-examples#server-localization

drawing

server-localize.py
import requests
import json
import base64

user_token = "自分のtokenを入れて"

def ConvertToBase64(src_filepath):
    with open(src_filepath, 'rb') as imageFileAsBinary:
        fileContent = imageFileAsBinary.read()
        b64_encoded_img = base64.b64encode(fileContent)

        return b64_encoded_img

def ServerLocalize(url, token, imagePath):
    complete_url = url + '/localizeb64'

    data = {
        "token": token,
        "fx": 1455.738159, # image focal length in pixels on x axis
        "fy": 1455.738159, # image focal length in pixels on y axis
        "ox": 962.615967, # image principal point on x axis
        "oy": 694.292175, # image principal point on y axis
        "b64": str(ConvertToBase64(imagePath), 'utf-8'),
        "mapIds": [{"id": 1234}, {"id": 4567}] # 自分のマップリストからLocalizeする
    }

    json_data = json.dumps(data)

    r = requests.post(complete_url, data=json_data)
    print(r.text)

ServerLocalize('https://api.immersal.com', user_token, 'image_test.jpg')

コード実行します。画像はマップにいるなら、結果は下になります。

image.png

画像はマップのリストの中に一部じゃない場合は結果はしたになります。

image.png

前回の記事でモデル配置を説明したので、あのサンプルに参考して、今回はVPS(Visual Positioning Service)を試します。

参考
https://qiita.com/brocolly/items/d97f406aa18440d291a3#content-placement--%E3%83%A2%E3%83%87%E3%83%AB%E9%85%8D%E7%BD%AE

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
4
Help us understand the problem. What are the problem?