利用pybind11实现python和C++图像之间的相互调用。将Mat类引入python中。
图像相互转换通过左值引用及智能指针实现。封装了类操作及8个函数(Mat和numpy相互转换)
以下所有实例都通过测试。欢迎交流
1.dll项目文件:制作py_opencv_module.pyd
add.h
add.cpp
sub.h
sub.cpp
imageHeader.h
NumpyMatConver.h
NumpyMatConver.cpp
2.python中调用C++Mat图像
2.1.python文件夹结构
pybind11\test.py
pybind11\py_opencv_module.pyd
2.2.用途:
python中调用C++中Mat图形
2.3.说明:
py::array_t<unsigned char> matToNumpy_Gray(cv::Mat& img);
py::array_t<unsigned char> matToNumpy_Color(cv::Mat& img);
其实python调用C++ Mat仅需要以上两个函数
本动态库将Mat类引入python中,你可以调用4个numpy和Mat的相互转换。
3.C++调用python中numpy图像
3.1.文件夹结构
imageHeader.h
testpybind11.h
test.cpp
testpybind11.cpp
pyStudent.py
testopencv.py
3.2.用途:C++中调用python中图像
//1.1.add.h
int add(int, int);
//1.2.add.cpp
int add(int i, int j) {return i + j; }
//1.3.sub.h
int sub(int, int);
//1.4.sub.cpp
int sub(int x, int y) { return x - y; }
//1.5.imageHeader.h
using std::string;
using std::cout;
using std::endl;
namespace py = pybind11;
using namespace py::literals;
//1.6.NumpyMatConver.h
//$(ProjectName)
namespace py = pybind11;
using namespace py::literals;
//Python->C++ Mat
cv::Mat numpyToMat_Gray(py::array_t<unsigned char>& img);
cv::Mat numpyToMat_Color(py::array_t<unsigned char>& img);
//C++ Mat ->numpy
py::array_t<unsigned char> matToNumpy_Gray(cv::Mat& img);
py::array_t<unsigned char> matToNumpy_Color(cv::Mat& img);
py::array_t<unsigned char> getMat(const char* path, bool graymode = true);
class NumpyMatConver{
public:
//Python->C++ Mat
cv::Mat numpyToMat_Gray(py::array_t<unsigned char>& img);
cv::Mat numpyToMat_Color(py::array_t<unsigned char>& img);
std::shared_ptr<cv::Mat> numpyToMatGray(py::array_t<unsigned char>& img);
std::shared_ptr<cv::Mat> numpyToMatColor(py::array_t<unsigned char>& img);
//C++ Mat ->numpy
py::array_t<unsigned char> matToNumpy_Gray(cv::Mat& img);
py::array_t<unsigned char> matToNumpy_Color(cv::Mat& img);
py::array_t<unsigned char> matToNumpyGray(std::shared_ptr<cv::Mat> img);
py::array_t<unsigned char> matToNumpyColor(std::shared_ptr<cv::Mat> img);
};
//1.7.NumpyMatConver.cpp
//Python->C++ Mat
cv::Mat NumpyMatConver::numpyToMat_Gray(py::array_t<unsigned char>& img){
if (img.ndim() != 2)
throw std::runtime_error("1-channel image must be 2 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC1, (unsigned char*)buf.ptr);
return mat;
//return numpyToMat_Gray(img);能编译警告不能正常工作
}
cv::Mat NumpyMatConver::numpyToMat_Color(py::array_t<unsigned char>& img) {
if (img.ndim() != 3)
throw std::runtime_error("3-channel image must be 3 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC3, (unsigned char*)buf.ptr);
return mat;
}
std::shared_ptr<cv::Mat> NumpyMatConver::numpyToMatGray(py::array_t<unsigned char>& img) {
return std::make_shared<cv::Mat>(numpyToMat_Gray(img));
}
std::shared_ptr<cv::Mat> NumpyMatConver::numpyToMatColor(py::array_t<unsigned char>& img) {
return std::make_shared<cv::Mat>(numpyToMat_Color(img));
}
//C++ Mat ->numpy
py::array_t<unsigned char> NumpyMatConver::matToNumpy_Gray(cv::Mat& img) {
return py::array_t<unsigned char>({ img.rows,img.cols }, img.data);
}
py::array_t<unsigned char> NumpyMatConver::matToNumpy_Color(cv::Mat& img) {
return py::array_t<unsigned char>({ img.rows,img.cols,3 }, img.data);
}
py::array_t<unsigned char> NumpyMatConver::matToNumpyGray(std::shared_ptr<cv::Mat> img) {
return matToNumpy_Gray(*img);
}
py::array_t<unsigned char> NumpyMatConver::matToNumpyColor(std::shared_ptr<cv::Mat> img) {
return matToNumpy_Color(*img);
}
//===========================函数==================================
cv::Mat numpyToMat_Gray(py::array_t<unsigned char>& img) {
if (img.ndim() != 2)
throw std::runtime_error("1-channel image must be 2 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC1, (unsigned char*)buf.ptr);
return mat;
}
cv::Mat numpyToMat_Color(py::array_t<unsigned char>& img) {
if (img.ndim() != 3)
throw std::runtime_error("3-channel image must be 3 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC3, (unsigned char*)buf.ptr);
return mat;
}
//C++ Mat ->numpy
py::array_t<unsigned char> matToNumpy_Gray(cv::Mat& img) {
return py::array_t<unsigned char>({ img.rows,img.cols }, img.data);
}
py::array_t<unsigned char> matToNumpy_Color(cv::Mat& img) {
return py::array_t<unsigned char>({ img.rows,img.cols,3 }, img.data);
}
py::array_t<unsigned char> getMat(const char* path, bool graymode) {
py::array_t<unsigned char> rst;
int flag = graymode ? 0 : 1;
cv::Mat mat = cv::imread(path, flag);
if (graymode)
rst = matToNumpy_Gray(mat);
else
rst = matToNumpy_Color(mat);
return rst;
}
//1.8.compile.bat
::将多个C++原文件打包成动态库供python调用
::后缀为pyd,模块名要与pybind11中的模块名一致PYBIND11_MODULE(模块名, m)
::作者:tcy
::g++ ^
::-O3 -Wall -static -shared -std=c++17 ^
::-DMS_WIN64 -fPIC -I C:\pybind11-master\include ^
::-I C:\ProgramData\Anaconda3\include ^
::-L C:\ProgramData\Anaconda3\libs example1.cpp example.cpp ^
::-o example.pyd -lPython38
以上代码无问题。
g++ ^
-O3 -Wall -static -shared -std=c++17 ^
-DMS_WIN64 -fPIC -I C:\pybind11-master\include ^
-I C:\opencv\build\include ^
-I C:\opencv\build\include\opencv2 ^
-L C:\opencv\build\include ^
-L C:\opencv\build\include\opencv2 ^
-I C:\ProgramData\Anaconda3\include ^
-L C:\opencv\build\x64\vc14\lib ^
-L C:\opencv\build\x64\vc15\lib ^
-L C:\ProgramData\Anaconda3\libs compile_py_opencv.cpp NumpyMatConver.cpp add.cpp sub.cpp ^
-o py_opencv_module.pyd -lPython38
以上代码有问题,欢迎高手解决。目前利用VS2017编译无问题
//1.9.compile_py_opencv.cpp
PYBIND11_MODULE(py_opencv_module, m) {
m.doc() = "pybind11 python opencv convert";
m.def("numpyToMat_Gray", &numpyToMat_Gray);
m.def("numpyToMat_Color", &numpyToMat_Color);
m.def("matToNumpy_Gray", &matToNumpy_Gray);
m.def("matToNumpy_Color", &matToNumpy_Color);
m.def("add", &add, "add function");
m.def("sub", &sub, "sub function");
m.def("getMat", &getMat, "getMat function");
py::class_<cv::Mat, std::shared_ptr<cv::Mat>>(m, "Mat")
.def(py::init<>())
.def(py::init<int, int, int>())
.def(py::init<const cv::Mat&>())
;
py::class_<NumpyMatConver>(m, "NumpyMatConver")
.def(py::init<>()) //包装构造函数(py::init()无参构造)
.def("numpyToMat_Gray", &NumpyMatConver::numpyToMat_Gray)
.def("numpyToMat_Color", &NumpyMatConver::numpyToMat_Color)
.def("matToNumpy_Gray", &NumpyMatConver::matToNumpy_Gray)
.def("matToNumpy_Color", &NumpyMatConver::matToNumpy_Color)
.def("numpyToMatGray", &NumpyMatConver::numpyToMatGray)
.def("numpyToMatColor", &NumpyMatConver::numpyToMatColor)
.def("matToNumpyGray", &NumpyMatConver::matToNumpyGray)
.def("matToNumpyColor", &NumpyMatConver::matToNumpyColor);
}
//2.1.pybind11/test.py
# !/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import os,cv2,sys
import pybind_11.py_opencv_module as obj
if __name__=="__main__":
pass
print('ss',obj.add(2,3))
print('ss', obj.sub(2, 3))
color=r'C:\Users\Administrator\Desktop\Fastener\Resources\Pictures\girl.jpg'
gray=r'C:\Users\Administrator\Desktop\Fastener\Resources\Pictures\image.jpg'
color_img=cv2.imread(color)
gray_img=cv2.imread(gray)
#C++Mat转numpy
m1 = obj.getMat(color,False)
m2 = obj.getMat(gray,True)
cv2.imshow("m1", m1)
cv2.imshow("m2", m2)
#测试函数:
mat1=obj.numpyToMat_Color(color_img)
img1 = obj.matToNumpy_Color(mat1)
cv2.imshow("img1",img1)
mat2 = obj.numpyToMat_Color(gray_img)
img2 = obj.matToNumpy_Color(mat2)
cv2.imshow("img2", img2)
#测试类:普通函数
a = obj.NumpyMatConver()
mat1 = a.numpyToMat_Color(color_img)
img1 = a.matToNumpy_Color(mat1)
cv2.imshow("img_1", img1)
mat2 = a.numpyToMat_Color(gray_img)
img2 = a.matToNumpy_Color(mat2)
cv2.imshow("img_2", img2)
# 测试类:智能指针
a = obj.NumpyMatConver()
mat1 = a.numpyToMatColor(color_img)
img1 = a.matToNumpyColor(mat1)
cv2.imshow("img_p1", img1)
mat2 = a.numpyToMat_Color(gray_img)
img2 = a.matToNumpy_Color(mat2)
cv2.imshow("img_p2", img2)
cv2.waitKey()
3.1.testpybind11.h
struct PythonInit {
static inline bool py_status = false;
static bool interpreter();
};
void imshow_cv(const cv::Mat& mat, const string& no = "Mat image");
void imshow_cv(const string& file, const string& no = "Mat image");
void print_py_dict(py::dict dict);
void test_py_list();
void test_py_dict();
void test_pybind11();
void test_ReadPythonNumpy();
3.2.testpybind11.cpp
//python初始化:
bool PythonInit::interpreter() {
if (!py_status)
{
py::scoped_interpreter guard{};//python初始化
py_status = true;
}
return true;
}
void imshow_cv(const cv::Mat& mat, const string& no)
{
if (mat.empty())return;
cv::namedWindow(no);
cv::imshow(no, mat);
cv::waitKey();
}
void imshow_cv(const string& file, const string& no)
{
cv::Mat img = cv::imread(file);
imshow_cv(img, no);
}
//Python对象作为参数
void test_py_list() {
py::list lst = py::list(2); //构建list
lst[0] = "Tom";
lst.insert(1, 2); //C++中函数
lst.attr("insert")(3, 4); //python中函数
lst.append(5);
lst.attr("append")(6);
//lst[2] = py::none();
//显示列表:
py::print("1.lst=", lst); //['Tom', 2, <NULL>, 4, 5, 6]
int i = 0;
for (auto it = lst.begin(); it != lst.end(); ++it) {
if (!it->ptr())
lst[i] = py::none(); //将list中NULL值改为None
++i;
}
py::print("2.lst=", lst); //['Tom', 2, None, 4, 5, 6]
cout << endl;
}
void print_py_dict(py::dict dict) {
/* Easily interact with Python types */
for (auto item : dict)
std::cout << "key=" << std::string(py::str(item.first)) << ", "
<< "value=" << std::string(py::str(item.second)) << std::endl;
}
void test_py_dict() {
auto d = py::dict("name"_a = "Tom", "age"_a = 42);
py::print("1.dict d = ", d);
d["city"] = "shanghai";
py::print("2.dict d = ", d);
d.attr("clear")();
py::print("3.dict d = ", d);
cout << endl;
}
void test_pybind11() {
//调用python模块:
py::module os = py::module::import("os");
py::print("1.current path=", os.attr("getcwd")());
//导入python main程序入口:
py::object py_environment = py::module_::import("__main__").attr("__dict__");
cout << "2.py_environment exists=" << py_environment.is_none() << endl;
py::print("3.environment=",py_environment);
cout << endl << "1.exec=" << endl;
py::exec(
"print('Hello')\n"
"print('world!');",
py_environment);
py::eval_file("testopencv.py", py_environment);
auto img = py_environment["img"];
py::print("2.img.shape=",img.attr("shape"));
py::object x = py::cast(1);
py_environment["x"] = 1;
py::print("3.x=",py_environment);
int result = py::eval("x + 10", py_environment).cast<int>();
cout << "4.x+10="<<result << endl;
}
//=====================================================
cv::Mat numpyToMat_Gray(py::array_t<unsigned char>& img) {
if (img.ndim() != 2)
throw std::runtime_error("1-channel image must be 2 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC1, (unsigned char*)buf.ptr);
return mat;
}
cv::Mat numpyToMat_Color(py::array_t<unsigned char>& img) {
if (img.ndim() != 3)
throw std::runtime_error("3-channel image must be 3 dims ");
py::buffer_info buf = img.request();
cv::Mat mat(static_cast<int>(buf.shape[0]), static_cast<int>(buf.shape[1]),
CV_8UC3, (unsigned char*)buf.ptr);
return mat;
}
//================================================
void test_ReadPythonNumpy() {
const char* color = "C:\\Users\\Administrator\\Desktop\\PybindProject\\pictures\\girl.jpg";
const char* gray = "C:\\Users\\Administrator\\Desktop\\PybindProject\\pictures\\image.jpg";
py::module cv2 = py::module::import("cv2");
py::array_t<unsigned char> np_gray = cv2.attr("imread")(gray, 0);
py::array_t<unsigned char> np_color = cv2.attr("imread")(color, 1);
cv::Mat mat1 = numpyToMat_Gray(np_gray);
cv::Mat mat2 = numpyToMat_Color(np_color);
cv::imshow("gray", mat1);
cv::imshow("color", mat2);
cv::waitKey();
}
3.3.test.cpp
using namespace std;
using namespace cv;
//void test_mat() {
// Mat mat_girl = imread("../pictures/girl.jpg");
//
// auto PyOpenCVModule = py::module_::import("PyOpenCVModule");
// auto np_girl = PyOpenCVModule.attr("matToNumpy_Color")(mat_girl);
// auto mat_img = py::cast<Mat>(PyOpenCVModule.attr("numpyToMat_Color")(np_girl));
//
// imshow_cv(mat_img);
//}
int main() {
py::scoped_interpreter guard{};//python初始化
//py::scoped_interpreter python;//等效上面
/*test_py_list();
test_py_dict();
test_pybind11();*/
//test_mat();
cout << "============================" << endl;
test_ReadPythonNumpy();
}
3.4.pyStudent.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
#PyStudent.py
#define function:
def add(a,b):
lst=[1,2,3]
return a+b
def foo(a,b):
lst=[1,2,3]
return a+b,lst
def sortTuple(t:tuple):
t=sorted(t)
return t
def sortList(lst:list):
lst.sort()
return lst
def sortDict(d:dict):
s=pd.Series([1,2,3],dtype=np.int64)
arr=np.array([10,10,10],dtype=np.int64)
arr=arr+np.array(s)
lst=list(arr)
names=['a1','a2','a3','a4']
d1=dict(zip(names,lst))
d1.update(d)
return d1
def getNumpyArr(arr,n):
return arr
class Student:
def __init__(self,name='Tom',age=22):
self.name=name
self.age=age
def getAge(self):
return self.age
def setAge(self,age):
self.age=age
def add(self,x,lst):
arr=np.array(lst,dtype=np.float64)
arr=arr+x
arr=arr.tolist()
return arr
if __name__ =="__main__":
t=(1,2,3)
lst=[1,2,3]
d={'Tom':22,"Bob":30}
print(add(2,3))
print(sortTuple(t))
print(sortList(lst))
print(sortDict(d))
a=Student()
print(a.age,a.name)
a.setAge(33)
print(a.age,a.name)
print(a.add(10,lst))
3.5.testopencv.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import cv2
path=r'..\pictures\girl.jpg'
img=cv2.imread(path)
cv2.imshow("sss",img)
cv2.waitKey()