簡體   English   中英

如何將 ctypes C 指針轉換為 Numpy 數組?

[英]How to convert a ctypes C pointer to a Numpy array?

我在 Python 中寫了一個回調 function:

@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

谷歌讓它聽起來像是 Python 中的一個長期存在的錯誤(我在 3.8 上) - 什么是解決方法?

清單[Python.Docs]:ctypes - 用於 Python 和 [NumPy] 的外部 function 庫[NumPy]:C-Types 外部 Z86408593C34AF77FDD90DF932F8B5libpy61 接口 后者陳述了以下兩項(重點是我的):

  1. as_array

    從 ctypes 數組或 POINTER 創建一個 numpy 數組。

  2. 指針

    ndpointer 實例用於描述 restypes 和 argtypes 規范中的 ndarray。 這種方法比使用例如POINTER(c_double)更靈活,因為可以指定幾個限制,這些限制在調用 ctypes function 時得到驗證。

imageBuffer_ptr不是ctypes 數組或 POINTER ”(字面意思是:它不是ctypes.POINTER實例,而是ctypes.c_void_p之一(兩者之間存在細微差別))。

C層(在我們的例子中位於中間)不知道Z3B7F949B2343F9E5390 E29F6EF5E1778Z arrays 等等只是關於形狀的信息,所以從它的PoV未簽名的角度來看,該參數是一個簡短的信息……) . 因此,在另一邊(在Python回調中),您必須從普通的C指針重建數組。 這可以通過兩種方式實現,就像我在下面的示例中所做的那樣:

  • callback_ct :使用舊的C方式:修改回調的簽名以使用ct.POINTER(ct.c_ushort) 這是最直接的,但缺點是它在調用時會丟失所有額外的檢查,這意味着它需要任何指針而不僅僅是一個ndarray

  • callback_np :從參數手動重新創建數組(使用一系列轉換)。 它更先進(有些人甚至可能認為它有點駭人聽聞)

代碼00.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)

Output

 [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.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM