I'm trying to create Python/Cython wrapper for C++ library that uses cv::Mat class from OpenCV. In official Python wrapper all functions take NumPy's ndarray instead of cv::Mat, which is quite convenient. But in my own wrapper, how do I do such conversion? That is, how do I create cv::Mat from np.ndarray?
As suggested by kyamagu, you can use OpenCV's official python wrapper code, especially the pyopencv_to and pyopencv_from.
I've been struggling as you did with all the dependencies and the generated header files. Nevertheless, it is possible to reduce the complexity of this by "cleaning" the cv2.cpp as lightalchemist did here in order to keep only what is necessary. You will need to adapt it to your need and to the version of OpenCV you're using but its basically the same code that I used.
#include <Python.h>
#include "numpy/ndarrayobject.h"
#include "opencv2/core/core.hpp"
static PyObject* opencv_error = 0;
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;
}
class PyAllowThreads
{
public:
PyAllowThreads() : _state(PyEval_SaveThread()) {}
~PyAllowThreads()
{
PyEval_RestoreThread(_state);
}
private:
PyThreadState* _state;
};
class PyEnsureGIL
{
public:
PyEnsureGIL() : _state(PyGILState_Ensure()) {}
~PyEnsureGIL()
{
PyGILState_Release(_state);
}
private:
PyGILState_STATE _state;
};
#define ERRWRAP2(expr) \
try \
{ \
PyAllowThreads allowThreads; \
expr; \
} \
catch (const cv::Exception &e) \
{ \
PyErr_SetString(opencv_error, e.what()); \
return 0; \
}
using namespace cv;
static PyObject* failmsgp(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 size_t REFCOUNT_OFFSET = (size_t)&(((PyObject*)0)->ob_refcnt) +
(0x12345678 != *(const size_t*)"\x78\x56\x34\x12\0\0\0\0\0")*sizeof(int);
static inline PyObject* pyObjectFromRefcount(const int* refcount)
{
return (PyObject*)((size_t)refcount - REFCOUNT_OFFSET);
}
static inline int* refcountFromPyObject(const PyObject* obj)
{
return (int*)((size_t)obj + REFCOUNT_OFFSET);
}
class NumpyAllocator : public MatAllocator
{
public:
NumpyAllocator() {}
~NumpyAllocator() {}
void allocate(int dims, const int* sizes, int type, int*& refcount,
uchar*& datastart, uchar*& data, size_t* step)
{
PyEnsureGIL gil;
int depth = CV_MAT_DEPTH(type);
int cn = CV_MAT_CN(type);
const int f = (int)(sizeof(size_t)/8);
int typenum = depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
depth == CV_32S ? NPY_INT : depth == CV_32F ? NPY_FLOAT :
depth == CV_64F ? NPY_DOUBLE : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
int i;
npy_intp _sizes[CV_MAX_DIM+1];
for( i = 0; i < dims; i++ )
_sizes[i] = sizes[i];
if( cn > 1 )
{
/*if( _sizes[dims-1] == 1 )
_sizes[dims-1] = cn;
else*/
_sizes[dims++] = cn;
}
PyObject* o = PyArray_SimpleNew(dims, _sizes, typenum);
if(!o)
CV_Error_(CV_StsError, ("The numpy array of typenum=%d, ndims=%d can not be created", typenum, dims));
refcount = refcountFromPyObject(o);
npy_intp* _strides = PyArray_STRIDES(o);
for( i = 0; i < dims - (cn > 1); i++ )
step[i] = (size_t)_strides[i];
datastart = data = (uchar*)PyArray_DATA(o);
}
void deallocate(int* refcount, uchar*, uchar*)
{
PyEnsureGIL gil;
if( !refcount )
return;
PyObject* o = pyObjectFromRefcount(refcount);
Py_INCREF(o);
Py_DECREF(o);
}
};
NumpyAllocator g_numpyAllocator;
enum { ARG_NONE = 0, ARG_MAT = 1, ARG_SCALAR = 2 };
static int pyopencv_to(const PyObject* o, Mat& m, const char* name = "<unknown>", bool allowND=true)
{
if(!o || o == Py_None)
{
if( !m.data )
m.allocator = &g_numpyAllocator;
return true;
}
if( PyInt_Check(o) )
{
double v[] = {PyInt_AsLong((PyObject*)o), 0., 0., 0.};
m = Mat(4, 1, CV_64F, v).clone();
return true;
}
if( PyFloat_Check(o) )
{
double v[] = {PyFloat_AsDouble((PyObject*)o), 0., 0., 0.};
m = Mat(4, 1, CV_64F, v).clone();
return true;
}
if( PyTuple_Check(o) )
{
int i, sz = (int)PyTuple_Size((PyObject*)o);
m = Mat(sz, 1, CV_64F);
for( i = 0; i < sz; i++ )
{
PyObject* oi = PyTuple_GET_ITEM(o, i);
if( PyInt_Check(oi) )
m.at<double>(i) = (double)PyInt_AsLong(oi);
else if( PyFloat_Check(oi) )
m.at<double>(i) = (double)PyFloat_AsDouble(oi);
else
{
failmsg("%s is not a numerical tuple", name);
m.release();
return false;
}
}
return true;
}
if( !PyArray_Check(o) )
{
failmsg("%s is not a numpy array, neither a scalar", name);
return false;
}
bool needcopy = false, needcast = false;
int typenum = PyArray_TYPE(o), new_typenum = typenum;
int type = typenum == NPY_UBYTE ? CV_8U :
typenum == NPY_BYTE ? CV_8S :
typenum == NPY_USHORT ? CV_16U :
typenum == NPY_SHORT ? CV_16S :
typenum == NPY_INT ? CV_32S :
typenum == NPY_INT32 ? CV_32S :
typenum == NPY_FLOAT ? CV_32F :
typenum == NPY_DOUBLE ? CV_64F : -1;
if( type < 0 )
{
if( typenum == NPY_INT64 || typenum == NPY_UINT64 || type == NPY_LONG )
{
needcopy = needcast = true;
new_typenum = NPY_INT;
type = CV_32S;
}
else
{
failmsg("%s data type = %d is not supported", name, typenum);
return false;
}
}
int ndims = PyArray_NDIM(o);
if(ndims >= CV_MAX_DIM)
{
failmsg("%s dimensionality (=%d) is too high", name, ndims);
return false;
}
int size[CV_MAX_DIM+1];
size_t step[CV_MAX_DIM+1], elemsize = CV_ELEM_SIZE1(type);
const npy_intp* _sizes = PyArray_DIMS(o);
const npy_intp* _strides = PyArray_STRIDES(o);
bool ismultichannel = ndims == 3 && _sizes[2] <= CV_CN_MAX;
for( int i = ndims-1; i >= 0 && !needcopy; i-- )
{
// these checks handle cases of
// a) multi-dimensional (ndims > 2) arrays, as well as simpler 1- and 2-dimensional cases
// b) transposed arrays, where _strides[] elements go in non-descending order
// c) flipped arrays, where some of _strides[] elements are negative
if( (i == ndims-1 && (size_t)_strides[i] != elemsize) ||
(i < ndims-1 && _strides[i] < _strides[i+1]) )
needcopy = true;
}
if( ismultichannel && _strides[1] != (npy_intp)elemsize*_sizes[2] )
needcopy = true;
if (needcopy)
{
if( needcast )
o = (PyObject*)PyArray_Cast((PyArrayObject*)o, new_typenum);
else
o = (PyObject*)PyArray_GETCONTIGUOUS((PyArrayObject*)o);
_strides = PyArray_STRIDES(o);
}
for(int i = 0; i < ndims; i++)
{
size[i] = (int)_sizes[i];
step[i] = (size_t)_strides[i];
}
// handle degenerate case
if( ndims == 0) {
size[ndims] = 1;
step[ndims] = elemsize;
ndims++;
}
if( ismultichannel )
{
ndims--;
type |= CV_MAKETYPE(0, size[2]);
}
if( ndims > 2 && !allowND )
{
failmsg("%s has more than 2 dimensions", name);
return false;
}
m = Mat(ndims, size, type, PyArray_DATA(o), step);
if( m.data )
{
m.refcount = refcountFromPyObject(o);
if (!needcopy)
{
m.addref(); // protect the original numpy array from deallocation
// (since Mat destructor will decrement the reference counter)
}
};
m.allocator = &g_numpyAllocator;
return true;
}
static PyObject* pyopencv_from(const Mat& m)
{
if( !m.data )
Py_RETURN_NONE;
Mat temp, *p = (Mat*)&m;
if(!p->refcount || p->allocator != &g_numpyAllocator)
{
temp.allocator = &g_numpyAllocator;
ERRWRAP2(m.copyTo(temp));
p = &temp;
}
p->addref();
return pyObjectFromRefcount(p->refcount);
}
Once you have a cleaned up cv2.cpp file, here is some Cython code that takes care of the conversion. Notice the definition and the call to the import_array() function (it's a NumPy function defined in a header included somewhere in cv2.cpp), this is necessary to define some macros used by pyopencv_to, if you don't call it you will get segmentation faults as lightalchemist pointed out.
from cpython.ref cimport PyObject
# Declares OpenCV's cv::Mat class
cdef extern from "opencv2/core/core.hpp":
cdef cppclass Mat:
pass
# Declares the official wrapper conversion functions + NumPy's import_array() function
cdef extern from "cv2.cpp":
void import_array()
PyObject* pyopencv_from(const _Mat&)
int pyopencv_to(PyObject*, _Mat&)
# Function to be called at initialization
cdef void init():
import_array()
# Python to C++ conversion
cdef Mat nparrayToMat(object array):
cdef Mat mat
cdef PyObject* pyobject = <PyObject*> array
pyopencv_to(pyobject, mat)
return <Mat> mat
# C++ to Python conversion
cdef object matToNparray(Mat mat):
return <object> pyopencv_from(mat)
Note: somehow I got an error with NumPy 1.8.0 on Fedora 20 while compiling due to a strange return statement in the import_array macro, I had to manually remove it to make it work but I can't find this return statement in the NumPy's 1.8.0 GitHub source code
It turns out that there's no simple way to convert (any) np.ndarray into corresponding cv::Mat. Basically, one needs to do only 2 things:
Create empty cv::Mat of corresponding size and type.
Copy data.
However, devil hides in details. Both ndarray and Mat may hold quite varying data formats. For instance, data in NumPy arrays may be in C or in Fortran order, array object may own its data or keep a view to another array, channels may go in a different order (RGB in NumPy vs. BGR in OpenCV), etc.
So instead of trying to solve generic problem I decided to stay with simple code that fits my needs and may be easily modified by anyone interested.
Following code in Cython works with float32/CV_32FC1 images with default byte order:
cdef void array2mat(np.ndarray arr, Mat& mat):
cdef int r = arr.shape[0]
cdef int c = arr.shape[1]
cdef int mat_type = CV_32FC1 # or CV_64FC1, or CV_8UC3, or whatever
mat.create(r, c, mat_type)
cdef unsigned int px_size = 4 # 8 for single-channel double image or
# 1*3 for three-channel uint8 image
memcpy(mat.data, arr.data, r*c*px_size)
To use this code in Cython one also needs to declare some types and constants, e.g. like this:
import numpy as np
# Cython makes it simple to import NumPy
cimport numpy as np
# OpenCV's matrix class
cdef extern from "opencv2/opencv.hpp" namespace "cv":
cdef cppclass Mat:
Mat() except +
Mat(int, int, int, void*) except +
void create(int, int, int)
void* data
int type() const
int cols
int rows
int channels()
Mat clone() const
# some OpenCV matrix types
cdef extern from "opencv2/opencv.hpp":
cdef int CV_8UC3
cdef int CV_8UC1
cdef int CV_32FC1
cdef int CV_64FC1
Opposite conversion (from cv::Mat to np.ndarray) may be achieved in a similar way.
Bonus: there's also nice blog post describing same kind of conversion for RGB/BGR images.
I guess you can directly use or take some logic from the converter from the official python wrapper. There isn't much documentation for this module, but maybe the output of the wrapper generator is helpful to understand how to use it.
If it helps, I wrote a wrapper that does exactly this. It's a convenience library that registers a boost::python converter to implicitly convert between OpenCV's popular cv::Mat datatype and NumPy's popular np.array() datatype. This allows a developer to go back and forth between their OpenCV C++ API and Python API written using NumPy with relative ease, avoiding the need to write additional wrappers that handle PyObjects being passed around or returned.
Take a look:
https://github.com/spillai/numpy-opencv-converter
Based on tlorieul's answer, here is the code I used for building a Python/C++ module:
https://gist.github.com/des0ps/88f1332319867a678a74bdbc0e7401c2
This has been tested with Python3 and OpenCV3.
Related
Basically I have a ufunc that requires some randomness. In order to keep the ufuncs as reproducible as possible I would like to use numpy's random number generator for that; basically because setting the seed will be more intuitive this way.
However I cannot find the documentation of the numpy.random C-API (does it have one?).
My current approach looks like that:
#include <numpy/random.h> // does not exist
...
static void
ufunc_M( char ** args
, npy_intp * dimensions
, npy_intp * steps
, void * data)
{
basic_gate_argument_t argument = *((basic_gate_argument_t *) data);
PYQCS_GATE_GENERIC_SETUP;
npy_intp i;
npy_double amplitude_1 = 0;
for(i = 0; i < ndim; i++)
{
if(i & (1 << argument.act))
{
amplitude_1 += qm_in[i].real * qm_in[i].real;
amplitude_1 += qm_in[i].imag * qm_in[i].imag;
}
}
npy_double rand = random_uniform(0, 1); // does not exist
...
*measured_out = 1 << argument.act;
}
...
As it turns out: one cannot do it using the numpy.random library directly. I found out about that after searching the numpy headers for a while. The random library is just not exported.
My workaround is passing a python callable to the ufunc:
static void
ufunc_M( char ** args
, npy_intp * dimensions
, npy_intp * steps
, void * data)
{
basic_gate_argument_t argument = *((basic_gate_argument_t *) data);
PYQCS_GATE_GENERIC_SETUP;
npy_intp i;
...
npy_double randr;
//==================================================//
// Get some random value. I do not like the way this
// is done but it seems like there is no better way.
PyObject * random_result = PyObject_CallFunctionObjArgs(argument.rng, NULL);
if(!PyFloat_Check(random_result))
{
randr = 0;
}
else
{
randr = PyFloat_AsDouble(random_result);
}
Py_DECREF(random_result);
//==================================================//
...
}
One must check wheter the passed object is a callable when constructing the ufunc:
static int
BasicGate_init
( BasicGate * self
, PyObject * args)
{
char type;
if(!PyArg_ParseTuple(args, "ClldO"
, &type
, &(self->argument.act)
, &(self->argument.control)
, &(self->argument.r)
, &(self->argument.rng))
)
{
return -1;
}
if(!PyCallable_Check(self->argument.rng))
{
PyErr_SetString(PyExc_TypeError, "random (5th argument) must be a callable (returning float)");
return -1;
}
...
case 'M':
{
self->ufunc = PyUFunc_FromFuncAndDataAndSignature(
ufunc_M_funcs // func
, self->data // data
, ufunc_types //types
, 1 // ntypes
, 2 // nin
, 3 // nout
, PyUFunc_None // identity
, "M_function" // name
, "Computes the M (Measurement) gate on a state." // doc
, 0 // unused
, "(n),(m)->(n),(m),()");
...
}
Ufuncs however cannot fail, so when the passed function does not return PyFloat s the ufunc will produce nonsense.
I have trained model for semantic segmentation using this repo, got good results and tried to use this net in small library writen with tensorflow c API. I turned my keras model into protobuf file using this repo and run session using this code:
typedef struct model_t {
TF_Graph* graph;
TF_Session* session;
TF_Status* status;
TF_Output input, target, output;
TF_Operation *init_op, *train_op, *save_op, *restore_op;
TF_Output checkpoint_file;
} model_t;
typedef struct NetProperties {
int width;
int height;
int border;
int classes;
int inputSize;
} NetProperties;
static model_t * model;
static NetProperties * properties;
extern "C" EXPORT int ModelCreate(const char* nnFilename, const char* inputName, const char* outputName, int pictureWidth, int pictureHeight, int border, int classes) {
ModelDestroy();
model = (model_t*)malloc(sizeof(model_t));;
model->status = TF_NewStatus();
model->graph = TF_NewGraph();
properties = (NetProperties*)malloc(sizeof(NetProperties));
properties->width = pictureWidth;
properties->height = pictureHeight;
properties->border = border;
properties->classes = classes;
properties->inputSize = (pictureWidth + border * 2) * (pictureHeight + border * 2) * 3;
{
// Create the session.
TF_SessionOptions* opts = TF_NewSessionOptions();
model->session = TF_NewSession(model->graph, opts, model->status);
TF_DeleteSessionOptions(opts);
if (!Okay(model->status)) return 0;
}
TF_Graph* g = model->graph;
{
// Import the graph.
TF_Buffer* graph_def = read_file(nnFilename);
if (graph_def == NULL) return 0;
printf("Read GraphDef of %zu bytes\n", graph_def->length);
TF_ImportGraphDefOptions* opts = TF_NewImportGraphDefOptions();
TF_GraphImportGraphDef(g, graph_def, opts, model->status);
TF_DeleteImportGraphDefOptions(opts);
TF_DeleteBuffer(graph_def);
if (!Okay(model->status)) return 0;
}
// Handles to the interesting operations in the graph.
model->input.oper = TF_GraphOperationByName(g, inputName);
model->input.index = 0;
model->target.oper = TF_GraphOperationByName(g, "target");
model->target.index = 0;
model->output.oper = TF_GraphOperationByName(g, outputName);
model->output.index = 0;
model->init_op = TF_GraphOperationByName(g, "init");
model->train_op = TF_GraphOperationByName(g, "train");
model->save_op = TF_GraphOperationByName(g, "save/control_dependency");
model->restore_op = TF_GraphOperationByName(g, "save/restore_all");
model->checkpoint_file.oper = TF_GraphOperationByName(g, "save/Const");
model->checkpoint_file.index = 0;
// first prediction is slow
unsigned char * randomData = (unsigned char*)malloc(properties->inputSize * sizeof(unsigned char));
for (int i = 0; i < properties->inputSize; i++) {
randomData[i] = (unsigned char)100;
}
ModelPredict(randomData);
free(randomData);
return 1;
}
extern "C" EXPORT void ModelDestroy() {
if (model == nullptr) return;
TF_DeleteSession(model->session, model->status);
Okay(model->status);
TF_DeleteGraph(model->graph);
TF_DeleteStatus(model->status);
free(model);
}
extern "C" EXPORT unsigned char* ModelPredict(unsigned char * batch1) {
if (model == NULL) return NULL;
const int64_t dims[4] = { 1, properties->height + properties->border * 2, properties->width + properties->border * 2, 3 };
size_t nbytes = properties->inputSize;
// can be faster
float * arrayOfFloats = (float*)malloc(nbytes * sizeof(float));
//float sumUp = 0;
for (int i = 0; i < properties->inputSize; i++) {
arrayOfFloats[i] = batch1[i] * (1.f / 255.f);
//sumUp += arrayOfFloats[i];
}
//std::cout << sumUp << std::endl;
// removed due to jdehesa answer
//float ** inputFloats = (float**)malloc(nbytes * sizeof(float*));
//inputFloats[0] = arrayOfFloats;
// Optionally, you can check that your input_op and input tensors are correct
//// by using some of the functions provided by the C API.
//std::cout << "Input op info: " << TF_OperationNumOutputs(input_op) << "\n";
//std::cout << "Input data info: " << TF_Dim(input, 0) << "\n";
std::vector<TF_Output> inputs;
std::vector<TF_Tensor*> input_values;
TF_Operation* input_op = model->input.oper;
TF_Output input_opout = { input_op, 0 };
inputs.push_back(input_opout);
// reworked due to jdehesa answer
//TF_Tensor* input = TF_NewTensor(TF_FLOAT, dims, 4, (void*)inputFloats, //nbytes * sizeof(float), &Deallocator, NULL);
TF_Tensor* input = TF_NewTensor(TF_FLOAT, dims, 4, (void*)arrayOfFloats, nbytes * sizeof(float), &Deallocator, NULL);
input_values.push_back(input);
int outputSize = properties->width * properties->height * properties->classes;
int64_t out_dims[] = { 1, properties->height, properties->width, properties->classes };
// Create vector to store graph output operations
std::vector<TF_Output> outputs;
TF_Operation* output_op = model->output.oper;
TF_Output output_opout = { output_op, 0 };
outputs.push_back(output_opout);
// Create TF_Tensor* vector
//std::vector<TF_Tensor*> output_values(outputs.size(), nullptr);
// Similar to creating the input tensor, however here we don't yet have the
// output values, so we use TF_AllocateTensor()
TF_Tensor* output_value = TF_AllocateTensor(TF_FLOAT, out_dims, 4, outputSize * sizeof(float));
//output_values.push_back(output_value);
//// As with inputs, check the values for the output operation and output tensor
//std::cout << "Output: " << TF_OperationName(output_op) << "\n";
//std::cout << "Output info: " << TF_Dim(output_value, 0) << "\n";
TF_SessionRun(model->session, NULL,
&inputs[0], &input_values[0], inputs.size(),
&outputs[0], &output_value, outputs.size(),
/* No target operations to run */
NULL, 0, NULL, model->status);
if (!Okay(model->status)) return NULL;
TF_DeleteTensor(input_values[0]);
// memory allocations take place here
float* prediction = (float*)TF_TensorData(output_value);
//float* prediction = (float*)malloc(sizeof(float) * properties->inputSize / 3 * properties->classes);
//memcpy(prediction, TF_TensorData(output_value), sizeof(float) * properties->inputSize / 3 * properties->classes);
unsigned char * charPrediction = new unsigned char[outputSize * sizeof(unsigned char)];
sumUp = 0;
for (int i = 0; i < outputSize; i++) {
charPrediction[i] = (unsigned char)((prediction[i] * 255));
//sumUp += prediction[i];
}
//std::cout << sumUp << std::endl << std::endl;
//free(prediction);
TF_DeleteTensor(output_value);
return charPrediction;
}
The problem is that prediction result is always the same. I tried to pass random data and real images but the result was equal. However, defferent trained models give different prediction result, but for each model it's always same. As you can see in code snippet, I checked that pass different data and get same prediction every time
// first is float sum of passed picture, second is the float sum of answer
724306
22982.6
692004
22982.6
718490
22982.6
692004
22982.6
720861
22982.6
692004
22982.6
I tried to write my own keras to tensorflow .pb converter but result was the same.
import os, argparse
import tensorflow as tf
from tensorflow.keras.utils import get_custom_objects
from segmentation_models.losses import bce_dice_loss,dice_loss,cce_dice_loss
from segmentation_models.metrics import iou_score
# some custom functions from segmentation_models
get_custom_objects().update({
'dice_loss': dice_loss,
'bce_dice_loss': bce_dice_loss,
'cce_dice_loss': cce_dice_loss,
'iou_score': iou_score,
})
def freeze_keras(model_name):
tf.keras.backend.set_learning_phase(0)
model = tf.keras.models.load_model(model_name)
sess = tf.keras.backend.get_session()
constant_graph = tf.graph_util.convert_variables_to_constants(sess, sess.graph.as_graph_def(), [out.op.name for out in model.outputs])
tf.train.write_graph(constant_graph, './', 'saved_model.pb', as_text=False)
freeze_keras('best-weights.hdf5')
Help me to find out how to fix prediction result in c api.
UPDATE 1: Reworked input array as jdehesa suggested
UPDATE 2: Added definition of model and NetProperties
I think you are not setting the input data correctly. Let's see.
float * arrayOfFloats1 = (float*)malloc(nbytes * sizeof(float));
float sumUp = 0;
Here you create arrayOfFloats1 to hold all the image data.
for (int i = 0; i < properties->inputSize; i++) {
arrayOfFloats1[i] = batch1[i] * (1.f / 255.f);
sumUp += arrayOfFloats1[i];
}
std::cout << sumUp << std::endl;
Here you set arrayOfFloats1 to the image data. This is all fine.
But then:
float ** inputFloats = (float**)malloc(nbytes * sizeof(float*));
Here you have inputFloats, which has space for nbytes float pointers. First, you probably would want to allocate space for float values, not float pointers (which probably do not have the same size). And then:
inputFloats[0] = arrayOfFloats1;
Here you are setting the first of those nbytes pointers to the pointer arrayOfFloats1. And then inputFloats is used as input to the model. But the remaining nbytes - 1 pointers have not been set to anything. Although not required, they are probably set all to zero.
If you just want to make an "array of arrays of floats" with arrayOfFloats1 you don't need to allocate any memory, you can simply do:
float ** inputFloats = &arrayOfFloats1;
But then you actually use inputFloats like this:
TF_Tensor* input = TF_NewTensor(
TF_FLOAT, dims, 4, (void*)inputFloats, nbytes * sizeof(float), &Deallocator, NULL);
So here you are saying that input is made up of the data in inputFloats, which will be a pointer to arrayOfFloats1 and then uninitialized memory. Probably you actually want something like:
TF_Tensor* input = TF_NewTensor(
TF_FLOAT, dims, 4, (void*)arrayOfFloats1, nbytes * sizeof(float), &Deallocator, NULL);
Which means input will be a tensor made up of the data in arrayOfFloats1 that you copied before. In fact, I don't think your code needs inputFloats at all.
Otherwise, from what I can tell the rest of the code seems correct. You should ensure that all allocated memory is properly freed in all cases (e.g. when you do if (!Okay(model->status)) return NULL; you should probably delete the input and output tensors before returning), but that is a different issue.
The issue was in the model. I have trained it using not normalized data from images (pixel values are between 0.0 and 255.0) and tried to interfere normilezed data (I devided each pixel value by 255 arrayOfFloats[i] = batch1[i] * (1.f / 255.f); and got values between 0.0 and 1.0) so my model thought that it gets black images every time and gave me similar answers. So I removed normalization and the model started to predict.
I am a python programmer. My girlfriend is taking a C class. This frustrates me, something so simple I can't find online nor I can figure out. Let's cut to the chase. I have a simple Python program that I need help trying to translate to C.
lst = input("Enter a list of numbers with a space in between each number\n")
newList = lst.split(" ")
#selection sort has been pre defined
x = newList.selectSort()
print(x)
Sorry this was done on my phone.
Her assignment isn't just this. It's adding multiple functions that work together. I just need to know how this works in order to pull the full program together.
First of all, you have to define the number of item in the list then you can input them.
Then, you have to store them in an array and do the sorting process manually.
I've done the sorting process without defining a function. If you want to use a function, just pass the array and return the sorted array.
#include <stdio.h>
int main()
{
int n, c, d, position, swap;
printf("Enter number of elements\n");
scanf("%d", &n);
int array[n];
printf("Enter %d integers\n", n);
for ( c = 0 ; c < n ; c++ )
scanf("%d", &array[c]);
for ( c = 0 ; c < ( n - 1 ) ; c++ )
{
position = c;
for ( d = c + 1 ; d < n ; d++ )
{
if ( array[position] > array[d] )
position = d;
}
if ( position != c )
{
swap = array[c];
array[c] = array[position];
array[position] = swap;
}
}
printf("Sorted list in ascending order:\n");
for ( c = 0 ; c < n ; c++ )
printf("%d\n", array[c]);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
// Macro for sorting
#define sort(name, data_set, len, comparator, inverse) \
name##_sort(data_set, len, comparator, inverse)
#define SORT_DEFINE(name, data_type) \
\
/* Sort data set
#data_set data set to sort
#len length of data set
#comparator comparator to compare two elements, return positive value when first element is bigger
#inverse whether the result should be inversed
*/\
void name##_sort(data_type *data_set, int len, int (*comparator)(data_type, data_type), bool inverse) \
{ \
int i; \
int j; \
bool change = true; \
int ret; \
data_type tmp; \
\
for (i = 0; change && i < len - 1; i++) \
{ \
change = false; \
for (j = 0; j < len - 1 - i; j++) \
{ \
ret = comparator(data_set[j], data_set[j + 1]); \
if ((!inverse && ret > 0) || (inverse && ret < 0)) \
{ \
change = true; \
tmp = data_set[j]; \
data_set[j] = data_set[j + 1]; \
data_set[j + 1] = tmp; \
} \
} \
} \
}
/* Split string
#content origin string content
#delim delimiter for splitting
#psize pointer pointing at the variable to store token size
#return tokens after splitting
*/
const char **split(char *content, const char *delim, int *psize)
{
char *token;
const char **tokens;
int capacity;
int size = 0;
token = strtok(content, delim);
if (!token)
{
return NULL;
}
// Initialize tokens
tokens = malloc(sizeof(char *) * 64);
if (!tokens)
{
exit(-1);
}
capacity = 64;
tokens[size++] = token;
while ((token = strtok(NULL, delim)))
{
if (size >= capacity)
{
tokens = realloc(tokens, sizeof(char *) * capacity * 2);
if (!tokens)
{
exit(-1);
}
capacity *= 2;
}
tokens[size++] = token;
}
*psize = size;
return tokens;
}
// Define sort function for data_type = const char *
SORT_DEFINE(str, const char *);
// Define sort function for data_type = int
SORT_DEFINE(int, int)
int intcmp(int v1, int v2)
{
return v1 - v2;
}
int main(int argc, char *argv[])
{
char buff[128];
const char **tokens;
int size;
int i;
int *ints;
// Get input from stdin
fgets(buff, 128, stdin);
// Split string
tokens = split(buff, " \t\n", &size);
ints = malloc(sizeof(int) * size);
// Sort strings [min -> max]
sort(str, tokens, size, strcmp, false);
// Print strings and transfer them to integers
for (i = 0; i < size; i++)
{
printf("[%02d]: <%s>\n", i, tokens[i]);
ints[i] = atoi(tokens[i]);
}
// Sort integers [max -> min]
sort(int, ints, size, intcmp, true);
// Print integers
for (i = 0; i < size; i++)
{
printf("[%02d]: <%d>\n", i, ints[i]);
}
free(ints);
free(tokens);
return 0;
}
Use macro SORT_DEFINE(), sort(), and function split() to do your own job. The main() function is just a demo to show how to use them.
I know this question has been asked before, but I don't find a useful solution. The full error is :
Executing: "/home/mint/Documents/test_sensor/cycl_test/top_block.py"
Using Volk machine: avx_64_mmx_orc
Traceback (most recent call last):
File "/home/mint/Documents/test_sensor/cycl_test/top_block.py", line 87, in <module>
tb = top_block()
File "/home/mint/Documents/test_sensor/cycl_test/top_block.py", line 61, in __init__
self.cycl_MME_cpp_0 = cycl.MME_cpp(1000, 16, 0.1)
AttributeError: 'module' object has no attribute 'MME_cpp'
I have found some possible reasons from previous questions:
mismatching of function parameter(including referencing function in .cc and .h)
swig problem
callbacks in .xml file
nm -C -u libgnuradio-.so
I've checked the first 3 reasons, but I'm not sure how to find out the undefined symblos using the last methods. There is part of the outcome:
U gsl_linalg_SV_decomp
U gsl_matrix_alloc
U gsl_matrix_set
U gsl_matrix_set_zero
U gsl_vector_alloc
U gsl_vector_get
Does this means all the gsl functions are undefined? If so how can I deal with it?
Except for the four reasons,is there any other hints about my questions?
I appreciate your help.
addendum:
1.MME_cpp_impl.cc
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gnuradio/io_signature.h>
#include "MME_cpp_impl.h"
#include <stdio.h>
#include <math.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_linalg.h>
namespace gr {
namespace cycl {
MME_cpp::sptr
MME_cpp::make(int Ns, int M, float Pfa)
{
return gnuradio::get_initial_sptr
(new MME_cpp_impl(Ns, M, Pfa));
}
/*
* The private constructor
*/
MME_cpp_impl::MME_cpp_impl(int Ns, int M, float Pfa)
: gr::sync_block("MME_cpp",
gr::io_signature::make(1, 1, sizeof(float)),
gr::io_signature::make(1, 1, sizeof(float))),
d_Ns(Ns), d_M(M), d_Pfa(Pfa)
{}
/*
* Our virtual destructor.
*/
MME_cpp_impl::~MME_cpp_impl()
{
}
/*This function gives the CDF value for the pfa in input*/
float
TracyWidom (float p){
float pd, tw;
tw = 0.45;
pd = 1 - p;
if (pd >= 0.01 && pd <= 0.05){
tw = 18*(pd - (17/75)); printf("a - %f\n", tw);
}else if (pd >= 0.05 && pd <= 0.1){
tw = 8*(pd - (179/400)); printf("b - %f\n", tw);
}else if (pd >= 0.1 && pd <= 0.3){
tw = (87/20)*(pd - (643/870)); printf("c - %f\n", tw);
}else if (pd >= 0.3 && pd <= 0.5){
tw = (16/5)*(pd - (287/320)); printf("d - %f\n", tw);
}else if (pd >= 0.5 && pd <= 0.7){
tw = (17/5)*(pd - (297/340)); printf("e - %f\n", tw);
}else if (pd >= 0.7 && pd <= 0.9){
tw = (5.2)*(pd - (0.813)); printf("f - %f\n", tw);
}else if (pd >= 0.9 && pd <= 0.95){
tw = (53/5)*(pd - (909/1060)); printf("g - %f\n", tw);
}else if (pd >= 0.95 && pd <= 1){
tw = 26*(pd - (593/650)); printf("h - %f\n", tw);
}else{
printf ("wrong pfa value: it must be between 0 and 1\n");
printf ("the pfa value standard is 0.1\n");
tw = (53/5)*(0.9 - (909/1060));
}
return tw;
}
/*this function calculates the threshold for the test
the inputs are:
ns = numbers of samples/L;
L = length of the correlation function;
pfa = probability of false alarm*/
float
gamma (int ns, int L, float tw){
float A, B, C, ratio1, ratio2, g;
A = sqrt(ns)+sqrt(L*ns);
B = sqrt(ns)-sqrt(L*ns);
C = ns*ns*L;
ratio1 = pow(A,2)/pow(B,2);
ratio2 = 1+( pow(A,-0.667) / pow(C,0.167) )*tw;
g = ratio1*ratio2;
return g;
}
/*This function makes the detection test*/
float
test (float r, float t){
float decision;
if(r > -1){
if(r <= t){
decision = 0;
}
else{
decision = 1;
}
}
return decision;}
//-------------end functions-----------
int
MME_cpp_impl::work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
const float *in = (const float *) input_items[0];
float *out = (float *) output_items[0];
//float cov;
//int ninputs = input_items.size ();
//for(int i=0; i<noutput_items*Ns; ++i){
// cov = compute_convariance(in[i]);
//int lenght = floor(d_samples / d_L) * d_L;
float vett[d_Ns];
int lenght = floor(d_Ns / d_M) ;
int p, j, k=0;
float thr, lmax, lmin, ratio=-1, TW, mem=0;
// char c[1];
gsl_matrix * hankel = gsl_matrix_alloc (lenght,d_M);
gsl_matrix * V = gsl_matrix_alloc (d_M,d_M);
gsl_vector * S = gsl_vector_alloc (d_M);
gsl_vector * temp = gsl_vector_alloc (d_M);
//FILE *story;
gsl_matrix_set_zero (hankel);
TW = TracyWidom (d_Pfa);
thr = gamma(lenght, d_M, TW); //calculate the threshold
for (int i = 0; i < noutput_items; i++){
vett[k]=in[i];
k++;
if (k >= lenght*d_M){
k = 0;
// story = fopen("filestory.txt", "a");
for( p=0; p<lenght; p++ ){
for( j=0; j<d_M; j++ ){
gsl_matrix_set (hankel, p, j, vett[p+j]);
}
}
gsl_linalg_SV_decomp (hankel, V, S, temp);//using SDV to calculate eigenvalue
lmax = gsl_vector_get(S, 0);//maximal eigenvalue
lmin = gsl_vector_get(S, (d_M -1));//minimal eigenvalue
ratio = lmax/lmin;
mem = test(ratio, thr);
//fprintf(story, "%f - ratio=%f - soglia=%f\n ", mem, ratio, thr);
//fclose(story);
}
out[i] = mem;
}
// Tell runtime system how many output items we produced.
return noutput_items;
}
} /* namespace cycl /
} / namespace gr */
2.MME_cpp_impl.h
#ifndef INCLUDED_CYCL_MME_CPP_IMPL_H
#define INCLUDED_CYCL_MME_CPP_IMPL_H
#include <cycl/MME_cpp.h>
namespace gr {
namespace cycl {
class MME_cpp_impl : public MME_cpp
{
private:
int d_Ns, d_M;
float d_Pfa;
public:
MME_cpp_impl(int Ns, int M, float Pfa);
~MME_cpp_impl();
int Ns() const { return d_Ns; }
void set_Ns(int Ns) { d_Ns = Ns; }
int M() const { return d_M; }
void set_M(int M) { d_M = M; }
float Pfa() const { return d_Pfa; }
void set_Pfa(float Pfa) { d_Pfa = Pfa; }
// Where all the action really happens
int work(int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);
//float compute_covariance(float & d, int i, int j);
friend float TracyWidom (float p);
friend float gamma (int ns, int L, float tw);
friend float test (float r, float t);
};
float TracyWidom (float p);
float gamma (int ns, int L, float tw);
float test (float r, float t);
} // namespace cycl
} // namespace gr
#endif /* INCLUDED_CYCL_MME_CPP_IMPL_H */
3.MME_cpp.h
#ifndef INCLUDED_CYCL_MME_CPP_H
#define INCLUDED_CYCL_MME_CPP_H
#include <cycl/api.h>
#include <gnuradio/sync_block.h>
namespace gr {
namespace cycl {
/*!
* \brief <+description of block+>
* \ingroup cycl
*
*/
class CYCL_API MME_cpp : virtual public gr::sync_block
{
public:
typedef boost::shared_ptr<MME_cpp> sptr;
/*!
* \brief Return a shared_ptr to a new instance of cycl::MME_cpp.
*
* To avoid accidental use of raw pointers, cycl::MME_cpp's
* constructor is in a private implementation
* class. cycl::MME_cpp::make is the public interface for
* creating new instances.
*/
static sptr make(int Ns, int M, float Pfa);
virtual int Ns() const = 0;
virtual void set_Ns(int Ns) = 0;
virtual int M() const = 0;
virtual void set_M(int M) = 0;
virtual float Pfa() const = 0;
virtual void set_Pfa(float Pfa) = 0;
};
} // namespace cycl
} // namespace gr
#endif /* INCLUDED_CYCL_MME_CPP_H */
4.cycl_MME_cpp.xml
<?xml version="1.0"?>
<block>
<name>MME_cpp</name>
<key>cycl_MME_cpp</key>
<category>cycl</category>
<import>import cycl</import>
<make>cycl.MME_cpp($Ns, $M, $Pfa)</make>
<callback>set_Ns($Ns)</callback>
<callback>set_M($M)</callback>
<callback>set_Pfa($Pfa)</callback>
<param>
<name>Number of samples</name>
<key>Ns</key>
<type>int</type>
</param>
<param>
<name>Length of correlation function</name>
<key>M</key>
<type>int</type>
</param>
<param>
<name>false probability</name>
<key>Pfa</key>
<type>float</type>
</param>
<sink>
<name>in</name>
<type>float</type>
</sink>
<source>
<name>out</name>
<type>float</type>
</source>
</block>
I had the same problem while developing a block. I noticed that the CMake script complained that the swig library is missing. Although this was not a fatal error, it does not work without it.
After installing swig I could use my module: sudo apt-get install swig
This is likely due to the path that your .so is installed by default. I recently ran into this issue, and found that /usr/local/lib was not in my /etc/ld.so.conf by default (Arch Linux). After updating /etc/ld.so.conf, I ran:
sudo ldconfig
and the issue was resolved.
I am looking to use some C code that returns multiple arrays of unknown size. Because there are multiple arrays, I think I need to use passed in pointers, and I'm not sure how to combine that with malloc, which is used to setup the arrays.
This is some representative C code:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
//gcc -fPIC -shared -o array_test_c.so array_test_c.c
void return_array(int * outdata1v, int * outdata2v) {
int i;
int N = 10;
int * mydatav2, * mydatav3;
mydatav2 = (int *) malloc(sizeof(int) * N);
mydatav3 = (int *) malloc(sizeof(int) * N);
for (i = 0; i<N; i++){
mydatav2[i] = i;
mydatav3[i] = i*2;
}
//this doesn't work which makes sense
outdata1v = mydatav2;
outdata2v = mydatav3;
}
And I'm trying to hook it to Python with something along these lines (this does not work):
import os
import ctypes
#for c interface
test_module = ctypes.cdll.LoadLibrary(
os.path.join(os.path.dirname(__file__), './array_test_c.so'))
outdata1 = (ctypes.c_int * 0)()
outdata2 = (ctypes.c_int * 0)()
test_module.return_array(outdata1, outdata2)
outdata1 = (ctypes.c_int*10).from_address(ctypes.addressof(outdata1))
print "out", outdata1[-1], outdata1, outdata2
This does not work, and I can never get 20 to print out. Any ideas?
test.c
#include <stdlib.h>
#define N 10
void test(int *size, int **out1, int **out2) {
int i;
int *data1, *data2;
data1 = (int *)malloc(sizeof(int) * N);
data2 = (int *)malloc(sizeof(int) * N);
for (i = 0; i < N; i++){
data1[i] = i;
data2[i] = i * 2;
}
*size = N;
*out1 = data1;
*out2 = data2;
}
test.py
from ctypes import CDLL, POINTER, c_int, byref
dll = CDLL('test.so')
data1 = POINTER(c_int)()
data2 = POINTER(c_int)()
size = c_int()
dll.test(byref(size), byref(data1), byref(data2))
for i in range(size.value):
print i, data1[i], data2[i]
Edit: You should consider providing a function to free the malloc'd data. So you can then do, e.g. dll.cleanup(data1, data2)
You need pointers to pointers:
void return_array(int **outdata1v, int **outdata2v) {
int i;
int N = 10;
int * mydatav2, * mydatav3;
mydatav2 = (int *) malloc(sizeof(int) * N);
mydatav3 = (int *) malloc(sizeof(int) * N);
for (i = 0; i<N; i++){
mydatav2[i] = i;
mydatav3[i] = i*2;
}
*outdata1v = mydatav2;
*outdata2v = mydatav3;
}
I don't know about the python part.