Commit d57e5406 authored by Dmitry Kurtaev's avatar Dmitry Kurtaev

Add readNet* functions which parse models from byte arrays

parent 61d8719b
...@@ -644,13 +644,23 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN ...@@ -644,13 +644,23 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
CV_EXPORTS_W Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String()); CV_EXPORTS_W Net readNetFromDarknet(const String &cfgFile, const String &darknetModel = String());
/** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files. /** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files.
* @param cfgFile file node to the .cfg file with text description of the network architecture. * @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture.
* @param darknetModel file node to the .weights file with learned network. * @param bufferModel A buffer contains a content of .weights file with learned network.
* @returns Network object that ready to do forward, throw an exception in failure cases. * @returns Net object.
* @returns Net object. */
*/ CV_EXPORTS_W Net readNetFromDarknet(const std::vector<char>& bufferCfg,
CV_EXPORTS_W Net readNetFromDarknet(const FileNode &cfgFile, const FileNode &darknetModel = FileNode()); const std::vector<char>& bufferModel = std::vector<char>());
/** @brief Reads a network model stored in <a href="https://pjreddie.com/darknet/">Darknet</a> model files.
* @param bufferCfg A buffer contains a content of .cfg file with text description of the network architecture.
* @param lenCfg Number of bytes to read from bufferCfg
* @param bufferModel A buffer contains a content of .weights file with learned network.
* @param lenModel Number of bytes to read from bufferModel
* @returns Net object.
*/
CV_EXPORTS Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg,
const char *bufferModel = NULL, size_t lenModel = 0);
/** @brief Reads a network model stored in <a href="http://caffe.berkeleyvision.org">Caffe</a> framework's format. /** @brief Reads a network model stored in <a href="http://caffe.berkeleyvision.org">Caffe</a> framework's format.
* @param prototxt path to the .prototxt file with text description of the network architecture. * @param prototxt path to the .prototxt file with text description of the network architecture.
...@@ -659,6 +669,14 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN ...@@ -659,6 +669,14 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
CV_EXPORTS_W Net readNetFromCaffe(const String &prototxt, const String &caffeModel = String()); CV_EXPORTS_W Net readNetFromCaffe(const String &prototxt, const String &caffeModel = String());
/** @brief Reads a network model stored in Caffe model in memory.
* @param bufferProto buffer containing the content of the .prototxt file
* @param bufferModel buffer containing the content of the .caffemodel file
* @returns Net object.
*/
CV_EXPORTS_W Net readNetFromCaffe(const std::vector<char>& bufferProto,
const std::vector<char>& bufferModel = std::vector<char>());
/** @brief Reads a network model stored in Caffe model in memory. /** @brief Reads a network model stored in Caffe model in memory.
* @details This is an overloaded member function, provided for convenience. * @details This is an overloaded member function, provided for convenience.
* It differs from the above function only in what argument(s) it accepts. * It differs from the above function only in what argument(s) it accepts.
...@@ -680,6 +698,14 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN ...@@ -680,6 +698,14 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
CV_EXPORTS_W Net readNetFromTensorflow(const String &model, const String &config = String()); CV_EXPORTS_W Net readNetFromTensorflow(const String &model, const String &config = String());
/** @brief Reads a network model stored in <a href="https://www.tensorflow.org/">TensorFlow</a> framework's format.
* @param bufferModel buffer containing the content of the pb file
* @param bufferConfig buffer containing the content of the pbtxt file
* @returns Net object.
*/
CV_EXPORTS_W Net readNetFromTensorflow(const std::vector<char>& bufferModel,
const std::vector<char>& bufferConfig = std::vector<char>());
/** @brief Reads a network model stored in <a href="https://www.tensorflow.org/">TensorFlow</a> framework's format. /** @brief Reads a network model stored in <a href="https://www.tensorflow.org/">TensorFlow</a> framework's format.
* @details This is an overloaded member function, provided for convenience. * @details This is an overloaded member function, provided for convenience.
* It differs from the above function only in what argument(s) it accepts. * It differs from the above function only in what argument(s) it accepts.
...@@ -743,6 +769,18 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN ...@@ -743,6 +769,18 @@ CV__DNN_EXPERIMENTAL_NS_BEGIN
*/ */
CV_EXPORTS_W Net readNet(const String& model, const String& config = "", const String& framework = ""); CV_EXPORTS_W Net readNet(const String& model, const String& config = "", const String& framework = "");
/**
* @brief Read deep learning network represented in one of the supported formats.
* @details This is an overloaded member function, provided for convenience.
* It differs from the above function only in what argument(s) it accepts.
* @param[in] framework Name of origin framework.
* @param[in] bufferModel A buffer with a content of binary file with weights
* @param[in] bufferConfig A buffer with a content of text file contains network configuration.
* @returns Net object.
*/
CV_EXPORTS_W Net readNet(const String& framework, const std::vector<char>& bufferModel,
const std::vector<char>& bufferConfig = std::vector<char>());
/** @brief Loads blob which was serialized as torch.Tensor object of Torch7 framework. /** @brief Loads blob which was serialized as torch.Tensor object of Torch7 framework.
* @warning This function has the same limitations as readNetFromTorch(). * @warning This function has the same limitations as readNetFromTorch().
*/ */
......
...@@ -453,6 +453,12 @@ Net readNetFromCaffe(const char *bufferProto, size_t lenProto, ...@@ -453,6 +453,12 @@ Net readNetFromCaffe(const char *bufferProto, size_t lenProto,
return net; return net;
} }
Net readNetFromCaffe(const std::vector<char>& bufferProto, const std::vector<char>& bufferModel)
{
return readNetFromCaffe(&bufferProto[0], bufferProto.size(),
bufferModel.empty() ? NULL : &bufferModel[0], bufferModel.size());
}
#endif //HAVE_PROTOBUF #endif //HAVE_PROTOBUF
CV__DNN_EXPERIMENTAL_NS_END CV__DNN_EXPERIMENTAL_NS_END
......
...@@ -181,45 +181,71 @@ public: ...@@ -181,45 +181,71 @@ public:
} }
}; };
static Net readNetFromDarknet(std::istream &cfgFile, std::istream &darknetModel)
{
Net net;
DarknetImporter darknetImporter(cfgFile, darknetModel);
darknetImporter.populateNet(net);
return net;
} }
Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= String()*/) static Net readNetFromDarknet(std::istream &cfgFile)
{ {
Net net; Net net;
DarknetImporter darknetImporter(cfgFile);
darknetImporter.populateNet(net);
return net;
}
}
Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= String()*/)
{
std::ifstream cfgStream(cfgFile.c_str()); std::ifstream cfgStream(cfgFile.c_str());
if(!cfgStream.is_open()) { if (!cfgStream.is_open())
{
CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(cfgFile)); CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(cfgFile));
return net;
} }
DarknetImporter darknetImporter; if (darknetModel != String())
if (darknetModel != String()) { {
std::ifstream darknetModelStream(darknetModel.c_str()); std::ifstream darknetModelStream(darknetModel.c_str(), std::ios::binary);
if(!darknetModelStream.is_open()){ if (!darknetModelStream.is_open())
{
CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(darknetModel)); CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(darknetModel));
return net;
} }
darknetImporter = DarknetImporter(cfgStream, darknetModelStream); return readNetFromDarknet(cfgStream, darknetModelStream);
} else {
darknetImporter = DarknetImporter(cfgStream);
} }
darknetImporter.populateNet(net); else
return net; return readNetFromDarknet(cfgStream);
} }
Net readNetFromDarknet(const FileNode &cfgFile, const FileNode &darknetModel /*= FileNode()*/) struct BufferStream : public std::streambuf
{ {
DarknetImporter darknetImporter; BufferStream(const char* s, std::size_t n)
if(darknetModel.empty()){ {
std::istringstream cfgStream((std::string)cfgFile); char* ptr = const_cast<char*>(s);
darknetImporter = DarknetImporter(cfgStream); setg(ptr, ptr, ptr + n);
}else{
std::istringstream cfgStream((std::string)cfgFile);
std::istringstream darknetModelStream((std::string)darknetModel);
darknetImporter = DarknetImporter(cfgStream, darknetModelStream);
} }
Net net; };
darknetImporter.populateNet(net);
return net; Net readNetFromDarknet(const char *bufferCfg, size_t lenCfg, const char *bufferModel, size_t lenModel)
{
BufferStream cfgBufferStream(bufferCfg, lenCfg);
std::istream cfgStream(&cfgBufferStream);
if (lenModel)
{
BufferStream weightsBufferStream(bufferModel, lenModel);
std::istream weightsStream(&weightsBufferStream);
return readNetFromDarknet(cfgStream, weightsStream);
}
else
return readNetFromDarknet(cfgStream);
}
Net readNetFromDarknet(const std::vector<char>& bufferCfg, const std::vector<char>& bufferModel)
{
return readNetFromDarknet(&bufferCfg[0], bufferCfg.size(),
bufferModel.empty() ? NULL : &bufferModel[0], bufferModel.size());
} }
CV__DNN_EXPERIMENTAL_NS_END CV__DNN_EXPERIMENTAL_NS_END
......
...@@ -3047,6 +3047,23 @@ Net readNet(const String& _model, const String& _config, const String& _framewor ...@@ -3047,6 +3047,23 @@ Net readNet(const String& _model, const String& _config, const String& _framewor
model + (config.empty() ? "" : ", " + config)); model + (config.empty() ? "" : ", " + config));
} }
Net readNet(const String& _framework, const std::vector<char>& bufferModel,
const std::vector<char>& bufferConfig)
{
String framework = _framework.toLowerCase();
if (framework == "caffe")
return readNetFromCaffe(bufferConfig, bufferModel);
else if (framework == "tensorflow")
return readNetFromTensorflow(bufferModel, bufferConfig);
else if (framework == "darknet")
return readNetFromDarknet(bufferConfig, bufferModel);
else if (framework == "torch")
CV_Error(Error::StsNotImplemented, "Reading Torch models from buffers");
else if (framework == "dldt")
CV_Error(Error::StsNotImplemented, "Reading Intel's Model Optimizer models from buffers");
CV_Error(Error::StsError, "Cannot determine an origin framework with a name " + framework);
}
Net readNetFromModelOptimizer(const String &xml, const String &bin) Net readNetFromModelOptimizer(const String &xml, const String &bin)
{ {
return Net::readFromModelOptimizer(xml, bin); return Net::readFromModelOptimizer(xml, bin);
......
...@@ -1856,5 +1856,11 @@ Net readNetFromTensorflow(const char* bufferModel, size_t lenModel, ...@@ -1856,5 +1856,11 @@ Net readNetFromTensorflow(const char* bufferModel, size_t lenModel,
return net; return net;
} }
Net readNetFromTensorflow(const std::vector<char>& bufferModel, const std::vector<char>& bufferConfig)
{
return readNetFromCaffe(&bufferModel[0], bufferModel.size(),
bufferConfig.empty() ? NULL : &bufferConfig[0], bufferConfig.size());
}
CV__DNN_EXPERIMENTAL_NS_END CV__DNN_EXPERIMENTAL_NS_END
}} // namespace }} // namespace
...@@ -65,16 +65,32 @@ TEST(Test_Darknet, read_yolo_voc) ...@@ -65,16 +65,32 @@ TEST(Test_Darknet, read_yolo_voc)
ASSERT_FALSE(net.empty()); ASSERT_FALSE(net.empty());
} }
TEST(Test_Darknet, read_filestorage_yolo_voc) TEST(Test_Darknet, read_yolo_voc_stream)
{ {
std::ifstream ifile(_tf("yolo-voc.cfg").c_str()); Mat ref;
std::stringstream buffer; Mat sample = imread(_tf("dog416.png"));
buffer << " " << ifile.rdbuf(); // FIXME: FileStorage drops first character. Mat inp = blobFromImage(sample, 1.0/255, Size(416, 416), Scalar(), true, false);
FileStorage ofs(".xml", FileStorage::WRITE | FileStorage::MEMORY); const std::string cfgFile = findDataFile("dnn/yolo-voc.cfg", false);
ofs.write("cfgFile", buffer.str()); const std::string weightsFile = findDataFile("dnn/yolo-voc.weights", false);
FileStorage ifs(ofs.releaseAndGetString(), FileStorage::READ | FileStorage::MEMORY | FileStorage::FORMAT_XML); // Import by paths.
Net net = readNetFromDarknet(ifs["cfgFile"]); {
ASSERT_FALSE(net.empty()); Net net = readNetFromDarknet(cfgFile, weightsFile);
net.setInput(inp);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
ref = net.forward();
}
// Import from bytes array.
{
std::string cfg, weights;
readFileInMemory(cfgFile, cfg);
readFileInMemory(weightsFile, weights);
Net net = readNetFromDarknet(&cfg[0], cfg.size(), &weights[0], weights.size());
net.setInput(inp);
net.setPreferableBackend(DNN_BACKEND_OPENCV);
Mat out = net.forward();
normAssert(ref, out);
}
} }
class Test_Darknet_layers : public DNNTestLayer class Test_Darknet_layers : public DNNTestLayer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment