我正在尝试在Python中实现图像分类算法。问题是 python 循环遍历数组需要很长时间。这就是为什么我决定编写一个执行数组处理的Delphi dll。我的问题是我不知道如何将多维 python 数组传递给我的 dll 函数。
德尔福dll提取:(我只使用这个函数进行测试)
type
TImgArray = array of array of Integer;
function count(a: TImgArray): Integer; cdecl;
begin
result:= high(a);
end;
相关的 Python 代码:
arraydll = cdll.LoadLibrary("C:\ArrayFunctions.dll")
c_int_p = ctypes.POINTER(ctypes.c_int32)
data = valBD.ReadAsArray()
data = data.astype(np.int32)
data_p = data.ctypes.data_as(c_int_p)
print arraydll.count(data_p)
dll 函数返回的值不正确(它是 2816 而不是 7339)。 这就是为什么我想我的类型转换:(有些问题提前感谢,马里奥
您正在执行的操作不起作用,并且还可能损坏内存。
Delphi 动态数组在后台实现为一种数据结构,其中包含有关数组的一些元数据,包括长度。 但是你传递给它的是一个 C 风格的指针即数组,它是一个指针,而不是 Delphi 动态数组数据结构。 该结构特定于Delphi,您不能在其他语言中使用它。 (即使你设法用另一种语言实现了完全相同的结构,你仍然无法将其传递给Delphi DLL并使其正常工作,因为Delphi的内存管理器在后台参与其中。这样做只是要求堆损坏和/或内存管理器引发的异常。
如果要将 C 样式数组传递到 DLL 中,则必须执行 C 方式,即传递包含数组长度的第二个参数。你的 Python 代码应该已经知道长度,并且不需要任何时间来计算它。 您绝对可以使用德尔福来加速图像处理。 但是数组维度必须来自 Python 端。 这里没有捷径可以走。
您的 Delphi 函数声明应如下所示:
type
TImgArray = array[0..MAXINT] of Integer;
PImgArray = ^TImgArray;
function ProcessSomething(a: PImgArray; size: integer): Integer; cdecl;
普通的Python数组通常被称为"列表"。Python 中的 numpy.array 类型是一种特殊的类型,它比普通 Python 浮点对象的普通 Python 列表更节省内存。 Numpy.array 包装一个标准内存块,该内存块作为本机 C 数组类型进行访问。 反过来,这不会完全映射到德尔菲数组类型。
正如David所说,如果你愿意使用C,这一切都会更容易。 如果你想使用Delphi并访问Numpy.array,我怀疑最简单的方法是找到一种方法来导出一些访问Numpy.array类型的简单C函数。在 C 语言中,我会导入 numpy 标头,然后编写可以从 Pascal 调用的函数。然后,我将从 DLL 导入这些函数:
function GetNumpyArrayValue( arrayObj:Pointer; index:Integer):Double;
我已经有一段时间没有写任何CPython包装器代码了。 如果你想简单地从Delphi访问CORE PYTHON类型,这会更容易。现有的 Python-for-delphi 包装器将为您提供帮助。 将 numpy 与 Delphi 一起使用只是更多的工作。
由于你只写一个DLL而不是一个完整的应用程序,我强烈建议你忘记Delphi,用普通的C写这只小狗,这就是Python扩展(这就是你正在编写的)真正应该写的。
简而言之,由于您正在编写一个 DLL,因此在 Pascal 中,您至少需要另一个 C 语言的小 DLL,只是为了桥接 Python 扩展类型 (numpy.array) 和 Python 浮点值之间的类型。即便如此,您也不会轻易(快速)获得可以在 Delphi 中读取的数组值作为本机 delphi 数组类型。
我能想到的最快的访问机制是这样的:
type
PDouble = ^Double;
function GetNumpyArrayValue( arrayObj:Pointer; var doubleVector:PDouble; var doubleVectorLen:Integer):Boolean;
然后,可以使用 doubleVector(指针)类型的数学来访问基础 C 数组内存类型。