在Android上结合图像和视频流
我正在研究Android上的增强现实技术 我正在Android应用程序中使用ARCore和Sceneform 我已经试用了示例项目,现在想开发自己的应用程序 我希望实现的一个效果是将图像(比如.jpeg或.png)与相机上设备的实时馈送相结合/叠加 图像将有一个透明的背景,允许用户同时看到实时提要和图像 但是,我不希望覆盖图像是固定/静态水印,当用户放大、缩小或平移时,覆盖图像还必须放大、缩小和平移等 我不希望过度渲染的图像变成3d或者任何类似的东西 Sceneform是否可能产生这种效果?或者我需要使用其他第三方库和/或工具来实现所需的结果 更新 用户正在白纸上绘图。纸张的方向是这样的,用户可以轻松地(用左手或右手)绘图。用户可以在完成图像时自由移动纸张 一个安卓设备放在一张纸的上方,用来拍摄用户绘制他们选择的图像 现场摄像机正在向大电视或监视器屏幕播放 为了帮助用户,他们选择了一个静态图像进行“跟踪”或“复制” 此图像在Android设备上选择,并与Android应用程序中的实时摄像机流相结合 用户可以放大和缩小他们的图形,组合的实时流和选定的静态图像也将放大和缩小,这将使用户能够通过“徒手”绘制选定静态图像的准确副本 当用户直接看这张纸时,他们只看到自己的图纸在Android上结合图像和视频流,android,png,arcore,sceneform,Android,Png,Arcore,Sceneform,我正在研究Android上的增强现实技术 我正在Android应用程序中使用ARCore和Sceneform 我已经试用了示例项目,现在想开发自己的应用程序 我希望实现的一个效果是将图像(比如.jpeg或.png)与相机上设备的实时馈送相结合/叠加 图像将有一个透明的背景,允许用户同时看到实时提要和图像 但是,我不希望覆盖图像是固定/静态水印,当用户放大、缩小或平移时,覆盖图像还必须放大、缩小和平移等 我不希望过度渲染的图像变成3d或者任何类似的东西 Sceneform是否可能产生这种效果?或者
当用户在电视或显示器上观看他们的绘图的直播流时,他们会看到他们的绘图和所选的静态图像叠加在一起。用户可以控制静态图像的透明度,以帮助他们准确复制图像。我认为您需要的是使用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);
}