How can i cast a double pointer ctype to numpy array?

Question:

Hey I got this code which i’m using to cast numpy 2d array to ctype double pointer.

import ctypes as ct
import numpy as np

arr = np.empty([500, 500], dtype=np.uint8)

UI8Ptr = ct.POINTER(ct.c_uint8)
UI8PtrPtr = ct.POINTER(UI8Ptr)

ct_arr = np.ctypeslib.as_ctypes(arr)
UI8PtrArr = UI8Ptr * ct_arr._length_
ct_ptr = ct.cast(UI8PtrArr(*(ct.cast(row, UI8Ptr) for row in ct_arr)), UI8PtrPtr)

How can i cast ct_ptr back to numpy 2d array?

Asked By: Dan Shorla Ki

||

Answers:

Note: This is a follow up to [SO]: How to pass a 2d array from Python to C?.

One way would be going through the following states:

  1. CTypes pointer

  2. Python lists

  3. NumPy array

2 observations automatically arise:

  • It’s very inefficient, but unfortunately I’m not aware how to get rid of #2. (which is the culprit)

  • The pointer holds information about the base type, but not about the dimension(s) of the array it was created from, so you have to "save" them, as you’ll need them when "deconstructing" the pointer

code00.py:

#!/usr/bin/env python3

import ctypes as ct
import sys

import numpy as np


def main(*argv):
    dim0 = 3
    dim1 = 4
    arr0 = np.empty([dim0, dim1], dtype=np.uint8)
    print("Initial array:n{0:}".format(arr0))

    UI8Ptr = ct.POINTER(ct.c_uint8)
    UI8PtrPtr = ct.POINTER(UI8Ptr)

    ct_arr = np.ctypeslib.as_ctypes(arr0)
    UI8PtrArr = UI8Ptr * ct_arr._length_
    ct_ptr = ct.cast(UI8PtrArr(*(ct.cast(row, UI8Ptr) for row in ct_arr)), UI8PtrPtr)

    arr1 = np.array([[ct_ptr[i][j] for j in range(dim1)] for i in range(dim0)], dtype=ct_ptr._type_._type_._type_)
    print("nFinal array:n{0:}".format(arr1))
    print("nEqual arrays: {0:}".format(np.array_equal(arr0, arr1)))


if __name__ == "__main__":
    print("Python {:s} {:03d}bit on {: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:WorkDevStackOverflowq058781199]> "e:WorkDevVEnvspy_064_03.07.03_test0Scriptspython.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 064bit on win32

Initial array:
[[ 96 100 101 115]
 [105 114 101 100]
 [ 96  96  32 115]]

Final array:
[[ 96 100 101 115]
 [105 114 101 100]
 [ 96  96  32 115]]

Equal arrays: True

Done.

Fore more info on this topic check [SO]: Numpy error when converting array of ctypes types to void pointer (@CristiFati’s answer).

Answered By: CristiFati