安装好IDE后, 会一直显示同步失败, 看看如下步骤:
需要注意的是:
-> 安装NDK 自带的NDK版本有问题 自己去下一个15版本的
-> 按照系统提示一步一步安装其他未安装的组件
-> 最终代码写好后, 需要安装自己的需要创建 android模拟器, 新建一个 X86-android4.4的模拟器;
开发android程序 - 结构:
-> AndroidManifest.xml 设置权限, 注册AppCompatActive窗口, 设置主函数入口。
-> 图片存储在res-drawable, res-layout调用图片等资源。
使用android-studio ndk生成 so文件。
-> 创建C++接口加载器
-> 手动创建插件
$JDKPath$\bin\javah -d $ModuleFileDir$\src\main\jni -jni $FileClass$ $ModuleFileDir$\build\intermediates\classes\debug
-> build project 一下
-> 在OpenCVHelper类上右键, 选择External Tool 使用插件
-> 编辑C文件
#include "com_admin_opencv4android_OpenCVHelper.h" #include <sstream> JNIEXPORT jstring JNICALL Java_com_admin_opencv4android_OpenCVHelper_getStringTmp(JNIEnv *env, jclass instance){ std::stringstream ss; ss << "Hello from c++ " << std::endl; return env->NewStringUTF(ss.str().c_str()); }
新建 Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := OpenCVHelper LOCAL_SRC_FILES := MyLib.cpp include $(BUILD_SHARED_LIBRARY)
新建 Application.mk APP_ABI := all APP_STL:=stlport_static
-> 使用命令行进入jni目录, 使用ndk命令编译so
-> 调用刚才生成好的 so
在app/build 下
android { ... sourceSets { main() { jniLibs.srcDirs = ['src/main/libs'] jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程 } } }
在主程序中: public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.sample_text); textView.setText(OpenCVHelper.getStringTmp()); } }
使用android studio 整合 opencv第三方库:
-> 在OpenCVHelper中新增接口函数:
public class OpenCVHelper { static { System.loadLibrary("OpenCVHelper"); } public static native String getStringTmp(); public static native int[] getGrayImage(int[] pixels, int w, int h); }
-> 重写MyLib.cpp:
#include "com_admin_opencv4android_OpenCVHelper.h" #include <sstream> #include <opencv2/opencv.hpp> JNIEXPORT jstring JNICALL Java_com_admin_opencv4android_OpenCVHelper_getStringTmp(JNIEnv *env, jclass instance){ std::stringstream ss; ss << "Hello from c++ " << std::endl; return env->NewStringUTF(ss.str().c_str()); } JNIEXPORT jintArray JNICALL Java_com_admin_opencv4android_OpenCVHelper_getGrayImage(JNIEnv *env, jobject, jintArray buf, int w, int h){ jint *pixels = env->GetIntArrayElements(buf, NULL); if(pixels == NULL){ return NULL; } cv::Mat imgData(h, w, CV_8UC4, pixels); uchar *ptr = imgData.ptr(0); for(int i=0; i<w*h; i++){ int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114); ptr[4*i+0] = (uchar)grayScale; ptr[4*i+1] = (uchar)grayScale; ptr[4*i+2] = (uchar)grayScale; } int size = w * h; jintArray result = env->NewIntArray(size); env->SetIntArrayRegion(result, 0, size, pixels); env->ReleaseIntArrayElements(buf, pixels, 0); return result; }
所有配置请参照opencv官网, https://docs.opencv.org/2.4/doc/tutorials/introduction/android_binary_package/dev_with_OCV_on_Android.html#native-c
-> Android.mk :
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) OPENCV_CAMERA_MODULES:=on OPENCV_INSTALL_MODULES:=on OPENCV_LIB_TYPE:=STATIC include D:/library/OpenCV-android-sdk/sdk/native/jni/OpenCV.mk LOCAL_MODULE := OpenCVHelper LOCAL_SRC_FILES := MyLib.cpp include $(BUILD_SHARED_LIBRARY)
-> Application.mk
APP_ABI := all APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions
-> 配置好之后, 使用ndk-build
-> activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.admin.opencv4android.MainActivity"> <TextView android:id="@+id/sample_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="aa!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" app:srcCompat="@drawable/tutu" android:layout_centerInParent="true" /> <Button android:id="@+id/bt_Gray" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:text="Gray" /> </android.support.constraint.ConstraintLayout>
-> MainActivity类:
public class MainActivity extends AppCompatActivity { private TextView textView; private Button bt_photo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.sample_text); textView.setText(OpenCVHelper.getStringTmp()); bt_photo = (Button) findViewById(R.id.bt_Gray); bt_photo.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub ImageView img = (ImageView) findViewById(R.id.img); Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable( R.drawable.tutu)).getBitmap(); int w = bitmap.getWidth(), h = bitmap.getHeight(); int[] pix = new int[w * h]; bitmap.getPixels(pix, 0, w, 0, 0, w, h); int[] resultPixes = OpenCVHelper.getGrayImage(pix, w, h); Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); result.setPixels(resultPixes, 0, w, 0, 0, w, h); img.setImageBitmap(result); } }); } }
-> 至于Cmake之类的, 可以全部注释, jni全部删除都可以, 因为已经有so了, 甚至头文件都不需要:
##################################################################################
-> 在上述案例中, 是在 jni文件夹中 使用Android.mk 导入存储在本地(项目文件外面)的第三方静态库, 使得jni中需要编译的程序 MyLib.cpp可以引用opencv, 并指定 LOCAL_MODULE := OpencvHelper
-> 编译好后的 .so 通过build.gradle jniLibs.srcDirs = ['src/main/libs'] 在编译器链接动态库,
-> 在实现native的接口类中, System.loadLibrary("OpenCVHelper"); 在java程序中加载动态库。
编译zbar生成其动态库, 并调用摄像头扫描二维码。
-> 使用zbar, libiconv编译 .so, 并使用java编写扫描程序的项目: https://blog.csdn.net/yanzhenjie1003/article/details/71641368
-> 添加完整工程zbar, 对第一次使用android studio ndk的人来说 难度不小, 不如先从一个小案例做起:
新建一个 first.h 头文件 #ifndef OPENCV4ANDROID_COMPILE_ZBAR_FIRST_H #define OPENCV4ANDROID_COMPILE_ZBAR_FIRST_H int add(int input); #endif //OPENCV4ANDROID_COMPILE_ZBAR_FIRST_H first.cpp #include "first.h" int add(int input) { return input * 2; } 在交叉接口 MyLib.cpp 中: #include "com_admin_opencv4android_ZbarHelper.h" #include <sstream> #include "first.h" JNIEXPORT jstring JNICALL Java_com_admin_opencv4android_ZbarHelper_getStringTmp(JNIEnv *env, jclass instance, jint prompt){ int c = prompt; int result = add(c); std::stringstream ss; ss << "Hello from c++ " << std::endl; ss << result << std::endl; return env->NewStringUTF(ss.str().c_str()); }
Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := ZbarHelper LOCAL_SRC_FILES := \ first.cpp \ MyLib.cpp LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/first.h \ include $(BUILD_SHARED_LIBRARY)
在第一次使用ndk编译时, 总提示 undefine function add() ..... , 我反复检查 无论是在 LOCAL_SRC_FILES, LOCAL_C_INCLUDES 中该函数的 头文件 或 实现函数 都在classpath下, 不会有错!
最终查明, 在使用ndk编译时, 需要将CMakeLists.txt 中的所有选项都注释掉, 就不会找不到引用。
在使用ndk编译c++时, 报错 找不到 #include exception , 因为ndk编译器 默认最小库编译, 因此在 Application.mk里添加 APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions
在做平台移植时, 最麻烦的问题在于 要考虑 目标平台编译器的问题。
android.mk 使用进阶:
对编译成功的so库 进行预编译加载 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := zbar LOCAL_SRC_FILES := libs/libzbar.so LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/zbar include $(PREBUILT_SHARED_LIBRARY) 调用该库 ## ------------------------------------- include $(CLEAR_VARS) LOCAL_MODULE := ZbarHelper LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/zbar \ LOCAL_SRC_FILES := MyLib.cpp LOCAL_SHARED_LIBRARIES := \ zbar include $(BUILD_SHARED_LIBRARY)
一些参考资料地址: https://www.cnblogs.com/tt2015-sz/p/6148723.html
ndk-build 时, 找不到 mathcalls.h 系统库, 将 APP_PLATFORM := android-19, 因为之前的系统库 没有相应的库。