ARCore 构建增强图像应用程序,识别图片加载模型

2019-08-14  本文已影响0人  橙果子

Github源码地址

在本教程中,您将学习如何通过将锚点设置为特定场景而不是常规平面来将3D模型放置在现实世界中。通过Google的ARCore,您可以增加可以被arcore识别的2D图像,然后将3D模型放在它们上面。

您提供一些参考图像,并且ARCore跟踪确定这些图像在环境中的物理位置。增强图像已经广泛使用,如书籍,报纸,杂志等。

您将对ARCore和Sceneform中的一些术语有基本的了解,例如Scene,Anchor,Node,TransformableNode等。

什么是增强图像?

ARCore中的增强图像允许您构建可在用户环境中响应2D图像(例如海报或产品包装)的AR应用程序。您提供了一组参考图像,一旦在摄像机视图中检测到这些图像,ARCore跟踪就会告诉您这些图像在AR会话中的物理位置。

基本上,使用增强图像,您可以将简单的2D图像转换为增强图像,该图像可以被您的应用程序识别,然后用于在其上方放置3D模型。

当您可能想要使用增强图像?

以下是使用增强图像之前可能需要考虑的一些限制:

选择一个好的参考图像

以下是一些选择良好参考图像以提高arcore可检测性的技巧:

如何使用 arcoreimg工具:

从这个链接下载arcore sdk for android:
在任何您喜欢的地方解压缩zip文件的zip内容。
导航到解压缩的文件夹,然后转到工具 - > arcoreimg - > windows(linux / macos,无论你使用什么)
在此位置打开命令提示符。
现在输入以下命令:

// 将dog.png替换为图像的完整路径。
arcoreimg.exe eval-img --input_image_path=dog.png

开始使用增强图像应用程序

现在你已经熟悉了ARCore和Sceneform,并选择了一个分数为75+的好参考图像,现在是时候开始编写应用程序!

编写代码

将创建一个自定义片段以添加到界面中。需要一个自定义代码,将改变默认代码的一些属性。

创建一个名为“CustomArFragment”的类,并从ArFragment扩展它。以下是CustomArFragment的代码:

package com.ayusch.augmentedimages;

import android.util.Log;

import com.google.ar.core.Config;
import com.google.ar.core.Session;
import com.google.ar.sceneform.ux.ArFragment;

public class CustomArFragment extends ArFragment {

    @Override
    protected Config getSessionConfiguration(Session session) {
        getPlaneDiscoveryController().setInstructionView(null);
        Config config = new Config(session);
        config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
        session.configure(config);
        getArSceneView().setupSession(session);

        return config;
    }
}

首先,我们将平面发现指令设置为null。通过这样做,我们关闭在初始化片段之后出现的手形图标,该图标指示用户移动他的手机。我们不再需要它,因为我们没有检测随机平面而是特定图像。

接下来,我们将会话的更新模式设置为LATEST_CAMERA_IMAGE。这可确保在相机帧更新时调用更新侦听器。它配置更新方法的行为。

设置增强图像数据库
在assets文件夹中添加您选择的参考图像(您要在物理世界中检测)。如果您的资源文件夹不存在,请创建一个。 现在我们将添加增强图像到我们的数据库,然后在现实世界中检测到。

我们将在创建片段(场景)后立即设置此数据库。然后我们检查此调用的成功与否,并相应地设置日志。将以下代码添加到自定义片段:

if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) {
    Log.d("SetupAugImgDb", "Success");
} else {
    Log.e("SetupAugImgDb","Faliure setting up db");
}

这是CustomArFragment的代码:

package com.ayusch.augmentedimages;

import android.util.Log;

import com.google.ar.core.Config;
import com.google.ar.core.Session;
import com.google.ar.sceneform.ux.ArFragment;

public class CustomArFragment extends ArFragment {

    @Override
    protected Config getSessionConfiguration(Session session) {
        getPlaneDiscoveryController().setInstructionView(null);
        Config config = new Config(session);
        config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
        session.configure(config);
        getArSceneView().setupSession(session);

        if ((((MainActivity) getActivity()).setupAugmentedImagesDb(config, session))) {
            Log.d("SetupAugImgDb", "Success");
        } else {
            Log.e("SetupAugImgDb","Faliure setting up db");
        }
        return config;
    

}

我们很快将 在MainActivity中创建setupAugmentedImagesDb方法。现在创建了CustomArFragment,让我们将它添加到activity_main.xml,这里是您的activity_main.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/sceneform_fragment"
        android:name="com.google.ar.sceneform.samples.augmentedimage.CustomArFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</RelativeLayout>

请注意,我们将此片段的名称设置为CustomArFragment。这是确保添加的片段是我们的自定义片段所必需的。这将确保处理权限处理和会话初始化。

将图像添加到增强图像数据库

在这里,我们将设置我们的图像数据库,在现实世界中找到参考图像,然后相应地添加3D模型。

让我们从设置数据库开始。在MainActivity.java类中创建一个公共函数setupAugmentedImagesDb

public boolean setupAugmentedImagesDb(Config config, Session session) {
    AugmentedImageDatabase augmentedImageDatabase;
    Bitmap bitmap = loadAugmentedImage();
    if (bitmap == null) {
        return false;
    }

    augmentedImageDatabase = new AugmentedImageDatabase(session);
    augmentedImageDatabase.addImage("tiger", bitmap);
    config.setAugmentedImageDatabase(augmentedImageDatabase);
    return true;
}

private Bitmap loadAugmentedImage() {
      try (InputStream is = getAssets().open("default.jpg")) {
             return BitmapFactory.decodeStream(is);
       } catch (IOException e) {
              Log.e("ImageLoad", "IO Exception", e);
       }

       return null;
}

我们还有loadAugmentedImage方法,它从assets文件夹加载图像并返回一个位图。

setupAugmentedImagesDb中,我们首先为此会话初始化数据库,然后将图像添加到此数据库。我们将我们的形象命名为“老虎”。然后我们为此会话配置设置数据库并返回true,表示图像已成功添加。

default.jpg识别图, frame_lower_left.sfb模型文件

检测现实世界中的参考图像

现在我们将开始在现实世界中检测我们的参考图像。为了做到这一点,我们将为场景添加一个监听器,每次创建一个帧时都会调用该监听器,并且将分析该帧以查找我们的参考图像。

在MainActivity.java 的onCreate方法中添加此行

arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);

现在将onUpdateFrame方法添加到MainActivity:

@RequiresApi(api = Build.VERSION_CODES.N)
private void onUpdateFrame(FrameTime frameTime) {
    Frame frame = arFragment.getArSceneView().getArFrame();

    Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
    for (AugmentedImage augmentedImage : augmentedImages) {
        if (augmentedImage.getTrackingState() == TrackingState.TRACKING) {
            if (augmentedImage.getName().equals("tiger") && shouldAddModel) {
                placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("models/frame_upper_left.sfb"));
                shouldAddModel = false;
            }
        }
    }
}

在第一行中,我们从场景中获取帧。甲帧可以被想象为在视频的中间的快照。如果您熟悉视频的工作原理,您可能会知道它们是一系列静止图像,一个接一个地快速翻转,给人以电影的印象。我们正在提取其中一张照片。

一旦我们有了框架,我们就会分析我们的参考图像。我们使用frame.getUpdatedTrackables提取了ARCore跟踪的所有项目的列表。这是所有检测到的图像的集合。然后我们循环收集并检查框架中是否存在我们的图像“tiger”。
如果我们找到匹配项,那么我们继续并在检测到的图像上放置3D模型。

注意:我已添加,shouldAddModel 以确保我们只添加一次模型。

将3D模型放在参考图像上

现在我们已经在现实世界中检测到了我们的图像,我们可以开始在其上添加3D模型。我们将从之前的项目中复制placeObject和addNodeToScene方法并在此处添加它们。

虽然我之前已经逐行解释了这些方法的作用,但这里有一个概述:

这是我们最终的MainActivity.java类:

package com.ayusch.augmentedimages;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.google.ar.core.Anchor;
import com.google.ar.core.AugmentedImage;
import com.google.ar.core.AugmentedImageDatabase;
import com.google.ar.core.Config;
import com.google.ar.core.Frame;
import com.google.ar.core.Session;
import com.google.ar.core.TrackingState;
import com.google.ar.sceneform.AnchorNode;
import com.google.ar.sceneform.FrameTime;
import com.google.ar.sceneform.rendering.ModelRenderable;
import com.google.ar.sceneform.rendering.Renderable;
import com.google.ar.sceneform.ux.ArFragment;
import com.google.ar.sceneform.ux.TransformableNode;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;

public class MainActivity extends AppCompatActivity {
    ArFragment arFragment;
    boolean shouldAddModel = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        arFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_fragment);
        arFragment.getPlaneDiscoveryController().hide();
        arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);
    }


    @RequiresApi(api = Build.VERSION_CODES.N)
    private void placeObject(ArFragment arFragment, Anchor anchor, Uri uri) {
        ModelRenderable.builder()
                .setSource(arFragment.getContext(), uri)
                .build()
                .thenAccept(modelRenderable -> addNodeToScene(arFragment, anchor, modelRenderable))
                .exceptionally(throwable -> {
                            Toast.makeText(arFragment.getContext(), "Error:" + throwable.getMessage(), Toast.LENGTH_LONG).show();
                            return null;
                        }

                );
    }

@RequiresApi(api = Build.VERSION_CODES.N)
    private void onUpdateFrame(FrameTime frameTime) {
        Frame frame = arFragment.getArSceneView().getArFrame();

        Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
        for (AugmentedImage augmentedImage : augmentedImages) {
            if (augmentedImage.getTrackingState() == TrackingState.TRACKING) {
                if (augmentedImage.getName().equals("tiger") && shouldAddModel) {
                    placeObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), Uri.parse("Mesh_BengalTiger.sfb"));
                    shouldAddModel = false;
                }
            }
        }
    }

    public boolean setupAugmentedImagesDb(Config config, Session session) {
        AugmentedImageDatabase augmentedImageDatabase;
        Bitmap bitmap = loadAugmentedImage();
        if (bitmap == null) {
            return false;
        }

        augmentedImageDatabase = new AugmentedImageDatabase(session);
        augmentedImageDatabase.addImage("tiger", bitmap);
        config.setAugmentedImageDatabase(augmentedImageDatabase);
        return true;
    }

private Bitmap loadAugmentedImage() {
        try (InputStream is = getAssets().open("blanket.jpeg")) {
            return BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            Log.e("ImageLoad", "IO Exception", e);
        }

        return null;
    }

    private void addNodeToScene(ArFragment arFragment, Anchor anchor, Renderable renderable) {
        AnchorNode anchorNode = new AnchorNode(anchor);
        TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
        node.setRenderable(renderable);
        node.setParent(anchorNode);
        arFragment.getArSceneView().getScene().addChild(anchorNode);
        node.select();
    }


}

现在运行你的应用程序 您应该看到如下所示的屏幕。在我们的手机上移动一点参考物体。ARCore将检测特征点,一旦在现实世界中检测到参考图像,它就会将3D模型添加到其中。
有了这个,我们使用Arcore by Google和Sceneform SDK创建了我们的第一个增强图像应用程序!


效果图
上一篇下一篇

猜你喜欢

热点阅读