简体   繁体   English

如何显示从相机拍摄的图像

[英]How can I show image taken from camera

I'm trying to write an android app, that works with the camera. 我正在尝试编写可与相机配合使用的android应用。 I show a preview of the camera in a textureview, that is working. 我在Textureview中显示了相机的预览,可以正常工作。 If you press a button the camera will take a picture and show it on an imageview on the second half of the screen. 如果按下按钮,相机将拍摄照片并将其显示在屏幕后半部分的图像视图中。 But everytime I press the button my app stops working, it tells me the error 但是每当我按下按钮时,我的应用就会停止运行,它会告诉我错误

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. android.view.ViewRootImpl $ CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能触摸其视图。

So I looked it up, and it seems I can't change the image of the imageview as I try to. 所以我抬起头来,似乎无法更改imageview的图像。 But I don't know how else I could solve my problem. 但是我不知道我还能怎么解决我的问题。 Can you give me some advise? 你能给我一些建议吗? Here is my code: The image is changed in the "ImageReader.OnImageAvailableListener" in the method takePicture(). 这是我的代码:在takePicture()方法的“ ImageReader.OnImageAvailableListener”中更改了图像。

public class MainActivityOld extends Activity {

    private TextureView mTextureView;
    private ImageView mImageView;
    private CameraDevice mCameraDevice;
    private Size mPreviewSize;
    private CaptureRequest.Builder mPreviewBuilder;
    private CameraCaptureSession mPreviewSession;

    private Button mBtnShot;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //no titlebar
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        mTextureView = (TextureView) findViewById(R.id.texture);
        mTextureView.setSurfaceTextureListener(mSurfaceListener);

        mImageView = (ImageView) findViewById(R.id.lastPicture);

        mBtnShot = (Button) findViewById(R.id.btn_takepicture);
        mBtnShot.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                takePicture();
            }
        });
    }

    private void takePicture() {
        Log.e("MyTag", "Take picture");
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

        try {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
            Size[] jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
            int width = jpegSizes[0].getWidth();
            int height = jpegSizes[0].getHeight();

            ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);


            List<Surface> outputSurfaces = new ArrayList<Surface>(2);
            outputSurfaces.add(reader.getSurface());
            outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));


            final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){

                @Override
                public void onImageAvailable(ImageReader reader) {
                    Image image = reader.acquireLatestImage();
                    ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                    byte[] bytes = new byte[buffer.capacity()];
                    buffer.get(bytes);
                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                    mImageView.setImageBitmap(bitmap);
                }
            };


            HandlerThread thread = new HandlerThread("CameraPicture");
            thread.start();
            final Handler backgroundHandler = new Handler(thread.getLooper());
            reader.setOnImageAvailableListener(readerListener,backgroundHandler);

            final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);
                    startPreview();
                }
            };
            mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        session.capture(captureBuilder.build(), captureListener, backgroundHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {
                }
            }, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void openCamera() {
        CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            String cameraId = manager.getCameraIdList()[0];
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
            StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            mPreviewSize = map.getOutputSizes(SurfaceTexture.class)[0];

            manager.openCamera(cameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        Log.e("MyTag", "openCamera");
    }

    private TextureView.SurfaceTextureListener mSurfaceListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            Log.e("myLog", "onSurfaceTextureAvailable, width=" + width + ",height=" + height);
            openCamera();
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(CameraDevice camera) {
            Log.e("myTag", "onOpened");
            mCameraDevice = camera;
            startPreview();
        }

        @Override
        public void onDisconnected(CameraDevice camera) {
            Log.e("myTag", "onDisconnected");
        }

        @Override
        public void onError(CameraDevice camera, int error) {
            Log.e("myTag", "onDisconnected");
        }
    };

    protected void startPreview() {
        if (mCameraDevice == null || mTextureView.isAvailable() || mPreviewSize == null) {
            Log.e("MyTag", "startPreview failed, still working, so just ignore it");
            // return;
        }
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        Surface surface = new Surface(texture);

        try {
            mPreviewBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        mPreviewBuilder.addTarget(surface);

        try {
            mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {

                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mPreviewSession = session;
                    updatePreview();
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {
                    Toast.makeText(MainActivityOld.this, "onConfigureFailed", Toast.LENGTH_LONG).show();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    protected void updatePreview() {
        mPreviewBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
        HandlerThread thread = new HandlerThread("CameraPreview");
        thread.start();
        Handler backgroundHandler = new Handler(thread.getLooper());

        try {
            mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(), null, backgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}

As the Exception says CalledFromWrongThreadException , your readerListener is working on another thread, from where you cannot change your views. 正如Exception所说的CalledFromWrongThreadException ,您的readerListener正在另一个线程上工作,在该线程上您无法更改视图。

Change your code to: 将您的代码更改为:

ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener(){
    @Override
    public void onImageAvailable(final ImageReader reader) {
        MainActivityOld.this.runOnUIThread(new Runnable() {
            @Override
            public void run() {
                Image image = reader.acquireLatestImage();
                ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                byte[] bytes = new byte[buffer.capacity()];
                buffer.get(bytes);
                Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
                mImageView.setImageBitmap(bitmap);
            }
        });
    }
};

I think you will be better of trying to stream to a surface view, not sure if this can even be done with a imageview. 我认为您最好尝试流式传输到表面视图,不确定是否可以使用imageview来完成。

try this tutorial it should get you going in the right direction 试试本教程,它应该使您朝正确的方向前进

or this for a more up to date example provided by google 或者是由Google提供的最新示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将从相机拍摄的图像保存到内部存储器中 - How can I save image taken from camera into internal storage 如何将以相机意图拍摄的图像设置为ImageView? - How can i set an image taken from the Camera intent into a ImageView? 如何保存从相机拍摄的图像并将其显示到列表视图-发生“ IllegalStateException”崩溃 - how to save image taken from camera and show it to listview - crashes with “IllegalStateException” 如何保存从相机意图拍摄的图像用作个人资料图像? - How can i save the image taken from camera intent to be used as a profile image? 如何旋转相机拍摄的照片? - How can I rotate the photos taken with the camera? 存储从相机拍摄的图像 - Storing image taken from camera Android在哪里可以获取本机相机应用程序拍摄的图像 - Android where can I get image taken by native camera app 如何在图库中的imageView上设置图像以及在Android中由相机拍摄的图像? - How to set an image on imageView from the gallery and image taken by camera in Android? 如何将图像路径作为要从相机拍摄的图像的参数传递 - How to pass image path as parameter for an image to be taken from camera 从相机拍摄照片后如何在图像视图中预览图像 - How to preview image in image view after picture taken from camera
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM