I want to use some native c++ code/library in my Android application. The c++ part is heavily based on openCV.
I am aware of opencv-android-sdk and have seen plenty of detailed tutorials on how to do it with Android Studio (like this one), but these all just use the opencv-android-sdk that only supports a limited subset of openCV functions (I am not talking about those that do not make sense on a mobile device, like gpu-related functionalities, but some other functions that simply do not exist in the opencv-android-sdk and I need them for the c++ code).
Anyway, my question is: can I somehow compile and use the "full set of modules" of openCV in my Android Studio project (using NDK, etc.)?
I saw also this one, and it claims that "[it] will build most of the OpenCV modules [for android]", but it is not clear to me how to use it...
Any hint would be highly appreciated!
OK! I guess I figured it out!
Basically one needs to follow this tutorial, but just replace the path in Android.mk to point to the compiled full version of openCV, instead of openCV-Android-SDK (as well as some other small changes; for those I just copy here what I have in Android.mk and Application.mk).
Eventually, my Android.mk looks like this (OPENCVROOT need to be set properly):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCVROOT:= /path/to/opencv-2.4.10/platforms/build_android_arm
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include ${OPENCVROOT}/OpenCV.mk
LOCAL_SRC_FILES := main.cpp
LOCAL_LDLIBS += -llog
LOCAL_MODULE := hello
include $(BUILD_SHARED_LIBRARY)
And Application.mk looks like this:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-19
Just a short note on compiling openCV with Android NDK:
For compiling full openCV using NDK, one can still use the method mentioned here; the description is based on NDK-r8e, but if needed, one can download NDK-r10d and use it instead. I had to turn-off cuda-related parts in openCV source, in order to successfully compile it with NDK (just adding -D WITH_CUDA=OFF to opencv-2.4.10/platforms/scripts/cmake_android_arm.sh , in the last line, after cmake, does the job!). In case you need to have the nonfree modules (like SURF and SIFT, do NOT clone it from github, just download it in a single zip from here; I used version 2.4.10 by the way).
Now I have access to almost all openCV functions in the native c++ code that I am integrating into my Android App!
I hope this helps others, too!
You should investigate JNI (The Java Native Interface) which is a means of wrapping C libraries with Java.
Also you may want to consider getting hold of this book: Mastering OpenCV with Practical Computer Vision Projects
Which goes into this in some detail.
Related
I recently started to use Android NDK and I’m facing some problems with shared libraries.
I created a project with Eclipse that allows me to use NDK and natives functions. But now, I would like to use another shared library that I created with QtCreator.
So here is my question. Is that possible to include a shared library to my NDK project, even if I didn’t invoke ndk-build to create it?
Let’s take an example. If I create a simple shared library like that:
g++ -Wall -shared -fPIC -o libapi.so MyDLL.cpp
Could I be able to use it on my NDK project like this (Android.mk):
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := api
LOCAL_SRC_FILES := ../sharedLibs/libapi.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := dbapi
LOCAL_SRC_FILES := dbapi.cpp
LOCAL_C_INCLUDES += ../includes
LOCAL_SHARED_LIBRARIES := api
include $(BUILD_SHARED_LIBRARY)
And of course, could I be able to use its functions on my native NDK side?
Using this method, I'm facing this error when I try to build my Eclipse project:
/libs/armeabi-v7a/libapi.so: File format not recognized
I thought my shared lib was not compatible with ndk-build (true, false?).
Thank you for your answers.
How did you build your shared lib? Is it compiled for arm, with NDK?
If not, it cannot work.
The people in the comments are indicating that you have almost certainly compiled for x86 instead of arm. (You say you are using cygwin with Windows, which will compile to x86 by default unless your windows box is an arm box, which I am guessing is not the case.)
Inside the Android ndk is a script called make-standalone-toolchain.sh. If you are in the current directory where your ndk is installed, you can use this by typing:
./android-ndk-r9/build/tools/make-standalone-toolchain.sh --platform=<your desired android platform> --install-dir=<location where you want android toolchain>
This will create a set of build tools which you can use to build arm binaries to run on your device. These tools will be named things like, e.g.
arm-linux-androideabi-gcc
Put those tools in your path and use them to build your library.
I don't know whether cygwin includes a "file" command, but you may be able to determine the architecture of your shared library by typing:
file libapi.so
If it says it's arm, you're good. If it says x86, it won't work (except on an x86 android device, that is).
I want to use libcurl in my native project. How can I integrate this library and build using ndk? Is there any post available that can guide me through the process?
I tried the docs from official site, but that's not working. FYI I am on windows platform.
Create a JNI folder within your project and add a folder for each architecture(arm, armv7,x86 etc). Place the corresponding libcurl.so files in the respective folders. Since this is a rebuilt shared binary you need to add this to your Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := <Curl> //add the module name here.
LOCAL_SRC_FILES := <libCurl.so> //add the .so file name here
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../jni/include
include $(PREBUILT_SHARED_LIBRARY)
Create a JNI C file that uses the libraries from Curl and call the native code from Java source.
static {
System.loadLibrary("curl");
}
It shouldnt make a difference if you are on Windows platform. Adding open source liv files to Android NDK is pretty much the same process on all platforms.
No idea about windows, but as to the linker magic, see the links in
Integrating MuPDF as a library project (Android)
I'm a bit confused with what I'm currently attempting: I want to cross-compile a C library for use with Android through the NDK, so that I can create a JNI wrapper and call some of its functions from my Android java code.
I followed this guide to crosscompile libopus (the library I want to include in my project): http://mortoray.com/2012/08/21/android-ndk-cross-compile-setup-libpng-and-freetype/ which means I currently have a standalone toolchain at /opt/android-ext/, with a lib folder that contains the library I cross-compiled (libopus.a, libopus.so, etc).
I also already have a jni folder on my Android project, which contains some C code with the JNI bindings that I want, and that I can call from my Java code, but it does nothing (I can call it but it's a blank function). This means that in my project, there's a /lib/armeabi directory with "libopusUtilsNative.so" (the wrapper).
My question is:
How do I add the library that I just crosscompiled to the project, so that (for example) I can just do an #include call on the C source code file that I already have and get access to the library functions? I'm a bit lost with how to:
Include the library I cross-compiled into my project.
How to make the wrapper code I created include it (I'm guessing this has something to do with adding some code to my Android.mk file, but I'm clueless).
The guide that you linked to contains an example of how to modify the Android.mk file for your JNI library (or in his case, a native app) to link against the cross-compiled library:
PLATFORM_PREFIX := /opt/android-ext/
LOCAL_PATH := $(PLATFORM_PREFIX)/lib
include $(CLEAR_VARS)
LOCAL_MODULE := libpng
LOCAL_SRC_FILES := libpng.a
include $(PREBUILT_STATIC_LIBRARY)
# The in your project add libpng
LOCAL_STATIC_LIBRARIES := android_native_app_glue libpng
That's pretty much how you'd do it if you wanted to link statically against libopus. Or if you want to link against the shared library, use something like this: Using my own prebuilt shared library in an Android NDK project
I'm currently implementing a custom Logging mechanism that I need to be accessible from both native and Java code. The fundamentals of the logging are implemented in C/C++ with a Java wrapper, and the two together are being built as an android Library Project.
The issue at hand is that while my Java code can access the Library project output, there doesn't seem to be a way for my native code to access the native .so or headers from the Library project. Is there an additional step I'm missing or is this just a limitation of the current ADT? More specifically, is there a makefile/eclipse configuration that will address the things I'm used to getting out of Library projects in general? (Build .so as needed, import rebuilt .so, import relevant headers for c/c++ compilation, etc.)
I don't think it's a limitation. We are supposed to declare native code dependencies in Android.mk and Application.mk
Worked out a way to get what I wanted - most of the information is (of course) in the NDK documentation, but what I was trying to do isn't 100% supported within the ADT. It should also be noted that I'm currently stuck developing in a windows environment, so much of this might be easier or unnecessary in Linux. The first key is the $(call import-module ...) macro. Within your library project, move the source files and the Android.mk folder into a named directory you can locate later. My Library project directory looked like this:
MyProject
> src
> res
v jni
- Application.mk
v MyLib
- source.cpp
- source.h
- Android.mk
I also had to edit my Application.mk to point to the project:
APP_PROJECT_PATH := <path-to-my-project>
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/MyProject/Android.mk
Annoyingly, this broke my Android.mk in ways unforseen until I added a ./ to my source files. Also you need to export your includes for linking:
LOCAL_SRC_FILES := ./source.cpp
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
Ensure that the system path variable NDK_MODULE_PATH is set to include your library's JNI directory, e.g. <path-to-my-project>/jni (Note: I had to restart eclipse after I did this).
In the receiving application's Android.mk file (the one you'd like to link natively to your app), import the module:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := MyNativeProject
LOCAL_SRC_FILES := source.cpp
LOCAL_CFLAGS := -DANDROID_NDK -g -std=c99
LOCAL_SHARED_LIBRARIES := MyLib
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)
$(call import-module, IntelLog)
At this point everything built perfectly, but the APK packager didn't like the generated .so binary being included twice (once from the Library project's natural import process, and again from the import-module call). To solve this, clean the library and don't build it again! the import-module call will build the .so and import it into your project. (Obviously, if your project only requires the Java API, you would need that .so file to be built). Congratulations! you have a functional (if not straightforward) build process with a hybrid native/Java Library
I have written an Android app. It uses a main C-code module and a linked-in C-code module. Now I want to replace the linked-in module with an ARM assembler module. Anyone have a simple example?
Here's an example of Android.mk file that will build sourcetree containing assembly. To see a complete example check the hello-neon sample distributed in the NDK package.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_ARM_MODE := arm # remove this if you want thumb mode
LOCAL_ARM_NEON := true # remove this if you want armv5 mode
LOCAL_CFLAGS := -std=c99 -pedantic -v
LOCAL_SRC_FILES := # list your C, C++ and assembly sources here.
# assembly source files ends with extension .S
# add .arm after the extension if you want to compile in armv5 mode (default is thumb)
# add .arm.neon to compile in armv7 mode
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := #the name of your shared library
include $(BUILD_SHARED_LIBRARY)
I wrote a tutorial to do exactly this.
http://www.eggwall.com/2011/09/android-arm-assembly-calling-assembly.html
ARM assembly in Android isn't difficult, but there are many moving pieces: you need an assembly source, a C stub, a Makefile, and Java stub "native" methods that call the underlying assembly code.
You could download the source code from the link above, and see how it works. Once you have one working example, it is easy to poke and make it fit your need.
I Saw the article by vikram I have an opinion that for beginners, it is better to build and run assembler code in Android using android source code.
e.g. you can create a module with the specification "BUILD_EXECUTABLE" in the Android.mk
You can have a main function inside the C code and have the assembler code built along with main.c
You can add such a module even under gingebread/frameworks/base/<mymodule>