gpt4 book ai didi

android - 在 Android 上将图像与视频流结合

转载 作者:太空狗 更新时间:2023-10-29 16:26:27 25 4
gpt4 key购买 nike

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

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

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

我想要实现的一个效果是将图像(比如 .jpeg 或 .png)与来自设备机载摄像头的实时馈送相结合/叠加。

图像将具有透明背景,允许用户同时查看实时提要和图像

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

我不希望过度播放的图像变成 3d 或任何类似性质的图像。

Sceneform 可以实现这种效果吗?或者我是否需要使用其他第 3 方库和/或工具来实现预期的结果。

更新

用户正在一张空白的白纸上绘图。纸张的方向使用户可以舒适地绘画(左手或右手)。用户在完成图像的同时可以自由移动纸张。

Android 设备放在一张纸上方,拍摄用户绘制所选图像的过程。

正在将实时摄像机画面转换到大电视或监视器屏幕上。

为了帮助用户,他们选择了静态图像来“跟踪”或“复制”。

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

用户可以放大和缩小他们的绘图,组合的实时流和选定的静态图像也会放大和缩小,这将使用户能够通过绘制“Free Hand”来准确复制选定的静态图像.

当用户直视纸张时,他们只会看到自己的绘图。

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

最佳答案

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

这有两个部分。首先是找到那张纸,其次是将图像放在纸上,并在手机四处移动时将其保持在那里。

定位纸张可以通过检测纸张的平面来完成(与普通的白纸相比有一些对比,或图案或其他东西会有所帮助),然后点击页面中心应该在哪里是。这是在 HelloSceneform 示例中完成的。

如果你想要更准确的纸张边界,你可以点击纸张的 4 个角,然后在那里创建 anchor 。为此,请在 onCreate()

中注册一个平面监听器
   arFragment.setOnTapArPlaneListener(this::onPlaneTapped);

然后在 onPlaneTapped 中,创建 4 个 anchor 节点。有了 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);
}

最后一部分是将四边形定位在角的中心,并创建一个 Transformable 节点,这样图像就可以被微移到适当的位置、旋转或缩放到完美的大小。

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);
}

关于android - 在 Android 上将图像与视频流结合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50294777/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com