如何从 jni C++ 函数 return 向量 <Point>?
How to return a vector<Point> from a jni C++ function?
我正在开发一个 android 项目,使用 Opencv 处理图像。
我写了一个 android jni 函数,它应该 return 一个向量,但我不知道如何正确地做到这一点。
我尝试将向量转换为 jobjectArray,但它不起作用。
这是我正在处理的代码:
jobjectArray
Java_com_grimg_testtt_MainActivity_getQuadrilateral(
JNIEnv *env,
jobject /* this */,
cv::Mat & grayscale,
cv::Mat & output) {
std::vector<std::string> vec;
cv::Mat approxPoly_mask(grayscale.rows, grayscale.cols, CV_8UC1);
approxPoly_mask = cv::Scalar(0);
std::vector<std::vector<cv::Point>> contours;
std::vector<int> indices(contours.size());
std::iota(indices.begin(), indices.end(), 0);
sort(indices.begin(), indices.end(), [&contours](int lhs, int rhs) {
return contours[lhs].size() > contours[rhs].size();
});
/// Find the convex hull object for each contour
std::vector<std::vector<cv::Point>> hull(1);
cv::convexHull(cv::Mat(contours[indices[0]]), hull[0], false);
std::vector<std::vector<cv::Point>> polygon(1);
approxPolyDP(hull[0], polygon[0], 20, true);
drawContours(approxPoly_mask, polygon, 0, cv::Scalar(255));
//imshow("approxPoly_mask", approxPoly_mask);
if (polygon[0].size() >= 4) // we found the 4 corners
{
return(polygon[0]);
}
return(std::vector<cv::Point>());
}
在最后两行中,我收到了这个很明显的错误:
Returning 'std::vector<cv::Point> &' from a function returning 'jobjectArray': Types 'jobjectArray' and 'std::vector<cv::Point>' are not compatible.
我该怎么做才能克服这个问题?
编辑:
jclass clazz = (*env).FindClass("java/util/ArrayList");
jobjectArray result = (*env).NewObjectArray(polygon[0].size(), clazz, 0);
if (polygon[0].size() >= 4) // we found the 4 corners
{
for (int n=0;n<polygon[0].size();n++)
{
cv::Point point = (cv::Point) static_cast<cv::Point>(polygon[0][n]);
(*env).CallVoidMethod(result, (*env).GetMethodID(clazz, "add", "(java/lang/Object)V"), point);
}
return result;
}
return result;
}
编辑 2:
jclass ptCls = env->FindClass("java/awt/Point");
jobjectArray result = (*env).NewObjectArray(polygon[0].size(), ptCls, NULL);
if (result == NULL) return NULL;
if (polygon[0].size() >= 4) // we found the 4 corners
{
for (int n=0;n<polygon[0].size();n++)
{
jobject point = (jobject) static_cast<jobject>(polygon[0][n]);
//(*env).CallVoidMethod(result, (*env).GetMethodID(ptCls, "add", "(java/lang/Object)V"), polygon[0][n]);
(*env).SetObjectArrayElement(result, polygon[0].size(), point);
}
return result;
}
return result;
错误
error: cannot cast from type 'std::__ndk1::__vector_base<cv::Point_<int>, std::__ndk1::allocator<cv::Point_<int> > >::value_type' (aka 'cv::Point_<int>') to pointer type 'jobject' (aka '_jobject *')
jobject point = (jobject) static_cast<jobject>(polygon[0][n]);
在 JNI 层中,您应该将本机对象映射到 Java 个对象(Java 个对象分配在 JVM 堆上)。
cv::Point
需要转换为 Java class 并且 std::vector
需要转换为 jobjectArray
.
使用 (*env)->NewObjectArray
创建 jobjectArray
像这样:
jobjectArray result = (*env)->NewObjectArray(env, size, PointCls, NULL);
if (result == NULL) return NULL;
PointCls
应该是指对应你母语的JavaclassPoint
class.
然后遍历每个原生 cv::Point 对象,create a Java Point from it, copy the fields, and put it into the array (using (*env)->SetObjectArrayElement
).
然后你可以 return result
数组。
例如像这样:
std::vector<cv::Point> const& input = polygon[0];
jclass doubleArray = env->FindClass("[D");
if (doubleArray == NULL) return NULL;
jobjectArray result = env->NewObjectArray(input.size(), doubleArray, NULL);
if (result == NULL) return NULL;
for (int i = 0; i < input.size(); ++i) {
jdoubleArray element = env->NewDoubleArray(2);
if (element == NULL)
break;
jdouble buf[2] = { input[i].x, input[i].y };
env->SetDoubleArrayRegion(element, 0, 2, buf);
env->SetObjectArrayElement(result, i, element);
}
return result;
这将return一个二维数组double[][]
,其中x
、y
对应二维的0
、1
.
我正在开发一个 android 项目,使用 Opencv 处理图像。 我写了一个 android jni 函数,它应该 return 一个向量,但我不知道如何正确地做到这一点。
我尝试将向量转换为 jobjectArray,但它不起作用。 这是我正在处理的代码:
jobjectArray
Java_com_grimg_testtt_MainActivity_getQuadrilateral(
JNIEnv *env,
jobject /* this */,
cv::Mat & grayscale,
cv::Mat & output) {
std::vector<std::string> vec;
cv::Mat approxPoly_mask(grayscale.rows, grayscale.cols, CV_8UC1);
approxPoly_mask = cv::Scalar(0);
std::vector<std::vector<cv::Point>> contours;
std::vector<int> indices(contours.size());
std::iota(indices.begin(), indices.end(), 0);
sort(indices.begin(), indices.end(), [&contours](int lhs, int rhs) {
return contours[lhs].size() > contours[rhs].size();
});
/// Find the convex hull object for each contour
std::vector<std::vector<cv::Point>> hull(1);
cv::convexHull(cv::Mat(contours[indices[0]]), hull[0], false);
std::vector<std::vector<cv::Point>> polygon(1);
approxPolyDP(hull[0], polygon[0], 20, true);
drawContours(approxPoly_mask, polygon, 0, cv::Scalar(255));
//imshow("approxPoly_mask", approxPoly_mask);
if (polygon[0].size() >= 4) // we found the 4 corners
{
return(polygon[0]);
}
return(std::vector<cv::Point>());
}
在最后两行中,我收到了这个很明显的错误:
Returning 'std::vector<cv::Point> &' from a function returning 'jobjectArray': Types 'jobjectArray' and 'std::vector<cv::Point>' are not compatible.
我该怎么做才能克服这个问题?
编辑:
jclass clazz = (*env).FindClass("java/util/ArrayList");
jobjectArray result = (*env).NewObjectArray(polygon[0].size(), clazz, 0);
if (polygon[0].size() >= 4) // we found the 4 corners
{
for (int n=0;n<polygon[0].size();n++)
{
cv::Point point = (cv::Point) static_cast<cv::Point>(polygon[0][n]);
(*env).CallVoidMethod(result, (*env).GetMethodID(clazz, "add", "(java/lang/Object)V"), point);
}
return result;
}
return result;
}
编辑 2:
jclass ptCls = env->FindClass("java/awt/Point");
jobjectArray result = (*env).NewObjectArray(polygon[0].size(), ptCls, NULL);
if (result == NULL) return NULL;
if (polygon[0].size() >= 4) // we found the 4 corners
{
for (int n=0;n<polygon[0].size();n++)
{
jobject point = (jobject) static_cast<jobject>(polygon[0][n]);
//(*env).CallVoidMethod(result, (*env).GetMethodID(ptCls, "add", "(java/lang/Object)V"), polygon[0][n]);
(*env).SetObjectArrayElement(result, polygon[0].size(), point);
}
return result;
}
return result;
错误
error: cannot cast from type 'std::__ndk1::__vector_base<cv::Point_<int>, std::__ndk1::allocator<cv::Point_<int> > >::value_type' (aka 'cv::Point_<int>') to pointer type 'jobject' (aka '_jobject *')
jobject point = (jobject) static_cast<jobject>(polygon[0][n]);
在 JNI 层中,您应该将本机对象映射到 Java 个对象(Java 个对象分配在 JVM 堆上)。
cv::Point
需要转换为 Java class 并且 std::vector
需要转换为 jobjectArray
.
使用 (*env)->NewObjectArray
创建 jobjectArray
像这样:
jobjectArray result = (*env)->NewObjectArray(env, size, PointCls, NULL);
if (result == NULL) return NULL;
PointCls
应该是指对应你母语的JavaclassPoint
class.
然后遍历每个原生 cv::Point 对象,create a Java Point from it, copy the fields, and put it into the array (using (*env)->SetObjectArrayElement
).
然后你可以 return result
数组。
例如像这样:
std::vector<cv::Point> const& input = polygon[0];
jclass doubleArray = env->FindClass("[D");
if (doubleArray == NULL) return NULL;
jobjectArray result = env->NewObjectArray(input.size(), doubleArray, NULL);
if (result == NULL) return NULL;
for (int i = 0; i < input.size(); ++i) {
jdoubleArray element = env->NewDoubleArray(2);
if (element == NULL)
break;
jdouble buf[2] = { input[i].x, input[i].y };
env->SetDoubleArrayRegion(element, 0, 2, buf);
env->SetObjectArrayElement(result, i, element);
}
return result;
这将return一个二维数组double[][]
,其中x
、y
对应二维的0
、1
.