- 1、前言
- 2、ndarray和Mat类型转换
- 2.1 c++代码
- 2.2 python中调用MatSo::get_mat_and_return_uchar()
- 2.3 python中调用MatSo::get_mat_and_return_buffer()
- End
该系列文章:
(一)python调用c++代码《从C++共享链接库编译到python调用指南》
(二)ndarray(Python)与Mat(C++)数据的传输
(三)C++结构体与python的传输 1、前言
在(一)python调用c++代码《从C++共享链接库编译到python调用指南》中,我们已经实现了在python中调用C++代码的效果。但是新的问题产生了,python中opencv的图像数据是ndarray格式,C++中opencv的图像数据是Mat格式,在C++中定义的test函数入参是Mat数据,在python中调用是不能直接将ndarray数据作为test函数的参数。
2、ndarray和Mat类型转换该部分我们将设计c++函数接收并返回图像数据,你可以看到图像数据是如何在python的ndarray和c++的Mat直接流转的。
2.1 c++代码在这里我们定义一个MatSo类,该类有两个函数,一个函数接收uchar类型(图像数据),并返回uchar类型(图像数据);另一个函数接收uchar*类型(图像数据),并返回buffer类型(图像数据)。
// Dll2.cpp: 定义 DLL 应用程序的导出函数。 #define EXPORT __declspec(dllexport) #include#include using namespace cv; using namespace std; // MatSO声明 class MatSO { public: // 该函数接收uchar数据,转为Mat数据,显示,然后再返回uchar数据 uchar *get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels); // 该函数接收uchar数据,转为Mat数据,显示,然后再返回buffle数据 uchar *get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels); }; // mat数据接收并以uchar返回 uchar *MatSO::get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels) { // 将接收的uchar转为Mat cout << "rows=" << rows << "ncols=" << cols << "nchannels=" << channels; Mat input_mat = Mat(Size(cols, rows), CV_8UC3, Scalar(255, 255, 255)); input_mat.data = matrix; // 显示Mat imshow("input_mat", input_mat); cv::waitKey(0); // 将Mat转为uchar类型并返回 // 注意:要记住这里Mat的rol、row和channels,在python中才能正确接收 uchar *s = input_mat.data; // Mat转ucahr* return s; } // mat数据接收并以buffer返回 uchar *MatSO::get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels) { // 将接收的uchar转为Mat cout << "rows=" << rows << "ncols=" << cols << "nchannels=" << channels; Mat input_mat = Mat(Size(cols, rows), CV_8UC3, Scalar(255, 255, 255)); input_mat.data = matrix; // 显示Mat imshow("input_mat", input_mat); cv::waitKey(0); // 将Mat转为buffer并返回 // 注意:要记住这里Mat的rol、row和channels,在python中才能正确接收 int height = input_mat.cols; int width = input_mat.rows; uchar *buffer = (uchar *)malloc(sizeof(uchar) * height * width * 3); memcpy(buffer, input_mat.data, height * width * 3); return buffer; } extern "C" { MatSO td; // 包装MatSO,使之可以在so文件外调用 uchar *get_mat_and_return_uchar(uchar *matrix, int rows, int cols, int channels) { return td.get_mat_and_return_uchar(matrix, rows, cols, channels); } uchar *get_mat_and_return_buffer(uchar *matrix, int rows, int cols, int channels) { return td.get_mat_and_return_buffer(matrix, rows, cols, channels); } }
顺便给出CMakeLists.txt配置:
cmake_minimum_required(VERSION 3.0.0)
project(hbp VERSION 0.1.0) # 项目名称
set(CMAKE_CXX_FLAGS "-std=c++11") # 添加c++11标准
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS}) # 头文件目录
add_library(MatSo SHARED MatSo.cpp) # 设置输出的库的类型
target_link_libraries(MatSo ${OpenCV_LIBS})
2.2 python中调用MatSo::get_mat_and_return_uchar()
在这里我们要完成cv2读取一张图片,并调用MatSo类中的函数,得到返回的数据并显示。
主要步骤为:
- 加载so共享链接库
- 定义要使用函数的入参和出参类型
- 对入参数据进行转换为目的类型
- 调用
- 对返回数据进行类型转换
import cv2
import ctypes
from ctypes import *
import numpy as np
# 加载共享链接库
matso = ctypes.cdll.LoadLibrary("build/libMatSo.so")
# matso中有两个函数我们会使用到
# 现在对这两个函数定义入参和出参的类型
# 参考:https://blog.csdn.net/qq_40047008/article/details/107785856
matso.get_mat_and_return_uchar.argtypes = (POINTER(c_ubyte), c_int, c_int, c_int)
matso.get_mat_and_return_uchar.restype = POINTER(c_ubyte)
img = cv2.imread("face.jpeg")
rows, cols, channels = img.shape
img = img.ctypes.data_as(POINTER(c_ubyte)) # 将ndarray转为c++的uchar类型
return_uchar_data = matso.get_mat_and_return_uchar(img, rows, cols, channels) # 调用链接库函数,得到uchar*数据
# 注意这里的rows、rows和channels是C++函数中返回时的Mat尺寸,与上面中不是同一个意思
# 但是因为上面传入函数并返回过程中没有改变图像的shape,所以在数值上是一样的
np_canny = np.array(np.fromiter(return_uchar_data, dtype=np.uint8, count=cols * rows * channels))
np_canny = np_canny.reshape((rows, cols, 3))
cv2.imshow("q", np_canny)
cv2.waitKey(0)
2.3 python中调用MatSo::get_mat_and_return_buffer()
get_mat_and_return_uchar和get_mat_and_return_buffer的区别在于返回类型不同,分别是uchar*和buffer,但是从函数类型可以看出都是uchar,所以在python中的代码都一样
import cv2
import ctypes
from ctypes import *
import numpy as np
# 加载共享链接库
matso = ctypes.cdll.LoadLibrary("build/libMatSo.so")
# matso中有两个函数我们会使用到
# 现在对这两个函数定义入参和出参的类型
# 参考:https://blog.csdn.net/qq_40047008/article/details/107785856
matso.get_mat_and_return_buffer.argtypes = (POINTER(c_ubyte), c_int, c_int, c_int)
# matso.get_mat_and_return_buffer.restype = POINTER(c_uint8)
matso.get_mat_and_return_buffer.restype = POINTER(c_ubyte)
img = cv2.imread("face.jpeg")
rows, cols, channels = img.shape
img = img.ctypes.data_as(POINTER(c_ubyte)) # 将ndarray转为c++的uchar类型
return_uchar_data = matso.get_mat_and_return_buffer(img, rows, cols, channels) # 调用链接库函数,得到uchar*数据
# 注意这里的rows、rows和channels是C++函数中返回时的Mat尺寸,与上面中不是同一个意思
# 但是因为上面传入函数并返回过程中没有改变图像的shape,所以在数值上是一样的
np_canny = np.array(np.fromiter(return_uchar_data, dtype=np.uint8, count=cols * rows * channels))
np_canny = np_canny.reshape((rows, cols, 3))
cv2.imshow("q", np_canny)
cv2.waitKey(0)
End
参考:Python调用c++的动态dll中数据映射(Mat类型传递及结构体传递)



