liunx python调用c++库(类、函数),传入传出参数

一、使用c++封装动态库

参考文献:http://www.linuxidc.com/Linux/2012-09/70502.htm

1.新建test类

1.1新建 test.cpp 文件

代码如下:

#include

           extern "C" 

           int myadd(int a, int  b) 

           { 

                    return a + b; 

            }

备注:extern"C" 必须有,不然会报undefined symbol: myadd.


1.2新建test.h文件

代码如下:

#ifndef _TESTSO_H  

                   #define_TESTSO_H  

                   extern"C"  

                   { 

                            intmyadd(int a, int b); 

                            typedefint myadd_t(int, int); // myadd function type  

                   } 

                   #endif// _TESTSO_H 

备注:test.h文件可以没有,因为test.cpp也没有#include ,再说myadd()函数也不是类的成员函数。


2.编译

g++  -shared -fPIC  -o test.so test.cpp

 

备注1:

-fPIC:生成位置无关目标代码,适用于动态连接;

-L path:表示在path目录中搜索库文件,如-L.表示在当前目录;

-I path:表示在path目录中搜索头文件;

-o file:制定输出文件为file;

-shared:生成一个共享库文件;

备注2:

编译多个cpp文件:

g++ -shared-fPIC -o demo.so demo.cpp CCNF_patch_expert.cpp LandmarkDetectorFunc.cppLandmarkDetectorModel.cpp LandmarkDetectorUtils.cppLandmarkDetectorParameters.cpp LandmarkDetectionValidator.cpp Patch_experts.cppPAW.cpp PDM.cpp SVR_patch_expert.cpp stdafx.cpp$(pkg-config opencv --cflags --libs) $(/usr/lib/x86_64-linux-gnu/libboost_filesystem.so;/usr/lib/x86_64-linux-gnu/libboost_system.so)-I /usr/include/boost -L /usr/lib/x86_64-linux-gnu/ -I boost_system –l boost_filesystem

(在使用上面命令代码编译时,先将代码放到txt中,写成一行,最后在赋值到命令行进行编译,不然可能会出错)

,最好是写个makefile文件来编译。

3. C++方式调用库

3.1新建main.cpp

         代码如下:

   

                   #include   
                   #include    //必须有
                   #include 
                   #include"test.h"                    // for dynamic library函数  

                   int main(int argc, char*argv[]) 
                   { 
                           if (2 != argc)
                           { 
                                 return-1; 
                           } 
                            const char *soname =argv[1];        
                            void *so_handle = dlopen(soname,RTLD_LAZY); // 载入.so文件  
                            if (!so_handle)
                            { 
                                 fprintf(stderr,"Error: load so `%s' failed./n", soname); 
                                 return-1; 
                            }                
                            dlerror(); // 清空错误信息  
                            myadd_t *fn =(myadd_t*)dlsym(so_handle,"myadd"); // 载入函数  
                            char *err =dlerror(); 
                            if (NULL != err)
                            { 
                                  fprintf(stderr,"%s/n", err); 
                                   return-1; 
                            } 
                            printf("myadd57 + 3 = %d/n", fn(57, 3)); // 调用函数  
                            dlclose(so_handle);// 关闭so句柄  
                            return 0; 
                   }  

3.2 编译

 g++ main.cpp -o main -ldl 

        

备注:如果没有-ldl参数,会报undefinedreference to `dlopen'错误解决。

3.3运行

./main test.so

4. Python方式调用库

4.1新建main.py

from ctypesimport *

 

                   #loaddll and get the function object

                   dll= cdll.LoadLibrary(’/landmark/LandmarkDetector/test.so');

                   t= dll.myadd(1,2)

                   print(t)

4.2运行

        python main.py

二、python调c++库,并传入传出参数

2.1 c++库函数

例如:

c++库函数:

inttest(const cv::Mat img,  conststd::vector vRect, const std::string sModelPath, cv::Vec3f&pose)

 

输入参数

const cv::Mat img:图片数据

conststd::vector vRect:人脸区域

const std::stringsModelPath:模型路径

                             输出参数:

cv::Vec3f& pose:人脸角度(x,y,z)

                  

由于python、c++是两种不同的编程语言,在相互调用时,需要将数据类型转换成对方认可的。

2.2 输入参数

2.2.1 const cv::Mat img参数修改

参考文献:http://bbs.csdn.net/topics/340060802

C++库部分

1.      const cv::Mat img 参数改成(int*img, int rows, int cols, int channels)

2.      将int* img图像数据解析成cv::Mat img。

代码如下:

cv::Mat show_matrix(int *matrix, int rows, int cols, int channels)
{
int i, j, c;
if (3==channels)
{
           cv::Mat img(rows,cols,CV_8UC3,cv::Scalar(0,0,0));
           std::cout<(0);
           for (i=0; i(ii);
                             j = i%(cols*2*3)/2;
                             c = j%3;
                             j = j/3;
                             pxvec[j*3 + c] =(unsigned char)matrix[i];
                             //printf("pxvec[%d][%d][%d]= %d\n", ii,j,c, matrix[i]);
                    }
           }
           return img;
}
else
{
          cv::Mat img(rows,cols,CV_8UC1,cv::Scalar(0,0,0));
           std::cout<(0);
           for (i=0; i(ii);
                             j = i%(cols*2)/2;
                             pxvec[j] =(unsigned char)matrix[i];
                             //printf("pxvec[%d][%d]= %d\n", ii, j, matrix[i]);
                   }
           }
           return img;
  }
}

Python调用部分

         代码如下:

         src= cv2.imread("/OpenFace-master/test/face_0.jpg") #0 - gray

         cols= src.shape[1]

         rows =src.shape[0]

         channels= 0

       if 3==len(src.shape):

                   channels= 3

 

         src= np.asarray(src, dtype=np.int)#需要与定义的int* img类型一致

         src1 = src.ctypes.data_as(ctypes.c_char_p)#将一个多维数组转成char*

         t =dll.test(src1, rows, cols, channels)

 

备注:

           src = np.array([[11,22],[3,4]])

           src1 = src.ctypes.data_as(ctypes.c_char_p)

           t = dll.test(src1, rows, cols, channels)

           c++中src1的数值如下:

           matrix[0] = 11

           matrix[1] = 0

           matrix[2]= 22

           matrix[3]= 0

           matrix[4]= 3

           matrix[5]= 0

           matrix[6]= 4

           matrix[7] = 0

2.2.2  const cv::vector vRect参数修改

c++库部分

1.      const cv::vectorvRect参数改成(int* rect, int num)

2.      将int* rect人脸区域数据解析成cv::vector vRect;

代码如下:

vector show_rect(int* rect, introws)
{
vector vRect;
int cols = 4; //(x,y,w,h)
int i,j;
int x=0,y=0,w=0,h=0;      
cv::Rect  roi;

for (i=0; i

Python调用部分

代码如下:

         num = 1  #表示人脸区域的个数

         rect = np.zeros((num,4),dtype=np.int) #4表示人脸区域的(x,y,w,h)

 

rect[0][0] = 0

rect[0][1] = 0

rect[0][2] = cols-1

rect[0][3] = rows-1

#print (src.dtype) #uint8

rect = np.asarray(rect, dtype=np.int)

#print (src.dtype) #int64

rect1 = rect.ctypes.data_as(ctypes.c_char_p)

 

t = dll.test(src1, rows, cols, channels, rect1, num)

备注:如果是float类型,需要使用 c_float(cx)转换后,再传入就ok,不然会报类型不匹配。


2.3  输出参数

参考文献:http://blog.csdn.net/uniqsa/article/details/78603082

2.3.1  cv::Vec3f& pose参数修改

c++库部分

1.      将cv::Vec3f& pose参数改成struHeadPose& pose;

2.      在test.cpp中定义struHeadPose结构体:

structstruHeadPose 

    float                            angleX;                     

    float                            angleY; 

    float                            angleZ; 

};

3.      struHeadPose pose赋值并返回:

pose.angleX = angleX;

pose.angleY = angleY;

           pose.angleZ= angleZ;

python调用部分

         代码如下:

   class struHeadPose(ctypes.Structure): 
         _fields_ =[("angleX", ctypes.c_float),("angleY",ctypes.c_float),("angleZ", ctypes.c_float)] 
pose =struHeadPose(0.0, 0.0, 0.0)

sModelPath ="/LandmarkDetector/model/main_clnf_general.txt"

t = dll.test(src1,rows, cols, channels, rect1, num, sModelPath, ctypes.byref(pose))
print(pose.angleX)
print(pose.angleY)
print(pose.angleZ)

 
  

三、c++封装类的动态库、python调用

参考文献:http://blog.csdn.net/wuchuanpingstone/article/details/77763455(很不错的)

3.1 c++封装类的动态库

3.1.1 demo.h文件

#ifndef _DEMOSO_H	
#define _DEMOSO_H	

// OpenCV includes
#include 
#include 
#include 

struct struHeadPose	 
{  
	float							 angleX;					  
	float							 angleY;  
	float							 angleZ;  
}; 

class CCaculateFaceAngle
{  
	public:
		int getPose(int* imgData, int h, int w, int channels, float cx, float cy, float fx, float fy,struHeadPose& pose);		 
		int LoadModel(char* sModelPath); 
		
	private:
		LandmarkDetector::FaceModelParameters m_det_parameters;
		LandmarkDetector::CLNF m_clnf_model;
}; 
#endif // _DEMOSO_H	

3.1.2 demo.cpp文件

#include "demo.h"

int CCaculateFaceAngle::getPose(int* imgData, int h, int w, int channels, float cx, float cy, float fx, float fy, struHeadPose& pose)
{
	内容省略
}
int CCaculateFaceAngle::LoadModel(char* sModelPath)
{
内容省略
}

//以下是重点,不然不会导出c++的类。
extern "C" 
{
	CCaculateFaceAngle obj;	 
int getPose(int* imgData, int h, int w, int channels, float cx, float cy, float fx, float fy,struHeadPose& pose) 
	{
		return obj.getPose(imgData, h, w, channels, cx, cy, fx, fy,pose);	
	}
	int LoadModel(char* sModelPath) 
	{  
		return obj.LoadModel(sModelPath);	
	}
}

3.2 python调用c++类

from ctypes import *
import cv2
import ctypes
import numpy as np

dll = cdll.LoadLibrary('/LandmarkDetector/class_so/demo.so');
# model path
sModelPath = "/LandmarkDetector/model/main_clnf_general.txt"

#image data
src = cv2.imread("/OpenFace-master/test/face_0.jpg") #0-gray
cols = src.shape[1]
rows = src.shape[0]
#print('img shape:{}'.format(src.shape))
channels = 0
if 3==len(src.shape):
	channels = 3	
src = np.asarray(src, dtype=np.int) 
src1 = src.ctypes.data_as(ctypes.c_char_p)

#fx fy cx cy
cx = cols / 2.0
cy = rows / 2.0
fx = 500 * (cols / 640.0)
fy = 500 * (rows / 480.0)
fx = (fx + fy) / 2.0
fy = fx

cx1 = c_float(cx)
cy1 = c_float(cy)
fx1 = c_float(fx)
fy1 = c_float(fy)

#head pose	
class struHeadPose(ctypes.Structure):  
	_fields_ = [("angleX", ctypes.c_float),("angleY", ctypes.c_float),("angleZ", ctypes.c_float)]  
pose = struHeadPose(0.0, 0.0, 0.0) 

if dll.LoadModel(sModelPath) > -1:
	t = dll.getPose(src1, rows, cols, channels, cx1, cy1, fx1, fy1, ctypes.byref(pose))

print (pose.angleX)
print (pose.angleY)
print (pose.angleZ)



附件

liunx python调用c++库(类、函数),传入传出参数_第1张图片

 
 

你可能感兴趣的:(python,c++)