android中利用opencv进行图像识别

    xiaoxiao2021-03-25  143

    之前开发的时候老大让研究下图像识别的功能,同事推荐看看opencv,发现对于移动端来说opencv的资料和demo都比较少,现在整理下之前的工作成果。 首先是进行配置工作,先导入opencv的一个代码模块 之后是导入opencv的具体的算法,当然是c++写的

    配置完毕后开始进行正式的代码阶段,首先权限设置,主要就是摄像头权限的获取

    <uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false" /> <uses-feature android:name="android.hardware.camera.front" android:required="false" /> <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false" />

    接下来布局方面

    <?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.example.imgrecognition.ImgRecognitionActivity"> <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" /> </RelativeLayout>

    我们只需要添加一个JavaCameraView控件就可以,这个控件是opencv提供的,继承了SurfaceView。 回到Activity中,在初始化JavaCameraView后,我们需要为其设置一个监听事件

    JavaCameraView jcv = (JavaCameraView) findViewById(R.id.jcv); jcv.setVisibility(SurfaceView.VISIBLE); jcv.setCvCameraViewListener(this);

    需要实现的方法为

    @Override public void onCameraViewStarted(int width, int height) { } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { return null; }

    从名字上我们可以看出来,前两个方法分别是在摄像头获取影像和停止获取时调用,而第三个方法则是摄像头获取的每一帧画面后回调,我们进行图像识别就是主要在第三个方法中实现。 在开始使用opencv的功能前还要进行它的初始化的工作

    @Override protected void onResume() { super.onResume(); OpenCVLoader.initDebug(); mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS); } private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { case LoaderCallbackInterface.SUCCESS: { jcv.enableView(); } break; default: { super.onManagerConnected(status); } break; } } }; @Override protected void onPause() { super.onPause(); if (jcv != null) jcv.disableView(); } @Override protected void onDestroy() { super.onDestroy(); if (jcv != null) jcv.disableView(); }

    接着我们在onCameraViewStarted方法中设置下我们需要识别的图片,我就随便找了几张卡牌游戏的图片放进去了,当然了我们也可以从网上来获取图片

    // The filters. private Filter[] mImageDetectionFilters; private int[] mImgs = {R.mipmap.a, R.mipmap.b, R.mipmap.c, R.mipmap.d, R.mipmap.e}; @Override public void onCameraViewStarted(int width, int height) { int i = 0; mImageDetectionFilters = new Filter[mImgs.length]; for (int mImg : mImgs) { Filter starryNight = null; try { starryNight = new ImageDetectionFilter(this, mImg); } catch (IOException e) { e.printStackTrace(); } mImageDetectionFilters[i] = starryNight; i++; } }

    接着在onCameraFrame中进行图像对比

    private long lastTime; /** * describe 管理发送消息的线程池 */ private ExecutorService mThreadPool = Executors.newCachedThreadPool(); @Override public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) { final Mat rgba = inputFrame.rgba(); long time = System.currentTimeMillis() / 1000; if (time > lastTime) { if (mImageDetectionFilters != null) { for (int i = 0; i < mImageDetectionFilters.length; i++) { final int y = i; mThreadPool.execute(new Runnable() { @Override public void run() { if (mImageDetectionFilters[y].match(rgba, rgba)) { h.sendEmptyMessage(y); } } }); } } } lastTime = time; return rgba; }

    因为图片识别需要大量的计算,十分消耗内存,不注意的话很容易造成卡顿甚至是程序崩溃,所以在这里我让他一秒进行一次匹配,而且具体的计算过程是利用线程池进行,如果匹配成功的话,则利用Handler发送消息

    boolean isFinish; private Handler h = new Handler() { @Override public void handleMessage(Message msg) { if (!isFinish) { int i = msg.what; Intent intent = new Intent(); intent.putExtra("data", i); setResult(RESULT_OK, intent); isFinish = true; finish(); } super.handleMessage(msg); } };

    经过测试,识别的准确率应该在70%~80%左右。但是对于它使用的具体算法还是没有太搞懂,需要进一步学习

    Demo只能识别在资源目录下的那几张图片,运行Demo后摄像头里要有那几张图片才会发生作用 点击下载Demo

    转载请注明原文地址: https://ju.6miu.com/read-3672.html

    最新回复(0)