在Android上结合图像和视频流

在Android上结合图像和视频流,android,png,arcore,sceneform,Android,Png,Arcore,Sceneform,我正在研究Android上的增强现实技术 我正在Android应用程序中使用ARCore和Sceneform 我已经试用了示例项目,现在想开发自己的应用程序 我希望实现的一个效果是将图像(比如.jpeg或.png)与相机上设备的实时馈送相结合/叠加 图像将有一个透明的背景,允许用户同时看到实时提要和图像 但是,我不希望覆盖图像是固定/静态水印,当用户放大、缩小或平移时,覆盖图像还必须放大、缩小和平移等 我不希望过度渲染的图像变成3d或者任何类似的东西 Sceneform是否可能产生这种效果?或者

我正在研究Android上的增强现实技术

我正在Android应用程序中使用ARCore和Sceneform

我已经试用了示例项目,现在想开发自己的应用程序

我希望实现的一个效果是将图像(比如.jpeg或.png)与相机上设备的实时馈送相结合/叠加

图像将有一个透明的背景,允许用户同时看到实时提要和图像

但是,我不希望覆盖图像是固定/静态水印,当用户放大、缩小或平移时,覆盖图像还必须放大、缩小和平移等

我不希望过度渲染的图像变成3d或者任何类似的东西

Sceneform是否可能产生这种效果?或者我需要使用其他第三方库和/或工具来实现所需的结果

更新

用户正在白纸上绘图。纸张的方向是这样的,用户可以轻松地(用左手或右手)绘图。用户可以在完成图像时自由移动纸张

一个安卓设备放在一张纸的上方,用来拍摄用户绘制他们选择的图像

现场摄像机正在向大电视或监视器屏幕播放

为了帮助用户,他们选择了一个静态图像进行“跟踪”或“复制”

此图像在Android设备上选择,并与Android应用程序中的实时摄像机流相结合

用户可以放大和缩小他们的图形,组合的实时流和选定的静态图像也将放大和缩小,这将使用户能够通过“徒手”绘制选定静态图像的准确副本

当用户直接看这张纸时,他们只看到自己的图纸


当用户在电视或显示器上观看他们的绘图的直播流时,他们会看到他们的绘图和所选的静态图像叠加在一起。用户可以控制静态图像的透明度,以帮助他们准确复制图像。

我认为您需要的是使用AR显示图像,以便图像保持在原位,例如在一张纸上,以便作为在纸上绘制图像副本的指南

这有两个部分。第一种方法是定位纸张,第二种方法是将图像放置在纸张上,并在手机移动时将其保留在纸张上

只需检测纸张的平面即可确定纸张的位置(与纯白色纸张相比,具有一些对比度、图案或其他东西会有所帮助),然后点击页面中心位置。这是在HelloSceneform样本中完成的

如果要对纸张进行更精确的边界,可以轻触纸张的4个角,然后在那里创建锚定。为此,请在
onCreate()中注册一个平面侦听器

然后在OnPlaneTapted中,创建4个锚点节点。获得4后,初始化要显示的图形

private void onPlaneTapped(HitResult hitResult, Plane plane, MotionEvent event) {
    if (cornerAnchors.size() != 4) {
        AnchorNode corner = createCornerNode(hitResult.createAnchor());
        arFragment.getArSceneView().getScene().addChild(corner);
        cornerAnchors.add(corner);
    }

    if (cornerAnchors.size() == 4 && drawingNode == null) {
        initializeDrawing();
    }
}
若要初始化图形,请从位图或可绘制图形创建Sceneform纹理。这可以来自资源或文件URL。您希望纹理显示整个图像,并在调整容纳纹理的模型的大小时进行缩放

private void initializeDrawing() {
    Texture.Sampler sampler = Texture.Sampler.builder()
            .setWrapMode(Texture.Sampler.WrapMode.CLAMP_TO_EDGE)
            .setMagFilter(Texture.Sampler.MagFilter.NEAREST)
            .setMinFilter(Texture.Sampler.MinFilter.LINEAR_MIPMAP_LINEAR)
            .build();
    Texture.builder()
            .setSource(this, R.drawable.logo_google_developers)
            .setSampler(sampler)
            .build()
            .thenAccept(texture -> {
                MaterialFactory.makeTransparentWithTexture(this, texture)
                        .thenAccept(this::buildDrawingRenderable);
            });
}
保存纹理的模型只是一个平面四边形,大小为角之间的最小尺寸。这与使用OpenGL布局四边形的逻辑相同

private void buildDrawingRenderable(Material material) {

    Integer[] indices = {
            0, 1, 3, 3, 1, 2
    };

    //Calculate the center of the corners.
    float min_x = Float.MAX_VALUE;
    float max_x = Float.MIN_VALUE;
    float min_z = Float.MAX_VALUE;
    float max_z = Float.MIN_VALUE;
    for (AnchorNode node : cornerAnchors) {
        float x = node.getWorldPosition().x;
        float z = node.getWorldPosition().z;
        min_x = Float.min(min_x, x);
        max_x = Float.max(max_x, x);
        min_z = Float.min(min_z, z);
        max_z = Float.max(max_z, z);
    }

    float width = Math.abs(max_x - min_x);
    float height = Math.abs(max_z - min_z);
    float extent = Math.min(width / 2, height / 2);

    Vertex[] vertices = {
            Vertex.builder()
                    .setPosition(new Vector3(-extent, 0, extent))
                    .setUvCoordinate(new Vertex.UvCoordinate(0, 1)) // top left
                    .build(),
            Vertex.builder()
                    .setPosition(new Vector3(extent, 0, extent))
                    .setUvCoordinate(new Vertex.UvCoordinate(1, 1)) // top right
                    .build(),
            Vertex.builder()
                    .setPosition(new Vector3(extent, 0, -extent))
                    .setUvCoordinate(new Vertex.UvCoordinate(1, 0)) // bottom right
                    .build(),
            Vertex.builder()
                    .setPosition(new Vector3(-extent, 0, -extent))
                    .setUvCoordinate(new Vertex.UvCoordinate(0, 0)) // bottom left
                    .build()
    };

    RenderableDefinition.Submesh[] submeshes = {
            RenderableDefinition.Submesh.builder().
                    setMaterial(material)
                    .setTriangleIndices(Arrays.asList(indices))
                    .build()
    };

    RenderableDefinition def = RenderableDefinition.builder()
            .setSubmeshes(Arrays.asList(submeshes))

            .setVertices(Arrays.asList(vertices)).build();

    ModelRenderable.builder().setSource(def)
            .setRegistryId("drawing").build()
            .thenAccept(this::positionDrawing);
}
最后一部分是将四边形放置在角点的中心,并创建一个可变换的节点,以便可以将图像推进到位、旋转或缩放为完美大小

private void positionDrawing(ModelRenderable drawingRenderable) {


    //Calculate the center of the corners.
    float min_x = Float.MAX_VALUE;
    float max_x = Float.MIN_VALUE;
    float min_z = Float.MAX_VALUE;
    float max_z = Float.MIN_VALUE;
    for (AnchorNode node : cornerAnchors) {
        float x = node.getWorldPosition().x;
        float z = node.getWorldPosition().z;
        min_x = Float.min(min_x, x);
        max_x = Float.max(max_x, x);
        min_z = Float.min(min_z, z);
        max_z = Float.max(max_z, z);
    }

    Vector3 center = new Vector3((min_x + max_x) / 2f,
            cornerAnchors.get(0).getWorldPosition().y, (min_z + max_z) / 2f);

    Anchor centerAnchor = null;
    Vector3 screenPt = arFragment.getArSceneView().getScene().getCamera().worldToScreenPoint(center);
    List<HitResult> hits = arFragment.getArSceneView().getArFrame().hitTest(screenPt.x, screenPt.y);
    for (HitResult hit : hits) {
        if (hit.getTrackable() instanceof Plane) {
            centerAnchor = hit.createAnchor();
            break;
        }
    }

    AnchorNode centerNode = new AnchorNode(centerAnchor);
    centerNode.setParent(arFragment.getArSceneView().getScene());

    drawingNode = new TransformableNode(arFragment.getTransformationSystem());
    drawingNode.setParent(centerNode);
    drawingNode.setRenderable(drawingRenderable);
}
private void positionDrawing(ModelRenderable drawing renderable){
//计算角点的中心。
float min_x=float.MAX_值;
float max_x=float.MIN_值;
float min_z=float.MAX_值;
float max_z=float.MIN_值;
用于(锚点节点:角锚点){
float x=node.getWorldPosition().x;
float z=node.getWorldPosition().z;
min_x=Float.min(min_x,x);
max_x=Float.max(max_x,x);
min_z=Float.min(min_z,z);
max_z=Float.max(max_z,z);
}
矢量3中心=新矢量3((最小值+最大值)/2f,
get(0.getWorldPosition().y,(最小值+最大值)/2f);
锚定中心锚定=空;
Vector3 screenPt=arFragment.getArSceneView().getScene().getCamera().worldToScreenPoint(中);
List hits=arFragment.getArSceneView().getArFrame().hitTest(screenPt.x,screenPt.y);
for(命中结果命中:命中){
if(平面的hit.getTrackable()实例){
centerAnchor=hit.createAnchor();
打破
}
}
锚点节点中心节点=新锚点节点(中心锚点);
setParent(arFragment.getArSceneView().getScene());
drawingNode=新的TransformableNode(arFragment.getTransformationSystem());
drawingNode.setParent(中心节点);
drawingNode.setRenderable(drawingRenderable);
}

可以使用ARobjects作为点来缩放预期AR参考图像,以便为用户调整模板的大小

更复杂的AR图像将不容易工作,因为AR图像覆盖在用户跟踪的顶部,这将妨碍他们的笔尖

我的解决办法是把白皮书涂成彩色。这将用所选图像或实时提要替换白皮书。除非您有跟踪纸张位置的方法,否则按照指定的方式移动纸张将是一个问题

正如您在本例中所看到的,AR对象位于前面,而chromakey是背景。跟踪面(纸)将位于中心

下面的链接提供了对该示例的参考

RJ


您能详细介绍一下您正在尝试做的事情吗?如果你想要一个纹理成为AR场景的一部分,它应该被放置在场景中,所以我对你的
private void positionDrawing(ModelRenderable drawingRenderable) {


    //Calculate the center of the corners.
    float min_x = Float.MAX_VALUE;
    float max_x = Float.MIN_VALUE;
    float min_z = Float.MAX_VALUE;
    float max_z = Float.MIN_VALUE;
    for (AnchorNode node : cornerAnchors) {
        float x = node.getWorldPosition().x;
        float z = node.getWorldPosition().z;
        min_x = Float.min(min_x, x);
        max_x = Float.max(max_x, x);
        min_z = Float.min(min_z, z);
        max_z = Float.max(max_z, z);
    }

    Vector3 center = new Vector3((min_x + max_x) / 2f,
            cornerAnchors.get(0).getWorldPosition().y, (min_z + max_z) / 2f);

    Anchor centerAnchor = null;
    Vector3 screenPt = arFragment.getArSceneView().getScene().getCamera().worldToScreenPoint(center);
    List<HitResult> hits = arFragment.getArSceneView().getArFrame().hitTest(screenPt.x, screenPt.y);
    for (HitResult hit : hits) {
        if (hit.getTrackable() instanceof Plane) {
            centerAnchor = hit.createAnchor();
            break;
        }
    }

    AnchorNode centerNode = new AnchorNode(centerAnchor);
    centerNode.setParent(arFragment.getArSceneView().getScene());

    drawingNode = new TransformableNode(arFragment.getTransformationSystem());
    drawingNode.setParent(centerNode);
    drawingNode.setRenderable(drawingRenderable);
}