【问题标题】:How to convert a ctypes C pointer to a Numpy array?如何将 ctypes C 指针转换为 Numpy 数组?
【发布时间】:2021-04-29 18:29:38
【问题描述】:

我正在用 Python 写一个回调函数:

@ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, np.ctypeslib.ndpointer(dtype=ctypes.c_ushort))
def FastModeCallback(hCam, x, y, w, h, binx, biny, imageBuffer_ptr):

    image = np.ctypeslib.as_array(imageBuffer_ptr, shape=(h, w))

如何将imageBuffer_ptr 转换为shape=(h,w)dtype=c.ushort 的Numpy 数组?

我读到了这个答案:Convert Pointer to Array of Unsigned Chars to Numpy Array

这个答案:Getting data from ctypes array into numpy

两者都建议使用np.ctypeslib.as_array,但是当我尝试它时,我得到了这个错误:

Exception ignored on calling ctypes callback function: <function FastModeCallback at 0x00000224E2992DC0>
Traceback (most recent call last):
  File "C:\Users\Dave\data\Code\Python\Cheese\atik.py", line 472, in FastModeCallback
    image = np.ctypeslib.as_array(imageBuffer_ptr, shape=(h, w))
  File "C:\Program_Files\anaconda3\lib\site-packages\numpy\ctypeslib.py", line 521, in as_array
    return array(obj, copy=False)
ValueError: '<P' is not a valid PEP 3118 buffer format string

Google 说这是 Python 中的一个长期存在的错误(我使用的是 3.8)- 什么是解决方法?

【问题讨论】:

  • 也许stackoverflow.com/questions/58049957/… 会有所帮助。
  • 另外你是怎么调用函数的?你向它传递了什么论据?
  • @CristiFati 这是第 3 方 DLL;我没有来源,也不知道怎么称呼。

标签: python numpy ctypes


【解决方案1】:

列出[Python.Docs]: ctypes - A foreign function library for Python[NumPy]: C-Types Foreign Function Interface (numpy.ctypeslib)。后者陈述了以下 2 项(强调是我的):

  1. as_array

    从 ctypes 数组或 POINTER 创建一个 numpy 数组。

  2. ndpointer

    ndpointer 实例用于描述 restypes 和 argtypes 规范中的 ndarray。这种方法比使用 POINTER(c_double) 更灵活,因为可以指定多个限制,这些限制在调用 ctypes 函数时进行验证。

imageBuffer_ptr 不是ctypes 数组或指针”(字面意思:它不是 ctypes.POINTER 实例,但 ctypes.c_void_p 一个(两者之间存在细微差别)。

C 层(在我们的例子中位于中间)不知道 NumPy 数组等等,所以从它的 PoV em>,该参数只是一个 unsigned short*(没有关于形状的信息,...)。因此,另一方面(在 Python 回调中),您必须从普通的 C 指针重建数组。这可以通过两种方式实现,就像我在下面的示例中所做的那样:

  • callback_ct:使用旧的C方式:修改回调的签名以使用ct.POINTER(ct.c_ushort) 。这是最直接的,但缺点是它在调用时会丢失所有额外的检查,这意味着它需要任何指针而不仅仅是 ndarray one

  • callback_np:根据参数手动重新创建数组(使用一系列转换)。它更先进(有些人甚至可能认为它有点骇人听闻)

code00.py

#!/usr/bin/env python

import sys
import ctypes as ct
import numpy as np


Base = ct.c_ushort

NpPtr = np.ctypeslib.ndpointer(
    dtype=Base,
    flags='C_CONTIGUOUS',
    #ndim=1,
)

CtPtr = ct.POINTER(Base)


@ct.CFUNCTYPE(None, ct.c_int, ct.c_int, NpPtr)
def callback_np(w, h, data):
    print("\ncallback_np:")
    #print(data, type(data), type(data).__mro__, hex(data.value))
    #print(data._ndim_, data._dtype_, data._shape_, data._type_, data._objects)
    img = np.ctypeslib.as_array(ct.POINTER(Base).from_address(ct.addressof(data)), shape=(h, w))
    #img = np.ctypeslib.as_array(data, shape=(h, w))  # Original form
    print(img)


@ct.CFUNCTYPE(None, ct.c_int, ct.c_int, CtPtr)
def callback_ct(w, h, data):
    print("\ncallback_ct:")
    img = np.ctypeslib.as_array(data, shape=(h, w))
    print(img)


def main(*argv):
    w = 2
    h = 3
    arr = np.array(range(h * w), dtype=Base)
    print("Array argument: ", arr, type(arr), arr.shape, arr.dtype, arr.ndim)
    callback_ct(w, h, np.ctypeslib.as_ctypes(arr))
    callback_np(w, h, arr)


if __name__ == "__main__":
    print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
    rc = main(*sys.argv[1:])
    print("\nDone.")
    sys.exit(rc)

输出

[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q067323177]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" code00.py
Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] 64bit on win32

Array argument:  [0 1 2 3 4 5] <class 'numpy.ndarray'> (6,) uint16 1

callback_ct:
[[0 1]
 [2 3]
 [4 5]]

callback_np:
[[0 1]
 [2 3]
 [4 5]]

Done.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 2021-10-01
    • 1970-01-01
    • 2020-01-22
    • 1970-01-01
    • 2023-04-01
    • 2021-08-03
    相关资源
    最近更新 更多