【问题标题】:How to correctly receive camera images from onImageAvailable?如何正确接收来自 onImageAvailable 的相机图像?
【发布时间】:2016-12-06 15:48:34
【问题描述】:

我正在尝试实现从一个 android 设备到另一个设备的视频流。为了做到这一点,我想从相机获取帧,通过套接字发送它们并在另一部手机的 ImageView 上显示。问题是我必须使用具有特定格式的 ImageReader - YUV_420_888。当我尝试根据该图像中的字节创建位图时,我只能得到 ALPHA_8(其他格式导致异常说缓冲区对于像素来说不够大),这是黑白 + 方向错误。我想知道是否有办法直接获得正确的版本或以某种方式对其进行转换,以便我可以制作正确的位图以在 ImageView 上显示。这是一些代码:

public class MainActivity extends AppCompatActivity
{
  private ImageReader mImageReader;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.imageView = (ImageView) findViewById(R.id.image);

        this.handler = new Handler(){
            @Override
            public void handleMessage(Message msg)
            {
                if(msg.what == Worker.PROCESSED_IMAGE)
                {
                    imageView.setImageBitmap((Bitmap) msg.obj);
                }
            }
        };
    }

    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];
            mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.YUV_420_888, 50);
            mImageReader.setOnImageAvailableListener(new Worker(this, this.handler, mPreviewSize.getWidth(), mPreviewSize.getHeight()), new Handler());

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

    }

}


public class Worker implements ImageReader.OnImageAvailableListener
{
    @Override
    public void onImageAvailable(ImageReader imageReader)
    {
        Image image = imageReader.acquireLatestImage();

        Image.Plane plane = image.getPlanes()[0];
        ByteBuffer buffer = plane.getBuffer();
        Bitmap bm = Bitmap.createBitmap(width, heigth, Bitmap.Config.ALPHA_8);
        bm.copyPixelsFromBuffer(buffer);
        image.close();
        handler.obtainMessage(PROCESSED_IMAGE, bm).sendToTarget();

}

【问题讨论】:

  • 对于 YUV_420_888,您需要 image 的所有三个平面

标签: android live-streaming android-camera2


【解决方案1】:

我使用辅助函数将图像转换为位图:

Preview2.kt@image -> bitmap

Preview.kt@yuvToBitmap

    protected fun yuvToBitmapFaster(bytes: ByteArray, w: Int, h: Int): Bitmap {
        if (yuvType == null) {
            yuvType = Type.Builder(rs, Element.U8(rs)).setX(bytes.size)
            `in` = Allocation.createTyped(rs, yuvType!!.create(), Allocation.USAGE_SCRIPT)
            rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(w).setY(h)
            out = Allocation.createTyped(rs, rgbaType?.create(), Allocation.USAGE_SCRIPT)
        }
        `in`?.copyFrom(bytes)
        yuvToRgbIntrinsic!!.setInput(`in`)
        yuvToRgbIntrinsic!!.forEach(out)
        val bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        out?.copyTo(bmp)
        return bmp
    }

顺便说一句,Google 有一个使用 MLkit 的示例来获取相机图像并将它们处理为:VisionProcessorBase.kttutorial

【讨论】:

    【解决方案2】:

    几乎正确,尝试改用这段代码:

    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = null;
        try {
            image = reader.acquireLatestImage();
    //        Log.d(TAG, String.format(Locale.getDefault(), "image w = %d; h = %d", image.getWidth(), image.getHeight()));
            Image.Plane[] planes = image.getPlanes();
            ByteBuffer buffer = planes[0].getBuffer();
            buffer.rewind();
            byte[] data = new byte[buffer.capacity()];
            buffer.get(data);
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    //use your bitmap
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (image != null) {
            image.close();
        }
    }
    

    【讨论】:

    • 位图大小不适合此代码。它不会填满屏幕。
    • @Donato“它没有填满屏幕” - 这与当前的问题/答案不匹配。也许你设置了错误的大小到ImageReader 或者这只是 UI 问题。
    猜你喜欢
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 2013-05-14
    • 1970-01-01
    • 2015-06-03
    • 2017-06-30
    相关资源
    最近更新 更多