3、使用Java api 和 jni混合方式调用OpenCV

<div style="font-family:'Helvetica Neue';font-size:14px;"></div><div><pre name="code" class="java"><pre name="code" class="java"><pre name="code" class="java">int a =b;
 
  
 
 
 
 


如果想在项目中直接使用opencv的java api 并且也需要自己编写c++,那么就需要Java Api与Jni混用,下面就以人脸检测为例,实验一些混合方式
一、创建项目
     创建项目FaceDetection


二、添加opencv的java api
     1、再项目中创建文件夹libopencv用来存放opencv的库module
     2、将 Android/OpenCV-android-sdk/sdk/java 复制到libopencv目录中,并将其改名opencv
 
     3、打开settings.gradle添加 include   ':libopencv:opencv并点击Sync Now
     4、在opencv中创建build.gradle文件,并将以下内容复制进去,注意按要求 替换内容然后点击Sync Now
apply plugin:'android-library'

buildscript{
    repositories{
        mavenCentral()
    }
    dependencies{
        classpath 'com.android.tools.build:gradle:1.3.0' // 和项目/build.gradle中的一致
    }
}

android{
    compileSdkVersion 22            //与 app/build.gradle中的一致
    buildToolsVersion "22.0.1"       //与 app/build.gradle中的一致

    defaultConfig {
        minSdkVersion 15             //与 app/build.gradle中的一致
        targetSdkVersion 22          //与 app/build.gradle中的一致
        versionCode 2411            //改成自己下的opencv的版本
        versionName "2.4.11"        //改成自己下的opencv的版本
    }

    sourceSets{
        main{
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            res.srcDirs = ['res']
            aidl.srcDirs = ['src']
        }
    }
}
      5、为app添加opencv依赖,在app上右键 open module settings,将opencv加进去

     
三、添加Opencv Face Detection Jni
1、打开opencv提供的人脸识别示例,将samples/face-detectioin/src/org/opencv/samples/facedetect/DetectionBasedTracker.java文件拷贝到app中包下,注意java文件package修改成当前的包
     错误是因为并没有native文件与之关联
     2、在app中创建autojavah.sh文件,用来创建jni文件夹及.h文件,内容如下:

#!/bin/sh
export ProjectPath=$(cd "../$(dirname "$1")"pwd)
export TargetClassName="com.lingyun.facedetection.DetectionBasedTracker" #换成你的包名.含有native方法的类名
export SourceFile="${ProjectPath}/app/src/main/java"    #java源文件目录
export TargetPath="${ProjectPath}/app/src/main/jni"     #输出jni文件目录
cd "${SourceFile}"
javah -d ${TargetPath} -classpath "${SourceFile}" "${TargetClassName}"
echo -d ${TargetPath} -classpath 
"${SourceFile}" "${TargetClassName}"

     3、右键运行autojavah.sh文件,如果没有插件,android Studio会提示是否下载安装插件
          此时可以看到多了jni目录以及一个.h文件

     4、将 OpenCV-android-sdk/samples/face-detection/jni中的.cpp 和.mk文件复制到jni目录中
          修改.cpp中的include头文件 #include <com_lingyun_facedetection_DetectionBasedTracker.h>
          修改函数名为.h中的函数名,这里有6个函数
          修改Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=off
OPENCV_LIB_TYPE:=STATIC
下面一行换成自己的opencvsdk
include /Users/lichuanpeng/Documents/Program_File/Android/OpenCV-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_SRC_FILES  := DetectionBasedTracker_jni.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_LDLIBS     += -lm -llog
LOCAL_MODULE     := detection_based_tracker
include $(BUILD_SHARED_LIBRARY)
          修改Application.mk文件
APP_STL:=gnustl_static
APP_CPPFLAGS:=-frtti -fexceptions
APP_ABI := armeabi armeabi-v7a x86 mips
APP_PLATFORM := android-8

     5、配置app的build.gradle
          我的配置是
apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.lingyun.facedetecttest"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
          这是添加的
        ndk{
            moduleName "app"
        }
    }
      这是添加的
    sourceSets.main {
        jniLibs.srcDir 'src/main/jnilibs'
        jni.srcDirs = [] //disable automatic ndk-build call
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:22+'
    compile project(':opencvlibs:opencv')
}


     6、新增NDK_BUILD 工具
          点击Android Studio->Preferences->External Tools 点击+新增
新增 NDK Build
Name: NDK Build
Group: NDK
Description: NDK Build
Options: 全打勾
Show in: 全打勾
Tools Settings:
Program: NDK目錄/ndk-build
Parameters: NDK_PROJECT_PATH=$ModuleFileDir$/build/intermediates/ndk NDK_LIBS_OUT=$ModuleFileDir$/src/main/jniLibs NDK_APPLICATION_MK=$ModuleFileDir$/src/main/jni/Application.mk APP_BUILD_SCRIPT=$ModuleFileDir$/src/main/jni/Android.mk V=1
Working directory: $SourcepathEntry$ 

     7、在app上右键点击NDK NDK Build
          可以看到多出来jniLibs目录
     8、将 OpenCV-android-sdk/sdk/native/libs  目录里面四个文件夹中的libopencv_java.so分别对应放在刚才生成的目录中,因为java api需要这些。

四、添加布局文件及activity和权限
     1、将 OpenCV-android-sdk/samples/face-detection/res/layout/face_detect_surface_view.xml 文件复制到app中的layout目录中
     2、在res中创建raw目录,并将 OpenCV-android-sdk/samples/face-detection/res/raw/lbpcascade_frontalface.xml 文件复制到raw中
     3、修改MainActivity      


import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.objdetect.CascadeClassifier;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
import com.lingyun.facedetection.R;

public class MainActivity extends AppCompatActivity implements CvCameraViewListener2{

    private static final String    TAG                 = "OCVSample::Activity";
    private static final Scalar    FACE_RECT_COLOR     = new Scalar(0, 255, 0, 255);
    public static final int        JAVA_DETECTOR       = 0;
    public static final int        NATIVE_DETECTOR     = 1;

    private MenuItem               mItemFace50;
    private MenuItem               mItemFace40;
    private MenuItem               mItemFace30;
    private MenuItem               mItemFace20;
    private MenuItem               mItemType;

    private Mat                    mRgba;
    private Mat                    mGray;
    private File                   mCascadeFile;
    private CascadeClassifier      mJavaDetector;
    private DetectionBasedTracker  mNativeDetector;

    private int                    mDetectorType       = JAVA_DETECTOR;
    private String[]               mDetectorName;

    private float                  mRelativeFaceSize   = 0.2f;
    private int                    mAbsoluteFaceSize   = 0;

    private CameraBridgeViewBase   mOpenCvCameraView;

    static {
        if(!OpenCVLoader.initDebug()){
            Log.d("MyDebug","Falied");
        }else{
            Log.d("MyDebug","success");
            System.loadLibrary("opencv_java");
        }
    }

    public void doDetect(){
        // Load native library after(!) OpenCV initialization
        System.loadLibrary("detection_based_tracker");//

        try {
            // load cascade file from application resources
            InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
            File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
            mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
            FileOutputStream os = new FileOutputStream(mCascadeFile);

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            is.close();
            os.close();

            mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
            if (mJavaDetector.empty()) {
                Log.e(TAG, "Failed to load cascade classifier");
                mJavaDetector = null;
            } else
                Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());

            mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);

            cascadeDir.delete();

        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
        }

        mOpenCvCameraView.enableView();
    }

    public MainActivity() {
        mDetectorName = new String[2];
        mDetectorName[JAVA_DETECTOR] = "Java";
        mDetectorName[NATIVE_DETECTOR] = "Native (tracking)";

        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.face_detect_surface_view);

        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.fd_activity_surface_view);
        mOpenCvCameraView.setCvCameraViewListener(this);
        doDetect();
    }

    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        // OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        mOpenCvCameraView.disableView();
    }

    public void onCameraViewStarted(int width, int height) {
        mGray = new Mat();
        mRgba = new Mat();
    }

    public void onCameraViewStopped() {
        mGray.release();
        mRgba.release();
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        if (mAbsoluteFaceSize == 0) {
            int height = mGray.rows();
            if (Math.round(height * mRelativeFaceSize) > 0) {
                mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
            }
            mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
        }

        MatOfRect faces = new MatOfRect();

        if (mDetectorType == JAVA_DETECTOR) {
            if (mJavaDetector != null)
                mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
                        new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
        }
        else if (mDetectorType == NATIVE_DETECTOR) {
            if (mNativeDetector != null)
                mNativeDetector.detect(mGray, faces);
        }
        else {
            Log.e(TAG, "Detection method is not selected!");
        }

        Rect[] facesArray = faces.toArray();
        for (int i = 0; i < facesArray.length; i++)
            Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);

        return mRgba;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.i(TAG, "called onCreateOptionsMenu");
        mItemFace50 = menu.add("Face size 50%");
        mItemFace40 = menu.add("Face size 40%");
        mItemFace30 = menu.add("Face size 30%");
        mItemFace20 = menu.add("Face size 20%");
        mItemType   = menu.add(mDetectorName[mDetectorType]);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
        if (item == mItemFace50)
            setMinFaceSize(0.5f);
        else if (item == mItemFace40)
            setMinFaceSize(0.4f);
        else if (item == mItemFace30)
            setMinFaceSize(0.3f);
        else if (item == mItemFace20)
            setMinFaceSize(0.2f);
        else if (item == mItemType) {
            int tmpDetectorType = (mDetectorType + 1) % mDetectorName.length;
            item.setTitle(mDetectorName[tmpDetectorType]);
            setDetectorType(tmpDetectorType);
        }
        return true;
    }

    private void setMinFaceSize(float faceSize) {
        mRelativeFaceSize = faceSize;
        mAbsoluteFaceSize = 0;
    }

    private void setDetectorType(int type) {
        if (mDetectorType != type) {
            mDetectorType = type;

            if (type == NATIVE_DETECTOR) {
                Log.i(TAG, "Detection Based Tracker enabled");
                mNativeDetector.start();
            } else {
                Log.i(TAG, "Cascade detector enabled");
                mNativeDetector.stop();
            }
        }
    }
     }

     4、添加摄像机权限
 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.lingyun.facedetection" >

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    <supports-screens android:resizeable="true"
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:anyDensity="true" />

    <uses-sdk android:minSdkVersion="8" />

    <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"/>

</manifest>

五、调试
     运行项目
   







     

猜你喜欢

转载自blog.csdn.net/li460998973/article/details/50733331
今日推荐