【问题标题】:How to get the Mat object from the Byte[] in openCV android?如何从 openCV android 中的 Byte[] 获取 Mat 对象?
【发布时间】:2014-02-02 11:47:57
【问题描述】:

我正在使用 Android 中的 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);
    }
}

因为我希望将图像数据进一步用于图像处理,而不是保存和重新加载图像。

从 Byte 数组中获取 Mat 对象的最有效方法是什么? 我已经尝试过这些方法:

  1. 不知道图像发生了什么。

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

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

我在保存图像以供将来使用时也没有任何问题,但这会导致我出现异常,因为当我使用以前存储的图像时,该文件尚未生成。

【问题讨论】:

    标签: java android opencv image-processing bitmap


    【解决方案1】:

    您必须指定图像/Mat 的宽度和高度以及通道深度。

    Mat mat = new Mat(width, height, CvType.CV_8UC3);
    mat.put(0, 0, data);
    

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

    【讨论】:

    • 你能定义数据吗?它是什么?
    • databyte[] 数组,其中包含一系列格式正确的像素。它可以从例如获得。 BufferedImage - byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
    • 高度和宽度参数我猜是错误的。 Mat mat = new Mat(height, width CvType.CV_8UC3);
    【解决方案2】:

    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 的形式出现。

    【讨论】:

      【解决方案3】:

      最好和最简单的方法是这样的:

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

      【讨论】:

      • 我看到这个粘贴在很多类似的问题上,但它会导致与内存相关的崩溃。当您的图像大于预期的 Mat 输出时,这似乎不是一个可行的解决方案。
      【解决方案4】:

      对我来说,下一个对我来说很好:

      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);
      
      }
      

      【讨论】:

        【解决方案5】:

        您可以使用作为 opencv 一部分的 imdecode 方法(这是用于 emgucv 但它应该在其他版本的 opencv 上具有类似的操作,语法可能会有所不同)

        例子:

        byte [] imageArray
        Mat dest
        
        CvInvoke.Imdecode(imageArray, ImreadModes.Unchanged, dest)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-04-11
          • 2014-07-06
          • 1970-01-01
          • 1970-01-01
          • 2012-12-27
          • 2017-01-01
          • 1970-01-01
          • 2013-01-01
          相关资源
          最近更新 更多