ImageTracking_CloudRecognition¶
演示如何使用云识别功能。
演示如何创建和使用本地缓存
演示如何在跟踪时停止网络请求
运行前配置¶
使用云识别需配置服务器访问信息,这些信息可以在EasyAR官网的开发中心中 云识别管理页面 中获得。在Unity中输入这些信息有两种方法:
一种是全局配置,所有使用全局配置的云识别场景都会使用这个配置。从Unity菜单中选择<EasyAR -> Change Global Cloud Recognizer Service Config>并在Inspector面板中输入从开发中心获取的信息。
另一种是在场景中配置,它只对当前场景有效。
用法¶
详解¶
触发云识别¶
从EasyAR Sense 4.1开始,所有 CloudRecognizer 的请求都由用户代码触发,SDK内部将不再触发从服务器发送和接收数据的调用。也就是说你可以自由控制请求的频次。
CloudRecognizer.Resolve(iFrame, (result) => {});
最低请求间隔限制为300ms。
周期性地触发云识别¶
建议在 ARSession.FrameChange 事件处理中触发云识别,这个事件会在frame图像数据变化的时候发生。可以在事件中获取 InputFrame 。
public void StartAutoResolve(float resolveRate)
{
...
Session.FrameChange += AutoResolve;
...
}
private void AutoResolve(OutputFrame oframe, Matrix4x4 displayCompensation)
{
...
using (var iFrame = oframe.inputFrame())
{
CloudRecognizer.Resolve(iFrame, (result) => {});
}
}
在这个sample中,如果target在被跟踪或是前一次的resolve未完成或时间间隔未到达预设值(1s)的时候,resolve不会被调用。
private void AutoResolve(OutputFrame oframe, Matrix4x4 displayCompensation)
{
var time = Time.time;
if (isTracking || resolveInfo.Running || time - resolveInfo.ResolveTime < autoResolveRate)
{
return;
}
resolveInfo.ResolveTime = time;
resolveInfo.Running = true;
...
}
云识别结果¶
云识别是EasyAR的独立功能,可以在不与图像跟踪一起使用。如果在识别之后不需要跟踪,直接使用resolve结果即可。
CloudRecognizer.Resolve(iFrame, (result) =>
{
...
resolveInfo.CloudStatus = result.getStatus();
...
var target = result.getTarget();
...
});
跟踪云返回的target¶
如果需要跟踪服务器识别到的图像,就需要用到result中的target信息。
在这个sample中target被clone了一份,因为它会在ImageTargetController中被引用,因此需要保留一份内部object的引用。
CloudRecognizer.Resolve(iFrame, (result) =>
{
...
var target = result.getTarget();
if (target.OnSome)
{
using (var targetValue = target.Value)
{
...
LoadCloudTarget(targetValue.Clone());
}
}
});
创建一个有 ImageTargetController 的 GameObject ,并将resolve回调中的 ImageTarget 赋给 ImageTargetController.TargetSource ,这样controller可以使用 ImageTargetController.DataSource.Target 来初始化。
private void LoadCloudTarget(ImageTarget target)
{
...
var go = new GameObject(uid);
targetObjs.Add(go);
var targetController = go.AddComponent<ImageTargetController>();
targetController.SourceType = ImageTargetController.DataSource.Target;
targetController.TargetSource = target;
LoadTargetIntoTracker(targetController);
targetController.TargetLoad += (loadedTarget, result) =>
{
...
AddCubeOnTarget(targetController);
};
...
}
没有必要多次加载同一个target,并且这样做也会失败。
if (!loadedCloudTargetUids.Contains(targetValue.uid()))
{
LoadCloudTarget(targetValue.Clone());
}
使用离线缓存¶
一个好的实践是,将识别到的target保持在文件存储中,以便在下次启动时加载。这会对下次应用启动时的识别有好处,可以减少响应时间,而且可以在离线状态下使用识别过的target。
可以使用 ImageTarget.save 将target保存为 .etd 文件。
target.save(OfflineCachePath + "/" + target.uid() + ".etd")
然后可以在下次运行时通过 ImageTargetController.DataSource.TargetDataFile 类型的数据使用 .etd 文件创建target。
private void LoadOfflineTarget(string file)
{
var go = new GameObject(Path.GetFileNameWithoutExtension(file) + "-offline");
targetObjs.Add(go);
var targetController = go.AddComponent<ImageTargetController>();
targetController.SourceType = ImageTargetController.DataSource.TargetDataFile;
targetController.TargetDataFileSource.PathType = PathType.Absolute;
targetController.TargetDataFileSource.Path = file;
LoadTargetIntoTracker(targetController);
targetController.TargetLoad += (loadedTarget, result) =>
{
...
loadedCloudTargetUids.Add(loadedTarget.uid());
cachedTargetCount++;
AddCubeOnTarget(targetController);
};
}