最近在做项目需要调用C++中的OpenCV源码,必须要将numpy类型的数组传到C++中才行,在网上找了一大圈方法,特别是这个大佬的代码:
https://github.com/Algomorph/pyboostcvconverter
刚开始用这位大佬的代码,得经过重重编译才能使用,起初一直编译不成功,要么就编译成功了调用失败,折腾了三天,终于成功调用它的实例代码了,但是当我想改C++代码中的函数来实现自己的需求时,又失败了,在反复折磨下,我放弃了。
后面自己还是慢慢摸索别的方法,终于!!!歪打正着让我碰上个特别简单的方法,用ctypes!!!最主要的是发现numpy库里面居然有对接ctypes的库,这下问题就好解决了。
numpy.ctypeslib的ndpointer可以将numpy数组变为指针类型通过ctype传入到C++中,然后numpy.ctypeslib中的as_array也可以将C++代码返回的指针重新变成numpy数组。
具体看代码:
import ctypes
import numpy as np
import cv2 as cv
from numpy.ctypeslib import ndpointer, as_array
src= cv.imread("test.jpg", cv.IMREAD_GRAYSCALE)
src = cv.equalizeHist(src)
height = src.shape[0]
width = src.shape[1]
# 这里要将numpy数组中的元素类型转换成ctypes类型
imageinfo = src.astype(ctypes.c_int)
dllfile = ctypes.CDLL("test.dll")
# 这里的ndpointer表示传入C++的参数是一个numpy数组指针
dllfile.C++函数名称.argtypes = [ndpointer(dtype=ctypes.c_int),
ctypes.c_int,
ctypes.c_int,
]
dllfile.C++函数名称.restype = ctypes.POINTER(ctypes.c_int)
result = dllfile.C++函数名称(imageinfo, height, width)
# 返回的result是一个指针,直接用as_array就可以将它变成numpy数组,shape可以定义数组维度。
numpy_array= as_array(result , shape=(num, 1))
现在Python传numpy数据和取C++的返回值都解决了,那么C++里面接收到numpy数据的指针又改如何将其变成Mat类型呢?
无论numpy数组之前的维度是什么,传到C++里面统一变成一维,我们要还原维度,就要传入图片各个维度信息,像我的代码里面传入了height和width,再配合指针,C++里面一行代码直接还原。
直接看代码:
//创建Mat并赋值,image就是传进来的numpy指针。
Mat src = Mat(height, width, CV_32S, image);
这样廖廖数行代码就将numpy数据转换成C++中OpenCV的Mat数据了,是不是超级简单,而且这个转换过程都是指针操作,不涉及内存复制啊,转移啊啥的耗时间的操作。
这次经历也告诉我,不要看到网上的方法就一股脑去做,在做之前要自己先想一想有没有什么简单的方法,自己多去尝试,总会发现新的东西的。