Question
Is it possible to call a C DLL with a pointer to a 3dim array via Ctypes?
Progress
First off, I'm quite new to C and DLLs, so I might not know/have overseen something trivial.
I've got it to run with a pointer to a 1dim array. However it would be really nice to be able to use a 3dim array because I want to manipulate RGB image data, which does need edge repetition.
Python-Code
import ctypes
import ctypes.util
from numpy.ctypeslib import ndpointer
import PBMS_ImageIO
import numpy as np
#Loads a image as 3dim array and converts it to 1dim array with "size" as length
image = PBMS_ImageIO.readImage('Image.png')
size = np.shape(image)[0]*np.shape(image)[1]*np.shape(image)[2]
imageIn = np.reshape(image, (size,))
PBMS_ImageConverter = ctypes.windll.LoadLibrary(ctypes.util.find_library('./PBMS_ImageConvert.dll'))
nd_pointer = np.ctypeslib.ndpointer(dtype=np.float32, ndim=1, flags=("C"))
PBMS_ImageConverter.RGB2BW.argtypes=[nd_pointer, ctypes.c_int]
PBMS_ImageConverter.RGB2BW.restype = ndpointer(dtype=ctypes.c_float,
shape=(size,))
imageOut = PBMS_ImageConverter.RGB2BW(imageIn, size)
C-Code
#include <math.h>
float * RGB2BW(const float * matrixIn, int size)
{
float * matrixOut = (float *)malloc(sizeof(float)*size);
for(int i = 0; i < size; i++)
{
matrixOut[i] = matrixIn[i];
}
return matrixOut;
}
Alternative
If calling a DLL via Ctypes is not capable of using a 3dim pointer, would it be feasible to convert a 1dim array to a 3dim array internally?
Uncertainty
I'm also not sure how a numpy array is stored in memory. Could it be that my efforts to pass a pointer to a 3dim array did not work out because the underlying numpy array is not really stored as 3dim?
Numpy arrays are stored in the same memory orientation as C arrays by default. On the Python side you can work with 3D arrays, but it's easier on the C side to treat as a 1D array and do the math to access rows and columns.
Example below requires a 3D numpy array as an argument, but passes the dimensions so the C code can access the elements. The C code modifies the array in-place:
test.c
#include <stdio.h>
__declspec(dllexport)
void RGB2BW(float* matrix, int x, int y, int z)
{
for(int i = 0; i < x; ++i)
for(int j = 0; j < y; ++j)
for(int k = 0; k < z; ++k)
{
int index = i * y * z + j * z + k;
printf("matrix[%d][%d][%d] = %f\n",i,j,k,matrix[index]);
matrix[index] *= 2;
}
}
test.py
import numpy as np
from ctypes import *
dll = CDLL('./test')
dll.RGB2BW.argtypes = np.ctypeslib.ndpointer(dtype=np.float32,ndim=3),c_int,c_int,c_int
dll.RGB2BW.restype = None
a = np.arange(0,2.4,.1,dtype=np.float32).reshape(2,3,4)
dll.RGB2BW(a,*a.shape)
print(a)
Output:
matrix[0][0][0] = 0.000000
matrix[0][0][1] = 0.100000
matrix[0][0][2] = 0.200000
matrix[0][0][3] = 0.300000
matrix[0][1][0] = 0.400000
matrix[0][1][1] = 0.500000
matrix[0][1][2] = 0.600000
matrix[0][1][3] = 0.700000
matrix[0][2][0] = 0.800000
matrix[0][2][1] = 0.900000
matrix[0][2][2] = 1.000000
matrix[0][2][3] = 1.100000
matrix[1][0][0] = 1.200000
matrix[1][0][1] = 1.300000
matrix[1][0][2] = 1.400000
matrix[1][0][3] = 1.500000
matrix[1][1][0] = 1.600000
matrix[1][1][1] = 1.700000
matrix[1][1][2] = 1.800000
matrix[1][1][3] = 1.900000
matrix[1][2][0] = 2.000000
matrix[1][2][1] = 2.100000
matrix[1][2][2] = 2.200000
matrix[1][2][3] = 2.300000
[[[0. 0.2 0.4 0.6 ]
[0.8 1. 1.2 1.4 ]
[1.6 1.8000001 2. 2.2 ]]
[[2.4 2.6000001 2.8 3. ]
[3.2 3.4 3.6000001 3.8 ]
[4. 4.2000003 4.4 4.6 ]]]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.