Java服务器部署基于OpenCV的C++图像处理项目(二)编译篇
部署好环境之后,本篇记录编译的详细步骤。部署环境篇
1.创建文件
在native.cpp中写入以下代码。
#include <jni.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
extern "C" {
using namespace cv;
using namespace std;
JNIEXPORT void JNICALL Java_opencv_opencvImp_stringFromJNI(
JNIEnv* env,
jclass jcls) {
printf("Hello from C++!\n");
}
JNIEXPORT void JNICALL Java_opencv_opencvImp_gray(
JNIEnv *env,
jclass jcls,
jlong jin,
jlong jout) {
cv::Mat & in = *(Mat*)jin;
cv::Mat & gray = *(Mat*)jout;
cv::cvtColor(in, gray, CV_BGR2GRAY);
printf("Hello from opencv++!\n");
}
}
继续创建文件,
vi CMakeLists.txt
写入以下代码:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
#cmake version
cmake_minimum_required(VERSION 2.8)
#设置OpenCv的路径变量,这里的/app/opencv即是opencv的安装目录
set(pathToOpenCv /app/opencv)
set(PROJECT_SOURCE_DIR /root/cmake_opencv_imp)
#支持-std=gnu++11
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#配置加载native依赖,这里加入自己的jdk路径。
include_directories(${pathToOpenCv}/include /usr/local/java/jdk1.8.0_191/include /usr/local/java/jdk1.8.0_191/include/linux)
#表示创建一个导入库,静态方式
add_library(lib_opencv STATIC IMPORTED )
#引入libopencv_java3.so文件
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION ${pathToOpenCv}/share/OpenCV/java/libopencv_java341.so )
# 自己的源文件
add_library(
# Sets the name of the library.
native
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
./native.cpp
)
#链接库
target_link_libraries(
# Specifies the target library.
native
# Links the target library to the lib_opencv library
lib_opencv
)
至此准备工作完成
2.编译
命令如下
mkdir build
cd build
cmake -D CMAKE_INSTALL_PREFIX=/root/cmake_opencv_imp/build ..
make
错误:‘JNIEXPORT’不是一个类型名,注意需编译的文件中#include <jni.h>
至此so库编译成功,将libnative.so拷贝到库搜索路径,例如:
cp libnative.so /usr/lib64
3.调用so库
在工程中的opencvImp中写入代码:
package opencv;
import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;
public class opencvImp {
static {
// 打印库搜索路径,一般有很多个
System.out.println(System.getProperty("java.library.path"));
// 加载so库
System.loadLibrary("native");
}
public static void check() {
stringFromJNI();
// 这里根据自己项目地址加载图片
Mat srcmat = Imgcodecs.imread(opencvImp.class.getResource("/").getPath()+"image/tt1t.jpg");
Mat outmat = new Mat();
gray(srcmat.getNativeObjAddr(),outmat.getNativeObjAddr());
}
// 声明方法,和native.cpp中方法对应。
public static native int[] gray(long jin, long jout);
public static native void stringFromJNI();
}
启动程序时System.loadLibrary("native");
会在默认路径中搜索 libnative. so,这里load方法中只需要写成native,不用加lib以及so后缀。
在需要的类中直接调用即可:
import opencv.opencvImp;
public static void main(){
opencvImp.check();
System.out.println("成功调用!");
}
此时已经完成了opencv的调用,直接运行main
由于测试方法没有实际体现,此处打印成功即表示之前的opencv调用没有问题,打印顺序暂时不知道是什么原因,如果有问题会报错。
到这一步编译打包基本就已经完成了,将这个工程打包传到服务器,使用java运行就可以了。
在后续开发中,调用时遇到链接错误,我这里遇到这个错是由于代码是使用c++语法,存在函数名相同但参数不同的函数,编译时却没有报错,调用的时候就错了。我修改了其中一个函数名就可以了:
[Handler dispatch failed; nested exception is java.lang.UnsatisfiedLinkError: opencv.opencvImp.decodetlevel(JJI)V] with root cause
java.lang.UnsatisfiedLinkError: opencv.opencvImp.decodetlevel(JJI)V
at opencv.opencvImp.decodetlevel(Native Method) ~[xcx_checkmark-0.0.1-SNAPAHOT.jar!/:0.0.1-SNAPSHOT]
...
参考资料:
https://yiheng.github.io/2016/06/01/build-jni-project-with-maven/