在 python 的 c 扩展中使用 opencv 时出现问题?
Problem using opencv in a c-extension for python?
我正在尝试编写一个简单的 python c 扩展,其中包含一些 opencv 代码。这是我的 C++ 代码:
#include "Python.h"
#include "numpy/arrayobject.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
/* .... C matrix utility functions ..................*/
double **pymatrix_to_Carrayptrs(PyArrayObject *arrayin);
double **ptrvector(long n);
void free_Carrayptrs(double **v);
int not_doublematrix(PyArrayObject *mat);
static PyObject *simple_cv_ops(PyObject *self, PyObject *args)
{
PyArrayObject *matin, *matout;
double **cin, **cout;
int n,m, dims[2];
/* Parse tuples separately since args will differ between C fcns */
if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &matin)) return NULL;
if (NULL == matin) return NULL;
/* Check that object input is 'double' type and a matrix
Not needed if python wrapper function checks before call to this routine */
if (not_doublematrix(matin)) return NULL;
/* Get the dimensions of the input */
n=dims[0]=matin->dimensions[0];
m=dims[1]=matin->dimensions[1];
/* Make a new double matrix of same dims */
matout=(PyArrayObject *) PyArray_FromDims(2,dims,NPY_DOUBLE);
/* Change contiguous arrays into C ** arrays (Memory is Allocated!) */
cin=pymatrix_to_Carrayptrs(matin);
cout=pymatrix_to_Carrayptrs(matout);
// _______ Program LOGIC HERE ________
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(10, 10), cv::Point(-1, -1));
cv::Mat imgIn(n, m, CV_64F, cin);
cv::Mat imgOut(n, m, CV_64F);
cv::morphologyEx(imgIn, imgOut, cv::MORPH_CLOSE, kernel);
cv::GaussianBlur(imgOut, imgOut, cv::Size(5, 5), 0, 0);
cv::medianBlur(imgOut, imgOut, 5);
cv::threshold(imgOut, imgOut, 127, 255, 0);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cout[i][j] = imgOut.at<double>(i,j);
}
}
// ____________________________________
/* Free memory, close file and return */
free_Carrayptrs(cin);
free_Carrayptrs(cout);
return PyArray_Return(matout);
}
/* ==== Set up the methods table ====================== */
static PyMethodDef simple_cv_methods[] = {
{"simple_cv_ops", simple_cv_ops, METH_VARARGS, "Just a simple cv operation"},
{NULL, NULL, 0, NULL} /* Sentinel - marks the end of this structure */
};
static struct PyModuleDef simple_cv_modules = {
PyModuleDef_HEAD_INIT,
"simple_cv",
"Python interface for the simple cv ops C library function",
-1,
simple_cv_methods
};
PyMODINIT_FUNC PyInit_simple_cv(void) {
PyObject *pyob;
pyob = PyModule_Create(&simple_cv_modules);
import_array();
return pyob;
}
/* ==== Create Carray from PyArray ======================
Assumes PyArray is contiguous in memory.
Memory is allocated! */
double **pymatrix_to_Carrayptrs(PyArrayObject *arrayin) {
double **c, *a;
int i,n,m;
n=arrayin->dimensions[0];
m=arrayin->dimensions[1];
c=ptrvector(n);
a=(double *) arrayin->data; /* pointer to arrayin data as double */
for ( i=0; i<n; i++) {
c[i]=a+i*m; }
return c;
}
/* ==== Allocate a double *vector (vec of pointers) ======================
Memory is Allocated! See void free_Carray(double ** ) */
double **ptrvector(long n) {
double **v;
v=(double **)malloc((size_t) (n*sizeof(double)));
if (!v) {
printf("In **ptrvector. Allocation of memory for double array failed.");
exit(0); }
return v;
}
/* ==== Free a double *vector (vec of pointers) ========================== */
void free_Carrayptrs(double **v) {
free((char*) v);
}
/* ==== Check that PyArrayObject is a double (Float) type and a matrix ==============
return 1 if an error and raise exception */
int not_doublematrix(PyArrayObject *mat) {
if (mat->descr->type_num != NPY_DOUBLE || mat->nd != 2) {
PyErr_SetString(PyExc_ValueError,
"In not_doublematrix: array must be of type Float and 2 dimensional (n x m).");
return 1; }
return 0;
}
为了编写 c-extension,我使用了 here 中的一些代码,除了我在我的代码中使用 opencv 时,它工作得很好。
这里我也post我的setup.py代码:
import numpy
from distutils.core import setup, Extension
def main():
setup(name="simple_cv",
version="1.0.0",
description="Python interface for the simple cv C extension library function",
author="My Name",
author_email="my_email@email.com",
ext_modules=[Extension("simple_cv", ["simple_cv.cpp"],
include_dirs=[numpy.get_include(), 'C:/opencv/build/include']),
])
if __name__ == "__main__":
main()
当我 运行 我的 python 设置时,我收到以下错误:
simple_cv.obj : error LNK2001: unresolved external symbol "double
__cdecl cv::threshold(class cv::_InputArray const &,class cv::_OutputArray const &,double,double,int)"
(?threshold@cv@@YANAEBV_InputArray@1@AEBV_OutputArray@1@NNH@Z)
simple_cv.obj : error LNK2001: unresolved external symbol "public:
void __cdecl cv::Mat::deallocate(void)" (?deallocate@Mat@cv@@QEAAXXZ)
simple_cv.obj : error LNK2001: unresolved external symbol "public:
void __cdecl cv::Mat::create(int,int const *,int)"
(?create@Mat@cv@@QEAAXHPEBHH@Z) simple_cv.obj : error LNK2001:
unresolved external symbol "class cv::Mat __cdecl
cv::getStructuringElement(int,class cv::Size_,class
cv::Point_)"
(?getStructuringElement@cv@@YA?AVMat@1@HV?$Size_@H@1@V?$Point_@H@1@@Z)
simple_cv.obj : error LNK2001: unresolved external symbol "void
__cdecl cv::GaussianBlur(class cv::_InputArray const &,class cv::OutputArray const &,class cv::Size,double,double,int)"
(?GaussianBlur@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@V?$Size_@H@1@NNH@Z)
simple_cv.obj : error LNK2001: unresolved external symbol "void
__cdecl cv::fastFree(void *)" (?fastFree@cv@@YAXPEAX@Z) simple_cv.obj : error LNK2001: unresolved external symbol "private: void __cdecl
cv::String::deallocate(void)" (?deallocate@String@cv@@AEAAXXZ)
simple_cv.obj : error LNK2001: unresolved external symbol "private:
char * __cdecl cv::String::allocate(unsigned __int64)"
(?allocate@String@cv@@AEAAPEAD_K@Z) simple_cv.obj : error LNK2001:
unresolved external symbol "void __cdecl cv::error(int,class
cv::String const &,char const *,char const *,int)"
(?error@cv@@YAXHAEBVString@1@PEBD1H@Z) simple_cv.obj : error LNK2001:
unresolved external symbol "void __cdecl cv::morphologyEx(class
cv::_InputArray const &,class cv::_OutputArray const &,int,class
cv::InputArray const &,class cv::Point,int,int,class
cv::Scalar_ const &)"
(?morphologyEx@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@H0V?$Point_@H@1@HHAEBV?$Scalar_@N@1@@Z)
simple_cv.obj : error LNK2001: unresolved external symbol "void
__cdecl cv::medianBlur(class cv::_InputArray const &,class cv::_OutputArray const &,int)"
(?medianBlur@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@H@Z)
build\lib.win-amd64-3.6\simple_cv_c.cp36-win_amd64.pyd : fatal error
LNK1120: 12 unresolved externals error: command 'C:\Program Files
(x86)\Microsoft Visual
Studio17\Enterprise\VC\Tools\MSVC.12.25827\bin\HostX86\x64\link.exe'
failed with exit status 1120
现在我知道这些是链接器错误。我在 Visual Studio 中编码时遇到了这个问题,我通过在我的 Visual Studios 项目设置的链接器选项卡中将 lib 路径添加到 Additional Library Directories 来解决它。但是在这里我不知道该怎么办。
顺便说一下,我使用的是 windows 10、Visual Studio 2017 和 python 3.6.
有人可以帮我吗?
我找到了答案。
看起来 Extension class 来自 distutils.core 模块有两个额外的库输入参数library_dirs 和 图书馆.
所以我只需要更改我的 setup.py 代码如下:
import numpy
from distutils.core import setup, Extension
def main():
setup(name="simple_cv",
version="1.0.0",
description="Python interface for the simple cv C extension library function",
author="My Name",
author_email="my_email@email.com",
ext_modules=[Extension("simple_cv", ["simple_cv.cpp"],
include_dirs=[numpy.get_include(), 'C:/opencv/build/include']),
library_dirs = ['C:\opencv\build\x64\vc14\lib'],
libraries = ['opencv_world330']])
if __name__ == "__main__":
main()
我正在尝试编写一个简单的 python c 扩展,其中包含一些 opencv 代码。这是我的 C++ 代码:
#include "Python.h"
#include "numpy/arrayobject.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
/* .... C matrix utility functions ..................*/
double **pymatrix_to_Carrayptrs(PyArrayObject *arrayin);
double **ptrvector(long n);
void free_Carrayptrs(double **v);
int not_doublematrix(PyArrayObject *mat);
static PyObject *simple_cv_ops(PyObject *self, PyObject *args)
{
PyArrayObject *matin, *matout;
double **cin, **cout;
int n,m, dims[2];
/* Parse tuples separately since args will differ between C fcns */
if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &matin)) return NULL;
if (NULL == matin) return NULL;
/* Check that object input is 'double' type and a matrix
Not needed if python wrapper function checks before call to this routine */
if (not_doublematrix(matin)) return NULL;
/* Get the dimensions of the input */
n=dims[0]=matin->dimensions[0];
m=dims[1]=matin->dimensions[1];
/* Make a new double matrix of same dims */
matout=(PyArrayObject *) PyArray_FromDims(2,dims,NPY_DOUBLE);
/* Change contiguous arrays into C ** arrays (Memory is Allocated!) */
cin=pymatrix_to_Carrayptrs(matin);
cout=pymatrix_to_Carrayptrs(matout);
// _______ Program LOGIC HERE ________
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(10, 10), cv::Point(-1, -1));
cv::Mat imgIn(n, m, CV_64F, cin);
cv::Mat imgOut(n, m, CV_64F);
cv::morphologyEx(imgIn, imgOut, cv::MORPH_CLOSE, kernel);
cv::GaussianBlur(imgOut, imgOut, cv::Size(5, 5), 0, 0);
cv::medianBlur(imgOut, imgOut, 5);
cv::threshold(imgOut, imgOut, 127, 255, 0);
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cout[i][j] = imgOut.at<double>(i,j);
}
}
// ____________________________________
/* Free memory, close file and return */
free_Carrayptrs(cin);
free_Carrayptrs(cout);
return PyArray_Return(matout);
}
/* ==== Set up the methods table ====================== */
static PyMethodDef simple_cv_methods[] = {
{"simple_cv_ops", simple_cv_ops, METH_VARARGS, "Just a simple cv operation"},
{NULL, NULL, 0, NULL} /* Sentinel - marks the end of this structure */
};
static struct PyModuleDef simple_cv_modules = {
PyModuleDef_HEAD_INIT,
"simple_cv",
"Python interface for the simple cv ops C library function",
-1,
simple_cv_methods
};
PyMODINIT_FUNC PyInit_simple_cv(void) {
PyObject *pyob;
pyob = PyModule_Create(&simple_cv_modules);
import_array();
return pyob;
}
/* ==== Create Carray from PyArray ======================
Assumes PyArray is contiguous in memory.
Memory is allocated! */
double **pymatrix_to_Carrayptrs(PyArrayObject *arrayin) {
double **c, *a;
int i,n,m;
n=arrayin->dimensions[0];
m=arrayin->dimensions[1];
c=ptrvector(n);
a=(double *) arrayin->data; /* pointer to arrayin data as double */
for ( i=0; i<n; i++) {
c[i]=a+i*m; }
return c;
}
/* ==== Allocate a double *vector (vec of pointers) ======================
Memory is Allocated! See void free_Carray(double ** ) */
double **ptrvector(long n) {
double **v;
v=(double **)malloc((size_t) (n*sizeof(double)));
if (!v) {
printf("In **ptrvector. Allocation of memory for double array failed.");
exit(0); }
return v;
}
/* ==== Free a double *vector (vec of pointers) ========================== */
void free_Carrayptrs(double **v) {
free((char*) v);
}
/* ==== Check that PyArrayObject is a double (Float) type and a matrix ==============
return 1 if an error and raise exception */
int not_doublematrix(PyArrayObject *mat) {
if (mat->descr->type_num != NPY_DOUBLE || mat->nd != 2) {
PyErr_SetString(PyExc_ValueError,
"In not_doublematrix: array must be of type Float and 2 dimensional (n x m).");
return 1; }
return 0;
}
为了编写 c-extension,我使用了 here 中的一些代码,除了我在我的代码中使用 opencv 时,它工作得很好。
这里我也post我的setup.py代码:
import numpy
from distutils.core import setup, Extension
def main():
setup(name="simple_cv",
version="1.0.0",
description="Python interface for the simple cv C extension library function",
author="My Name",
author_email="my_email@email.com",
ext_modules=[Extension("simple_cv", ["simple_cv.cpp"],
include_dirs=[numpy.get_include(), 'C:/opencv/build/include']),
])
if __name__ == "__main__":
main()
当我 运行 我的 python 设置时,我收到以下错误:
simple_cv.obj : error LNK2001: unresolved external symbol "double __cdecl cv::threshold(class cv::_InputArray const &,class cv::_OutputArray const &,double,double,int)" (?threshold@cv@@YANAEBV_InputArray@1@AEBV_OutputArray@1@NNH@Z) simple_cv.obj : error LNK2001: unresolved external symbol "public: void __cdecl cv::Mat::deallocate(void)" (?deallocate@Mat@cv@@QEAAXXZ) simple_cv.obj : error LNK2001: unresolved external symbol "public: void __cdecl cv::Mat::create(int,int const *,int)" (?create@Mat@cv@@QEAAXHPEBHH@Z) simple_cv.obj : error LNK2001: unresolved external symbol "class cv::Mat __cdecl cv::getStructuringElement(int,class cv::Size_,class cv::Point_)" (?getStructuringElement@cv@@YA?AVMat@1@HV?$Size_@H@1@V?$Point_@H@1@@Z) simple_cv.obj : error LNK2001: unresolved external symbol "void __cdecl cv::GaussianBlur(class cv::_InputArray const &,class cv::OutputArray const &,class cv::Size,double,double,int)" (?GaussianBlur@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@V?$Size_@H@1@NNH@Z) simple_cv.obj : error LNK2001: unresolved external symbol "void __cdecl cv::fastFree(void *)" (?fastFree@cv@@YAXPEAX@Z) simple_cv.obj : error LNK2001: unresolved external symbol "private: void __cdecl cv::String::deallocate(void)" (?deallocate@String@cv@@AEAAXXZ) simple_cv.obj : error LNK2001: unresolved external symbol "private: char * __cdecl cv::String::allocate(unsigned __int64)" (?allocate@String@cv@@AEAAPEAD_K@Z) simple_cv.obj : error LNK2001: unresolved external symbol "void __cdecl cv::error(int,class cv::String const &,char const *,char const *,int)" (?error@cv@@YAXHAEBVString@1@PEBD1H@Z) simple_cv.obj : error LNK2001: unresolved external symbol "void __cdecl cv::morphologyEx(class cv::_InputArray const &,class cv::_OutputArray const &,int,class cv::InputArray const &,class cv::Point,int,int,class cv::Scalar_ const &)" (?morphologyEx@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@H0V?$Point_@H@1@HHAEBV?$Scalar_@N@1@@Z) simple_cv.obj : error LNK2001: unresolved external symbol "void __cdecl cv::medianBlur(class cv::_InputArray const &,class cv::_OutputArray const &,int)" (?medianBlur@cv@@YAXAEBV_InputArray@1@AEBV_OutputArray@1@H@Z) build\lib.win-amd64-3.6\simple_cv_c.cp36-win_amd64.pyd : fatal error LNK1120: 12 unresolved externals error: command 'C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\VC\Tools\MSVC.12.25827\bin\HostX86\x64\link.exe' failed with exit status 1120
现在我知道这些是链接器错误。我在 Visual Studio 中编码时遇到了这个问题,我通过在我的 Visual Studios 项目设置的链接器选项卡中将 lib 路径添加到 Additional Library Directories 来解决它。但是在这里我不知道该怎么办。
顺便说一下,我使用的是 windows 10、Visual Studio 2017 和 python 3.6.
有人可以帮我吗?
我找到了答案。
看起来 Extension class 来自 distutils.core 模块有两个额外的库输入参数library_dirs 和 图书馆.
所以我只需要更改我的 setup.py 代码如下:
import numpy
from distutils.core import setup, Extension
def main():
setup(name="simple_cv",
version="1.0.0",
description="Python interface for the simple cv C extension library function",
author="My Name",
author_email="my_email@email.com",
ext_modules=[Extension("simple_cv", ["simple_cv.cpp"],
include_dirs=[numpy.get_include(), 'C:/opencv/build/include']),
library_dirs = ['C:\opencv\build\x64\vc14\lib'],
libraries = ['opencv_world330']])
if __name__ == "__main__":
main()