Как вернуть вектор <Point>из функции jni C ++? - PullRequest
0 голосов
/ 28 января 2019

Я работаю над проектом Android для обработки изображений с помощью Opencv.Я написал функцию Android JNI, которая должна возвращать вектор, но я не могу понять, как это сделать правильно.

Я пытался преобразовать вектор в 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]);

1 Ответ

0 голосов
/ 28 января 2019

В слое JNI необходимо сопоставить собственные объекты с объектами Java (объекты Java размещаются в куче JVM).

cv::Point необходимо преобразовать в класс Java, а std::vector -преобразован в jobjectArray.

Используйте (*env)->NewObjectArray для создания jobjectArray следующим образом:

jobjectArray result = (*env)->NewObjectArray(env, size, PointCls, NULL);
if (result == NULL) return NULL;

PointCls должен ссылаться на класс Java, которыйсоответствует вашему собственному Point классу.

Затем выполните итерации по каждому собственному объекту cv :: Point, создайте точку Java из нее, скопируйте поля и поместите ее в массив (используя (*env)->SetObjectArrayElement).

Затем вы можете вернуть массив 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;

Это будетвернуть двумерный массив double[][], с x, y, соответствующим 0, 1 во втором измерении.

...