我目前正在编写一个 JNI 加速器库来替换某些系统(Linux x64 和 macOS)上的 Java 方法。
我有一个用JavaCV 3.4.2用 Kotlin/Java 编写的工作代码
我创建了一个 JNI 库,它执行相同的工作以避免 JVM 和 JNI 之间的多次来回。
例子:
Kotlin 端(JVM + JavaCV)没有加速:
override fun process(image: Mat): FeaturesDetectorResult {
val faceDetection = Dlib.faceDetection(image)
...
}
JNI加速器部分:
科特林
@ByVal
protected external fun Process(imagePtr: Long, lines: List<opencv_core.Rect>): opencv_core.Mat?;
// method of class overriding the native method
override fun process(image: opencv_core.Mat): FeaturesDetectorResult {
val lines = ArrayList<opencv_core.Rect>()
val rotatedMat = Process(image.address(), lines)
return FeaturesDetectorResult(rotatedMat, lines)
}
C++
JNIEXPORT jlong JNICALL Java_fr_tessi_bmd_image_accel_MserFeaturesDetectorNative_Process
(JNIEnv *env, jobject self, jlong imagePtr, jobject list) {
在我的 C++ 方法结束时,我被困在将本机cv::Mat
转换为其 Java 对应项opencv_core.Mat
(不存在具有本机地址的构造函数)。
我查看了 javacpp 生成的源代码,似乎本机对象被视为jlong
. 我以这种方式进行的所有测试都会导致崩溃。
有人知道如何org.bytedeco.javacpp
使用自制的 JNI 库来回传递对象吗?
编辑:
我找到了一个部分解决方法来创建opencv_mat.Mat
:cv::Mat
//Safety checks removed for simplicity
#define ptr_to_jlong(a) ((jlong)(uintptr_t)(a))
Mat* toReturnToJava;
jclass pointerClass = env->FindClass("org/bytedeco/javacpp/Pointer");
jfieldID addressFld = env->GetFieldID(pointerClass, "address", "J");
jobject pointerObj = env->AllocObject(pointerClass);
env->SetLongField(pointerObj, addressFld, ptr_to_jlong(toReturnToJava));
将在 Java 端将返回值声明为 时Mat
返回给 Java 。jlong
opencv.Mat
相同类型的代码似乎不适用于 Rect(我使用了构造函数 Rect(x, y, w, h) 代替)。