0

I'm trying to write a simple python c-extension which includes some opencv code. Here is my c++ code:

#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;
}

To write the c-extension I used some codes from here which works perfectly except when I use opencv in my code.

Here I also post my setup.py code:

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="[email protected]",
          ext_modules=[Extension("simple_cv", ["simple_cv.cpp"],
                  include_dirs=[numpy.get_include(), 'C:/opencv/build/include']),
                        ])

if __name__ == "__main__":
    main()

when I run my python setup I get the following errors:

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 Studio\2017\Enterprise\VC\Tools\MSVC\14.12.25827\bin\HostX86\x64\link.exe' failed with exit status 1120

Now I know that these are linker errors. I had this problem when coding in Visual Studio and I resolved it by adding the lib path to Additional Library Directories at Linker tab of my Visual Studios project settings. But here I dont know what to do.

By the way I'm using windows 10, Visual Studio 2017 and python 3.6.

Can someone help me please?

1 Answer 1

2

I found the answer.

Looks like Pythons Extension class from distutils.core module hass two additional input arguments for libraries which are library_dirs and libraries.

So I just had to change my setup.py code as below:

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="[email protected]",
          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()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.