Android将字节数组从Camera API转换为颜色Mat对象openCV

Posted

技术标签:

【中文标题】Android将字节数组从Camera API转换为颜色Mat对象openCV【英文标题】:Android convert byte array from Camera API to color Mat object openCV 【发布时间】:2014-04-21 17:12:48 【问题描述】:

我正在尝试从相机 API 中获取数据并进行颜色后处理。我的问题是,虽然我可以将 byte[] 对象转换为 Mat 对象,但我无法在没有收到错误的情况下获取颜色通道。我从以下帖子开始:How to get the Mat object from the Byte[] in openCV android? 但该实现不起作用。

以下是相关代码:

@Override
public void onPictureTaken(byte[] data, Camera camera) 
    // The camera preview was automatically stopped. Start it again.
    mCamera.startPreview();
    mCamera.setPreviewCallback(this);

    // Write the image in a file (in jpeg format)
    File pictureFile_interp = getOutputMediaFile(MEDIA_TYPE_IMAGE);

    try 

        //Now try to convert and save.
        Parameters params = camera.getParameters();
        Size sz = params.getPictureSize();

        //ERROR IN THE LINE BELOW!!!!
        Mat raw = new Mat(sz.height,sz.width,CvType.CV_8UC4);
        raw.put(0, 0, data);
        Mat targ = Highgui.imdecode(raw, 0);

        orig = new Mat();
        Imgproc.cvtColor(targ, orig, Imgproc.COLOR_GRAY2RGB);
        //Imgproc.cvtColor(targ, fixed, Imgproc.COLOR_BGR2RGB);

        //now we have the target we want...let's interpolate.
        interp = interpExperiment(orig,interpBy);
        Highgui.imwrite(pictureFile_interp.toString(), interp);

     finally

    


当我尝试该代码时,我得到一个异常:

Provided data element number should be multiple of the Mat channels count (3)

我将有问题的行替换为

Mat raw = new Mat(sz.height,sz.width,CvType.CV_8U);
raw.put(0, 0, data);
Mat targ = Highgui.imdecode(raw, 0);

我可以获得灰度图像。我做错了什么

Mat raw = new Mat(sz.height,sz.width,CvType.CV_8UC3);

?我已经查看了很多解决此问题的 *** 帖子,但没有一个适用于颜色矩阵。非常感谢任何帮助。

【问题讨论】:

异常发生在 raw.put(0,0,data);行 【参考方案1】:

我找到了一个解决方法:使用 Bitmapfactory,您可以将 byte[] 数组转换为位图,然后您可以正确地将其转换为 Mat。

Bitmap bmp = BitmapFactory.decodeByteArray(data , 0, data.length);
Mat orig = new Mat(bmp.getHeight(),bmp.getWidth(),CvType.CV_8UC3);
Bitmap myBitmap32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, orig);

Imgproc.cvtColor(orig, orig, Imgproc.COLOR_BGR2RGB,4);

似乎应该有更好的方法,但这是可行的。

【讨论】:

你找到更直接的方法了吗?【参考方案2】:
public Mat Byte_to_Mat(byte[] data) 

    Mat jpegData = new Mat(1, data.length, CvType.CV_8UC1);
    jpegData.put(0, 0, data);


    Mat bgrMat = new Mat();
    bgrMat = Highgui.imdecode(jpegData, Highgui.IMREAD_COLOR);

【讨论】:

此代码有效。我不知道如何使用Highgui.imdecode 但现在我知道了:) 谢谢@Idol 我不知道这怎么没有得到更多的选票。这对我有用,但遗憾的是它比解码为位图要慢:(【参考方案3】:

使用时:

raw.put(0, 0, data);

您通常会在点 (0,0) 处设置像素的所有通道值;因此,如果您有一个 3 通道图像,那么您将提供一个包含三个值的字节数组,例如:

byte data[] = 1,2,3

您可以一次设置多个像素,但关键是您的数据数组需要是多个通道,否则 opencv 将不知道查看所有像素值的内容。因此,例如,对于 3 通道 Mat,您可以:

byte data[] = 1,2,3,4,5,6; 

这会将像素值 (0,0) 设置为 (1,2,3) 并将 (0,1) 设置为 (4,5,6)

但不是:

byte data[] = 1,2,3,4,5,6,7;

因为这是 7 个元素,不是 3 的倍数。

您看到的错误是因为您的数据数组长度不是通道数的倍数。

您应该检查数据数组的实际格式。根据我在设备上的经验,它往往是 YUV,它与 RGB 具有不同的尺寸,因此需要进行一些转换。

【讨论】:

啊,这是有道理的——我只是不确定 Mat 的正确结构是什么。不过,将数据格式设为 YUV 是有意义的。【参考方案4】:

您将获得的数据很可能是YUV 格式。一般为1通道矩阵,如果是RGB或灰度,宽度相同,高度为图像高度的1.5倍。

Mat raw = new Mat(sz.height*1.5,sz.width,CvType.CV_8UC1); // YUV data
raw.put(0, 0, data);
orig = new Mat(sz.height, sz.height, CvType.CV_8UC4); // RGBA image
Imgproc.cvtColor(raw, orig, Imgproc.COLOR_YUV2RGBA_NV21); // This might vary depending on the camera image type

【讨论】:

谢谢! Mat 类似乎没有采用 (double,int,int) 的构造函数,因此我将 1.5*sz.height 转换为整数并进行了尝试。结果是一个完全绿色的图像。 转换为 RGBA 后?还是您保存了原始 Mat? 我尝试了发布的确切代码,结果是绿色图像。我认为类型转换中有些东西搞砸了(即您发布的第 4 行)。我正在使用 Nexus 5。我想我在某处看到这款手机保存为 YUV...我转换为位图,根据我最近的帖子它运行良好。【参考方案5】:

@user3502402 所做的更改是绝对正确的。您只需将 Highgui.imdecode(raw, 1) 中的标志从 0 更改为 1,代码即可提供完美的彩色照片

【讨论】:

【参考方案6】:

正确答案是===>

int width = camera.getParameters().getPreviewSize().width; // 获取相机预览尺寸的宽度

int height = camera.getParameters().getPreviewSize().height; // 获取相机预览尺寸的高度

Mat mat = new Mat(height + height/2,width, CvType.CV_8UC1); //为NV21 byte[]创建mat对象

mat.put(0, 0, 字节); //将byte[]放入mat生成raw mat

Mat mRgba = new Mat(); //创建新的mat对象,将NV21 mat转换为RGBA

Imgproc.cvtColor(mat, mRgba, Imgproc.COLOR_YUV2RGB_NV21,4); //将mat转换成新的rgba mat

Bitmap bitmap = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888); //创建与相机预览大小相同的位图。哦。它会抛出错误。

Utils.matToBitmap(mRgba,bitmap); // 最后将 mat 对象转换为位图。

你好啊……

在个人项目上进行测试,它正在 100% 工作

【讨论】:

让我知道您在上面的代码中遇到了什么问题。然后投票;)

以上是关于Android将字节数组从Camera API转换为颜色Mat对象openCV的主要内容,如果未能解决你的问题,请参考以下文章

将 Android camera2 api YUV_420_888 转换为 RGB

Android JNI:将cv :: Mat转换为jbyteArray

在Android camera2下将YUV_420_888转换为位图的图像不正确

使用 Android Camera2 API 进行人脸检测和画圆

有没有办法在android studio中将音频文件转换为字节数组

无法将文件路径转换为字节数组android [重复]