- python调用c++程序,传入参数类型为基本数据类型
- python调用c++程序处理图像,需要传入图片信息
前言:
由于c语言是最为接近底层的语言,所以运行速度相对于其他高级语言来说会比较快。使用python处理图像时可以考虑使用c处理图像来提升运行速度。但是我在网上学习c语言opencv的时候见到的大多是c++语言,老师给的示例代码也是c++的,c++和c比起来效率不会差太多,所以就直接用c++了。
至于学习图像处理使用到的opencv的相关资料,c语言版本《学习opencv》,c++版本《opencv3编程入门》,这两本是我在搜索相关资料时找到的两本,网上也有相关的电子版书籍可以下载(无广告商,纯友情推荐,大佬可忽略不计)
python调用c++程序,传入参数为基本数据类型
这一部分推荐看这位博主的,简单明了。讲的是python与c/c++程序的互相调用。链接:python与c/c++程序的互相调用
使用博主里的例子时有一点需要注意,例子使用的python语法是python2,但现在一般使用的是python3,所以需要将 print '×××’修改为 print(“×××”)
下面是python调用c++部分。
Python调用C++程序时需要extern "C"来辅助,也就是说还是只能调用C函数,不能直接调用方法,但是能解析C++方法。extern "C"在这里的作用相当于给c++程序披了一层c程序的外衣(披了羊皮的狼)
首先是c++程序,文件名为pycallclass.cpp
#include <iostream>
using namespace std;
class TestLib {
public:
void display();
int display(int a);
};
void TestLib::display() {
cout<<"First display"<<endl;
}
int TestLib::display(int a) {
cout<<"Second display:"<<a<<endl;
return a+100;
}
extern "C" {
TestLib obj;
void display() {
obj.display();
}
int display_int(int x) {
return obj.display(x);
}
}
然后是python程序,文件名为:pycallclass.py
ctypes这个库具体的可以去查一下,作用就是可以让python调用c++的动态库,也就是.so文件。
import ctypes
so = ctypes.cdll.LoadLibrary
lib = so("./pycallclass.so")
print("display()")
lib.display()
print("display(200)")
t = lib.display_int(200)
print(t)
这里c++程序和python程序处于同一文件目录下。
运行(在命令行运行):
g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp//编译生成动态库文件
python3 pycallclass.py//运行.py文件
//运行结果:
c++示例里的函数也可以直接写在extern "C"中,如下:
#include <iostream>
using namespace std;
extern "C" {
void display() {
cout<<"First display"<<endl;
}
int display_int(int x) {
cout<<"Second display:"<<x<<endl;
return x+100;
}
}
python调用c++程序处理图像,需要传入图片信息
传入图像这块,编译c++的命令还和上面不一样(导致又气了很久),具体原因:处理图像需要用到opencv,使用opencv需要引入相关的函数,所以编译时需要加上相关的库,也就是下面示例编译时添加的-l内容,如果不想每次写那么多的话,可以使用CMakeList(但是我现在还不会),有关CMakeList的用法可以网上查(有好的链接可以拿出来分享一下,先行谢过啦,嘿嘿)
这部分主要是看的这位博主的链接 链接
c++程序如下,文件名为iden.cpp
#include <opencv2/opencv.hpp>
#include <opencv2/opencv.hpp>
#include <iostream>
#include <stdio.h>
using namespace cv;
using namespace std;
class Mydisplay{
public:
void testplay(int height,int width,uchar* data);
};
void Mydisplay::testplay(int height,int width,uchar* data){
Mat image(height,width,CV_8UC3);//将data转换为Mat类型,也就是C++中的图像存储类型
uchar* pxvec = image.ptr<uchar>(0);
//image.str可以得到图像任意行的首地址.例如uchar*data=image.ptr<uchar>(j),则它返回给uchar*data的值就是image的第j行的首地址
//下面这一部分可以不考虑,这里主要是遍历一下
int count = 0;
for(int i=0;i<height;i++){
pxvec = image.ptr<uchar>(i);
for(int j=0;j<width;j++){
for(int k=0;k<3;k++){
cout<<(int)pxvec[i*3+j]<<" ";
//这里需要转换为int型数据,否则输出的会是对应的ASCII码
pxvec[j*3+k] = data[count];
count++;
}
cout<<endl;
}
cout<<i<<" output end"<<height<<width<<endl;
}
cout<<"end"<<endl;
return ;
}
extern "C"
{
Mydisplay obj;
void test(int height,int width,uchar* data){
obj.testplay(height,width,data);
}
}
python程序,文件名为:ien.py
import ctypes
import cv2
import numpy as np
img = cv2.imread('example.jpg')
h,w,c = img.shape
if c > 1:
img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img_data = np.asarray(img, dtype=np.uint8)
img_data = img_data.ctypes.data_as(ctypes.c_char_p)
test_pyc = ctypes.cdll.LoadLibrary("./iden.so")
#test_pyc.test.argtypes = (ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_ubyte))
#argtypes写明输入类型,例子中未使用
test_pyc.test.restype = ctypes.POINTER(ctypes.c_uint8)#restype写明返回类型
#ctypes.POINTER可以看下文的链接,里面有详细介绍
test_pyc.test(h,w,img_data)
运行(命令行上运行):
g++ -o iden.so -shared -fPIC iden.cpp -lopencv_core -lopencv_highgui -lopencv_imgcodecs
python3 ien.py
//运行结果如下:
ctypes.POINTER相关介绍:ctypes介绍
后记
学会一门编程语言之后学其它语言会轻松很多,但这不代表会毫无压力。就比如c++,在写这个的时候,改了一堆错误,比如将结构体里面的函数拿出来写时,需要函数名前面加 “结构体名::”,总之,如果不想深入学习,但是暂时需要使用的话,建议还是多看看示例,多仔细对比一下,不要想当然地大概略过,不然被气了半天之后会发现只是个语法问题,那滋味……