Мне дали проект, основанный на распознавании лиц, написанный на JavaCV, который нужно улучшить. Идея состояла в том, чтобы либо переписать программу с использованием C ++, либо написать привязки JNI, чтобы все еще использовать Java. Я провел некоторые исследования и, согласно официальному сайту OpenCV, начиная с версии 2.4.4, есть привязки для Java и Python. И так, так как официальный сайт заявил, что я решил пойти с ним. Обратите внимание, что я не программировал на C ++ раньше и не писал никаких JNI-оболочек в прошлом. Если на официальном сайте не указано, что он содержит привязки для Java, я просто написал бы это на C ++, используя Qt Digia.
Так или иначе, я сделал все остальное, что хотел сделать с проектом Java, и у меня осталась часть распознавания лиц. К сожалению согласно (Актуальный вопрос № 1, Актуальный вопрос № 2) Я обнаружил, что в FaceRecognizer есть ошибка и что JNI-оболочка для распознавания лиц должна быть написана от руки.
Я нашел довольно хороший JNI C ++ Java-учебник и я попытался использовать это с кодом, упомянутым в соответствующем вопросе № 1, связанном выше. На скриншоте ниже показано, что я получил прямо сейчас.
Код выглядит следующим образом:
LBPHFaceRecognizer.java
import org.opencv.contrib.FaceRecognizer;
public class LBPHFaceRecognizer extends FaceRecognizer
{
static{
System.loadLibrary("opencv_java248");
System.loadLibrary("facerec");
}
private static native long n_createLBPHFaceRecognizer();
public LBPHFaceRecognizer()
{
super(n_createLBPHFaceRecognizer());
}
FaceRecognizer facerec = new LBPHFaceRecognizer();
}
LBPHFaceRecognizer.c
// facerec.dll
#include "jni.h"#include "opencv2/contrib/contrib.hpp"
extern "C" {JNIEXPORT jlong JNICALL Java_org_matxx_n_createLBPHFaceRecognizer(JNIEnv* env, jclass, jint);
JNIEXPORT jlong JNICALL Java_org_matxx_n_createLBPHFaceRecognizer(JNIEnv* env, jclass, jint)
{
try {
cv::Ptr<cv::FaceRecognizer> ptr = cv::createLBPHFaceRecognizer();
cv::FaceRecognizer * pf = ptr.get();
ptr.addref(); //don't let it self-destroy here..
return (jlong) pf;
} catch (...) {
jclass je = env->FindClass("java/lang/Exception");
env->ThrowNew(je, "sorry, dave..");
}
return 0;
}
} // extern "C"
Makefile
# Define a variable for classpath
CLASS_PATH = ../bin
# Define a virtual path for .class in the bin directory
vpath %.class $(CLASS_PATH)
all : facerec.dll
# $@ matches the target, $< matches the first dependancy
facerec.dll : LBPHFaceRecognizer.o
gcc -m64 -Wl,--add-stdcall-alias -shared -o $@ $<
# $@ matches the target, $< matches the first dependancy
LBPHFaceRecognizer.o : LBPHFaceRecognizer.c LBPHFaceRecognizer.h
gcc -m64 -I"C:\Program Files\Java\jdk1.7.0_51\include" -I"C:\Program Files\Java\jdk1.7.0_51\include\win32" -I"C:\Users\User\Desktop\OPENCVINSTALLATION\opencv" -I"C:\Users\User\Desktop\OPENCVINSTALLATION\opencv\build\java\x64" -c $< -o $@
# $* matches the target filename without the extension
LBPHFaceRecognizer.h : LBPHFaceRecognizer.class
javah -classpath $(CLASS_PATH) $*
clean :
rm LBPHFaceRecognizer.h LBPHFaceRecognizer.o facerec.dll
В целом мне удалось создать facerec.dll, но есть ряд проблем. Сначала, когда я создавал facerec.dll, у LBPHFacerecognizer.java не было импорта вверху, потому что он жаловался на это. Я добавил это позже, чтобы не видеть ошибку.
Во-вторых, код .c жалуется на все, как показано на скриншоте ниже.
и что интересно, он не жалуется на импорт jni.h, тогда как заголовочный файл, как видно на скриншоте ниже, делает.
Вот и все, может кто-нибудь взглянуть на это и сказать мне, правильно ли я это сделал? Есть что-то, что я должен изменить? Эти ошибки в порядке, учитывая тот факт, что DLL была создана? Или, может быть, кто-то делал это в прошлом и хочет поделиться файлом DLL. Я еще не удосужился протестировать его с помощью Java-кода JavaCV.
Я использую OpenCV 2.4.8, Win 7 64 бит, Mingw 64 бит, Java 64 бит 7_0_51 релиз, Eclipse 64 бит.
Заранее спасибо.
#include "jni.h"
не то же самое, что #include <jni.h>
Вот почему он жалуется на одно, а не на другое. Цитаты означают относительный путь. Другими словами, файл находится в той же папке, что и ваш проект. Или подпапка. В противном случае вы используете <...>
и включает в себя файлы в каталоге поиска компилятора.
Подпись принимает параметры: JNIEnv*, jclass, jint
когда это должно быть: принимая JNIEnv*, jclass
, Зачем? Потому что согласно подписи у вас на стороне Java private static native long n_createLBPHFaceRecognizer();
.. это не принимает никаких параметров .. Однако, вы объявили на нативной стороне, что принимают int.
По этой подписи: Java_org_matxx_n_createLBPHFaceRecognizer
, n_createLBPHFaceRecognizer
находится в пакете под названием Java_org_matxxx
но ваш java-код, похоже, не находится ни в каком пакете, кроме пакета «по умолчанию».
Если у функции jni есть подчеркивание в ее имени на стороне Java, вы должны заменить подчеркивание на _1
на родной стороне .. Пример:
Сторона Java (в пакете com.foo.bar): n_createLBPHFaceRecognizer
Родная сторона: Java_com_foo_bar_n_1createLBPHFaceRecognizer
В качестве простого обходного решения целесообразно не использовать подчеркивания в названии.
Других решений пока нет …