在使用jna将c代码Map到java时,应该为这种结构使用哪些类?

vu8f3i0k  于 2021-08-25  发布在  Java
关注(0)|答案(1)|浏览(328)

这是我的第一个问题,我认为这是解决这个问题的最佳社区。
我正在开发一个与图像处理相关的java应用程序,并尝试使用jna使用cviptools库(用c/c++编写)的函数,但这是我第一次使用此方法。
当我试图执行一个小测试来检查我是否能够执行c函数rst_不变量时,我得到了以下错误:

java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.Error: Invalid memory access
    at com.sun.jna.Native.invokePointer(Native Method)
    at com.sun.jna.Function.invokePointer(Function.java:497)
    at com.sun.jna.Function.invoke(Function.java:441)
    at com.sun.jna.Function.invoke(Function.java:361)
    at com.sun.jna.Library$Handler.invoke(Library.java:265)
    at com.sun.proxy.$Proxy2.rst_invariant(Unknown Source)
    at aplicacion.Main.main(Main.java:75)
    ... 11 more
Exception running application aplicacion.Main

显然,这个错误与内存管理有关,但我没有足够的知识和经验来检测它。我认为问题可能与c数据类型和我使用的java类之间的无效关系有关,但我不确定。
我附上了原始c函数的代码、结构和我尝试过的Map。
每一个改进代码的建议都是受欢迎的。如果您需要其他信息,请告诉我:d
非常感谢你!!!
rst_不变量.c

double* rst_invariant(Image* label_image, int r, int c) {
    int**         image;              /* 2-d matrix data pointer */

    int             y,                  /* Índice de fila */
                    x,                  /* Índice de columna */
                    p, q, i, j, label;

    double* ptr;
    double          moment[2][2],       /* zeroth moment and first moment */
                    moment1[4][4],      /* central moment */
                    moment2[4][4];      /* normalization of central moment */

    unsigned int    rows,               /* Número de filas en la imagen */
                    cols;               /* Número de columnas en la imagen */

    rows = getNoOfRows_Image(label_image);
    cols = getNoOfCols_Image(label_image);

    ptr = (double*)malloc(7 * sizeof(double));

    printf("hola\n");

    for (i = 0; i < 7; i++) ptr[i] = 0.0;

    for (i = 0; i < 2; i++)
        for (j = 0; j < 2; j++) moment[i][j] = 0.0;

    for (i = 0; i < 4; i++)
        for (j = 0; j < 4; j++) { 
            moment1[i][j] = 0.0; 
            moment2[i][j] = 0.0; 
        }

    /*
        Compara el valor del píxel de la ubicación (y,x)
        con el valor del umbral. Si es más grande que
        el umbral escribe 255 en la localización, si no escribe 0
    */

    image = (int**)getData_Image(label_image, 0);
    label = image[r][c];

    for (p = 0; p <= 1; p++) {
        for (q = 0; q <= 1; q++) {
            for (y = 1; y < rows; y++) {
                for (x = 1; x < cols; x++) {
                    if (image[y][x] == label) {
                        moment[p][q] = moment[p][q] + pow(x, p) * pow(y, q) * 1;   /* Para imágenes binarias, considera patrones binarios. Donde f(x, y) = 1 or 0, aquí 1 es blanco, 0 es negro */
                    }
                }
            }
        }
    }

    for (p = 0; p <= 3; p++) {
        for (q = 0; q <= 3; q++) {
            for (y = 1; y < rows; y++) {
                for (x = 1; x < cols; x++) {
                    if (image[y][x] == label) {
                        moment1[p][q] = moment1[p][q] + pow((x - (moment[1][0] / moment[0][0])), p) * pow((y - (moment[0][1] / moment[0][0])), q) * 1;  /* Para imágenes binarias, considera patrones binarios. Donde f(x, y) = 1 or 0, aquí 1 es blanco, 0 es negro */
                    }
                }
            }
        }
    }

    for (p = 0; p < 4; p++) {
        for (q = 0; q < 4; q++) {
            if ((p + q) == 2 || (p + q) == 3) {
                moment2[p][q] = moment1[p][q] / pow(moment1[0][0], ((p + q) * 0.5) + 1);
            }
        }
    }

    ptr[0] = moment2[2][0] + moment2[0][2];

    ptr[1] = (moment2[2][0] - moment2[0][2]) * (moment2[2][0] - moment2[0][2]) + 4 * (moment2[1][1]) * (moment2[1][1]);

    ptr[2] =
        (moment2[3][0] - 3 * moment2[1][2]) * (moment2[3][0] - 3 * moment2[1][2]) + (3 * moment2[2][1] - moment2[0][3]) * (3 * moment2[2][1] - moment2[0][3]);

    ptr[3] =
        (moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) + (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3]);

    ptr[4] =
        (moment2[3][0] - 3 * moment2[1][2]) * (moment2[3][0] + moment2[1][2]) * ((moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) - 3 * (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3])) + (3 * moment2[2][1] - moment2[0][3]) * (moment2[2][1] + moment2[0][3]) * (3 * (moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) - (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3]));

    ptr[5] =
        (moment2[2][0] - moment2[0][2]) * ((moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) - (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3])) + 4 * (moment2[1][1]) * (moment2[3][0] + moment2[1][2]) * (moment2[2][1] + moment2[0][3]);

    ptr[6] =
        (3 * moment2[2][1] - moment2[0][3]) * (moment2[3][0] + moment2[1][2]) * ((moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) - 3 * (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3])) - (moment2[3][0] - 3 * moment2[1][2]) * (moment2[2][1] + moment2[0][3]) * (3 * (moment2[3][0] + moment2[1][2]) * (moment2[3][0] + moment2[1][2]) - (moment2[2][1] + moment2[0][3]) * (moment2[2][1] + moment2[0][3]));

    return ptr;
}

图像结构

typedef struct {
    int image_format;
    int color_space;
    int bands;
    MATRIX**image_ptr;
} IMAGE;

# define bandP image_ptr

typedef IMAGE Image;

矩阵结构

typedef struct {
    int data_type;
    int data_format;
    unsigned int rows;
    unsigned int cols;
    char**rptr;
    char**iptr;
} MATRIX;

typedef MATRIX Matrix;

java中的图像结构Map

@Structure.FieldOrder({ "data_type", "color_space", "bands", "image_ptr" })
public class Image extends Structure {
    public int data_type;       // enum se mapea como int
    public int color_space;     // enum se mapea como int
    public int bands;
    public Matrix image_ptr;   // MATRIX**(doble puntero a struct)

    public Image() {
        super();
    }

    public Image(Matrix image_ptr) {
        super();
        // Valores por defecto, quizás se puedan eliminar
        this.data_type = 0;
        this.color_space = 0;
        this.bands = 0;

        this.image_ptr = image_ptr;
    }

java中的矩阵结构Map

@FieldOrder({ "data_type", "data_format", "rows", "cols", "rptr", "iptr" })
public class Matrix extends Structure {
    public int data_type;
    public int data_format;
    public int rows;
    public int cols;
    public Pointer rptr;
    public Pointer iptr;

    // CONSTRUCTOR
    public Matrix() {
        super();
    }

    public Matrix (int imagenMatriz[][], int columnas, int filas) {
        super();

        // Valores por defecto, quizás se puedan eliminar
        this.data_type = 0;
        this.data_format = 0;

        // Filas y columnas
        this.rows = filas;
        this.cols = columnas;

        // Asignación de memoria para la matriz 
        this.rptr = new Memory(this.rows * 8); // Creamos vector de Pointer con tamanho = alto de la imagen (número de filas). Cada puntero ocupa 8 bytes.

        for(int i = 0; i < this.rows; i++) {
            Pointer fila = new Memory(this.cols * Integer.BYTES);
            this.rptr.setPointer(i * 8, fila);

            for(int j = 0; j < this.cols; j++) {
                this.rptr.getPointer(i * 8).setInt(j * Integer.BYTES, imagenMatriz[j][i]); //Comentar y revisar esto, creo que está OK
            }
        }

        // Probablemente, eliminable, de momento lo dejamos así
        this.iptr = new Memory(8);
    }

java中的接口定义

public interface I_CVIPTools extends Library {
    I_CVIPTools INSTANCE = (I_CVIPTools) Native.load("rst_invariant", I_CVIPTools.class);

    public Pointer rst_invariant(Image label_image, int r, int c);

}

我试图执行的测试(我在最后一行中得到错误)

Matrix test_matrix = new Matrix(test.getMatriz(), test.getColumnas(), test.getFilas());
System.out.println("Píxel (702, 242) = " + test_matrix.getPixel(702, 242));

Image test_image = new Image(test_matrix);

Pointer vector = new Memory(7 * Double.BYTES);
vector = I_CVIPTools.INSTANCE.rst_invariant(test_image, 242, 702);
i1icjdpr

i1icjdpr1#

Map结构时要理解的关键点是它们何时被值和引用使用。
默认情况下,未装饰的结构是 ByReference 在方法/函数参数中使用时,以及 ByValue 在结构内部使用时。如果需要以默认方式以外的方式使用它,则需要专门使用适当的接口。
这个 Image 结构包含此本机元素:

MATRIX**image_ptr;

在jna中,这只是一个指针,或者 ByReference 结构。您错误地将其Map为内联 ByValue (默认情况下)结构:

public Matrix image_ptr;

这就是导致当前“无效内存访问”错误的原因。你正在填充 Image 使用来自您的 Matrix 结构。但是本机代码处理 Image struct看到两个整数 data_typedata_format 并试图将它们解释为指向结构数据所在位置的指针。你不拥有被指向的记忆。
我看不到全部 Matrix Map在您的问题中,但您需要包括 ByReference 间接寻址级别之一的标记。

@Structure.FieldOrder({ "data_type", "data_format", "rows", "cols", "rptr", "iptr" })
public class Matrix extends Structure {
    public static class ByReference implements Structure.ByReference {
    }

    public int data_type;
    public int data_format;
    public int rows;
    public int cols;
    public Pointer rptr;
    public Pointer iptr;
}

此外,由于有两种间接方式,您需要实际传递 PointerByReference 给你 Image 结构,因此您将使用以下内容替换当前Map:

public PointerByReference image_ptr;

要填充该值,请执行以下操作:

Matrix.ByReference matrix = new Matrix.ByReference();
test_image.image_ptr = new PointerByReference(matrix.getPointer());

相关问题