目的:在python中调用C++的OPENCV功能,并探索加速的可能性
假设:已有python cv2包,已有g++,cmake
实验结果:得到了相对较快的调用方案
配置OPENCV环境
make -j8
就算完成python调用C++
ctypes.cdll.LoadLibrary
函数将.so加载进来,从而获得一个可以重复调用的函数接口src.ctypes.data_as(ctypes.c_char_p)
将传入的numpy array转化成了一个字符指针,指向了numpy定义的数组,方便传参用(这个指针类型在待会儿可能会觉得有点别扭)dll.cpp_absdiff(h,w,src1, src2, src3)
直接调用C++程序暴露出来的函数接口,注意该C++函数会将最终的差分结果放在src3所指向的numpy array中C++下的实现
cv::Mat src(height, width, CV_8UC1, data);
利用传过来的指针,直接构造Mat,注意这种构造方法的一个特点,就是会直接在data指向的数据上进行操作,且在程序结束指向时不修改data指向的数据。第三个参数CV_8UC1是说明通道数和每个像素所用比特数目的,在这个absdiff中用的是单通道8bit数据,如果是处理彩色图要注意修改。cv::absdiff(src, src2, dist);
调用C++下的函数,该函数所进行的操作是将结果放到dist中,考虑到3.2中提到的特性,我们这么调用的话会比原版cv2快,因为原来的cv2为了能完成类似于dist = cv2.absdiff(src, src2)
这样的调用形式,在它的实现中必然要先重新分配一个用于存储dist数据的数据块,然后再把这个引用返回给python中的变量,这样子做涉及到一个空间分配的步骤以及一个数据类型转换(将C++的数据块指针转换为numpy引用,这个部分其实用numpy提供的接口实现起来非常慢,但是cv2却能实现的相当快了)的步骤,因此可以提速。/* test.cpp */
/* 测试环境用的代码 */
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <stdlib.h>
using namespace cv;
extern "C" uchar* cpp_absdiff(int height, int width, uchar* data, uchar* data2) {
cv::Mat src(height, width, CV_8UC1, data);
cv::Mat src2(height, width, CV_8UC1, data2);
cv::Mat dst;
cv::absdiff(src, src2, dst);
uchar* buffer = (uchar*)malloc(sizeof(uchar)*height*width);
memcpy(buffer, dst.data, height*width);
return buffer;
}
extern "C" void release(uchar* data) {
free(data);
}
# example.py
import cv2
from numpy.ctypeslib import ndpointer
import ctypes
import numpy as np
dll=ctypes.cdll.LoadLibrary('./test.so')
def cpp_absdiff(src, src2, dst):
h, w=src.shape[0],src.shape[1]
# 获取numpy对象的数据指针
src = src.ctypes.data_as(ctypes.c_char_p)
src2 = src2.ctypes.data_as(ctypes.c_char_p)
src3 = src3.ctypes.data_as(ctypes.c_char_p)
#调用dll里面的cpp_absdiff函数,结果会被直接写到dst里面
pointer = dll.cpp_absdiff(h,w,src, src2, dst)
return
img=cv2.imread('test.jpg')
img2 = cv2.imread('test.jpg')
img3 = cv2.imread('test.jpg')
img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
img2=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
img3=cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
img=np.asarray(img, dtype=np.uint8)
img2=np.asarray(img2, dtype=np.uint8)
img3=np.asarray(img3, dtype=np.uint8)
import time
start = time.time()
for i in range(1):
cpp_absdiff(img, img2, img3)
end = time.time()
print(end - start)
for i in range(1):
cv2.absdiff(img, img2, img3)
end = time.time()
print(end - start)
// example.cpp
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <stdlib.h>
using namespace cv;
extern "C" void cpp_absdiff(int height, int width, uchar* data, uchar* data2, uchar* data3) {
cv::Mat src(height, width, CV_8UC1, data);
cv::Mat src2(height, width, CV_8UC1, data2);
cv::Mat dst(height, width, CV_8UC1, data3);
cv::absdiff(src, src2, dst);
return;
}