本文主要是介绍ctypes实现numpy和OpenCV Mat之间的数据交互,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、目的
将c/c++编译成动态链接库,通过python调用,实现常见变量比如int,字符串之间的交互,以及np.ndarray和cv::Mat间的交互. 更简单的方式参考:pybind11实现numpy和OpenCV Mat的数据交互-CSDN博客
2 步骤
新建CMakeLists.txt,如下,需要安装opencv,安装教程参考Ubuntu 18.04 安装opencv4.2.0,如果遇到IPPICV问题参考解决编译opencv时,卡在IPPICV
cmake_minimum_required(VERSION 3.10)
project(test)
add_definitions(-std=c++11)
add_definitions(-DAPI_EXPORTS)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
find_package(OpenCV)
include_directories(${OpenCV_INCLUDE_DIRS})
add_library(myplugins SHARED ${PROJECT_SOURCE_DIR}/test.cpp)
target_link_libraries(myplugins ${OpenCV_LIBS})
新建test.cpp
#include <opencv2/opencv.hpp>
#include <string>
using namespace std;#if defined(_MSC_VER)
#define API __declspec(dllimport)
#else
#define API
#endif // API_EXPORTStypedef struct test
{/* data */int ages;std::string name;cv::Mat pic;
} Person;extern "C" API void * init(int age_, char * name_ptr, unsigned char *src_data, int rows, int cols)
{Person *handle = new Person();std::string name_ = name_ptr;handle->ages = age_;handle->name = name_;handle->pic = cv::Mat(rows, cols, CV_8UC3, src_data);return (void*) handle;
}extern "C" API int get_ages(void* handle_)
{Person * handle = (Person*)handle_;return handle->ages;
}extern "C" API char* get_name(void* handle_)
{Person * handle = (Person*)handle_;return (char*)handle->name.c_str();
}extern "C" API void get_pic(void* handle_, int rows, int cols, unsigned char* out_data)
{Person * handle = (Person*)handle_;cv::imshow("raw", handle->pic);cv::waitKey();//数据处理//....//返回结果memcpy(out_data, handle->pic.data, rows*cols*3);
}
新建test.py,具体转换见代码注释
from ctypes import *
import cv2
import numpy as np
import numpy.ctypeslib as npct#加载链接库
lib = CDLL('./build/libmyplugins.so')#定义函数的输入类型和输出类型
lib.get_ages.restype = c_int
lib.get_ages.argtypes = [c_void_p] #输入句柄(指针)
lib.get_name.restype = c_void_p #返回char*
lib.get_name.argtypes = [c_void_p] #输入句柄(指针)img = cv2.imread("oil-bin-1.png") #修改成自己的图片
ages = 23
name = bytes("kitty", "utf-8") #要对应c函数中的char*,需要转为二进制(rows, cols) = (img.shape[0], img.shape[1])
image_type = npct.ndpointer(dtype = np.uint8, ndim = 3, shape = img.shape, flags="C_CONTIGUOUS") #指定numpy图片的格式lib.init.restype = c_void_p #返回句柄(指针)
lib.init.argtypes = [c_int, c_void_p, image_type, c_int, c_int]#将np格式的图片传递到c
hd = lib.init(c_int(ages), c_char_p(name), img, c_int(rows), c_int(cols))print(lib.get_ages(hd)) #返回整数,直接打印
name = c_char_p(lib.get_name(hd)).value #返回char*, 需要转换
print(name.decode('utf-8')) #解码成字符串##第一种读取图片的方式,使用ndpointer指定图片类型
out_image = np.zeros_like(img).astype(np.uint8) #需要先开辟内存
lib.get_pic.argtypes = [c_void_p, c_int, c_int, image_type]
lib.get_pic(hd, c_int(rows), c_int(cols), out_image)
cv2.imshow("out1", out_image)##第二种读取图片的方式,不使用ndpointer指定图片类型
out_image = np.zeros_like(img).astype(np.uint8) #需要先开辟内存
lib.get_pic.argtypes = [c_void_p, c_int, c_int, c_void_p] #句柄(指针),rows,cols, 图片指针
lib.get_pic(hd, c_int(rows), c_int(cols), out_image.ctypes.data_as(POINTER(c_ubyte)))cv2.imshow("out2", out_image)
cv2.waitKey()
3、测试
将上述3个文件放到同一个目录,然后在命令行中进入到该目录,依次运行,会弹出图片,单击图片,按任意键即可
mkdir build
cd build
cmake ..
make
cd ..
python test.py
这篇关于ctypes实现numpy和OpenCV Mat之间的数据交互的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!