当使用JNA将C代码映射到Java时,我应该为这些结构使用哪些类



这是我在StackOverflow中的第一个问题,我认为这是解决这个问题的最佳社区。

我正在开发一个与图像处理相关的Java应用程序,并尝试使用JNA使用CVIPTools库(用C/C++编写(的函数,但这是我第一次为此目的使用这种方法。

当我试图执行一个小测试来检查我是否能够执行C函数时,我遇到了以下错误:

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

显然,这个错误与内存管理有关,但我对JNA没有足够的知识和经验来检测它。我认为这个问题可能与C数据类型和我使用的Java类之间的无效关系有关,但不确定。

我附上了原始C函数的代码、结构和我尝试过的映射

欢迎提出任何改进代码的建议。如果你需要传统信息,请告诉我:D

非常感谢你!!!

rst_invariation.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("holan");
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中的图像结构映射

@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中的矩阵结构映射

@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);

理解映射结构的关键点是按值使用与按引用使用。

默认情况下,在方法/函数参数中使用时,未修饰的结构为ByReference,在结构内部使用时为ByValue。如果您需要以默认以外的方式使用它,则需要专门使用适当的接口。

Image结构包括这个原生元素:

MATRIX** image_ptr;

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

public Matrix image_ptr; 

这就是导致您当前";无效存储器访问";错误您正在使用Matrix结构中的值填充Image结构。但是处理Image结构的本机代码看到两个intdata_typedata_format,并试图将它们解释为指向结构数据所在位置的指针。你不拥有被指向的记忆。

我在您的问题中没有看到完整的Matrix映射,但您需要为其中一个间接级别包含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结构,因此您将用替换当前映射

public PointerByReference image_ptr;

填充该值:

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

最新更新