0

I have been given a project based around face recognition written in JavaCV to be improved. The idea was to either rewrite the program using C++ or write JNI bindings to still use Java. I did some research and according to the official website OpenCV as of version 2.4.4 has bindings for Java and Python. And so, since the official website stated so I decided to go with it. Please note I haven't programmed in C++ before nor have I written any JNI wrappers in the past. If the official website didn't state that it includes bindings for Java I would just write it with C++ using Qt Digia.

This way or another I did everything else that I wanted to do with the Java project and was left with the face recognition part. Unfortunately according (Relevant question #1, Relevant question #2) I found out that there is a bug with FaceRecognizer and that JNI wrapper for face recognition has to be written by hand.

I found a pretty good jni c++ java tutorial and I tried to use that with the code mentioned in Relevant question #1 linked above. The screenshot below shows what I have got right now. c++ jni project screenshot
The code is as follows: 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

All in all I managed to create facerec.dll, but there are a number of problems. First when I was creating the facerec.dll the LBPHFacerecognizer.java did not have the import at the top, because it was complaining about it. I added it afterwards just not to see the error. Secondly the .c code complains about everything as seen on the screenshot below..c code errors

and interestingly enough it doesn't complain about the jni.h import whereas the header file as seen on screenshot below does.
error about jni.h

That's it, can someone have a look at it and tell me if I've done it correctly? Is there something I should change? Are those errors ok considering the fact the the dll has been created? Or maybe someone has done it in the past and is willing to share the dll file. I haven't gotten around to testing it with the java equivalent of JavaCV code yet.

I use OpenCV 2.4.8, Win 7 64bit, Mingw 64 bit, Java 64 bit 7_0_51 release, Eclipse 64 bit.

Thanks in advance.

4

1 回答 1

2
  1. #include "jni.h"#include <jni.h>这就是为什么它抱怨一个而不是另一个的原因不同。引号表示相对路径。换句话说,该文件与您的项目位于同一文件夹中。或子文件夹。否则,您使用<...>它并在编译器的搜索目录中包含文件。

  2. 签名采用参数:JNIEnv*, jclass, jint何时应该采用:采用JNIEnv*, jclass. 为什么?因为根据您在 Java 端的签名private static native long n_createLBPHFaceRecognizer();.. 它不带参数.. 但是,您在本机端将它声明为采用 int。

  3. 根据此签名名称:Java_org_matxx_n_createLBPHFaceRecognizer,n_createLBPHFaceRecognizer在一个名为Java_org_matxxx但您的 java 代码似乎不在“默认”包以外的任何包中。

  4. 如果 jni 函数在 Java 端的名称中包含下划线,则必须在本机端将下划线替换为_1.. 示例:

Java 端(在 com.foo.bar 包中):n_createLBPHFaceRecognizer

本机方面:Java_com_foo_bar_n_1createLBPHFaceRecognizer

作为一个简单的解决方法,明智的做法是名称中不要包含下划线。

于 2014-04-08T22:16:16.033 回答