深圳幻海软件技术有限公司 欢迎您!

Android基于opencv4.6.0实现人脸识别功能

2023-03-01

前言步骤:1.整合opencv2.获取相机的SurfaceView传到native层去检测(亦或是不断的获取SurfaceView的Bitmap,传到native层)3.检测人脸,在本地保存人脸特征信息4.上传至后台(不实现)人脸识别实现的思路(例:人脸登录)1.人脸信息录入1.1获取相机的Bitm

前言

步骤:

1.整合opencv

2.获取相机的SurfaceView传到native层去检测(亦或是不断的获取SurfaceView的Bitmap,传到native层)

3.检测人脸,在本地保存人脸特征信息

4.上传至后台(不实现)

人脸识别实现的思路(例:人脸登录)

1.人脸信息录入

1.1获取相机的Bitmap,检测人脸(保证人脸信息比较精准) 人脸要足够大,当前范围内人脸只能有一张人脸,正常、眨眼睛、张嘴巴(3张人脸信息)

1.2获取到人脸必须要保存人脸特征信息,然后上传至后台(后台会再次做算法优化),保存到数据库

2.人脸特征值匹配

2.1获取相机的Bitmap,检测人脸(保证人脸信息比较精准) 人脸要足够大,当前范围内人脸只能有一张人脸,正常、眨眼睛、张嘴巴(3张人脸信息)

2.2从后台去查询用户进行登录

一.Android Studio配置opencv

1.opencv资源获取

opencv官网:Home - OpenCV 

opencv最新的版本是4.6.0于2022年06月07日发布,4.6.0网址:OpenCV 4.6.0 Is Now Available! - OpenCV

opencv 4.6.0android sdk 下载链接https://nchc.dl.sourceforge.net/project/opencvlibrary/4.6.0/opencv-4.6.0-android-sdk.zip

2.解压opencv-4.6.0-android-sdk.zip文件

解压之后的文件夹:OpenCV-android-sdk

samples: 所有与android相关的一些示例代码,基本全部是java代码,封装了很多功能(图片转成灰度,高斯模糊,边缘检测)

sdk:所有的资源,so库,头文件,NDK自己动手写

源码下载链接:https://github.com/opencv/opencv/archive/4.6.0.zip

3.新建Android项目(native c++)

C++ Standard 选择C++11

 

 在main目录下新建jni文件夹

 将OpenCV-android-sdk\sdk\native\jni下的include文件夹复制至项目中的jni文件夹下

 

 将OpenCV-android-sdk\sdk\native\libs下的armeabi-v7a文件夹复制至jni文件夹下

 

 3.1配置CMakeLists.txt

引入头文件

 添加opencv库并设置目标属性(注意路径)

 添加目标链接库opencv-lib

 CMakeLists.txt内容:

  1. # For more information about using CMake with Android Studio, read the
  2. # documentation: https://d.android.com/studio/projects/add-native-code.html
  3. # Sets the minimum version of CMake required to build the native library.
  4. cmake_minimum_required(VERSION 3.10.2)
  5. # Declares and names the project.
  6. project("opencvtestapplication")
  7. #需要引入我们头文件,以这个配置的目录为基准
  8. include_directories(${CMAKE_SOURCE_DIR}/../jni/include)
  9. # Creates and names a library, sets it as either STATIC
  10. # or SHARED, and provides the relative paths to its source code.
  11. # You can define multiple libraries, and CMake builds them for you.
  12. # Gradle automatically packages shared libraries with your APK.
  13. add_library( # Sets the name of the library.
  14. native-lib
  15. # Sets the library as a shared library.
  16. SHARED
  17. # Provides a relative path to your source file(s).
  18. native-lib.cpp )
  19. # 添加opencv的库
  20. add_library(
  21. opencv-lib
  22. SHARED
  23. IMPORTED)
  24. set_target_properties(
  25. opencv-lib
  26. PROPERTIES IMPORTED_LOCATION
  27. ${CMAKE_SOURCE_DIR}/../jni/armeabi-v7a/libopencv_java4.so)
  28. # Searches for a specified prebuilt library and stores the path as a
  29. # variable. Because CMake includes system libraries in the search path by
  30. # default, you only need to specify the name of the public NDK library
  31. # you want to add. CMake verifies that the library exists before
  32. # completing its build.
  33. find_library( # Sets the name of the path variable.
  34. log-lib
  35. # Specifies the name of the NDK library that
  36. # you want CMake to locate.
  37. log )
  38. # Specifies libraries CMake should link to your target library. You
  39. # can link multiple libraries, such as libraries you define in this
  40. # build script, prebuilt third-party libraries, or system libraries.
  41. target_link_libraries( # Specifies the target library.
  42. native-lib opencv-lib
  43. # Links the target library to the log library
  44. # included in the NDK.
  45. ${log-lib} )

3.2修改app下的build.gradle文件 只支持armv7

 同步运行项目至手机设备

出现如下图所示错误:

 java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found

解决方式如下:

修改app下的build.gradle文件

 重新同步项目并运行项目至手机设备

3.3新建FaceDetection类

FaceDetection内容如下:

  1. package com.suoer.ndk.opencvtestapplication;
  2. import android.graphics.Bitmap;
  3. public class FaceDetection {
  4. // Used to load the 'native-lib' library on application startup.
  5. static {
  6. System.loadLibrary("native-lib");
  7. }
  8. /**
  9. * 检测人脸并保存人脸信息
  10. * @param faceBitmap
  11. */
  12. public native int faceDetectionSaveInfo(Bitmap faceBitmap);
  13. /**
  14. * 加载人脸识别的分类器文件
  15. * @param filePath
  16. */
  17. public native boolean loadCascade(String filePath);
  18. }

3.4修改MainActivity类

因为需要拍照以及保存图片,所以需要权限处理。这里使用rxpermissions

rxpermissions的具体使用请参照github链接:GitHub - tbruyelle/RxPermissions: Android runtime permissions powered by RxJava2

因为保存图片是耗时操作,需要开启子线程完成,所以需要处理线程问题。这里使用rxandroid

rxandroid的具体使用请参照github链接:GitHub - ReactiveX/RxAndroid: RxJava bindings for Android

修改app下的build.gradle文件

 app下的build.gradle文件内容:

  1. plugins {
  2. id 'com.android.application'
  3. }
  4. android {
  5. compileSdkVersion 32
  6. buildToolsVersion "32.0.0"
  7. defaultConfig {
  8. applicationId "com.suoer.ndk.opencvtestapplication"
  9. minSdkVersion 16
  10. targetSdkVersion 32
  11. versionCode 1
  12. versionName "1.0"
  13. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  14. externalNativeBuild {
  15. cmake {
  16. cppFlags "-std=c++11 -Wno-nonportable-include-path -Wno-deprecated-register -Wno-writable-strings"
  17. //远程下载
  18. arguments "-DANDROID_STL=c++_shared"
  19. }
  20. }
  21. ndk {
  22. abiFilters("armeabi-v7a")
  23. }
  24. }
  25. buildTypes {
  26. release {
  27. minifyEnabled false
  28. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  29. }
  30. }
  31. externalNativeBuild {
  32. cmake {
  33. path "src/main/cpp/CMakeLists.txt"
  34. version "3.10.2"
  35. }
  36. }
  37. compileOptions {
  38. sourceCompatibility JavaVersion.VERSION_1_8
  39. targetCompatibility JavaVersion.VERSION_1_8
  40. }
  41. }
  42. dependencies {
  43. implementation 'androidx.appcompat:appcompat:1.1.0'
  44. implementation 'com.google.android.material:material:1.1.0'
  45. implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
  46. testImplementation 'junit:junit:4.+'
  47. androidTestImplementation 'androidx.test.ext:junit:1.1.1'
  48. androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
  49. implementation 'com.github.tbruyelle:rxpermissions:0.12'
  50. implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
  51. }

修改项目下的build.gradle文件

 项目下的build.gradle文件内容:

  1. // Top-level build file where you can add configuration options common to all sub-projects/modules.
  2. buildscript {
  3. repositories {
  4. google()
  5. jcenter()
  6. }
  7. dependencies {
  8. classpath "com.android.tools.build:gradle:4.1.0"
  9. // NOTE: Do not place your application dependencies here; they belong
  10. // in the individual module build.gradle files
  11. }
  12. }
  13. allprojects {
  14. repositories {
  15. google()
  16. jcenter()
  17. maven { url 'https://jitpack.io' }
  18. maven { url "https://oss.jfrog.org/libs-snapshot" }
  19. }
  20. }
  21. task clean(type: Delete) {
  22. delete rootProject.buildDir
  23. }

修改AndroidManifest.xml添加权限

 

  1. <uses-permission android:name="android.permission.CAMERA" />
  2. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
  3. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

MainActivity类内容如下:

  1. package com.suoer.ndk.opencvtestapplication;
  2. import android.Manifest;
  3. import android.content.Context;
  4. import android.content.pm.PackageManager;
  5. import android.graphics.Bitmap;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. import android.view.SurfaceView;
  9. import android.view.View;
  10. import android.view.Window;
  11. import android.view.WindowManager;
  12. import android.widget.Button;
  13. import android.widget.ImageView;
  14. import android.widget.Toast;
  15. import com.suoer.ndk.opencvtestapplication.camerahandle.BitmapInterface;
  16. import com.suoer.ndk.opencvtestapplication.camerahandle.CameraSurfaceHolder;
  17. import com.suoer.ndk.opencvtestapplication.camerahandle.FrontCamera;
  18. import com.suoer.ndk.opencvtestapplication.camerahandle.SaveImageTask;
  19. import com.suoer.ndk.opencvtestapplication.camerahandle.SurfaceViewCallback;
  20. import com.tbruyelle.rxpermissions3.RxPermissions;
  21. import java.io.ByteArrayOutputStream;
  22. import java.io.File;
  23. import java.io.FileOutputStream;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import androidx.appcompat.app.AppCompatActivity;
  27. import io.reactivex.rxjava3.functions.Consumer;
  28. public class MainActivity extends AppCompatActivity {
  29. private static final String TAG = "MainActivity";
  30. private SurfaceView mSurfaceView;
  31. private ImageView faceImg;
  32. private Button faceDetectionBtn;
  33. private FaceDetection mFaceDetection;
  34. private File mCascadeFile;
  35. private CameraSurfaceHolder mCameraSurfaceHolder=new CameraSurfaceHolder();
  36. private SurfaceViewCallback mSurfaceViewCallback;
  37. private FrontCamera mFrontCamera;
  38. @Override
  39. protected void onCreate(Bundle savedInstanceState) {
  40. super.onCreate(savedInstanceState);
  41. requestWindowFeature(Window.FEATURE_NO_TITLE);
  42. getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
  43. initView();
  44. applyPermission();
  45. initFaceDetection();
  46. }
  47. private void initFaceDetection() {
  48. copyCascadeFile();
  49. mFaceDetection = new FaceDetection();
  50. if (mFaceDetection != null) {
  51. boolean load = mFaceDetection.loadCascade(mCascadeFile.getAbsolutePath());
  52. if (load) {
  53. Toast.makeText(this, "加载分类器文件成功!", Toast.LENGTH_SHORT).show();
  54. } else {
  55. Toast.makeText(this, "加载分类器文件失败!", Toast.LENGTH_SHORT).show();
  56. }
  57. }
  58. }
  59. //申请权限
  60. private void applyPermission() {
  61. if (!checkCameraHardware(this)) {
  62. return;
  63. }
  64. RxPermissions rxPermissions = new RxPermissions(this);
  65. rxPermissions.request(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA).subscribe(new Consumer<Boolean>() {
  66. @Override
  67. public void accept(Boolean aBoolean) throws Throwable {
  68. if (aBoolean) {
  69. Log.e(TAG, "accept: " + aBoolean);
  70. faceDetectionBtn.setVisibility(View.VISIBLE);
  71. mSurfaceView.setVisibility(View.VISIBLE);
  72. //权限全部获取
  73. initSurfaceViewPreView();
  74. }
  75. }
  76. });
  77. }
  78. private void initSurfaceViewPreView() {
  79. mCameraSurfaceHolder.setCameraSurfaceHolder(MainActivity.this, mSurfaceView);
  80. mSurfaceViewCallback = mCameraSurfaceHolder.mSurfaceViewCallback;
  81. if (mSurfaceViewCallback != null) {
  82. mFrontCamera = mSurfaceViewCallback.mFrontCamera;
  83. }
  84. }
  85. ;
  86. private void initView() {
  87. setContentView(R.layout.activity_main);
  88. mSurfaceView = findViewById(R.id.face_surfaceView);
  89. mSurfaceView.setVisibility(View.GONE);
  90. faceDetectionBtn = findViewById(R.id.faceDetectionBtn);
  91. faceImg = findViewById(R.id.faceImg);
  92. faceDetectionBtn.setOnClickListener(new View.OnClickListener() {
  93. @Override
  94. public void onClick(View v) {
  95. if (mFrontCamera != null) {
  96. //拍照的时候进行人脸识别
  97. mFrontCamera.takePicture(new BitmapInterface() {
  98. @Override
  99. public void setBitMap(Bitmap bitMap) {
  100. if(bitMap==null){
  101. Toast.makeText(MainActivity.this,"拍照失败!",Toast.LENGTH_SHORT).show();
  102. return;
  103. }
  104. //人脸识别
  105. int result = mFaceDetection.faceDetectionSaveInfo(bitMap);
  106. if (result != 0) {
  107. Toast.makeText(MainActivity.this, "检测人脸失败!", Toast.LENGTH_SHORT).show();
  108. return;
  109. }
  110. faceImg.setVisibility(View.VISIBLE);
  111. faceImg.setImageBitmap(bitMap);
  112. byte[]data= bitmap2byte(bitMap);
  113. //rxandroid实现开启子线程保存文件
  114. new SaveImageTask(MainActivity.this,faceImg).saveImage(data);
  115. //AsyncTask异步任务实现开启子线程保存文件
  116. //new SaveImageAsyncTask(MainActivity.this,faceImg).execute(data);
  117. }
  118. });
  119. }
  120. }
  121. });
  122. }
  123. private byte[] bitmap2byte(Bitmap photoBitmap){
  124. 创建对应的流对象
  125. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  126. photoBitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream);//将流对象与Bitmap对象进行关联。
  127. byte [] array=byteArrayOutputStream.toByteArray();//使用流对象,将Bitmap对象转换为byte[]数组
  128. return array;
  129. }
  130. private void copyCascadeFile() {
  131. try {
  132. // load cascade file from application resources
  133. InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
  134. File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
  135. mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
  136. if (mCascadeFile.exists()) return;
  137. FileOutputStream os = new FileOutputStream(mCascadeFile);
  138. byte[] buffer = new byte[4096];
  139. int bytesRead;
  140. while ((bytesRead = is.read(buffer)) != -1) {
  141. os.write(buffer, 0, bytesRead);
  142. }
  143. is.close();
  144. os.close();
  145. cascadeDir.delete();
  146. } catch (IOException e) {
  147. e.printStackTrace();
  148. Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
  149. }
  150. }
  151. /**
  152. * 检测是否存在摄像头
  153. *
  154. * @param context
  155. * @return
  156. */
  157. private boolean checkCameraHardware(Context context) {
  158. if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
  159. return true;
  160. } else {
  161. Toast.makeText(this, "不具备摄像头硬件", Toast.LENGTH_SHORT).show();
  162. return false;
  163. }
  164. }
  165. }


布局activity_main.xml

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <SurfaceView
  9. app:layout_constraintTop_toTopOf="@+id/faceDetectionBtn"
  10. android:id="@+id/face_surfaceView"
  11. android:layout_width="match_parent"
  12. android:layout_height="match_parent"/>
  13. <ImageView
  14. app:layout_constraintTop_toTopOf="@+id/faceDetectionBtn"
  15. android:visibility="gone"
  16. android:id="@+id/faceImg"
  17. android:src="@drawable/face"
  18. android:layout_width="match_parent"
  19. android:layout_height="match_parent"></ImageView>
  20. <Button
  21. android:visibility="gone"
  22. android:id="@+id/faceDetectionBtn"
  23. android:layout_width="match_parent"
  24. android:layout_height="wrap_content"
  25. android:text="人脸识别"
  26. app:layout_constraintBottom_toBottomOf="parent"
  27. app:layout_constraintLeft_toLeftOf="parent"
  28. app:layout_constraintRight_toRightOf="parent"
  29. />
  30. </androidx.constraintlayout.widget.ConstraintLayout>

3.5修改native-lib.cpp

  1. #include <jni.h>
  2. #include <string>
  3. #include <opencv2/opencv.hpp>
  4. #include <android/bitmap.h>
  5. #include <android/log.h>
  6. #include <opencv2/imgcodecs/legacy/constants_c.h>
  7. #define TAG "JNI_LOG"
  8. #define LOGE(...)__android_log_print(ANDROID_LOG_ERROR,TAG,__VA_ARGS__)
  9. using namespace cv;
  10. CascadeClassifier cascadeClassifier;
  11. //使用命名空间
  12. void bitmap2Mat(JNIEnv *env, Mat &mat, jobject bitmap);
  13. //mat转成bitmap
  14. void mat2Bitmap(JNIEnv *env, Mat mat, jobject bitmap);
  15. //bitmap转成mat
  16. void bitmap2Mat(JNIEnv *env, Mat &mat, jobject bitmap) {
  17. //Mat里面有个type:CV_8UC4 刚好对上bitmap中的ARGB_8888 CV_8UC2 刚好匹配bitmap中的RGB_565
  18. //1.获取bitmap信息
  19. AndroidBitmapInfo info;
  20. void *pixels;
  21. AndroidBitmap_getInfo(env,bitmap,&info);
  22. //锁定bitmap画布
  23. AndroidBitmap_lockPixels(env,bitmap,&pixels);
  24. //指定mat的宽高和type BGRA
  25. mat.create(info.height,info.width,CV_8UC4);
  26. if(info.format==ANDROID_BITMAP_FORMAT_RGBA_8888){
  27. //对应的mat应该是CV_8UC4
  28. Mat temp(info.height,info.width,CV_8UC4,pixels);
  29. //把数据temp复制到mat里面
  30. temp.copyTo(mat);
  31. }else if(info.format==ANDROID_BITMAP_FORMAT_RGB_565){
  32. //对应的mat应该是CV_8UC2
  33. Mat temp(info.height,info.width,CV_8UC2,pixels);
  34. //上面mat创建的是CV_8UC4 要改为CV_8UC2 CV_8UC2数据拷贝到CV_8UC4
  35. cvtColor(temp,mat,COLOR_BGR5652BGRA);
  36. }
  37. //其他需要自己去转
  38. //解锁画布
  39. AndroidBitmap_unlockPixels(env,bitmap);
  40. }
  41. extern "C"
  42. JNIEXPORT jint JNICALL
  43. Java_com_suoer_ndk_opencvtestapplication_FaceDetection_faceDetectionSaveInfo(JNIEnv *env,
  44. jobject thiz,
  45. jobject face_bitmap) {
  46. // TODO: implement faceDetectionSaveInfo()
  47. //检测人脸 opencv有关键的类是Mat,opencv是c和c++写的,只会处理Mat,android里面是Bitmap
  48. //1.Bitmap转成opencv能操作的c++对象 Mat ,Mat是一个矩阵
  49. Mat mat;
  50. bitmap2Mat(env,mat,face_bitmap);
  51. //处理灰度opencv 处理灰度图 提高效率,一般所有的操作都会对齐进行处理
  52. Mat gray_mat;
  53. cvtColor(mat,gray_mat,COLOR_BGRA2GRAY);
  54. //再次处理直方均衡补偿
  55. Mat equalize_mat;
  56. equalizeHist(gray_mat,equalize_mat);
  57. //识别人脸 当然我们可以直接用彩色图去做,识别人脸要加载人脸分类器文件
  58. std::vector<Rect> faces;
  59. cascadeClassifier.detectMultiScale(equalize_mat,faces,1.1,5);
  60. LOGE("人脸个数:%d",faces.size());
  61. if(faces.size()!=1){
  62. return -1;
  63. }
  64. Rect faceRect=faces[0];
  65. //在人脸部分画个图
  66. rectangle(mat,faceRect,Scalar(255,155,155),8);
  67. //把mat 放到bitmap中 图片展示出来
  68. //mat2Bitmap(env,mat,face_bitmap);
  69. //保存人脸信息 Mat,图片
  70. Mat face_info_mat(equalize_mat,faceRect);
  71. //保存face_info_mat
  72. mat2Bitmap(env,face_info_mat,face_bitmap);
  73. //mat2Bitmap(env,equalize_mat,face_bitmap);
  74. //保存人脸信息
  75. return 0;
  76. }
  77. void mat2Bitmap(JNIEnv *env, Mat mat, jobject bitmap) {
  78. //Mat里面有个type:CV_8UC4 刚好对上bitmap中的ARGB_8888 CV_8UC2 刚好匹配bitmap中的RGB_565
  79. //1.获取bitmap信息
  80. AndroidBitmapInfo info;
  81. void *pixels;
  82. AndroidBitmap_getInfo(env,bitmap,&info);
  83. //锁定bitmap画布
  84. AndroidBitmap_lockPixels(env,bitmap,&pixels);
  85. if(info.format==ANDROID_BITMAP_FORMAT_RGBA_8888){
  86. //对应的mat应该是CV_8UC4
  87. Mat temp(info.height,info.width,CV_8UC4,pixels);
  88. if(mat.type()==CV_8UC4){
  89. mat.copyTo(temp);
  90. }else if(mat.type()==CV_8UC2){
  91. cvtColor(mat,temp,COLOR_BGR5652BGRA);
  92. }
  93. else if(mat.type()==CV_8UC1){//灰度mat
  94. cvtColor(mat,temp,COLOR_GRAY2BGRA);
  95. }
  96. }else if(info.format==ANDROID_BITMAP_FORMAT_RGB_565){
  97. //对应的mat应该是CV_8UC2
  98. Mat temp(info.height,info.width,CV_8UC2,pixels);
  99. if(mat.type()==CV_8UC4){
  100. cvtColor(mat,temp,COLOR_BGRA2BGR565);
  101. }else if(mat.type()==CV_8UC2){
  102. mat.copyTo(temp);
  103. }
  104. else if(mat.type()==CV_8UC1){//灰度mat
  105. cvtColor(mat,temp,COLOR_GRAY2BGR565);
  106. }
  107. }
  108. //其他需要自己去转
  109. //解锁画布
  110. AndroidBitmap_unlockPixels(env,bitmap);
  111. }
  112. extern "C"
  113. JNIEXPORT jboolean JNICALL
  114. Java_com_suoer_ndk_opencvtestapplication_FaceDetection_loadCascade(JNIEnv *env, jobject thiz,
  115. jstring file_path) {
  116. // TODO: implement loadCascade()
  117. const char *filePath=env->GetStringUTFChars(file_path,0);
  118. bool load=cascadeClassifier.load(filePath);
  119. env->ReleaseStringUTFChars(file_path,filePath);
  120. return load;
  121. }

运行app至手机设备出现如下图所示错误

error: undefined reference to 'AndroidBitmap_getInfo'

 解决方式修改CMakeLists.txt

 

  1. target_link_libraries( # Specifies the target library.
  2. native-lib opencv-lib
  3. #加入该依赖库
  4. jnigraphics
  5. # Links the target library to the log library
  6. # included in the NDK.
  7. ${log-lib} )

CMakeLists.txt内容如下:

  1. # For more information about using CMake with Android Studio, read the
  2. # documentation: https://d.android.com/studio/projects/add-native-code.html
  3. # Sets the minimum version of CMake required to build the native library.
  4. cmake_minimum_required(VERSION 3.10.2)
  5. # Declares and names the project.
  6. project("opencvtestapplication")
  7. #需要引入我们头文件,以这个配置的目录为基准
  8. include_directories(${CMAKE_SOURCE_DIR}/../jni/include)
  9. # Creates and names a library, sets it as either STATIC
  10. # or SHARED, and provides the relative paths to its source code.
  11. # You can define multiple libraries, and CMake builds them for you.
  12. # Gradle automatically packages shared libraries with your APK.
  13. add_library( # Sets the name of the library.
  14. native-lib
  15. # Sets the library as a shared library.
  16. SHARED
  17. # Provides a relative path to your source file(s).
  18. native-lib.cpp )
  19. # 添加opencv的库
  20. add_library(
  21. opencv-lib
  22. SHARED
  23. IMPORTED)
  24. set_target_properties(
  25. opencv-lib
  26. PROPERTIES IMPORTED_LOCATION
  27. ${CMAKE_SOURCE_DIR}/../jni/armeabi-v7a/libopencv_java4.so)
  28. # Searches for a specified prebuilt library and stores the path as a
  29. # variable. Because CMake includes system libraries in the search path by
  30. # default, you only need to specify the name of the public NDK library
  31. # you want to add. CMake verifies that the library exists before
  32. # completing its build.
  33. find_library( # Sets the name of the path variable.
  34. log-lib
  35. # Specifies the name of the NDK library that
  36. # you want CMake to locate.
  37. log )
  38. # Specifies libraries CMake should link to your target library. You
  39. # can link multiple libraries, such as libraries you define in this
  40. # build script, prebuilt third-party libraries, or system libraries.
  41. target_link_libraries( # Specifies the target library.
  42. native-lib opencv-lib
  43. #加入该依赖库
  44. jnigraphics
  45. # Links the target library to the log library
  46. # included in the NDK.
  47. ${log-lib} )

其他详细内容可见Demo。

文章知识点与官方知识档案匹配,可进一步学习相关知识
OpenCV技能树首页概览13321 人正在系统学习中