如何在OpenCV Android中从Byte[]获取Mat对象?

15

我在安卓中使用OpenCV库。我有一个实现了PictureCallBack接口的类。

重写方法onPictureTaken()如下所示,

     @Override
public void onPictureTaken(byte[] data, Camera camera) {
    Log.i(TAG, "Saving a bitmap to file");
    // The camera preview was automatically stopped. Start it again.
    mCamera.startPreview();
    mCamera.setPreviewCallback(this);

    // Write the image in a file (in jpeg format)
    try {
        FileOutputStream fos = new FileOutputStream(mPictureFileName);
        fos.write(data);
        fos.close();

    } catch (java.io.IOException e) {
        Log.e("PictureDemo", "Exception in photoCallback", e);
    }
}

我希望能够在图像处理中进一步使用图像数据,而不是保存和重新加载图像。

如何以最有效的方式从字节数组中获取Mat对象? 我已经尝试过以下方法:

  1. 不知道图片出了什么问题。

    Mat m=new Mat(); m.put(0,0,data);

  2. 将其转换为位图,然后使用 bitmapToMat()。 在这种情况下,红色变成了蓝色。

我也没有保存图像供未来使用的问题,但当我使用之前存储的图像时,会出现异常,因为文件还没有生成。

5个回答

20
您需要指定图像/Mat的宽度、高度和通道深度。
Mat mat = new Mat(width, height, CvType.CV_8UC3);
mat.put(0, 0, data);

请确保您正在使用正确类型的Mat。也许您的数据不是3字节的RGB格式,您应该使用另一种类型,例如CvType.CV_8UC1
祝你好运!


请问您能否定义数据?它是什么? - Qadir Hussain
data 是一个 byte[] 数组,其中包含适当格式的一系列像素。它可以从例如 BufferedImage 中获取 - byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); - lukk
1
我猜高度和宽度参数是错误的。Mat mat = new Mat(height, width, CvType.CV_8UC3); - shantanu

14

最好和最简单的方法如下:

byte[] bytes = FileUtils.readFileToByteArray(new File("aaa.jpg"));
Mat mat = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);

1
我看到这个被贴在很多类似的问题上,但它会导致与内存相关的崩溃。当您有一个比预期的Mat输出更大的图像时,这似乎不是一种可行的解决方案。 - Abandoned Cart

1

OpenCV有一种简洁的方式将Mats写入文件——它可以根据提供的文件扩展名生成不同的格式。以下是一个最小示例:

    public void writeImageToFile(Mat image, String filename) {

    File root = Environment.getExternalStorageDirectory();
    File file = new File(root, filename);

    Highgui.imwrite(file.getAbsolutePath(), image);

    if (DEBUG)
        Log.d(TAG,
                "writing: " + file.getAbsolutePath() + " (" + image.width()
                        + ", " + image.height() + ")");
}

如果红色和蓝色被交换了,那么从onPictureTaken()获取的字节数据就是BGRA格式。您可以使用以下代码将其转换为RGBA格式:
Imgproc.cvtColor(bgrImg, rgbImg, Imgproc.COLOR_BGR2RGB);

实际上,格式是设备特定的 - 在某些设备上,它以YUV的形式传输。


0

对我来说,下面的代码可以正常工作:

Java端:

    Bitmap bitmap = mTextureView.getBitmap(mWidth, mHeight);
    int[] argb = new int[mWidth * mHeight];
    // get ARGB pixels and then proccess it with 8UC4 OpenCV convertion
    bitmap.getPixels(argb, 0, mWidth, 0, 0, mWidth, mHeight);
    // native method (NDK or CMake)
    processFrame8UC4(argb, mWidth, mHeight);

OpenCV 部分(NDK)

JNIEXPORT jint JNICALL com_native_detector_Utils_processFrame8UC4
    (JNIEnv *env, jobject object, jint width, jint height, jintArray frame) {

    jint *pFrameData = env->GetIntArrayElements(frame, 0);
    // it is the line:
    Mat mFrame = Mat(height,width,CV_8UC4,pFrameData).clone();
    // your code..
    env->ReleaseIntArrayElements(frame, pFrameData, 0);

}

0

你可以使用imdecode方法,这是opencv的一部分(对于emgucv来说是如此,但在其他版本的opencv上应该有类似的操作,语法可能会略有不同)

例如:

byte [] imageArray
Mat dest

CvInvoke.Imdecode(imageArray, ImreadModes.Unchanged, dest)

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