Android开发—基于OpenCV实现相机实时图像识别跟踪

<uses-feature

android:name=“android.hardware.camera.autofocus”

android:required=“false” />

<uses-feature

android:name=“android.hardware.camera.flash”

android:required=“false” />

权限提示方法

private void requestPermissions() {

final int REQUEST_CODE = 1;

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {

ActivityCompat.requestPermissions(this, new String[]{

Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},

REQUEST_CODE);

}

}

界面设计

activity_img_recognition.xml
<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”

xmlns:opencv=“http://schemas.android.com/apk/res-auto”

xmlns:tools=“http://schemas.android.com/tools”

android:id=“@+id/activity_img_recognition”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

tools:context=“com.sueed.imagerecognition.CameraActivity”>

<org.opencv.android.JavaCameraView

android:id=“@+id/jcv”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:visibility=“gone”

opencv:camera_id=“any”

opencv:show_fps=“true” />

主要逻辑代码

CameraActivity.java 【相机启动获取图像和包装MAT相关】

因为OpenCV中JavaCameraView继承自SurfaceView,若有需要可以自定义编写extends SurfaceView implements SurfaceHolder.Callback的xxxSurfaceView替换使用。

package com.sueed.imagerecognition;

import android.Manifest;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.os.Bundle;

import android.util.Log;

import android.view.Menu;

import android.view.MenuItem;

import android.view.SurfaceView;

import android.view.View;

import android.view.WindowManager;

import android.widget.ImageView;

import android.widget.RelativeLayout;

import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import androidx.core.app.ActivityCompat;

import androidx.core.content.ContextCompat;

import com.sueed.imagerecognition.filters.Filter;

import com.sueed.imagerecognition.filters.NoneFilter;

import com.sueed.imagerecognition.filters.ar.ImageDetectionFilter;

import com.sueed.imagerecognition.imagerecognition.R;

import org.opencv.android.CameraBridgeViewBase;

import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;

import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;

import org.opencv.android.JavaCameraView;

import org.opencv.android.OpenCVLoader;

import org.opencv.core.Mat;

import java.io.IOException;

// Use the deprecated Camera class.

@SuppressWarnings(“deprecation”)

public final class CameraActivity extends AppCompatActivity implements CvCameraViewListener2 {

// A tag for log output.

private static final String TAG = CameraActivity.class.getSimpleName();

// The filters.

private Filter[] mImageDetectionFilters;

// The indices of the active filters.

private int mImageDetectionFilterIndex;

// The camera view.

private CameraBridgeViewBase mCameraView;

@Override

protected void onCreate(final Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

//init CameraView

mCameraView = new JavaCameraView(this, 0);

mCameraView.setMaxFrameSize(size.MaxWidth, size.MaxHeight);

mCameraView.setCvCameraViewListener(this);

setContentView(mCameraView);

requestPermissions();

mCameraView.enableView();

}

@Override

public void onPause() {

if (mCameraView != null) {

mCameraView.disableView();

}

super.onPause();

}

@Override

public void onResume() {

super.onResume();

OpenCVLoader.initDebug();

}

@Override

public void onDestroy() {

if (mCameraView != null) {

mCameraView.disableView();

}

super.onDestroy();

}

@Override

public boolean onCreateOptionsMenu(final Menu menu) {

getMenuInflater().inflate(R.menu.activity_camera, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(final MenuItem item) {

switch (item.getItemId()) {

case R.id.menu_next_image_detection_filter:

mImageDetectionFilterIndex++;

if (mImageDetectionFilters != null && mImageDetectionFilterIndex == mImageDetectionFilters.length) {

mImageDetectionFilterIndex = 0;

}

return true;

default:

return super.onOptionsItemSelected(item);

}

}

@Override

public void onCameraViewStarted(final int width, final int height) {

Filter Enkidu = null;

try {

Enkidu = new ImageDetectionFilter(CameraActivity.this, R.drawable.enkidu);

} catch (IOException e) {

e.printStackTrace();

}

Filter akbarHunting = null;

try {

akbarHunting = new ImageDetectionFilter(CameraActivity.this, R.drawable.akbar_hunting_with_cheetahs);

} catch (IOException e) {

Log.e(TAG, "Failed to load drawable: " + “akbar_hunting_with_cheetahs”);

e.printStackTrace();

}

mImageDetectionFilters = new Filter[]{

new NoneFilter(),

Enkidu,

akbarHunting

};

}

@Override

public void onCameraViewStopped() {

}

@Override

public Mat onCameraFrame(final CvCameraViewFrame inputFrame) {

final Mat rgba = inputFrame.rgba();

if (mImageDetectionFilters != null) {

mImageDetectionFilters[mImageDetectionFilterIndex].apply(rgba, rgba);

}

return rgba;

}

}

ImageRecognitionFilter.java【图像特征过滤比对及绘制追踪绿框】

package com.nummist.secondsight.filters.ar;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

import org.opencv.android.Utils;

import org.opencv.calib3d.Calib3d;

import org.opencv.core.Core;

import org.opencv.core.CvType;

import org.opencv.core.DMatch;

import org.opencv.core.KeyPoint;

import org.opencv.core.Mat;

import org.opencv.core.MatOfDMatch;

import org.opencv.core.MatOfKeyPoint;

import org.opencv.core.MatOfPoint;

import org.opencv.core.MatOfPoint2f;

import org.opencv.core.Point;

import org.opencv.core.Scalar;

import org.opencv.features2d.DescriptorExtractor;

import org.opencv.features2d.DescriptorMatcher;

import org.opencv.features2d.FeatureDetector;

import org.opencv.imgcodecs.Imgcodecs;

import org.opencv.imgproc.Imgproc;

import android.content.Context;

import com.nummist.secondsight.filters.Filter;

public final class ImageDetectionFilter implements Filter {

// The reference image (this detector’s target).

private final Mat mReferenceImage;

// Features of the reference image.

private final MatOfKeyPoint mReferenceKeypoints = new MatOfKeyPoint();

// Descriptors of the reference image’s features.

private final Mat mReferenceDescriptors = new Mat();

// The corner coordinates of the reference image, in pixels.

// CvType defines the color depth, number of channels, and

// channel layout in the image. Here, each point is represented

// by two 32-bit floats.

private final Mat mReferenceCorners = new Mat(4, 1, CvType.CV_32FC2);

// Features of the scene (the current frame).

private final MatOfKeyPoint mSceneKeypoints = new MatOfKeyPoint();

// Descriptors of the scene’s features.

private final Mat mSceneDescriptors = new Mat();

// Tentative corner coordinates detected in the scene, in

// pixels.

private final Mat mCandidateSceneCorners = new Mat(4, 1, CvType.CV_32FC2);

// Good corner coordinates detected in the scene, in pixels.

private final Mat mSceneCorners = new Mat(0, 0, CvType.CV_32FC2);

// The good detected corner coordinates, in pixels, as integers.

private final MatOfPoint mIntSceneCorners = new MatOfPoint();

// A grayscale version of the scene.

private final Mat mGraySrc = new Mat();

// Tentative matches of scene features and reference features.

private final MatOfDMatch mMatches = new MatOfDMatch();

// A feature detector, which finds features in images.

private final FeatureDetector mFeatureDetector = FeatureDetector.create(FeatureDetector.ORB);

// A descriptor extractor, which creates descriptors of

// features.

private final DescriptorExtractor mDescriptorExtractor = DescriptorExtractor.create(DescriptorExtractor.ORB);

// A descriptor matcher, which matches features based on their

// descriptors.

private final DescriptorMatcher mDescriptorMatcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE_HAMMINGLUT);

// The color of the outline drawn around the detected image.

private final Scalar mLineColor = new Scalar(0, 255, 0);

public ImageDetectionFilter(final Context context, final int referenceImageResourceID) throws IOException {

// Load the reference image from the app’s resources.

// It is loaded in BGR (blue, green, red) format.

mReferenceImage = Utils.loadResource(context, referenceImageResourceID, Imgcodecs.CV_LOAD_IMAGE_COLOR);

// Create grayscale and RGBA versions of the reference image.

final Mat referenceImageGray = new Mat();

Imgproc.cvtColor(mReferenceImage, referenceImageGray, Imgproc.COLOR_BGR2GRAY);

Imgproc.cvtColor(mReferenceImage, mReferenceImage, Imgproc.COLOR_BGR2RGBA);

// Store the reference image’s corner coordinates, in pixels.

mReferenceCorners.put(0, 0, new double[]{0.0, 0.0});

mReferenceCorners.put(1, 0, new double[]{referenceImageGray.cols(), 0.0});

mReferenceCorners.put(2, 0, new double[]{referenceImageGray.cols(), referenceImageGray.rows()});

mReferenceCorners.put(3, 0, new double[]{0.0, referenceImageGray.rows()});

// Detect the reference features and compute their

// descriptors.

mFeatureDetector.detect(referenceImageGray, mReferenceKeypoints);

mDescriptorExtractor.compute(referenceImageGray, mReferenceKeypoints, mReferenceDescriptors);

}

@Override

public void apply(final Mat src, final Mat dst) {

// Convert the scene to grayscale.

Imgproc.cvtColor(src, mGraySrc, Imgproc.COLOR_RGBA2GRAY);

// Detect the scene features, compute their descriptors,

// and match the scene descriptors to reference descriptors.

mFeatureDetector.detect(mGraySrc, mSceneKeypoints);

mDescriptorExtractor.compute(mGraySrc, mSceneKeypoints, mSceneDescriptors);

mDescriptorMatcher.match(mSceneDescriptors, mReferenceDescriptors, mMatches);

// Attempt to find the target image’s corners in the scene.

findSceneCorners();

// If the corners have been found, draw an outline around the

// target image.

// Else, draw a thumbnail of the target image.

draw(src, dst);

}

private void findSceneCorners() {

final List matchesList = mMatches.toList();

if (matchesList.size() < 4) {

// There are too few matches to find the homography.

return;

}

final List referenceKeypointsList = mReferenceKeypoints.toList();

final List sceneKeypointsList = mSceneKeypoints.toList();

// Calculate the max and min distances between keypoints.

double maxDist = 0.0;

double minDist = Double.MAX_VALUE;

for (final DMatch match : matchesList) {

final double dist = match.distance;

if (dist < minDist) {

minDist = dist;

}

if (dist > maxDist) {

maxDist = dist;

}

}

// The thresholds for minDist are chosen subjectively

// based on testing. The unit is not related to pixel

// distances; it is related to the number of failed tests

// for similarity between the matched descriptors.

if (minDist > 50.0) {

// The target is completely lost.

// Discard any previously found corners.

mSceneCorners.create(0, 0, mSceneCorners.type());

return;

} else if (minDist > 25.0) {

// The target is lost but maybe it is still close.

// Keep any previously found corners.

return;

}

// Iden
tify “good” keypoints based on match distance.

final ArrayList goodReferencePointsList = new ArrayList();

final ArrayList goodScenePointsList = new ArrayList();

final double maxGoodMatchDist = 1.75 * minDist;

for (final DMatch match : matchesList) {

if (match.distance < maxGoodMatchDist) {

goodReferencePointsList.add(referenceKeypointsList.get(match.trainIdx).pt);

goodScenePointsList.add(sceneKeypointsList.get(match.queryIdx).pt);

}

}

if (goodReferencePointsList.size() < 4 || goodScenePointsList.size() < 4) {

// There are too few good points to find the homography.

return;

}

// There are enough good points to find the homography.

// (Otherwise, the method would have already returned.)

// Convert the matched points to MatOfPoint2f format, as

// required by the Calib3d.findHomography function.

final MatOfPoint2f goodReferencePoints = new MatOfPoint2f();

goodReferencePoints.fromList(goodReferencePointsList);

final MatOfPoint2f goodScenePoints = new MatOfPoint2f();

goodScenePoints.fromList(goodScenePointsList);
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料获取→专栏

// Find the homography.

final Mat homography = Calib3d.findHomography(goodReferencePoints, goodScenePoints);

// Use the homography to project the reference corner

// coordinates into scene coordinates.

Core.perspectiveTransform(mReferenceCorners, mCandidateSceneCorners, homography);

// Convert the scene corners to integer format, as required

// by the Imgproc.isContourConvex function.

mCandidateSceneCorners.convertTo(mIntSceneCorners, CvType.CV_32S);

// Check whether the corners form a convex polygon. If not,

// (that is, if the corners form a concave polygon), the

// detection result is invalid because no real perspective can

// make the corners of a rectangular image look like a concave

// polygon!

if (Imgproc.isContourConvex(mIntSceneCorners)) {

// The corners form a convex polygon, so record them as

// valid scene corners.

mCandidateSceneCorners.copyTo(mSceneCorners);

}

}

protected void draw(final Mat src, final Mat dst) {

if (dst != src) {

src.copyTo(dst);
erspectiveTransform(mReferenceCorners, mCandidateSceneCorners, homography);

// Convert the scene corners to integer format, as required

// by the Imgproc.isContourConvex function.

mCandidateSceneCorners.convertTo(mIntSceneCorners, CvType.CV_32S);

// Check whether the corners form a convex polygon. If not,

// (that is, if the corners form a concave polygon), the

// detection result is invalid because no real perspective can

// make the corners of a rectangular image look like a concave

// polygon!

if (Imgproc.isContourConvex(mIntSceneCorners)) {

// The corners form a convex polygon, so record them as

// valid scene corners.

mCandidateSceneCorners.copyTo(mSceneCorners);

}

}

protected void draw(final Mat src, final Mat dst) {

if (dst != src) {

src.copyTo(dst);

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值