Android摄像头预览中的byte[]转图像

18

尝试将Camera.onPreviewFramebyte[]转换为Bitmap,使用BitmapFactory.decodeByteArray出现错误SkImageDecoder::Factory returned null

以下是我的代码:

public void onPreviewFrame(byte[] data, Camera camera) {
    Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
}

也许对某些人有用。在这里看看我的解决方案:https://dev59.com/K2Ij5IYBdhLWcg3waEZe#34438806 - DeniSHow
4个回答

34

这很难找!但是自API 8以来,在android.graphics中有一个YuvImage类。它不是Image的子类,因此你可以做的所有事情就是将它保存为Jpeg,但是如果你需要的话,你可以将它保存到内存流中,然后加载到Bitmap Image中。

import android.graphics.YuvImage;

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    try {
        Camera.Parameters parameters = camera.getParameters();
        Size size = parameters.getPreviewSize();
        YuvImage image = new YuvImage(data, parameters.getPreviewFormat(),
                size.width, size.height, null);
        File file = new File(Environment.getExternalStorageDirectory()
                .getPath() + "/out.jpg");
        FileOutputStream filecon = new FileOutputStream(file);
        image.compressToJpeg(
                new Rect(0, 0, image.getWidth(), image.getHeight()), 90,
                filecon);
    } catch (FileNotFoundException e) {
        Toast toast = Toast
                .makeText(getBaseContext(), e.getMessage(), 1000);
        toast.show();
    }
}

2
这是一个非常hacky的解决方案。保存为jpeg,然后立即解码?我认为我宁愿使用自定义YUV函数。 - Timmmm
1
@Timmmm 我同意,一个自定义的YUV函数比通过JPEG保存和加载更好,而且这并不难实现。但是,如果你只想保存为JPEG格式,那么这仍然是最好的选择。我认为很遗憾YuvImage不是Image的子类,否则就不需要任何hack或自己编写YUV代码了。 - weston

7
自从Android 3.0版本起,您可以使用TextureViewTextureSurface来显示相机,并使用mTextureView.getBitmap()来检索友好的RGB预览帧。在TextureView文档中提供了一个非常基本的示例。请注意,您需要将应用程序或活动设置为硬件加速,方法是在清单文件中添加android:hardwareAccelerated="true"

4

经过长时间的寻找,我终于找到了答案。这里是...

我没有使用BitmapFactory,而是使用了自定义方法将byte[] data解码为有效的图像格式。为了将图像解码为有效的图像格式,需要调用camera.getParameters().getPictureFormat()来确定相机使用的图片格式。这将返回由ImageFormat定义的常量。在确定格式之后,使用适当的编码器对图像进行编码。

在我的情况下,byte[] data采用的是YUV格式,因此我寻找了YUVBMP转换,解决了我的问题。


请问您如何查询 **camera.getParametrs()**,以及如何检查我的图像格式? - Numair
@Numair http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getPictureFormat() - Andrew Wyld
也可以调用http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat(int),但不是所有相机都支持所有格式。 显然,NV21YV12被普遍支持,而默认值为NV21 - Andrew Wyld
@ArslanAhmad 不确定现在代码在哪里。可以考虑查看http://developer.android.com/reference/android/graphics/YuvImage.html(可能有帮助)。 - Vinod Maurya

2
您可以尝试以下内容: 此示例将相机帧发送到服务器。
 @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
        try {
            byte[] baos = convertYuvToJpeg(data, camera);
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.append("data:image/jpeg;base64,").append(Base64.encodeToString(baos, Base64.DEFAULT));
            mSocket.emit("newFrame", dataBuilder.toString());
        } catch (Exception e) {
           Log.d("########", "ERROR");
        }
    }

};


public byte[] convertYuvToJpeg(byte[] data, Camera camera) {

    YuvImage image = new YuvImage(data, ImageFormat.NV21,
            camera.getParameters().getPreviewSize().width, camera.getParameters().getPreviewSize().height, null);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int quality = 20; //set quality
    image.compressToJpeg(new Rect(0, 0, camera.getParameters().getPreviewSize().width, camera.getParameters().getPreviewSize().height), quality, baos);//this line decreases the image quality


    return baos.toByteArray();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接