PyObject_CallMethod returns Null - python

I have an image processing application that I am using OpenCV within Python and then have it embedded in Embarcadero C++ XE6 IDE for Windows.
I followed all the great exampled and was able to get the embedded Python code working in the bare application. However when I try to use numpy (loadImage) I get the following error:
<type 'exception.AttributeError'>:'NoneType' object has no attribute 'dtype'
If I simply return out of the Python function with a True (commented out now) it returns a valid PyObject. If I try to average the intensity of the pixels with numpy it returns a NULL object.
I am thinking I don't have the imports setup correctly. The stand-alone Python application works as expected but not when it's embedded into my C++ application.
Python Code:
import numpy
import cv2
class Camera:
def __init__(self):
print 'OpenCV Version:', cv2.__version__
def loadImage(self):
'''
Load image from file
'''
global img
img = cv2.imread('cameraImageBlob.png',cv2.IMREAD_GRAYSCALE)
#return True
return numpy.average(img)
if __name__ == '__main__':
dc = Camera()
print dc.loadImage()
C++ Code:
#include "Python.h"
int main() {
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pClass, *pInstance;
double dValue;
// Initilize the Python interpreter
Py_Initialize();
// Set runtime paths
PyRun_SimpleString("import sys");
PyRun_SimpleString("import numpy");
PyRun_SimpleString("import cv2");
// Build the name object - create a new reference
pName = PyString_FromString((char*)"OpenCVTest");
// Load the module object
pModule = PyImport_Import(pName);
if(pModule != NULL) {
//pDict is a borrowed reference so no DECREF
pDict = PyModule_GetDict(pModule);
// Get the Camera Class
pClass = PyDict_GetItemString(pDict, "Camera");
if(PyCallable_Check(pClass)) {
pInstance = PyObject_CallObject(pClass, NULL);
} else {
return;
}
// Load Image and get intensity
pValue = PyObject_CallMethod(pInstance, "loadImage", NULL);
if(pValue == NULL) {
GetError();
} else {
dValue = PyFloat_AsDouble(pValue);
}
}
Py_DecRef(pName);
Py_DecRef(pModule);
Py_DecRef(pValue);
Py_Finalize();
return 0;
}

Related

How to print custom Python types in boost.python

I am trying to use the boost.python library in order to get data from the Python skyfield API, but I am having trouble printing out the data. The program runs, but I get this error: "Error in Python: <class 'TypeError'>: 'NoneType' object is not callable"
The correct output should show something like this:
10h 47m 56.24s
+09deg 03' 23.1"
2.33251 au
I am using the first code example from this website as a reference: https://rhodesmill.org/skyfield/
If you have any ideas on how to get the data to correctly output, please let me know!
Here is my code so far:
#include <iostream>
#include <boost/python.hpp>
#include <Python.h>
namespace py = boost::python;
std::string parse_python_exception();
int main()
{
Py_Initialize(); //Initializes the Python interpreter
//Imports the __main__ module and extracts the namespace
//This creates a blank 'canvas' upon which we can call Python code
py::object main_module = py::import("__main__");
//Loads the dictionary object from the main module
py::object main_namespace = main_module.attr("__dict__");
try
{
//Imports
py::exec("from skyfield.api import load");
py::object skyfield_mod = py::import("skyfield.api");
py::object skyfield_load = skyfield_mod.attr("load");
py::object skyfield_load_timescale = skyfield_load.attr("timescale");
py::exec("print('This program computes the current position of Mars in the sky')", main_namespace);
py::object ts = skyfield_load_timescale();
py::object ts_now = ts.attr("now");
py::object t = ts_now();
py::object planets = skyfield_load("de421.bsp");
py::object earth = planets["earth"];
py::object mars = planets["mars"];
py::object earth_at = earth.attr("at");
py::object earth_at_observe = earth_at(t).attr("observe");
py::object m_earth_at_observe = earth_at_observe(mars);
py::object astrometric = m_earth_at_observe;
py::object ra, dec, distance = astrometric.attr("radec");
py::object m_ra = ra();
py::object m_dec = dec();
py::object m_distance = distance();
py::exec("print(m_ra)", main_namespace);
}
catch (boost::python::error_already_set const&)
{
std::string perror_str = parse_python_exception();
std::cout << "Error in Python: " << perror_str << std::endl;
}
}
// Parses the value of the active python exception
// NOTE SHOULD NOT BE CALLED IF NO EXCEPTION
std::string parse_python_exception() {
PyObject* type_ptr = NULL, * value_ptr = NULL, * traceback_ptr = NULL;
// Fetch the exception info from the Python C API
PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);
// Fallback error
std::string ret("Unfetchable Python error");
// If the fetch got a type pointer, parse the type into the exception string
if (type_ptr != NULL) {
py::handle<> h_type(type_ptr);
py::str type_pstr(h_type);
// Extract the string from the boost::python object
py::extract<std::string> e_type_pstr(type_pstr);
// If a valid string extraction is available, use it
// otherwise use fallback
if (e_type_pstr.check())
ret = e_type_pstr();
else
ret = "Unknown exception type";
}
// Do the same for the exception value (the stringification of the exception)
if (value_ptr != NULL) {
py::handle<> h_val(value_ptr);
py::str a(h_val);
py::extract<std::string> returned(a);
if (returned.check())
ret += ": " + returned();
else
ret += std::string(": Unparseable Python error: ");
}
// Parse lines from the traceback using the Python traceback module
if (traceback_ptr != NULL) {
py::handle<> h_tb(traceback_ptr);
// Load the traceback module and the format_tb function
py::object tb(py::import("traceback"));
py::object fmt_tb(tb.attr("format_tb"));
// Call format_tb to get a list of traceback strings
py::object tb_list(fmt_tb(h_tb));
// Join the traceback strings into a single string
py::object tb_str(py::str("\n").join(tb_list));
// Extract the string, check the extraction, and fallback in necessary
py::extract<std::string> returned(tb_str);
if (returned.check())
ret += ": " + returned();
else
ret += std::string(": Unparseable Python traceback");
}
return ret;
}

Python Method Call in a C++ Code through Python C-API

I am working on my Project which implies the use of Empirical Mode Decomposition in C++ for EEG Signals. The input Data is Eigen::MatrixXd, where the rows are the Channels and the columns are the samples.
I did not found a good C++ library for EMD so I want to use a Python one (dsatools). I have downloaded the package through Pip installer from the setup.py file on Xubuntu... so it's a system package now.
the problem is that the program can't read the module.
this is the code:
std::vector <Eigen::MatrixXd> DataAquisition::EMD (Eigen::MatrixXd array, int order, int iterations, int locality) {
std::vector <Eigen::MatrixXd> IMFs;
for (int i = 0; i < array.rows(); i++) {
Eigen::MatrixXd Kanals = array.row(i);
Eigen::MatrixXd IMFs_Cpp;
Py_Initialize();
//PyRun_SimpleString("from dsatools._base._imf_decomposition import * ");
PyObject* sys_path = PySys_GetObject("path");
PyObject* ProgrammName = PyUnicode_FromString("/home/user/Schreibtisch/mne-cpp-main/applications/mne_bci/MNE-BCI-QT/dsatools-master/dsatools/_base/_imf_decomposition/_emd.py");
PyList_Append(sys_path, ProgrammName);
PyObject* pModuleString = PyUnicode_FromString ((char*)"_emd.py");
PyObject* pModule = PyImport_Import(pModuleString);
PyObject* pFunction = PyObject_GetAttrString(pModule,(char*)"emd");
//PyObject* pDict = PyModule_GetDict(pModule);
//PyObject* pFunc = PyDict_GetItemString(pDict, (char*)"emd");
if (PyCallable_Check(pFunction))
{
PyObject* Signal = Py_BuildValue("(d)",(double*)Kanals.data());
PyObject* Order = Py_BuildValue("(i)",order);
PyObject* method = Py_BuildValue("(z)",(char*)"cubic");
PyObject* max_itter = Py_BuildValue("(i)",iterations);
PyObject* args = PyTuple_Pack(4,Signal,Order,method,max_itter);
PyErr_Print();
PyObject* IMFs_Py = PyObject_CallObject(pFunction,args);
PyErr_Print();
if (PyArray_Check(IMFs_Py))
std::cout << "EMD Output is NOT Array \n";
PyArrayObject *np_ret = reinterpret_cast <PyArrayObject*> (IMFs_Py);
int Rows = PyArray_SHAPE(np_ret)[0];
int Cols = PyArray_SHAPE(np_ret)[1];
double* c_out = reinterpret_cast<double*>(PyArray_DATA(np_ret));
Eigen::MatrixXd IMFs_Cpp = Eigen::Map <Eigen::MatrixXd> (c_out,Rows,Cols);
IMFs.push_back(IMFs_Cpp);
}
else
std::cout << "Python did not call the function \n";
Py_Finalize();
}
return IMFs;}
this is how the code in Python should look like and I just want to call the emd function:

How can I get the print of python function from cpp

I use cpp to call python function, I have compiled the program without errors, but why can not I see the print result in python function.
here is the cpp codes:
#include<python2.7/Python.h>
....
using namespace std;
int main()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("import os");
PyRun_SimpleString("import string");
PyRun_SimpleString("sys.path.append('./')");
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
PyObject * pClass = NULL;
PyObject * pInstance = NULL;
pModule = PyImport_ImportModule("download");
if(!pModule)
{
std::cout << "there is no this file." << std::endl;
}
pFunc= PyObject_GetAttrString(pModule, "geturl");
if(!pFunc)
{
std::cout << "there is no this func." << std::endl;
}
std::string url = "www";
PyObject* args = Py_BuildValue("ss", url.c_str());
PyEval_CallObject(pFunc, args);
Py_DECREF(pFunc);
Py_Finalize();
return 0;
}
here is the download.py file in the same dir
def geturl(url):
print(url)
print("hello")
here is result, without errors nor print:
root#cvm-172_16_20_84:~/klen/test/cpppython # g++ t.cpp -o printurl -lpython2.7
root#cvm-172_16_20_84:~/klen/test/cpppython # ./printurl
root#cvm-172_16_20_84:~/klen/test/cpppython #
How can I see the print, has the function geturl run successfully? Thanks
The PyEval_CallObject function is encountering a Python exception before it reaches your print statements. Adding error handling to this call (call PyErr_Print on NULL return value) will show the exception being raised:
TypeError: geturl() takes exactly 1 argument (2 given)
The root cause is the format string:
Py_BuildValue("ss", url.c_str());
You are creating a tuple of two values and passing that as the arguments geturl(). You need to pass a tuple with only one value. You are also invoking undefined behavior here because you haven't provided a second string pointer.
Resolve the issue by passing a tuple with only one value:
Py_BuildValue("(s)", url.c_str());

Passing OpenCv Mat from C++ to Python

I need to send an OpenCv image from C++ to Python to do some processing on it.
The Mat will be received through the code but for simplicity I am using imread here for the question.
What I did in the C++ part of the code was:
#include <Python.h>
#include <arrayobject.h>
#include <iostream>
#include <opencv2/opencv.hpp>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Mat image = imread("test.jpg");
Py_Initialize();
PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
pName = PyUnicode_FromString("prog");
if (pName == NULL)
{
PyErr_Print();
return 0;
}
pModule = PyImport_Import(pName);
if (pModule == NULL)
{
PyErr_Print();
return 0;
}
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, "add");
if (pFunc == NULL)
{
PyErr_Print();
return 0;
}
pArgs = PyTuple_New(1);
import_array ();
npy_intp dimensions[3] = {image.rows, image.cols, image.channels()};
pValue = PyArray_SimpleNewFromData(image.dims + 1, (npy_intp*)&dimensions, NPY_UINT8, image.data);
PyTuple_SetItem(pArgs, 0, pValue);
PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
if(pResult == NULL)
cout<<"Calling the add method failed"<<endl;
long result = PyLong_AsLong(pResult);
cout<<"Result = "<<result<<endl;
Py_Finalize();
return 0;
}
This code compiles and runs.
For the Python part:
import cv2
import numpy as np
def add (a):
print ("Contents of a :")
print (a)
# mat_array = cv2.fromarray(a, numpy.float32)
vis0 = cv.fromarray(a)
return 0
The Python code receives the numpy array from C++ (I think) and when I print the contents of a, I have an output (so I think I am receiving the image from C++).
Now I need to convert the data in a to a cv2 Mat in Python so that I can work on it.
Once I reach the mat_array = cv2.fromarray(a, numpy.float32) line or vis0 = cv.fromarray(a) the code crashes with the following output:
Exception ignored in: <module 'threading' from '/usr/lib/python3.5/threading.py'>
Traceback (most recent call last):
File "/usr/lib/python3.5/threading.py", line 1283, in _shutdown
assert tlock.locked()
SystemError: <built-in method locked of _thread.lock object at 0x7ff0f34d20d0> returned a result with an error set
How do I correctly send / receive the Mat object?
Please find my answer here. You can also find other answer here. for converting numpy -> cv::Mat and cv::Mat -> numpy.

Running opencv-python script hangs in sub-interpreter

I am hosting python interpreter(2.7.13) in a C application and running a python script that has some calls to opencv-python functions.
The problem is that when the script is run in the main interpreter, it works fine. But, when the script is run in a sub-interpreter, it hangs.
Is there any known incompatibility between opencv-python package and sub-interpreter ?
The C application code is as follows:-
const char *pythonSource = "abc_module";
const char *funcName = "abc_function";
Py_Initialize();
PyEval_InitThreads();
if(run_in_subinterpreter){
PyThreadState* threadState = Py_NewInterpreter();
PyThreadState *mainState = PyThreadState_Swap(threadState);
}
pName = PyString_FromString(pythonSource);
pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
pFunc = PyDict_GetItemString(pDict, funcName);
PyObject *pyList = PyList_New(gArray.size()); //std::vector<int> gArray;
for (size_t i = 0; i < gArray.size(); ++i)
{
PyObject *elem = PyInt_FromLong(gArray[i]);
PyList_SetItem(pyList, i, elem);
}
PyObject* pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, pyList);
pValue = PyObject_CallObject(pFunc, pArgs);
Py_Finalize();
return;
The python script code is as follows:-
import sys
import cv2
import numpy as np
def abc_function(list):
array = np.asarray(list)
array = np.reshape(array, (100, 200, 4)).astype(np.uint8)
array = abc_function_core(array)
return array
def abc_function_core(array):
# array is manipulated by calling the below functions
cv2.resize(....)
cv2.cvtColor(...)
cv2.equalizeHist(...)
cv2.CascadeClassifier.detectMultiScale(...)
cv2.rectangle(...)
return array

Categories