在OpenCV上进行ORB匹配

时间:2018-01-02 06:35:54

标签: android opencv computer-vision orb

我正在尝试学习计算机视觉,特别是在物体识别和图像匹配方面。我遇到过各种方法,如SIFT,SURF和ORB。到目前为止,我尝试在Android中使用开放式CV并找到此tutorial

这是代码初始化openCV:

private void initializeOpenCVDependencies() throws IOException {
    mOpenCvCameraView.enableView();
    detector = FeatureDetector.create(FeatureDetector.ORB);
    descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
    matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
    img1 = new Mat();
    AssetManager assetManager = getAssets();
    InputStream istr = assetManager.open("a.jpeg");
    Bitmap bitmap = BitmapFactory.decodeStream(istr);
    Utils.bitmapToMat(bitmap, img1);
    Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
    img1.convertTo(img1, 0); //converting the image to match with the type of the cameras image
    descriptors1 = new Mat();
    keypoints1 = new MatOfKeyPoint();
    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

}

以及我用来识别对象的代码:

 public Mat recognize(Mat aInputFrame) {

    Imgproc.cvtColor(aInputFrame, aInputFrame, Imgproc.COLOR_RGB2GRAY);
    descriptors2 = new Mat();
    keypoints2 = new MatOfKeyPoint();
    detector.detect(aInputFrame, keypoints2);
    descriptor.compute(aInputFrame, keypoints2, descriptors2);

    // Matching
    MatOfDMatch matches = new MatOfDMatch();
    if (img1.type() == aInputFrame.type()) {
        matcher.match(descriptors1, descriptors2, matches);
    } else {
        return aInputFrame;
    }
    List<DMatch> matchesList = matches.toList();

    Double max_dist = 0.0;
    Double min_dist = 100.0;

    for (int i = 0; i < matchesList.size(); i++) {
        Double dist = (double) matchesList.get(i).distance;
        if (dist < min_dist)
            min_dist = dist;
        if (dist > max_dist)
            max_dist = dist;
    }

    LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
    for (int i = 0; i < matchesList.size(); i++) {
        if (matchesList.get(i).distance <= (1.5 * min_dist))
            good_matches.addLast(matchesList.get(i));
    }

    MatOfDMatch goodMatches = new MatOfDMatch();
    goodMatches.fromList(good_matches);
    Mat outputImg = new Mat();
    MatOfByte drawnMatches = new MatOfByte();
    if (aInputFrame.empty() || aInputFrame.cols() < 1 || aInputFrame.rows() < 1) {
        return aInputFrame;
    }
    Features2d.drawMatches(img1, keypoints1, aInputFrame, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
    Imgproc.resize(outputImg, outputImg, aInputFrame.size());

    return outputImg;
}

这是完整的代码:

public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {

/*ImageView imageView1;
Context context;
Bitmap img;*/

private static final String TAG = "OCVSample::Activity";
private int w, h;
private CameraBridgeViewBase mOpenCvCameraView;
TextView tvName;
Scalar RED = new Scalar(255, 0, 0);
Scalar GREEN = new Scalar(0, 255, 0);
FeatureDetector detector;
DescriptorExtractor descriptor;
DescriptorMatcher matcher;
Mat descriptors2,descriptors1;
Mat img1;
MatOfKeyPoint keypoints1,keypoints2;

static {
    if (!OpenCVLoader.initDebug())
        Log.d("ERROR", "Unable to load OpenCV");
    else
        Log.d("SUCCESS", "OpenCV loaded");
}

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV loaded successfully");
                mOpenCvCameraView.enableView();
                try {
                    initializeOpenCVDependencies();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            break;
            default: {
                super.onManagerConnected(status);
            }
            break;
        }
    }
};

private void initializeOpenCVDependencies() throws IOException {
    mOpenCvCameraView.enableView();
    detector = FeatureDetector.create(FeatureDetector.ORB);
    descriptor = DescriptorExtractor.create(DescriptorExtractor.ORB);
    matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMING);
    img1 = new Mat();
    AssetManager assetManager = getAssets();
    InputStream istr = assetManager.open("a.jpeg");
    Bitmap bitmap = BitmapFactory.decodeStream(istr);
    Utils.bitmapToMat(bitmap, img1);
    Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGB2GRAY);
    img1.convertTo(img1, 0); //converting the image to match with the type of the cameras image
    descriptors1 = new Mat();
    keypoints1 = new MatOfKeyPoint();
    detector.detect(img1, keypoints1);
    descriptor.compute(img1, keypoints1, descriptors1);

}

public MainActivity() {

    Log.i(TAG, "Instantiated new " + this.getClass());
}
private static final int CAMERA_PERMISSION_CONSTANT = 100;
private static final int REQUEST_PERMISSION_SETTING = 101;
private boolean sentToSettings = false;
private SharedPreferences permissionStatus;
@Override
protected void onCreate(Bundle savedInstanceState) {
    //System.loadLibrary("opencv_java3");

    /*imageView1 = findViewById(R.id.imageView1);

    img = BitmapFactory.decodeResource(this.getResources(),R.drawable.bg_image);
    imageView1.setImageBitmap(img);*/

    Log.i(TAG, "called onCreate");
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.activity_main);
    permissionStatus = getSharedPreferences("permissionStatus",MODE_PRIVATE);
    mOpenCvCameraView = findViewById(R.id.tutorial1_activity_java_surface_view);
    startCamera();
    mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
    mOpenCvCameraView.setCvCameraViewListener(MainActivity.this);
    tvName = findViewById(R.id.text1);
}

public void startCamera(){
    if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {
            //Show Information about why you need the permission
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("Need Storage Permission");
            builder.setMessage("This app needs storage permission.");
            builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                    ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);
                }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
            builder.show();
        } else if (permissionStatus.getBoolean(Manifest.permission.CAMERA,false)) {
            //Previously Permission Request was cancelled with 'Dont Ask Again',
            // Redirect to Settings after showing Information about why you need the permission
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setTitle("Need Storage Permission");
            builder.setMessage("This app needs storage permission.");
            builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                    sentToSettings = true;
                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    Uri uri = Uri.fromParts("package", getPackageName(), null);
                    intent.setData(uri);
                    startActivityForResult(intent, REQUEST_PERMISSION_SETTING);
                    Toast.makeText(getBaseContext(), "Go to Permissions to Grant Storage", Toast.LENGTH_LONG).show();
                }
            });
            builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });
            builder.show();
        } else {
            //just request the permission
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);
        }


        SharedPreferences.Editor editor = permissionStatus.edit();
        editor.putBoolean(Manifest.permission.CAMERA,true);
        editor.commit();




    } else {
        //You already have the permission, just go ahead.
        proceedAfterPermission();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == CAMERA_PERMISSION_CONSTANT) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            //The External Storage Write Permission is granted to you... Continue your left job...
            proceedAfterPermission();
        } else {
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.CAMERA)) {
                //Show Information about why you need the permission
                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("Need Storage Permission");
                builder.setMessage("This app needs storage permission");
                builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();


                        ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_CONSTANT);


                    }
                });
                builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
                builder.show();
            } else {
                Toast.makeText(getBaseContext(),"Unable to get Permission",Toast.LENGTH_LONG).show();
            }
        }
    }
}

private void proceedAfterPermission() {
    //We've got the permission, now we can proceed further
    Toast.makeText(getBaseContext(), "We got the Storage Permission", Toast.LENGTH_LONG).show();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == REQUEST_PERMISSION_SETTING) {
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            //Got Permission
            proceedAfterPermission();
        }
    }
}

@Override
protected void onPostResume() {
    super.onPostResume();
    if (sentToSettings) {
        if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            //Got Permission
            proceedAfterPermission();
        }
    }
}
@Override
public void onPause() {
    super.onPause();
    if (mOpenCvCameraView != null)
        mOpenCvCameraView.disableView();
}

@Override
public void onResume() {
    super.onResume();
    if (!OpenCVLoader.initDebug()) {
        Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
    } else {
        Log.d(TAG, "OpenCV library found inside package. Using it!");
        mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
    }
}

public void onDestroy() {
    super.onDestroy();
    if (mOpenCvCameraView != null)
        mOpenCvCameraView.disableView();
}

/*public void toGray(View view) {

    Mat source = new Mat();
    Utils. bitmapToMat( img, source);
    Mat dest = new Mat(source.size(), CvType.CV_8UC1);

    Imgproc. cvtColor(source, dest, Imgproc.COLOR_RGB2GRAY, 4);
    Bitmap btmp = Bitmap.createBitmap(dest.width(),dest.height(),Bitmap.Config.ARGB_8888);
    Utils. matToBitmap(dest,btmp);
    imageView1.setImageBitmap(btmp);
}*/

@Override
public void onCameraViewStarted(int width, int height) {
    w = width;
    h = height;
}

public Mat recognize(Mat aInputFrame) {

    Imgproc.cvtColor(aInputFrame, aInputFrame, Imgproc.COLOR_RGB2GRAY);
    descriptors2 = new Mat();
    keypoints2 = new MatOfKeyPoint();
    detector.detect(aInputFrame, keypoints2);
    descriptor.compute(aInputFrame, keypoints2, descriptors2);

    // Matching
    MatOfDMatch matches = new MatOfDMatch();
    if (img1.type() == aInputFrame.type()) {
        matcher.match(descriptors1, descriptors2, matches);
    } else {
        return aInputFrame;
    }
    List<DMatch> matchesList = matches.toList();

    Double max_dist = 0.0;
    Double min_dist = 100.0;

    for (int i = 0; i < matchesList.size(); i++) {
        Double dist = (double) matchesList.get(i).distance;
        if (dist < min_dist)
            min_dist = dist;
        if (dist > max_dist)
            max_dist = dist;
    }

    LinkedList<DMatch> good_matches = new LinkedList<DMatch>();
    for (int i = 0; i < matchesList.size(); i++) {
        if (matchesList.get(i).distance <= (1.5 * min_dist))
            good_matches.addLast(matchesList.get(i));
    }

    MatOfDMatch goodMatches = new MatOfDMatch();
    goodMatches.fromList(good_matches);
    Mat outputImg = new Mat();
    MatOfByte drawnMatches = new MatOfByte();
    if (aInputFrame.empty() || aInputFrame.cols() < 1 || aInputFrame.rows() < 1) {
        return aInputFrame;
    }
    Features2d.drawMatches(img1, keypoints1, aInputFrame, keypoints2, goodMatches, outputImg, GREEN, RED, drawnMatches, Features2d.NOT_DRAW_SINGLE_POINTS);
    Imgproc.resize(outputImg, outputImg, aInputFrame.size());

    return outputImg;
}
@Override
public void onCameraViewStopped() {

}

@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    return recognize(inputFrame.rgba());
}
}

我在这一行收到错误,导致应用程序在第一次打开时停止:

matcher.match(descriptors1, descriptors2, matches);

这是stacktrace / logcat:

01-02 15:49:11.496 605-30317/? E/QCamera: <HAL><ERROR> static void*01-02 15:49:11.502 30174-30337/com.rahmat.app.opencvandroid E/AndroidRuntime: FATAL EXCEPTION: Thread-4415
                                                                          Process: com.rahmat.app.opencvandroid, PID: 30174
                                                                          CvException [org.opencv.core.CvException: cv::Exception: /build/master_pack-android/opencv/modules/core/src/stat.cpp:4017: error: (-215) type == src2.type() && src1.cols == src2.cols && (type == 5 || type == 0) in function void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool)
                                                                          ]
                                                                              at org.opencv.features2d.DescriptorMatcher.match_1(Native Method)
                                                                              at org.opencv.features2d.DescriptorMatcher.match(DescriptorMatcher.java:220)
                                                                              at com.rahmat.app.opencvandroid.MainActivity.recognize(MainActivity.java:328)
                                                                              at com.rahmat.app.opencvandroid.MainActivity.onCameraFrame(MainActivity.java:374)
                                                                              at org.opencv.android.CameraBridgeViewBase.deliverAndDrawFrame(CameraBridgeViewBase.java:392)
                                                                              at org.opencv.android.JavaCameraView$CameraWorker.run(JavaCameraView.java:373)
                                                                              at java.lang.Thread.run(Thread.java:818)

我认为它与匹配过程有关,任何人都有解决方案吗?或教程/参考/链接将非常感激。

0 个答案:

没有答案