diff --git a/modules/dnn/include/opencv2/dnn.hpp b/modules/dnn/include/opencv2/dnn.hpp index 9668acd63..fefd8373d 100644 --- a/modules/dnn/include/opencv2/dnn.hpp +++ b/modules/dnn/include/opencv2/dnn.hpp @@ -59,11 +59,11 @@ namespace dnn typedef Layer* (*Constuctor)(); - static void registerLayer(const String &type, Constuctor constructor); + CV_EXPORTS static void registerLayer(const String &type, Constuctor constructor); - static void unregisterLayer(const String &type); + CV_EXPORTS static void unregisterLayer(const String &type); - static Ptr createLayerInstance(const String &type); + CV_EXPORTS static Ptr createLayerInstance(const String &type); private: LayerRegister(); @@ -88,80 +88,71 @@ namespace dnn //setUp calls once (think that it's constructor) virtual void setUp(LayerParams ¶ms); - //after setUp the following two function must be able to return values - virtual int getNumInputs(); - virtual int getNumOutputs(); - //maybe useless function //shape of output blobs must be adjusted with respect to shape of input blobs virtual void adjustShape(const std::vector &inputs, std::vector &outputs); virtual void forward(std::vector &inputs, std::vector &outputs); + + virtual int getNumInputs(); + virtual int getNumOutputs(); + //each input/output can be labeled to easily identify their using "layer_name.output_name" + virtual String getInputName(int inputNum); + virtual String getOutputName(int outputNum); }; + + //containers for String and int + typedef DictValue LayerId; + typedef DictValue BlobId; - //TODO: divide NetConfiguration interface and implementation, hide internal data - //TODO: maybe eliminate all int ids and replace them by string names - //Proxy class for different formats - //Each format importer must populate it - CV_EXPORTS class NetConfiguration + CV_EXPORTS class Net { public: - CV_EXPORTS static Ptr create(); - - int addLayer(const String &name, const String &type); - - void deleteLayer(int layerId); - - void setLayerParams(int layerId, LayerParams ¶ms); + CV_EXPORTS Net(); + CV_EXPORTS ~Net(); + CV_EXPORTS int addLayer(const String &name, const String &type, LayerParams ¶ms = LayerParams()); + CV_EXPORTS void deleteLayer(LayerId layer); + //each output of each layer can be labeled by unique string label (as in Caffe) - //if label not specified then %layer_name%:c_%N% will be used - void setLayerOutputLabels(int layerId, const std::vector &outputNames); + //if label not specified then %layer_name%.%layer_output_id% can be used + void setOutputNames(LayerId layer, const std::vector &outputNames); - //version #1 - void addConnection(int fromLayer, int fromLayerOutput, int toLayer, int toLayerInput); + CV_EXPORTS void connect(BlobId input, BlobId output); + CV_EXPORTS void connect(const std::vector &outputs, const std::vector &inputs); + CV_EXPORTS void connect(const std::vector &outputs, LayerId layer); - //or maybe version #2 - inline int getBlobId(int layerId, int inputOutputNumber) - { - return (layerId << 16) + inputOutputNumber; - } + int getOutputId(LayerId layer, int outputNum); + int getInputId(LayerId layer, int inputNum); + int getLayerId(LayerId layer); - void addConnection(int outputId, int inputId); + void forward(); + void forward(LayerId toLayer); + void forward(LayerId startLayer, LayerId toLayer); + void forward(const std::vector &startLayers, const std::vector &toLayers); - void addConnections(const std::vector &outputIds, const std::vector &inputIds); + //[Wished feature] Optimized smart forward(). Makes forward only for layers which wasn't changed after previous forward(). + void forwardOpt(LayerId toLayer); + void forwardOpt(const std::vector &toLayers); - private: + void setBlob(BlobId outputName, const Blob &blob); + Blob getBlob(BlobId outputName); + + void setParam(LayerId layer, int numParam, const Blob &blob); + void getParam(LayerId layer, int numParam); - int lastLayerId; - std::map< int, Ptr > layers; - std::map< int, std::vector > layerOutputLabels; - }; - - - CV_EXPORTS class Net - { - public: - - CV_EXPORTS static Ptr create(Ptr config); - - virtual ~Net() = 0; - - virtual int getBlobId(int layerId, int outputId) = 0; - - virtual int getBlobId(const String &blobName) = 0; - - virtual void forward(std::vector< int, Ptr > &inputBlobs, std::vector > &outputBlobs) = 0; + private: - virtual void forward(int layer, std::vector > &layerOutputs) = 0; + struct Impl; + Ptr impl; }; CV_EXPORTS class Importer { public: - virtual void populateNetConfiguration(Ptr config) = 0; + virtual void populateNet(Net net) = 0; virtual ~Importer(); }; diff --git a/modules/dnn/include/opencv2/dnn/dnn.inl.hpp b/modules/dnn/include/opencv2/dnn/dnn.inl.hpp index 917da3852..efd37af06 100644 --- a/modules/dnn/include/opencv2/dnn/dnn.inl.hpp +++ b/modules/dnn/include/opencv2/dnn/dnn.inl.hpp @@ -31,6 +31,47 @@ namespace dnn CV_Assert(false); return Mat(); } + + inline + int Blob::cols() const + { + CV_DbgAssert(m.dims > 2); + return m.size[m.dims-1]; + } + + inline + int Blob::rows() const + { + CV_DbgAssert(m.dims > 2); + return m.size[m.dims-2]; + } + + inline + Size Blob::size() const + { + return Size(cols(), rows()); + } + + inline + int Blob::channels() const + { + CV_DbgAssert(m.dims >= 3); + return m.size[m.dims-3]; + } + + inline + int Blob::num() const + { + CV_DbgAssert(m.dims == 4); + return m.size[0]; + } + + inline + Vec4i Blob::shape() const + { + CV_DbgAssert(m.dims == 4); + return Vec4i(m.size.p); + } } } diff --git a/modules/dnn/src/caffe_importer.cpp b/modules/dnn/src/caffe_importer.cpp index 5d9ac18b9..ba10cfac8 100644 --- a/modules/dnn/src/caffe_importer.cpp +++ b/modules/dnn/src/caffe_importer.cpp @@ -154,11 +154,8 @@ namespace CV_Error(cv::Error::StsAssert, "Unknown shape of input blob"); } - size_t declaredBlobSize = 1; - for (int i = 0; i < shape.size(); i++) - declaredBlobSize *= shape[i]; - CV_Assert(declaredBlobSize == protoBlob.data_size()); dstBlob.create(shape.size(), shape, CV_32F); + CV_Assert(protoBlob.data_size() == dstBlob.getMatRef().total()); CV_DbgAssert(protoBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT); float *dstData = dstBlob.getMatRef().ptr(); @@ -167,7 +164,7 @@ namespace dstData[i] = protoBlob.data(i); } - void populateNetConfiguration(Ptr config) + void populateNet(Net dstNet) { int layersSize = net.layer_size(); diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 704d5c14c..acfa00b47 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -61,21 +61,38 @@ void Blob::create(int ndims, const int *sizes, int type /*= CV_32F*/) m.create(shape.channels, &shape[0], type); } -Net::~Net() +struct Net::Impl +{ + +}; + +Net::Net() : impl(new Net::Impl) { } +Net::~Net() +{ + +} Importer::~Importer() { } +#include +template +String toString(const T &v) +{ + std::stringstream ss; + ss << v; + return ss.str(); +} -Ptr NetConfiguration::create() +cv::String Layer::getInputName(int inputNum) { - return Ptr(new NetConfiguration()); + return "input" + toString(inputNum); } } diff --git a/modules/dnn/test/test_caffe_importer.cpp b/modules/dnn/test/test_caffe_importer.cpp index 3a090ab46..4f30f9695 100644 --- a/modules/dnn/test/test_caffe_importer.cpp +++ b/modules/dnn/test/test_caffe_importer.cpp @@ -22,15 +22,15 @@ static std::string getTestFile(const char *filename) TEST(ReadCaffePrototxt_gtsrb, Accuracy) { Ptr importer = createCaffeImporter(getTestFile("gtsrb.prototxt"), getTestFile("gtsrb_iter_36000.caffemodel") ); - Ptr config = NetConfiguration::create(); - importer->populateNetConfiguration(config); + Net net; + importer->populateNet(net); } -//TEST(ReadCaffePrototxt_GoogleNet, Accuracy) -//{ -// Ptr importer = createCaffeImporter(getOpenCVExtraDir() + "/dnn/googlenet_deploy.prototxt", ""); -// Ptr config = NetConfiguration::create(); -// importer->populateNetConfiguration(config); -//} +TEST(ReadCaffePrototxt_GoogleNet, Accuracy) +{ + Ptr importer = createCaffeImporter(getOpenCVExtraDir() + "/dnn/googlenet_deploy.prototxt", ""); + Net net; + importer->populateNet(net); +} } \ No newline at end of file