python - ctypes在使用指向类对象的指针调用函数时出错
问题描述
我的 C++ DLL 中有两个包装函数。
该函数CreateObj()
创建其他类的对象并返回指向该对象的指针 在第二个函数中DoSomething
,我将先前创建的指针作为第一个参数传递,第二个参数是无符号字符的 RGB 图像 (1200, 1200,3)。
在 python 端,我加载 DLL 并希望调用两个包装函数来对我在 python 端加载的 RGB 图像进行一些处理。DoSomething
在从 python调用的最后一步中,我得到了一个 OSError 。
任何帮助将不胜感激。
//The C++ library code
class Obj
{
/*..../*
};
extern "C"
{
#ifdef BUILD_AS_DLL
__declspec(dllexport)
#endif
Obj* CreateObj();
int DoSomething( Obj* ptr, uint8_t* t[1200][1200][]); //ptr was created using CreateObj and second argument is an image array of unsigned char of shape [1200][1200][3]
#ifdef BUILD_AS_DLL
__declspec(dllexport)
#endif
}
调用上述DLL的Python代码
from ctypes import *
import numpy as np
import numpy.ctypeslib as npct
import cv2
path = os.path.join(os.getcwd(), "mwe.dll")
lib = ctypes.CDLL(path)
create_func = lib.CreateObj
create_func.restype = c_void_p
obj = c_void_p(create_func())
dosomething_func = lib.DoSomething
ucharPtr = npct.ndpointer(dtype=np.uint8,
ndim=3,
shape = (1200,1200,3),
flags='CONTIGUOUS')
dosomething_func.argtype = (c_void_p,
ucharPtr)
dosomething_func.restype = c_int
img = cv2.imread("path/to/image")
img_ctype = byref(img.ctypes.data_as(c_void_p))
dosomething_func(byref(obj), img_ctype) // ERROR on this line
我收到错误
File "mwe.py", line 24, in <module>
res = dosomething_func(
OSError: exception: access violation reading 0xFFFFFFFFFFFFFFFF
解决方案
这是一个解决方案的最小可重现示例,演示了将一个小的 3D numpy 数组传入和传出函数:
测试.cpp:
请注意,这uint8_t* t[1200][1200][]
在语法上是不正确的。变量数组维度必须是第一个,而不是最后一个,这是一个指针数组而不是 8 位数据数组。
#include <cstdint>
#include <iostream>
using namespace std;
#define API __declspec(dllexport)
class Obj
{
int m_x;
public:
Obj(int x): m_x(x) {}
int get_x() const { return m_x; }
};
extern "C" {
API Obj* CreateObj() {
return new Obj(5);
}
API int DoSomething(Obj* ptr, uint8_t t[][3][3]) {
for(uint8_t i=0; i < 3; ++i) {
for(uint8_t j=0; j < 3; ++j) {
for(uint8_t k=0; k < 3; ++k) {
cout << static_cast<uint32_t>(t[i][j][k]) << ' ';
t[i][j][k] *= 2;
}
cout << endl;
}
cout << endl;
}
return ptr->get_x();
}
}
测试.py:
假设cv2.imread()
返回np.array
与声明类型相同的类型和形状ndpointer
,您只需将其直接传递给函数。
from ctypes import *
import numpy as np
import numpy.ctypeslib as npct
lib = CDLL('./test')
class OBJ(Structure):
_fields_ = []
ARRAY = npct.ndpointer(dtype=np.uint8,shape=(3,3,3))
lib.CreateObj.argtypes = c_int,
lib.CreateObj.restype = POINTER(OBJ)
lib.DoSomething.argtypes = POINTER(OBJ),ARRAY
lib.DoSomething.restype = c_int
arr = np.arange(27,dtype=np.uint8).reshape((3,3,3))
obj = lib.CreateObj(5)
result = lib.DoSomething(obj,arr)
print(f'result = {result}')
print(arr)
输出:
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
15 16 17
18 19 20
21 22 23
24 25 26
result = 5
[[[ 0 2 4]
[ 6 8 10]
[12 14 16]]
[[18 20 22]
[24 26 28]
[30 32 34]]
[[36 38 40]
[42 44 46]
[48 50 52]]]
推荐阅读
- oracle - SUBQUERIES数据库Oracle上的无效标识符
- python - 将嵌套字典元素移动到顶层并让剩余的嵌套元素值跟随 | 蟒蛇 | 姜戈
- python-3.x - 如何使用 colorama 将 Python 背景更改为某种颜色?
- swift - 如何在 Swift 4 中访问扩展
- docker - 容器级别的 GPU 统计信息
- xamarin - Xamarin iOS 渲染器中使用的“if (Control == null)”部分是什么?
- authentication - Jmeter 未通过我的脚本中的 Microsoft 身份验证以在我的测试网站上测试性能,显示访问被拒绝
- javascript - 以反应形式有条件地添加指令
- mongodb - Codeigniter 将 2 个元素数据更新到 mongodb
- typescript - TypeScript:在对象上强制执行单个动态键