#ifdef HAVE_OPENCV_DNN typedef dnn::DictValue LayerId; typedef std::vector vector_MatShape; typedef std::vector > 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 &blobs, const char *name) //required for Layer::blobs RW { return pyopencvVecConverter::to(o, blobs, ArgInfo(name, false)); } template PyObject* pyopencv_from(const dnn::DictValue &dv) { if (dv.size() > 1) { std::vector vec(dv.size()); for (int i = 0; i < dv.size(); ++i) vec[i] = dv.get(i); return pyopencv_from_generic_vec(vec); } else return pyopencv_from(dv.get()); } template<> PyObject* pyopencv_from(const dnn::DictValue &dv) { if (dv.isInt()) return pyopencv_from(dv); if (dv.isReal()) return pyopencv_from(dv); if (dv.isString()) return pyopencv_from(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::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 >::iterator it = pyLayers.find(type); if (it != pyLayers.end()) it->second.push_back(o); else pyLayers[type] = std::vector(1, o); } static void unregisterLayer(const std::string& type) { std::map >::iterator it = pyLayers.find(type); if (it != pyLayers.end()) { if (it->second.size() > 1) it->second.pop_back(); else pyLayers.erase(it); } } static Ptr create(dnn::LayerParams ¶ms) { std::map >::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(new pycvLayer(params, it->second.back())); } virtual bool getMemoryShapes(const std::vector > &inputs, const int, std::vector > &outputs, std::vector > &) 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 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 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 > pyLayers; PyObject* o; // Instance of implemented python layer. }; std::map > 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