如何将图像 uri 转换为 cv::Mat

How to convert an image uri to cv::Mat

我正在尝试创建一个简单的 Android 应用程序:

  1. 启动主程序 activity 以使用相机拍摄照片,然后
  2. 打开一个新的 activity 对您刚刚拍摄的照片执行图像处理(通过 opencv)。

主要 activity 的 class 代码在这里:

import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends AppCompatActivity {
    // Used for logging success or failure messages
    private static final String TAG = "MyApp::CaptureActivity";
    public static final String EXTRA_IMAGE_URI = "com.my.app.IMAGE_URI";
    private static final int REQUEST_IMAGE_CAPTURE = 1;
    private String mCurrentImageFilename;
    public Uri mImageUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i(TAG, "called onCreate");
        setContentView(R.layout.activity_main);
        dispatchTakePictureIntent();
    }

    private void dispatchTakePictureIntent() {
        Log.i(TAG, "Dispatching Intent to capture an image.");
        Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // Ensure that there's a camera activity to handle the intent
        if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
            Log.i(TAG, "Found camera activity to handle intent.");
            // Create the File where the photo should go
            File photoFile = null;
            try {
                photoFile = createImageFile();
            } catch (IOException ex) {
                // Error occurred while creating the File
                Log.i(TAG, "There was an error creating the file");
            }
            // Continue only if the File was successfully created
            if (photoFile != null) {
                mImageUri = FileProvider.getUriForFile(this,
                        "com.my.app.fileprovider",
                        photoFile);
                takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
            }
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            Log.i(TAG, "Image Capture Complete");
            Intent intent = new Intent(this, AnalyzeImageActivity.class);
            intent.putExtra(EXTRA_IMAGE_URI, mImageUri.toString());
            startActivity(intent);
        }
    }

    private File createImageFile() throws IOException {
        Log.i(TAG, "Creating Image File in directory...");
        // Create an image file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        File image = File.createTempFile(
                imageFileName,  /* prefix */
                ".jpg",         /* suffix */
                storageDir      /* directory */
        );

        // Save a file: path for use with ACTION_VIEW intents
        mCurrentImageFilename = imageFileName;
        return image;
    }

}

那么第二个activity就是AnalyzeImageActivity:

import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

import java.io.File;
import java.io.IOException;

public class AnalyzeImageActivity extends AppCompatActivity {

    private static final String TAG = "MyApp::AnalyzeImageActivity";
    private Uri mImageUri;
    private ImageView mMainImage;
    Mat mImageMatrix;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "Creating AnalyzeImageActivity");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_analyze_image);

        Log.i(TAG, "Parsing Intent to get asset URI");
        Intent intent = getIntent();
        mImageUri = Uri.parse(intent.getStringExtra(MainActivity.EXTRA_IMAGE_URI));

        Log.i(TAG, "Converting to OpenCV Assets");
        Bitmap bitmap = null;
        try {
            bitmap = Bitmap.createBitmap(MediaStore.Images.Media.getBitmap(getContentResolver(), mImageUri));
        } catch (IOException e) {
            e.printStackTrace();
        }
        mImageMatrix = new Mat (bitmap.getHeight(), bitmap.getWidth(), CvType.CV_8UC1);
        Utils.bitmapToMat(bitmap, mImageMatrix);

        Log.i(TAG, "Sending to ImageView");
        mMainImage = findViewById(R.id.cvImage);
        mMainImage.setImageURI(mImageUri);
        mMainImage.setRotation(90);


    }

    public void captureNewImage(View v) {
        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
    }
}

当我 运行 这段代码时,启动相机和保存照片效果很好——但是当第二个屏幕打开时, Log.i(TAG, "Converting to OpenCV Assets"); 下面的代码导致应用程序崩溃。该应用会引发一般性 "application has stopped" 错误。

来自 ADB 的调试是:

04-18 19:39:35.162 1763-1763/com.my.app I/MyApp::AnalyzeImageActivity: Creating AnalyzeImageActivity
04-18 19:39:35.178 1763-1763/com.my.app I/MyApp::AnalyzeImageActivity: Parsing Intent to get asset URI
    Converting to OpenCV Assets
04-18 19:39:35.621 1763-1763/com.my.app E/art: No implementation found for long org.opencv.core.Mat.n_Mat(int, int, int) (tried Java_org_opencv_core_Mat_n_1Mat and Java_org_opencv_core_Mat_n_1Mat__III)
04-18 19:39:35.622 1763-1763/com.my.app D/AndroidRuntime: Shutting down VM


    --------- beginning of crash
04-18 19:39:35.622 1763-1763/com.my.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.my.app, PID: 1763
    java.lang.UnsatisfiedLinkError: No implementation found for long org.opencv.core.Mat.n_Mat(int, int, int) (tried Java_org_opencv_core_Mat_n_1Mat and Java_org_opencv_core_Mat_n_1Mat__III)
        at org.opencv.core.Mat.n_Mat(Native Method)
        at org.opencv.core.Mat.<init>(Mat.java:39)
        at com.my.app.AnalyzeImageActivity.onCreate(AnalyzeImageActivity.java:46)
        at android.app.Activity.performCreate(Activity.java:6687)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2631)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2743)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1490)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6165)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:888)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:778)

看起来这个 cv::Mat 构造函数没有实现,但这直接来自 OpenCV - 谁能帮我弄清楚如何做到这一点?

谢谢!

您应该在您的设备上安装 OpenCV 管理器并在代码中对其进行初始化。

见亲戚 answer