Reading Darknet from cv::FileStorage#11104
Reading Darknet from cv::FileStorage#11104opencv-pushbot merged 3 commits intoopencv:3.4from tani:reading_from_stream
Conversation
| * @returns Network object that ready to do forward, throw an exception in failure cases. | ||
| * @returns Net object. | ||
| */ | ||
| CV_EXPORTS_W Net readNetFromDarknet(std::istream &cfgStream, std::istream &darknetModelStream); |
There was a problem hiding this comment.
Due std::istream has no wrapping policy we need to use CV_EXPORTS here and below.
There was a problem hiding this comment.
OK, now I will to replace std::istream to IStream of 3rdparty. Can I add 3rdparty/openexr/IlmImf/ImfIO.h ? Or what do I should use?
There was a problem hiding this comment.
I got your saying. I will change std::istream to the other buffered structure like #9994.
|
|
||
|
|
||
| bool ReadDarknetFromWeightsFile(const char *darknetModel, NetParameter *net) | ||
| bool ReadDarknetFromWeightsStream(std::istream &darknetModelStream, NetParameter *net) |
There was a problem hiding this comment.
Do you mind just rename darknetModelStream to ifile here?
| { | ||
| DarknetImporter darknetImporter(cfgFile.c_str(), darknetModel.c_str()); | ||
| std::ifstream cfgStream(cfgFile.c_str()); | ||
| CV_Assert(cfgStream.is_open()); |
There was a problem hiding this comment.
There were assertions include paths to files,
CV_Error(cv::Error::StsParseError, "Failed to parse NetParameter file: " + std::string(cfgFile));
I think it's useful to keep some kind of error message that prints actual paths.
|
@dkurt I added
|
| FileStorage ofs(".xml", FileStorage::WRITE | FileStorage::MEMORY); | ||
| ofs.write("cfgFile", buffer.str()); | ||
| FileStorage ifs(ofs.releaseAndGetString(), FileStorage::READ | FileStorage::MEMORY | FileStorage::FORMAT_XML); | ||
| Net net = readNetFromDarknet(ifs["cfgFile"]); |
There was a problem hiding this comment.
@Asciian, please remind me why you decided to replace std::istream to cv::FileNode? The last one seems to be more complicated here.
There was a problem hiding this comment.
@dkurt Because std::istream couldn't become the arguments of exporting functions and knew no way to implements the topic of this issue without cv::FileNode. If you know that, Please tell me.
There was a problem hiding this comment.
@dkurt Ah, I know another way. With raw string, we can implements that. But the way requires adding the function two arguments which are used for telling the length of content.
| ofs.write("cfgFile", buffer.str()); | ||
| FileStorage ifs(ofs.releaseAndGetString(), FileStorage::READ | FileStorage::MEMORY | FileStorage::FORMAT_XML); | ||
| Net net = readNetFromDarknet(ifs["cfgFile"]); | ||
| ASSERT_FALSE(net.empty()); |
There was a problem hiding this comment.
I think we need to check an accuracy too. Could you make some of existing accuracy tests to be parametric similar to one of our tests for loading models from a buffer?
opencv/modules/dnn/test/test_caffe_importer.cpp
Lines 85 to 116 in 1031dfe
|
@Asciian, I've reverted this changes back to |
|
I got it. BTW, I guess std::istream isn’t exported for Python and Java. Do you have any idea? We have the only way via FileNode, don’t you? |
|
@Asciian, I see your point. Please let me experiment a bit with a FileStorage and a binary data. |
|
@dkurt, filestorage supports base64-encoded data; I suggest to use that. Maybe embedded a Darknet model (or any deep learning model) into a FileStorage is not very good idea in general and we or users can implement so alternative options. E.g. extend our Darknet parser to read the net from memory, if it was the original intention. |
Remove some assertions Replace std::ifstream to std::istream Add test for new importer Remove constructor to load file Rename cfgStream and darknetModelStream to ifile Add error notification to inform pathname to user Use FileStorage instead of std::istream Use FileNode instead of FileStorage Fix typo
|
@Asciian, I've added methods which receive bytes buffers via import cv2 as cv
import numpy as np
with open('yolov3.cfg', 'rt') as f:
cfgFile = bytearray(f.read())
with open('yolov3.weights', 'rb') as f:
weightsFile = bytearray(f.read())
inp = np.random.standard_normal([1, 3, 416, 416]).astype(np.float32)
net = cv.dnn.readNetFromDarknet(cfgFile, weightsFile)
net.setInput(inp)
out = net.forward() |
|
It looks good. However, as my comments,
|
|
@Asciian, Thank you. I've fixed that. Please check File modelFile = new File(modelFileName);
byte[] modelBuffer = new byte[ (int)modelFile.length() ];
try {
FileInputStream fis = new FileInputStream(modelFile);
fis.read(modelBuffer);
fis.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
net = Dnn.readNetFromTensorflow(new MatOfByte(modelBuffer)); |
|
That's a bytearray. Thank you. I said that |
| } | ||
| catch (Exception e) { | ||
| System.out.println(e.getMessage()); | ||
| throw e; |
There was a problem hiding this comment.
In tests we can use this:
fail("DNN forward() failed: " + e.getMessage());
This pullrequest changes
I added new constructor for DarknetImporter to load from std::istream.
Current constructor gets to two pathnames which are raw strings. Without std::filesystem of C++17, some pathname has problem for cross-platform development. This changes makes abstractly to load files.
And more, by this changes we will be able to include resources into binary, like followings.