-
-
Notifications
You must be signed in to change notification settings - Fork 55.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reading Darknet from cv::FileStorage #11104
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Due std::istream
has no wrapping policy we need to use CV_EXPORTS
here and below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got your saying. I will change std::istream to the other buffered structure like #9994.
@@ -508,13 +502,9 @@ namespace cv { | |||
return true; | |||
} | |||
|
|||
|
|||
bool ReadDarknetFromWeightsFile(const char *darknetModel, NetParameter *net) | |||
bool ReadDarknetFromWeightsStream(std::istream &darknetModelStream, NetParameter *net) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mind just rename darknetModelStream
to ifile
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course. I renamed.
@@ -179,7 +185,32 @@ class DarknetImporter | |||
|
|||
Net readNetFromDarknet(const String &cfgFile, const String &darknetModel /*= String()*/) | |||
{ | |||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so too. I added it.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
TEST_P(Reproducibility_AlexNet, Accuracy) | |
{ | |
bool readFromMemory = get<0>(GetParam()); | |
Net net; | |
{ | |
const string proto = findDataFile("dnn/bvlc_alexnet.prototxt", false); | |
const string model = findDataFile("dnn/bvlc_alexnet.caffemodel", false); | |
if (readFromMemory) | |
{ | |
string dataProto; | |
ASSERT_TRUE(readFileInMemory(proto, dataProto)); | |
string dataModel; | |
ASSERT_TRUE(readFileInMemory(model, dataModel)); | |
net = readNetFromCaffe(dataProto.c_str(), dataProto.size(), | |
dataModel.c_str(), dataModel.size()); | |
} | |
else | |
net = readNetFromCaffe(proto, model); | |
ASSERT_FALSE(net.empty()); | |
} | |
net.setPreferableTarget(get<1>(GetParam())); | |
Mat sample = imread(_tf("grace_hopper_227.png")); | |
ASSERT_TRUE(!sample.empty()); | |
net.setInput(blobFromImage(sample, 1.0f, Size(227, 227), Scalar(), false), "data"); | |
Mat out = net.forward("prob"); | |
Mat ref = blobFromNPY(_tf("caffe_alexnet_prob.npy")); | |
normAssert(ref, out); | |
} |
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In tests we can use this:
fail("DNN forward() failed: " + e.getMessage());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! Fixed that.
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.