本文主要简化该博文的代码,解决了混合编译中矩阵传输问题(C++ Mat -----> Python numpy array),经过测试任意维度和数据类型的Mat均可使用此方法。python安装 opencv源码安装这里就不做讲解了,网上方法多着是。
值得注意以下几点:
1、本次操作在Ubuntu 16.04下进行。
2、在Ubuntu下也有图形化界面的cmake,使用sudo apt install cmake-qt-gui安装,使用这个配置opencv更加直观方便。
3、当配置安装路径不是默认的/usr/local时,需要注意要将编译生成路径下的/lib/python3.5文件夹拷贝到/usr/local/lib下。例如:我的opencv安装路径在/usr/local/opencv,并且我编译了python3.5,我需要将/usr/local/opencv/lib/python3.5下的文件拷贝到/usr/local/lib/python3.5下,否则编译的opencv在python中不可被调用
4、pip install安装后的文件放在~/.local/lib/python3.5下,sudo pip install在/usr/local/lib下
5、需要运行sudo apt install python3-dev 安装python的库,否则会报找不到Python.h错误。
6、需要运行sudo apt install python-numpy安装numpy库,否者会报找不到numpy/arrayobject.h错误。
混合编译指令:
终端端指令:
g++ -I/usr/include/python3.5 pythonwithcpp.cpp -L/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu -lpython3.
CLion CMakeLists.txt(使用其他IDE的配置方法会有所不同)
#工程名:test
cmake_minimum_required(VERSION 3.14)
project(test)
set(CMAKE_CXX_STANDARD 14)
set(Python_ADDITIONAL_VERSIONS 3.5)
add_executable(test main.cpp)
find_package(PythonLibs 3 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
target_link_libraries(test ${PYTHON_LIBRARIES})
find_package(OpenCV REQUIRED)
target_link_libraries(test ${OpenCV_LIBS})
代码功能描述:
本代码实现了一个使用C++ opencv打开摄像头读取图像,将图像传输给python opencv(numpy array类型)并显示,然后将图像返回,C++ opencv接收返回值,并显示图像。简单来说就是C++ —> Python —> C++。
main.cpp
#include <iostream>
#include <python3.5/Python.h>
#include <numpy/arrayobject.h>
#include <opencv2/opencv.hpp>
int main(int argc, char* argv[])
{
//初始化python
Py_Initialize();
import_array(); //numpy初始化,会报迷之警告,大家忽略它吧
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')"); //将当前路径加入,否者会出现找不到模块,这两句话非常重要
PyObject *py_Module = PyImport_ImportModule("TestModule"); //引入模块
PyObject *py_main = PyObject_GetAttrString(py_Module,"main"); //获取main函数
npy_intp Dims[3] = {480, 640, 3}; //给定维度信息
cv::VideoCapture cap(1);
cv::Mat frame;
while(1)
{
cap>>frame;
/*生成包含这个多维数组的PyObject对象,使用PyArray_SimpleNewFromData函数,
* 第一个参数2表示维度,第二个为维度数组Dims,第三个参数指出数组的类型,第四个参数为数组*/
/*关键:直接将矩阵的数据指针传入即可 numpy操作即可转换程对Mat操作。经测试任意维度的任意类型数据均适用*/
PyObject *PyArray = PyArray_SimpleNewFromData(3, Dims, NPY_UBYTE, frame.data);
PyObject *ArgArray = PyTuple_New(1);
PyTuple_SetItem(ArgArray, 0, PyArray); //同样定义大小与Python函数参数个数一致的PyTuple对象
PyArrayObject *py_return = (PyArrayObject *)PyEval_CallObject(py_main, ArgArray);
/*关键: 反馈回来的数据直接将矩阵数据指针指向ArrayObject的数据即可*/
cv::Mat img(cv::Size(640,480),CV_8UC3);
img.data = (u_char*)py_return->data; //直接将图像的数据指针指向numpy返回的数据
cv::imshow("c++",img);
cv::waitKey(1);
}
Py_Finalize(); //释放python
return 0;
}
TestModule.py
import cv2
def main(img):
cv2.imshow('py', img)
cv2.waitKey(1)
return img
if __name__ == "__main__":
cap = cv2.VideoCapture(1)
while True:
_, img = cap.read()
main(img)
最后也抛出一个问题,就是在返回参素的时候直接用指针指向返回的数据,这种操作安全吗?会不会被python释放掉那块内存而导致指针非法呢?虽然这个代码我跑了10多分钟都没出现问题。希望懂的大佬能解答一下。谢谢!!!!!