Unity
Theta
OculusGo

Ricoh thetaのJPGから角度を取り出すコード(2018年版)

はじめに

  • THETA Vの静止画から角度情報を取得して画像を正しい向きにする(天頂補正)際に実施した内容(取得編)

作業方針

  • THETA Vの静止画には角度情報がxmpとして入っているためその情報を取得する
    • 以前の方法では、リコー固有ブロックのExif情報を取得していました
  • 必要な部分だけ取り出す
    • XMLパーサなどを使用せずに軽量化

コード

XmpReader.cs
using UnityEngine;
using System.Collections;
using System.IO;
using System;

public class XmpReader 
{
    public static void SerchAngle(string filePath)
    {
        BinaryReader br = new BinaryReader(new FileStream(filePath, FileMode.Open));
        byte [] buf = br.ReadBytes((int)br.BaseStream.Length);
        br.Close();
        br = null;

        float pitch = getPitch(buf);
        float roll = getRoll(buf);

        Debug.Log("filePath : " + filePath);
        Debug.Log("pitch : " + pitch + ", roll : " + roll);
    }

    public static float getPitch(byte[] buf) {
        string pitchStr = getXMLTagData(buf, "GPano:PosePitchDegrees");
        float pitch = 0.0f;
        if (pitchStr != "") {
            pitch = float.Parse(pitchStr);
        }
        return pitch;
    }

    public static float getRoll(byte[] buf) {
        string rollStr = getXMLTagData(buf, "GPano:PoseRollDegrees");
        float roll = 0.0f;
        if (rollStr != "") {
            roll = float.Parse(rollStr);
        }
        return roll;
    }

    static string getXMLTagData(byte[] buf, string xmlTagName) {
        string strStart = String.Format("<{0}>", xmlTagName);
        byte[] byteStart = System.Text.Encoding.ASCII.GetBytes(strStart);
        int xmp_start = findData(buf, byteStart);
        if (xmp_start < 0) {
            return ""; 
        }
        string strEnd = String.Format("</{0}>", xmlTagName);
        byte[] byteEnd = System.Text.Encoding.ASCII.GetBytes(strEnd);
        int xmp_end = findData(buf, byteEnd); 
        if (xmp_end < 0) {
            return ""; 
        }
        xmp_end = xmp_end - strEnd.Length;

        byte[] buf_get = new byte[255];
        int copy_idx = 0;
        for (int i=xmp_start;i<xmp_end; i++) {
            buf_get[copy_idx] = buf[i];
            copy_idx++;
        }
        string result = System.Text.Encoding.ASCII.GetString(buf_get);
        return result;
    }

    static int findData(byte[] buf, byte[] pattern)
    {
        int max = buf.Length;
        if (max > 64*1000) { 
            max = 64*1000; 
        }

        for (int i = 0; i < max; i++) {
            int iTemp = i;
            for (int p = 0; p < pattern.Length ; p++, iTemp++) {
                if (pattern[p] != buf[iTemp] || iTemp >= max) {
                    break;
                }
                if (p == pattern.Length - 1) {
                    return iTemp + 1;
                }
            }
        }
        return -1;
    }
}

さいごに

  • この角度情報を実際に利用する方法はこちらに書きました
  • 他のアプリ(OculusGoのギャラリーなど)は、このXMPがあるためVR表示しますが天頂補正はしませんでした

参考資料