#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) { CV_UNUSED(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(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE { PyGILState_STATE gstate; gstate = PyGILState_Ensure(); std::vector<Mat> inputs, outputs; inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); PyObject* args = pyopencv_from(inputs); 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]); } } 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