一、使用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::vectorvRect, const std::string sModelPath, cv::Vec3f&pose)
输入参数:
const cv::Mat img:图片数据
conststd::vectorvRect:人脸区域
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
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
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::vectorvRect参数修改
c++库部分
1. const cv::vectorvRect参数改成(int* rect, int num)
2. 将int* rect人脸区域数据解析成cv::vectorvRect;
代码如下:
vectorshow_rect(int* rect, introws)
{
vectorvRect;
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)
附件