mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
7.0 KiB
221 lines
7.0 KiB
#ifdef HAVE_OPENCV_DNN |
|
typedef dnn::DictValue LayerId; |
|
typedef std::vector<dnn::MatShape> vector_MatShape; |
|
typedef std::vector<std::vector<dnn::MatShape> > vector_vector_MatShape; |
|
|
|
|
|
template<> |
|
bool pyopencv_to(PyObject *o, dnn::DictValue &dv, const char *name) |
|
{ |
|
(void)name; |
|
if (!o || o == Py_None) |
|
return true; //Current state will be used |
|
else if (PyLong_Check(o)) |
|
{ |
|
dv = dnn::DictValue((int64)PyLong_AsLongLong(o)); |
|
return true; |
|
} |
|
else if (PyInt_Check(o)) |
|
{ |
|
dv = dnn::DictValue((int64)PyInt_AS_LONG(o)); |
|
return true; |
|
} |
|
else if (PyFloat_Check(o)) |
|
{ |
|
dv = dnn::DictValue(PyFloat_AS_DOUBLE(o)); |
|
return true; |
|
} |
|
else if (PyString_Check(o)) |
|
{ |
|
dv = dnn::DictValue(String(PyString_AsString(o))); |
|
return true; |
|
} |
|
else |
|
return false; |
|
} |
|
|
|
template<> |
|
bool pyopencv_to(PyObject *o, std::vector<Mat> &blobs, const char *name) //required for Layer::blobs RW |
|
{ |
|
return pyopencvVecConverter<Mat>::to(o, blobs, ArgInfo(name, false)); |
|
} |
|
|
|
template<typename T> |
|
PyObject* pyopencv_from(const dnn::DictValue &dv) |
|
{ |
|
if (dv.size() > 1) |
|
{ |
|
std::vector<T> vec(dv.size()); |
|
for (int i = 0; i < dv.size(); ++i) |
|
vec[i] = dv.get<T>(i); |
|
return pyopencv_from_generic_vec(vec); |
|
} |
|
else |
|
return pyopencv_from(dv.get<T>()); |
|
} |
|
|
|
template<> |
|
PyObject* pyopencv_from(const dnn::DictValue &dv) |
|
{ |
|
if (dv.isInt()) return pyopencv_from<int>(dv); |
|
if (dv.isReal()) return pyopencv_from<float>(dv); |
|
if (dv.isString()) return pyopencv_from<String>(dv); |
|
CV_Error(Error::StsNotImplemented, "Unknown value type"); |
|
return NULL; |
|
} |
|
|
|
template<> |
|
PyObject* pyopencv_from(const dnn::LayerParams& lp) |
|
{ |
|
PyObject* dict = PyDict_New(); |
|
for (std::map<String, dnn::DictValue>::const_iterator it = lp.begin(); it != lp.end(); ++it) |
|
{ |
|
CV_Assert(!PyDict_SetItemString(dict, it->first.c_str(), pyopencv_from(it->second))); |
|
} |
|
return dict; |
|
} |
|
|
|
class pycvLayer CV_FINAL : public dnn::Layer |
|
{ |
|
public: |
|
pycvLayer(const dnn::LayerParams ¶ms, PyObject* pyLayer) : Layer(params) |
|
{ |
|
PyGILState_STATE gstate; |
|
gstate = PyGILState_Ensure(); |
|
|
|
PyObject* args = PyTuple_New(2); |
|
CV_Assert(!PyTuple_SetItem(args, 0, pyopencv_from(params))); |
|
CV_Assert(!PyTuple_SetItem(args, 1, pyopencv_from(params.blobs))); |
|
o = PyObject_CallObject(pyLayer, args); |
|
|
|
Py_DECREF(args); |
|
PyGILState_Release(gstate); |
|
if (!o) |
|
CV_Error(Error::StsError, "Failed to create an instance of custom layer"); |
|
} |
|
|
|
static void registerLayer(const std::string& type, PyObject* o) |
|
{ |
|
std::map<std::string, std::vector<PyObject*> >::iterator it = pyLayers.find(type); |
|
if (it != pyLayers.end()) |
|
it->second.push_back(o); |
|
else |
|
pyLayers[type] = std::vector<PyObject*>(1, o); |
|
} |
|
|
|
static void unregisterLayer(const std::string& type) |
|
{ |
|
std::map<std::string, std::vector<PyObject*> >::iterator it = pyLayers.find(type); |
|
if (it != pyLayers.end()) |
|
{ |
|
if (it->second.size() > 1) |
|
it->second.pop_back(); |
|
else |
|
pyLayers.erase(it); |
|
} |
|
} |
|
|
|
static Ptr<dnn::Layer> create(dnn::LayerParams ¶ms) |
|
{ |
|
std::map<std::string, std::vector<PyObject*> >::iterator it = pyLayers.find(params.type); |
|
if (it == pyLayers.end()) |
|
CV_Error(Error::StsNotImplemented, "Layer with a type \"" + params.type + |
|
"\" is not implemented"); |
|
CV_Assert(!it->second.empty()); |
|
return Ptr<dnn::Layer>(new pycvLayer(params, it->second.back())); |
|
} |
|
|
|
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs, |
|
const int, |
|
std::vector<std::vector<int> > &outputs, |
|
std::vector<std::vector<int> > &) const CV_OVERRIDE |
|
{ |
|
PyGILState_STATE gstate; |
|
gstate = PyGILState_Ensure(); |
|
|
|
PyObject* args = PyList_New(inputs.size()); |
|
for(size_t i = 0; i < inputs.size(); ++i) |
|
PyList_SET_ITEM(args, i, pyopencv_from_generic_vec(inputs[i])); |
|
|
|
PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("getMemoryShapes"), args, NULL); |
|
Py_DECREF(args); |
|
PyGILState_Release(gstate); |
|
if (!res) |
|
CV_Error(Error::StsNotImplemented, "Failed to call \"getMemoryShapes\" method"); |
|
CV_Assert(pyopencv_to_generic_vec(res, outputs, ArgInfo("", 0))); |
|
return false; |
|
} |
|
|
|
virtual void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &) CV_OVERRIDE |
|
{ |
|
PyGILState_STATE gstate; |
|
gstate = PyGILState_Ensure(); |
|
|
|
std::vector<Mat> inps(inputs.size()); |
|
for (size_t i = 0; i < inputs.size(); ++i) |
|
inps[i] = *inputs[i]; |
|
|
|
PyObject* args = pyopencv_from(inps); |
|
PyObject* res = PyObject_CallMethodObjArgs(o, PyString_FromString("forward"), args, NULL); |
|
Py_DECREF(args); |
|
PyGILState_Release(gstate); |
|
if (!res) |
|
CV_Error(Error::StsNotImplemented, "Failed to call \"forward\" method"); |
|
|
|
std::vector<Mat> pyOutputs; |
|
CV_Assert(pyopencv_to(res, pyOutputs, ArgInfo("", 0))); |
|
|
|
CV_Assert(pyOutputs.size() == outputs.size()); |
|
for (size_t i = 0; i < outputs.size(); ++i) |
|
{ |
|
CV_Assert(pyOutputs[i].size == outputs[i].size); |
|
CV_Assert(pyOutputs[i].type() == outputs[i].type()); |
|
pyOutputs[i].copyTo(outputs[i]); |
|
} |
|
} |
|
|
|
virtual void forward(InputArrayOfArrays, OutputArrayOfArrays, OutputArrayOfArrays) CV_OVERRIDE |
|
{ |
|
CV_Error(Error::StsNotImplemented, ""); |
|
} |
|
|
|
private: |
|
// Map layers types to python classes. |
|
static std::map<std::string, std::vector<PyObject*> > pyLayers; |
|
PyObject* o; // Instance of implemented python layer. |
|
}; |
|
|
|
std::map<std::string, std::vector<PyObject*> > pycvLayer::pyLayers; |
|
|
|
static PyObject *pyopencv_cv_dnn_registerLayer(PyObject*, PyObject *args, PyObject *kw) |
|
{ |
|
const char *keywords[] = { "type", "class", NULL }; |
|
char* layerType; |
|
PyObject *classInstance; |
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "sO", (char**)keywords, &layerType, &classInstance)) |
|
return NULL; |
|
if (!PyCallable_Check(classInstance)) { |
|
PyErr_SetString(PyExc_TypeError, "class must be callable"); |
|
return NULL; |
|
} |
|
|
|
pycvLayer::registerLayer(layerType, classInstance); |
|
dnn::LayerFactory::registerLayer(layerType, pycvLayer::create); |
|
Py_RETURN_NONE; |
|
} |
|
|
|
static PyObject *pyopencv_cv_dnn_unregisterLayer(PyObject*, PyObject *args, PyObject *kw) |
|
{ |
|
const char *keywords[] = { "type", NULL }; |
|
char* layerType; |
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kw, "s", (char**)keywords, &layerType)) |
|
return NULL; |
|
|
|
pycvLayer::unregisterLayer(layerType); |
|
dnn::LayerFactory::unregisterLayer(layerType); |
|
Py_RETURN_NONE; |
|
} |
|
|
|
#endif // HAVE_OPENCV_DNN
|
|
|