Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cmake android #1

Open
wants to merge 11 commits into
base: cmake_android
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@ set(CAFFE_TARGET_VERSION "1.0.0-rc3" CACHE STRING "Caffe logical version")
set(CAFFE_TARGET_SOVERSION "1.0.0-rc3" CACHE STRING "Caffe soname version")
add_definitions(-DCAFFE_VERSION=${CAFFE_TARGET_VERSION})

# Search packages for host system instead of packages for target system
# in case of cross compilation these macro should be defined by toolchain file
if(NOT COMMAND find_host_package)
macro(find_host_package)
find_package(${ARGN})
endmacro()
endif()
if(NOT COMMAND find_host_program)
macro(find_host_program)
find_program(${ARGN})
endmacro()
endif()

# ---[ Using cmake scripts and modules
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Modules)

Expand All @@ -38,6 +51,12 @@ caffe_option(USE_OPENCV "Build with OpenCV support" ON)
caffe_option(USE_LEVELDB "Build with levelDB" ON)
caffe_option(USE_LMDB "Build with lmdb" ON)
caffe_option(ALLOW_LMDB_NOLOCK "Allow MDB_NOLOCK when reading LMDB files (only if necessary)" OFF)
caffe_option(USE_HDF5 "Build with hdf5" ON)

if(ANDROID)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.so")
caffe_enable_cpp11_support()
endif()

# ---[ Dependencies
include(cmake/Dependencies.cmake)
Expand Down Expand Up @@ -72,6 +91,7 @@ add_subdirectory(src/gtest)
add_subdirectory(src/caffe)
add_subdirectory(tools)
add_subdirectory(examples)
add_subdirectory(android)
add_subdirectory(python)
add_subdirectory(matlab)
add_subdirectory(docs)
Expand Down
18 changes: 15 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,12 @@ ifneq ($(CPU_ONLY), 1)
LIBRARIES := cudart cublas curand
endif

LIBRARIES += glog gflags protobuf boost_system boost_filesystem m hdf5_hl hdf5
LIBRARIES += glog gflags protobuf boost_system boost_filesystem m

# handle IO dependencies
USE_LEVELDB ?= 1
USE_LMDB ?= 1
USE_HDF5 ?= 1
USE_OPENCV ?= 1

ifeq ($(USE_LEVELDB), 1)
Expand All @@ -191,13 +192,16 @@ endif
ifeq ($(USE_LMDB), 1)
LIBRARIES += lmdb
endif
ifeq ($(USE_HDF5), 1)
LIBRARIES += hdf5_hl hdf5
endif
ifeq ($(USE_OPENCV), 1)
LIBRARIES += opencv_core opencv_highgui opencv_imgproc
LIBRARIES += opencv_core opencv_highgui opencv_imgproc

ifeq ($(OPENCV_VERSION), 3)
LIBRARIES += opencv_imgcodecs
endif

endif
PYTHON_LIBRARIES ?= boost_python python2.7
WARNINGS := -Wall -Wno-sign-compare
Expand Down Expand Up @@ -341,6 +345,9 @@ ifeq ($(ALLOW_LMDB_NOLOCK), 1)
COMMON_FLAGS += -DALLOW_LMDB_NOLOCK
endif
endif
ifeq ($(USE_HDF5), 1)
COMMON_FLAGS += -DUSE_HDF5
endif

# CPU-only configuration
ifeq ($(CPU_ONLY), 1)
Expand All @@ -367,6 +374,11 @@ ifeq ($(BLAS), mkl)
MKLROOT ?= /opt/intel/mkl
BLAS_INCLUDE ?= $(MKLROOT)/include
BLAS_LIB ?= $(MKLROOT)/lib $(MKLROOT)/lib/intel64
else ifeq ($(BLAS), eigen)
# Eigen
COMMON_FLAGS += -DUSE_EIGEN
EIGEN_DIR ?= /opt/eigen
BLAS_INCLUDE ?= $(EIGEN_DIR)
else ifeq ($(BLAS), open)
# OpenBLAS
LIBRARIES += openblas
Expand Down
4 changes: 3 additions & 1 deletion Makefile.config.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# USE_OPENCV := 0
# USE_LEVELDB := 0
# USE_LMDB := 0
# USE_HDF5 := 0

# uncomment to allow MDB_NOLOCK when reading LMDB files (only if necessary)
# You should not set this flag if you will be reading LMDBs with any
Expand Down Expand Up @@ -41,10 +42,11 @@ CUDA_ARCH := -gencode arch=compute_20,code=sm_20 \

# BLAS choice:
# atlas for ATLAS (default)
# eigen for Eigen
# mkl for MKL
# open for OpenBlas
BLAS := atlas
# Custom (MKL/ATLAS/OpenBLAS) include and lib directories.
# Custom (MKL/Eigen/ATLAS/OpenBLAS) include and lib directories.
# Leave commented to accept the defaults for your choice of BLAS
# (which should work)!
# BLAS_INCLUDE := /path/to/your/blas
Expand Down
17 changes: 17 additions & 0 deletions android/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 2.8)

if(ANDROID)
add_library(caffe_jni SHARED caffe_jni.cpp caffe_mobile.cpp)
#add_executable(caffe_jni caffe_jni.cpp caffe_mobile.cpp)
target_link_libraries(caffe_jni ${Caffe_LINK})
caffe_default_properties(caffe_jni)

# set back RUNTIME_OUTPUT_DIRECTORY
set_target_properties(caffe_jni PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/android")

caffe_set_solution_folder(caffe_jni android)

# install
install(TARGETS caffe_jni DESTINATION lib)
endif()
205 changes: 205 additions & 0 deletions android/caffe_jni.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#include <string.h>
#include <jni.h>
#include <android/log.h>
#include <string>
#include <vector>

#ifdef USE_EIGEN
#include <omp.h>
#else
#include <cblas.h>
#endif

#include "caffe/caffe.hpp"
#include "caffe_mobile.hpp"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv/cv.h>
#include <opencv/highgui.h>


#ifdef __cplusplus
extern "C" {
#endif

using std::string;
using std::vector;
using caffe::CaffeMobile;

int getTimeSec() {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return (int)now.tv_sec;
}

string jstring2string(JNIEnv *env, jstring jstr) {
const char *cstr = env->GetStringUTFChars(jstr, 0);
string str(cstr);
env->ReleaseStringUTFChars(jstr, cstr);
return str;
}

JNIEXPORT void JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_setNumThreads(JNIEnv *env,
jobject thiz,
jint numThreads) {
int num_threads = numThreads;
#ifdef USE_EIGEN
omp_set_num_threads(num_threads);
#else
openblas_set_num_threads(num_threads);
#endif
}

JNIEXPORT void JNICALL Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_enableLog(
JNIEnv *env, jobject thiz, jboolean enabled) {}

JNIEXPORT jint JNICALL Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_loadModel(
JNIEnv *env, jobject thiz, jstring modelPath, jstring weightsPath) {
CaffeMobile::Get(jstring2string(env, modelPath),
jstring2string(env, weightsPath));
return 0;
}

JNIEXPORT void JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_setMeanWithMeanFile(
JNIEnv *env, jobject thiz, jstring meanFile) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
caffe_mobile->SetMean(jstring2string(env, meanFile));
}

JNIEXPORT void JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_setMeanWithMeanValues(
JNIEnv *env, jobject thiz, jfloatArray meanValues) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
int num_channels = env->GetArrayLength(meanValues);
jfloat *ptr = env->GetFloatArrayElements(meanValues, 0);
vector<float> mean_values(ptr, ptr + num_channels);
caffe_mobile->SetMean(mean_values);
}

JNIEXPORT void JNICALL Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_setScale(
JNIEnv *env, jobject thiz, jfloat scale) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
caffe_mobile->SetScale(scale);
}

JNIEXPORT jfloatArray JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_getConfidenceScore(
JNIEnv *env, jobject thiz, jstring imgPath) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
vector<float> conf_score =
caffe_mobile->GetConfidenceScore(jstring2string(env, imgPath));

jfloatArray result;
result = env->NewFloatArray(conf_score.size());
if (result == NULL) {
return NULL; /* out of memory error thrown */
}
// move from the temp structure to the java structure
env->SetFloatArrayRegion(result, 0, conf_score.size(), &conf_score[0]);
return result;
}

JNIEXPORT jintArray JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_predictImage(JNIEnv *env,
jobject thiz,
jstring imgPath,
jint k) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
vector<int> top_k =
caffe_mobile->PredictTopK(jstring2string(env, imgPath), k);

jintArray result;
result = env->NewIntArray(k);
if (result == NULL) {
return NULL; /* out of memory error thrown */
}
// move from the temp structure to the java structure
env->SetIntArrayRegion(result, 0, k, &top_k[0]);
return result;
}

JNIEXPORT jobjectArray JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_extractFeatures(
JNIEnv *env, jobject thiz, jstring imgPath, jstring blobNames) {
CaffeMobile *caffe_mobile = CaffeMobile::Get();
vector<vector<float>> features = caffe_mobile->ExtractFeatures(
jstring2string(env, imgPath), jstring2string(env, blobNames));

jobjectArray array2D =
env->NewObjectArray(features.size(), env->FindClass("[F"), NULL);
for (size_t i = 0; i < features.size(); ++i) {
jfloatArray array1D = env->NewFloatArray(features[i].size());
if (array1D == NULL) {
return NULL; /* out of memory error thrown */
}
// move from the temp structure to the java structure
env->SetFloatArrayRegion(array1D, 0, features[i].size(), &features[i][0]);
env->SetObjectArrayElement(array2D, i, array1D);
}
return array2D;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
jint result = -1;

if (vm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
LOG(FATAL) << "GetEnv failed!";
return result;
}

FLAGS_redirecttologcat = true;
FLAGS_android_logcat_tag = "caffe_jni";

return JNI_VERSION_1_6;
}

void getBGRFromYUV(void* data, const int width, const int height, cv::Mat& bgr)

{

cv::Mat yuv(height+height/2, width, CV_8UC1, data);

bgr = cv::Mat(height, width, CV_8UC4);

cv::cvtColor(yuv, bgr, CV_YUV420sp2BGR );
}


JNIEXPORT jfloatArray JNICALL
Java_com_sh1r0_caffe_1android_1lib_CaffeMobile_getConfidenceScore(
JNIEnv *env, jobject thiz, jbyteArray image, jint width, jint height, jint roiX, jint roiY, jint roiWidth, jint roiHeight) {

jbyte* image_ptr = env->GetByteArrayElements(image, 0);
cv::Mat previewBGR;
getBGRFromYUV(reinterpret_cast<void*>(image_ptr), width, height, previewBGR);

cv::Rect roi((int) roiX, (int) roiY, (int) roiWidth, (int) roiHeight);

// Need to rotate 270 degrees -> do a rotate and flip.
cv::Mat croppedImage = previewBGR(roi);
cv::Mat croppedRotated90;
cv::transpose(croppedImage, croppedRotated90);
cv::flip(croppedRotated90, croppedRotated90, -1);

CaffeMobile *caffe_mobile = CaffeMobile::Get();

vector<float> conf_score =
caffe_mobile->GetConfidenceScore(croppedRotated90);

jfloatArray result;
result = env->NewFloatArray(conf_score.size());
if (result == NULL) {
return NULL; /* out of memory error thrown */
}

env->SetFloatArrayRegion(result, 0, conf_score.size(), &conf_score[0]);
return result;
}

#ifdef __cplusplus
}
#endif
Loading