ARCore:如何在表面上显示设备保存的图像

时间:2018-06-13 16:33:23

标签: java android image mobile arcore

我是AR的新手。我想知道是否有一种方法可以使用ARCore for android将您在手机上保存的图片显示到表面。就像我能够使用具有预编码图像的Sceneform示例一样,但现在我想将我的图片文件夹中的照片显示到表面。我读到了纹理,但我不确定它是如何工作的。 感谢您的提示。

修改: 所以我创建了一个类,用户可以从中选择一个我通过Uri保存的图像

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == this.RESULT_CANCELED) {
        return;
    }
    if (requestCode == GALLERY) {
        if (data != null) {
            contentURI = data.getData();
            try {
                Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), contentURI);
                String path = saveImage(bitmap);
                Toast.makeText(imageSelector.this, "Image Saved!", Toast.LENGTH_SHORT).show();

                //set the image selected to bitmap so that imageView can display it
                imageview.setImageBitmap(bitmap);

                Intent intent = new Intent(this, HelloSceneformActivity.class);
                intent.putExtra("imageUri", contentURI.toString());
                startActivity(intent);

从ARclass方面我调用了intent并按照以下方式解析

//start the intent for the image chosen from the library
    Bundle extras = getIntent().getExtras();
    Uri myUri = Uri.parse(extras.getString("imageUri"));

    // When you build a Renderable, Sceneform loads its resources in the background while returning
    // a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
    ModelRenderable.builder()
            .setSource(this, myUri)
            .build()
            .thenAccept(renderable -> andyRenderable = renderable)
            .exceptionally(
                    throwable -> {
                        Toast toast =
                                Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG);
                        toast.setGravity(Gravity.CENTER, 0, 0);
                        toast.show();
                        return null;
                    });

我可以选择图片,但程序崩溃,我收到此错误

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.google.ar.sceneform.samples.hellosceneform/com.google.ar.sceneform.samples.hellosceneform.HelloSceneformActivity}: java.lang.IllegalArgumentException: Unable to parse url: 'content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F460/ORIGINAL/NONE/1926270799'

Caused by: java.lang.IllegalArgumentException: Unable to parse url: 'content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F460/ORIGINAL/NONE/1926270799'
        at com.google.ar.sceneform.utilities.LoadHelper.remoteUriToInputStreamCreator(Unknown Source:56)
        at com.google.ar.sceneform.utilities.LoadHelper.fromUri(Unknown Source:40)
        at com.google.ar.sceneform.rendering.Renderable$Builder.build(Renderable.java:343)
        at com.google.ar.sceneform.rendering.ModelRenderable$Builder.build(ModelRenderable.java:44)
        at com.google.ar.sceneform.samples.hellosceneform.HelloSceneformActivity.onCreate(HelloSceneformActivity.java:92)
        at android.app.Activity.performCreate(Activity.java:7174)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220)

2 个答案:

答案 0 :(得分:1)

根据https://github.com/google-ar/sceneform-android-sdk/issues/79,您目前无法从自定义URI加载:

  

在1.0中我们将所有file:// uris解释为相对于assets文件夹,这就是我们无法从外部存储加载的原因。因此,为了从Uri加载纹理,您需要将资源文件夹(即捆绑到您的apk中)放入,或者通过http:/在线提供它。 / scheme。

这意味着此时仅支持http://和file:// URIs,后者只能相对于assets文件夹。在https://github.com/google-ar/sceneform-android-sdk/issues/64上的malik-at-work回答中证实了这一点:

  

基于URI的文件加载不是在查看外部存储。现在,它只使用file://和以http://

开头的远程uris查找应用程序资产

编辑:我建议的解决方法是将ViewRenderable与内部使用单个ImageView的布局结合使用。 ViewRenderable可以在场景中创建2D布局,您只需将图像设置为ImageView,就像在通常的Android应用程序中一样,并根据自己的喜好定位/旋转生成的对象。您可以在solarsystem-Sceneform-example中找到ViewRenderable的示例用法,使用它实现速度的滑块。

编辑2: 似乎这已在Sceneform 1.4中修复,因为现在已经关闭了第一个提到的问题。

答案 1 :(得分:0)

您可以将图像作为Uri列表传递

public class MainActivity2 extends AppCompatActivity {
Button Gallery, AR;
private static final int PICK_IMAGE = 100;
Uri imageUri;
ImageView imageview;
private ArFragment arFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    Gallery = findViewById(R.id.select);
    AR = findViewById(R.id.ar);
    imageview = findViewById(R.id.imageView);

    AR.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent myIntent = new Intent(MainActivity2.this, MainActivity.class);
            MainActivity2.this.startActivity(myIntent);
        }
    });

    Gallery.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            openGallery();
        }
    });


}
private void openGallery() {
    Intent gallery = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
    startActivityForResult(gallery, PICK_IMAGE);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == RESULT_OK && requestCode == PICK_IMAGE) {
        imageUri = data.getData();
        imageview.setImageURI(imageUri);

        setContentView(R.layout.activity_main);
        arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.fragment);
        assert arFragment != null;
        arFragment.setOnTapArPlaneListener((hitResult, plane, motionEvent) - > {
            Anchor anchor = hitResult.createAnchor();
            createViewRenderable(hitResult.createAnchor());
        });

    }

}
private void addModeltoScene(Anchor anchor, ModelRenderable modelRenderable) {
    AnchorNode anchorNode = new AnchorNode(anchor);
    TransformableNode transformableNode = new TransformableNode(arFragment.getTransformationSystem());
    transformableNode.setParent(anchorNode);
    transformableNode.setRenderable(modelRenderable);
    arFragment.getArSceneView().getScene().addChild(anchorNode);
    transformableNode.select();
}
private void createViewRenderable(Anchor anchor) {
    ViewRenderable
        .builder()
        .setView(this, R.layout.text)
        .build()
        .thenAccept(viewRenderable - > {
            addtoScene(viewRenderable, anchor);
        });
}
private void addtoScene(ViewRenderable viewRenderable, Anchor anchor) {
    AnchorNode anchorNode = new AnchorNode(anchor);
    anchorNode.setRenderable(viewRenderable);
    arFragment.getArSceneView().getScene().addChild(anchorNode);
    View view = viewRenderable.getView();
    ViewPager viewPager = view.findViewById(R.id.viewPager);
    List < Uri > images = new ArrayList < > ();
    images.add(imageUri);
    Adapter adapter = new Adapter(images);
    viewPager.setAdapter(adapter);


}

class Adapter extends PagerAdapter {
    List < Uri > images;
    Adapter(List < Uri > images) {
        this.images = images;
    }
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        View view = getLayoutInflater().inflate(R.layout.item, container, false);
        ImageView imageView = view.findViewById(R.id.imageView);
        imageView.setImageURI(imageUri);
        container.addView(view);
        return view;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView((ImageView) object);
    }

    @Override
    public int getCount() {
        return images.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }
}
}

我在同一篇文章上写过一篇文章。请检查出来。这是关于以AR形式显示图库中的2D图像。 https://medium.com/@deveshbhatla952/displaying-2-d-images-from-external-storage-in-ar-form-using-google-sceneform-2baae45f1a42 我已经尝试过了,效果很好。