Java 从动态库中使用opencv时在运行时对opencv方法的未定义引用
我正在开发一个基于OpenCV(图像处理)和dlib(人脸地标检测)的人脸识别Java应用程序。为此,我手动构建并安装了这两个库Java 从动态库中使用opencv时在运行时对opencv方法的未定义引用,java,opencv,linker,java-native-interface,dlib,Java,Opencv,Linker,Java Native Interface,Dlib,我正在开发一个基于OpenCV(图像处理)和dlib(人脸地标检测)的人脸识别Java应用程序。为此,我手动构建并安装了这两个库 > git clone https://github.com/opencv/opencv.git > cd opencv > git checkout 3.4 && git reset --hard && git clean -qfdx > mkdir release > cd release > c
> git clone https://github.com/opencv/opencv.git
> cd opencv
> git checkout 3.4 && git reset --hard && git clean -qfdx
> mkdir release
> cd release
> cmake -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ..
> make -j8
> make install
> cd ..
> git clone https://github.com/davisking/dlib.git
> cd dlib
> mkdir build
> cd build
> cmake --config Release -DBUILD_SHARED_LIBS=1 ..
> make -j 8
> make install
我还没有看到为dlib创建Java绑定的方法。所以,我的方法是用C创建一个动态库,它执行一些混合dlib和opencv的操作
在我的Java应用程序上,我用相应的本机方法创建了一个Java类(ShapePredictor)
public final class ShapePredictor {
static {
System.loadLibrary("dlibsp");
}
public final long nativeObj;
ShapePredictor(String file) {
nativeObj = n_shape_predictor(file);
}
public long predict(Mat img, int rowStart, int rowEnd, int colStart, int colEnd) {
long nativeLandmarks = n_predict(nativeObj, img.nativeObj, colStart, colEnd, rowStart, rowEnd);
return landmarks;
}
@Override
protected void finalize() throws Throwable {
n_delete(nativeObj);
super.finalize();
}
static native long n_predict(long nativeObj, long img, int rowStart, int rowEnd, int colStart, int colEnd);
static native long n_shape_predictor(String filePath);
// native support for java finalize()
static native void n_delete(long nativeObj);
}
有了它,我创建了headers文件(dlibsp/shape\u predictor\u java.h)
并编写了一个cpp文件(shape\u predictor\u java.cpp)来实现这些方法
#include <dlib/image_processing/shape_predictor.h>
#include <dlib/image_processing.h>
#include <dlib/opencv/cv_image.h>
#include <dlib/opencv.h>
#include <dlibsp/shape_predictor_java.h>
#include <opencv2/opencv.hpp>
#include <opencv2/objdetect/objdetect.hpp>
jlong Java_es_bsc_compss_apps_utils_aligners_face_DlibAligner_00024ShapePredictor_n_1shape_1predictor( JNIEnv *env, jclass obj, jstring path)
{
const char *str = (env)->GetStringUTFChars(path, 0);
dlib::shape_predictor *sp = new dlib::shape_predictor();
dlib::deserialize(str) >> *sp;
(env)->ReleaseStringUTFChars(path, str);
return (jlong)sp;
}
jlong Java_es_bsc_compss_apps_utils_aligners_face_DlibAligner_00024ShapePredictor_n_1predict(JNIEnv *env, jclass obj, jlong me, jlong mat_ptr, jint x_start, jint x_end, jint y_start, jint y_end)
{
dlib::shape_predictor *sp_ptr = (dlib::shape_predictor *)me;
dlib::shape_predictor sp = *sp_ptr;
cv::Mat *img = (cv::Mat *)mat_ptr;
cv::Mat img_cv = *(img);
cv::Mat gray;
cv::cvtColor(img_cv, gray, cv::COLOR_BGR2GRAY);
return (jlong) new cv::Mat(gray);
}
void Java_es_bsc_compss_apps_utils_aligners_face_DlibAligner_00024ShapePredictor_n_1delete(JNIEnv *env, jclass obj, jlong self)
{
delete (dlib::shape_predictor *)self;
}
最后,我将include和动态库文件复制到/usr/local/lib文件夹中。
运行Java应用程序时,我的库似乎加载正确。正确创建shape_predictor对象,调用predict方法时,会出现错误
java: symbol lookup error: /usr/local/lib/libdlibsp.so: undefined symbol: _ZN2cv8cvtColorERKNS_11_InputArrayERKNS_12_OutputArrayEii
我在/usr/local/share/OpenCV/java/libopencv_java349.so上运行了nm,符号就在那里。我还在我的库上执行了一个ldd,出于某种原因,libopencv_java349没有作为依赖项列出。因此,似乎存在某种链接问题
ldd /usr/local/lib/libdlibsp.so
linux-vdso.so.1 => (0x00007ffed6100000)
libdlib.so.19.19.99 => /usr/local/lib/libdlib.so.19.19.99 (0x00007f3c048ea000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3c046d4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3c0430a000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3c040ed000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3c03d6b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3c03a62000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3c05045000)
我尝试在LD_LIBRARY_路径上添加/usr/local/share/OpenCV/java/libopencv_java349.so,并在链接器步骤上添加了-Wl,-rpath标志,试图强制加载库。再次检查
libopencv_java349。因此
是一个共享库。您在构建opencv时使用了BUILD\u SHARED\u LIBS=OFF
。如果将共享库与静态库符号链接在一起,则在那里将不可见。这可能就是问题所在!当我查看/usr/local/share/OpenCV/java/时,我看到了libopencv_java349.so。但是,在查看/usr/local/lib时,所有libopencv_*库都是libopencv_*.a,那么您的建议是什么?1-使用Build_SHARED_LIBS=ON构建opencv 2-将DLIB构建为动态库3-再次构建opencv,但使用Build_SHARED_LIBS=OFF(我需要它来创建java绑定)看起来这个符号实际上就在那里nm/usr/local/share/OpenCV/java/libopencv\u java349.so | grep | zn2cv8cvtclorerkns_11_InputArrayERKNS_12_OutputArrayEii 0000000000 85fee\u zn2cv8cvlorerkns_11_12_OutputArrayEii
注意nm
适用于静态和动态图书馆。我建议使用共享库重新编译OpenCV
。
java: symbol lookup error: /usr/local/lib/libdlibsp.so: undefined symbol: _ZN2cv8cvtColorERKNS_11_InputArrayERKNS_12_OutputArrayEii
ldd /usr/local/lib/libdlibsp.so
linux-vdso.so.1 => (0x00007ffed6100000)
libdlib.so.19.19.99 => /usr/local/lib/libdlib.so.19.19.99 (0x00007f3c048ea000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3c046d4000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3c0430a000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3c040ed000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f3c03d6b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3c03a62000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3c05045000)