numpy 转c指针【python调用c代码】

在写《瘦脸实现【Python】》时候实现了在python环境下的瘦脸功能,但实际使用起来,python的处理速度实在太慢,让人难以接受,所以用c语言重新实现了一次,速度有了很大的提升。因为之前的UI是用python搭建的,所以想通过python调用c的方法实现算法的加速。

因为联想到opencv也有python的API,在python下,图像处理的速度也很快,所以就查找了opencv通过怎样的方法来实现numpy转Mat的过程。

首先搜到了https://blog.csdn.net/jacke121/article/details/80275658,这篇博客,但是经过实验发现该方法并不支持python3.x版本(后来在原作者GitHub上经过提问,作者给出了最新版本,支持python2和3),后来我就自己翻看opencv的源码(XXX/modules/python/src2/cv2.cpp)发现numpy转化为Mat跟 pyopencv_to函数有关,于是我就找到了《从PyOpenCV到CV2》这篇博文,结合该代码和源码,将瘦脸代码改写成c代码,并编译成库,提供给python调用。

ps:在查找资料的过程中,也有大神是通过boost库实现的,但我觉得为了转换还多依赖一个库,很麻烦,而且opencv好像也并没有依赖该库,所以并没有按照这个方法去实验。

下面对实现的过程做一个详细的记录。

环境:【windows7+vs2013+python3.5】  和 【 windows10+vs2017+python3.6】

1.【建立Dll动态库工程】

建立一个dll工程,并添加如下头文件,库文件目录。python是64位系统的,平台要选择x64。

 

库目录,库文件

然后写瘦脸的c代码:

#include <Python.h>
#include<malloc.h> 
#include <numpy/arrayobject.h>
typedef unsigned char uchar;

//最近邻插值法
uchar* BilinearInter(uchar* data, int step_length, float ux, float uy)
{
	int ux_i = round(ux);
	int uy_i = round(uy);

	return (data + uy_i * step_length + ux_i * 3);
}


uchar * localTransform(uchar* data, int channel, int width, int height, int startX, int startY, int endX, int endY, float radius)
{
	float ddradius = radius * radius;
	int data_size = channel * width*height;
	int step_length = channel * width;
	uchar*  copyImg = (uchar*)malloc(sizeof(uchar) *data_size);
	memcpy(copyImg, data, data_size);
	float ddmc = (endX - startX) * (endX - startX) + (endY - startY) * (endY - startY);


	for (int j = 0; j < height; j++)
	{

		uchar* rowData = copyImg + j * step_length;

		for (int i = 0; i < width; i++)
		{

			if (abs(i - startX) > radius && abs(j - startY) > radius)
				continue;

			float distance = (i - startX) * (i - startX) + (j - startY) * (j - startY);

			if (distance < ddradius)
			{
				float ratio = (ddradius - distance) / (ddradius - distance + ddmc);
				ratio = ratio * ratio;

				float UX = i - ratio * (endX - startX);
				float UY = j - ratio * (endY - startY);

				uchar *insertValue = BilinearInter(data, step_length, UX, UY);
				memcpy(rowData + i * channel, insertValue, channel);
			}
		}
	}

	memcpy(data, copyImg, data_size);
	free(copyImg);

	return data;
}
static int failmsg(const char *fmt, ...) {
	char str[1000];

	va_list ap;
	va_start(ap, fmt);
	vsnprintf(str, sizeof(str), fmt, ap);
	va_end(ap);

	PyErr_SetString(PyExc_TypeError, str);
	return 0;
}

//尝试查看传过来的数组的数据
static PyObject* face_data(PyObject* self, PyObject* args)
{
	PyObject* pyobj_img = NULL;


	char ok = PyArg_ParseTuple(args, "O", &pyobj_img);
	if (ok)
	{
		PyArrayObject* oarr = (PyArrayObject*)pyobj_img;
		int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
		int ndims = PyArray_NDIM(oarr);

		uchar* data = (uchar*)PyArray_DATA(oarr);

		localTransform(data, 3, 606, 738, 145, 487, 447, 473, 80.0);

		PyObject *result = PyUnicode_FromFormat("result:%s", "ok");
		return result;
	}
	else
	{
		PyObject *result = PyUnicode_FromFormat("result:%d", 10);
		return result;
	}

}


static PyObject *
face_hello(PyObject *self, PyObject *args) {
	PyObject *name, *result;
	if (!PyArg_ParseTuple(args, "U:demo_hello", &name))
		return NULL;
	result = PyUnicode_FromFormat("Hello, %S!", name);
	return result;
}


// method table
static PyMethodDef DemoMethods[] = {

{ "hello", face_hello, METH_VARARGS, "I guess here is description." },
{ "face_data", (PyCFunction)face_data, METH_VARARGS | METH_KEYWORDS, "I guess here is description." },
{ NULL, NULL, 0, NULL }        /* Sentinel */
};

// The method table must be referenced in the module definition structure.
static struct PyModuleDef demomodule = {
PyModuleDef_HEAD_INIT,
"facethin",   /* name of module */
NULL, /* module documentation, may be NULL */
-1,       /* size of per-interpreter state of the module,
  or -1 if the module keeps state in global variables. */
  DemoMethods
};

// The initialization function must be named PyInit_name()
PyMODINIT_FUNC
PyInit_demo(void)
{
	return PyModule_Create(&demomodule);
}

最后生成动态库facethin.dll,修改后缀名demo.pyd,然后将demo.pyd移动到C:\Users\aUsernme\AppData\Local\Programs\Python\Python36\DLLs,其中username计算机用户名。

 

编写python代码:

import demo
import cv2
import time
img=cv2.imread('timg4.jpg')

start = time.clock()
hi=demo.demo_data(img)
end = time.clock()

print('run time:',end-start)

cv2.imshow('img',img)
cv2.imwrite('thin.jpg',img)

cv2.waitKey(0)

运行效果:

原图

瘦脸图:

总结:

在我的机器上,时间上大概是20多ms,而纯python实现需要1.5s左右,提升非常明显。

本文的主要目的是介绍下如何将numpy转c指针,瘦脸中某些参数只针对实例图像有效,不适用其他图像。

ps:图像来自网络,侵权请告知。

 

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值