1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

Allow protobuffer message to be compiled with LITE_RUNTIME

When adding "option optimize_for = LITE_RUNTIME;" to proto
messages, they are compiled as lighter MessageLite (the base class
of Message).

Those lighter messages do not allow for reflection though:

https://developers.google.com/protocol-buffers/docs/reference/cpp-generated

This fixes https://github.com/opencv/opencv/issues/20275
This commit is contained in:
Vincent Rabaud
2025-11-03 15:18:43 +01:00
parent 9282afa0c7
commit 1691a2355c
4 changed files with 82 additions and 12 deletions
+24 -2
View File
@@ -46,6 +46,7 @@
#include <fstream>
#include <sstream>
#include <algorithm>
#include <type_traits>
#include <google/protobuf/message.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -203,7 +204,9 @@ public:
return (str.size() >= _param.size()) && str.compare(str.size() - _param.size(), _param.size(), _param) == 0;
}
void extractLayerParams(const Message &msg, cv::dnn::LayerParams &params, bool isInternal = false)
template<class MSG>
typename std::enable_if<std::is_base_of<Message, MSG>::value, void>::type
extractLayerParams(const MSG &msg, cv::dnn::LayerParams &params, bool isInternal = false)
{
const Descriptor *msgDesc = msg.GetDescriptor();
const Reflection *msgRefl = msg.GetReflection();
@@ -238,6 +241,13 @@ public:
}
}
template<class MSG>
typename std::enable_if<!std::is_base_of<Message, MSG>::value, void>::type
extractLayerParams(const MSG &msg, cv::dnn::LayerParams &params, bool isInternal = false)
{
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
}
void blobShapeFromProto(const caffe::BlobProto &pbBlob, MatShape& shape)
{
shape.clear();
@@ -256,6 +266,18 @@ public:
shape.resize(1, 1); // Is a scalar.
}
template<class BLOB_PROTO>
typename std::enable_if<std::is_base_of<Message, BLOB_PROTO>::value, void>::type
AssertBlobProtoIsFloat(const BLOB_PROTO &pbBlob) {
CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT);
}
template<class BLOB_PROTO>
typename std::enable_if<!std::is_base_of<Message, BLOB_PROTO>::value, void>::type
AssertBlobProtoIsFloat(const BLOB_PROTO &pbBlob) {
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
}
void blobFromProto(const caffe::BlobProto &pbBlob, cv::Mat &dstBlob)
{
MatShape shape;
@@ -267,7 +289,7 @@ public:
// Single precision floats.
CV_Assert(pbBlob.data_size() == (int)dstBlob.total());
CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT);
AssertBlobProtoIsFloat(pbBlob);
Mat(dstBlob.dims, &dstBlob.size[0], CV_32F, (void*)pbBlob.data().data()).copyTo(dstBlob);
}
else
+39 -7
View File
@@ -101,6 +101,7 @@
#include <string>
#include <fstream>
#include <vector>
#include <type_traits>
#include "caffe_io.hpp"
#include "glog_emulator.hpp"
@@ -1110,7 +1111,7 @@ const char* UpgradeV1LayerType(const V1LayerParameter_LayerType type) {
static const int kProtoReadBytesLimit = INT_MAX; // Max size of 2 GB minus 1 byte.
bool ReadProtoFromBinary(ZeroCopyInputStream* input, Message *proto) {
bool ReadProtoFromBinary(ZeroCopyInputStream* input, MessageLite *proto) {
CodedInputStream coded_input(input);
#if GOOGLE_PROTOBUF_VERSION >= 3006000
coded_input.SetTotalBytesLimit(kProtoReadBytesLimit);
@@ -1133,7 +1134,12 @@ bool ReadProtoFromTextFile(const char* filename, Message* proto) {
return parser.Parse(&input, proto);
}
bool ReadProtoFromBinaryFile(const char* filename, Message* proto) {
bool ReadProtoFromTextFile(const char* filename, MessageLite* proto) {
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
return false;
}
bool ReadProtoFromBinaryFile(const char* filename, MessageLite* proto) {
std::ifstream fs(filename, std::ifstream::in | std::ifstream::binary);
CHECK(fs.is_open()) << "Can't open \"" << filename << "\"";
IstreamInputStream raw_input(&fs);
@@ -1151,26 +1157,52 @@ bool ReadProtoFromTextBuffer(const char* data, size_t len, Message* proto) {
return parser.Parse(&input, proto);
}
bool ReadProtoFromTextBuffer(const char* data, size_t len, MessageLite* proto) {
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
return false;
}
bool ReadProtoFromBinaryBuffer(const char* data, size_t len, Message* proto) {
bool ReadProtoFromBinaryBuffer(const char* data, size_t len, MessageLite* proto) {
ArrayInputStream raw_input(data, len);
return ReadProtoFromBinary(&raw_input, proto);
}
void ReadNetParamsFromTextFileOrDie(const char* param_file,
NetParameter* param) {
template<class MESSAGE>
typename std::enable_if<std::is_base_of<Message, MESSAGE>::value, void>::type
ReadNetParamsFromTextFileOrDieImpl(const char* param_file, MESSAGE* param) {
CHECK(ReadProtoFromTextFile(param_file, param))
<< "Failed to parse NetParameter file: " << param_file;
UpgradeNetAsNeeded(param_file, param);
}
void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len,
NetParameter* param) {
template<class MESSAGE>
typename std::enable_if<!std::is_base_of<Message, MESSAGE>::value, void>::type
ReadNetParamsFromTextFileOrDieImpl(const char* param_file, MESSAGE* param) {
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
}
void ReadNetParamsFromTextFileOrDie(const char* param_file, NetParameter* param) {
ReadNetParamsFromTextFileOrDieImpl(param_file, param);
}
template<class MESSAGE>
typename std::enable_if<std::is_base_of<Message, MESSAGE>::value, void>::type
ReadNetParamsFromTextBufferOrDieImpl(const char* data, size_t len, MESSAGE* param) {
CHECK(ReadProtoFromTextBuffer(data, len, param))
<< "Failed to parse NetParameter buffer";
UpgradeNetAsNeeded("memory buffer", param);
}
template<class MESSAGE>
typename std::enable_if<!std::is_base_of<Message, MESSAGE>::value, void>::type
ReadNetParamsFromTextBufferOrDieImpl(const char* data, size_t len, MESSAGE* param) {
CV_Error(Error::StsError, "DNN/CAFFE: do not have your message be a MessageLite");
}
void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len, NetParameter* param) {
ReadNetParamsFromTextBufferOrDieImpl(data, len, param);
}
void ReadNetParamsFromBinaryFileOrDie(const char* param_file,
NetParameter* param) {
CHECK(ReadProtoFromBinaryFile(param_file, param))
+4 -2
View File
@@ -119,9 +119,11 @@ void ReadNetParamsFromTextBufferOrDie(const char* data, size_t len,
// Utility functions used internally by Caffe and TensorFlow loaders
bool ReadProtoFromTextFile(const char* filename, ::google::protobuf::Message* proto);
bool ReadProtoFromBinaryFile(const char* filename, ::google::protobuf::Message* proto);
bool ReadProtoFromTextFile(const char* filename, ::google::protobuf::MessageLite* proto);
bool ReadProtoFromBinaryFile(const char* filename, ::google::protobuf::MessageLite* proto);
bool ReadProtoFromTextBuffer(const char* data, size_t len, ::google::protobuf::Message* proto);
bool ReadProtoFromBinaryBuffer(const char* data, size_t len, ::google::protobuf::Message* proto);
bool ReadProtoFromTextBuffer(const char* data, size_t len, ::google::protobuf::MessageLite* proto);
bool ReadProtoFromBinaryBuffer(const char* data, size_t len, ::google::protobuf::MessageLite* proto);
}
}
+15 -1
View File
@@ -27,6 +27,7 @@ Implementation of Tensorflow models parser
#include <algorithm>
#include <string>
#include <queue>
#include <type_traits>
#include "tf_graph_simplifier.hpp"
#endif
@@ -3290,6 +3291,19 @@ Net readNetFromTensorflow(const std::vector<uchar>& bufferModel, const std::vect
bufferConfigPtr, bufferConfig.size());
}
template<class GRAPH_DEF>
typename std::enable_if<std::is_base_of<Message, GRAPH_DEF>::value, void>::type
PrintToStringImpl(const GRAPH_DEF& net, std::string* content) {
google::protobuf::TextFormat::PrintToString(net, content);
}
template<class GRAPH_DEF>
typename std::enable_if<!std::is_base_of<Message, GRAPH_DEF>::value, void>::type
PrintToStringImpl(const GRAPH_DEF& net, std::string* content) {
CV_Error(Error::StsError, "DNN/TF: do not have your message be a MessageLite");
}
void writeTextGraph(const String& _model, const String& output)
{
String model = _model;
@@ -3312,7 +3326,7 @@ void writeTextGraph(const String& _model, const String& output)
}
std::string content;
google::protobuf::TextFormat::PrintToString(net, &content);
PrintToStringImpl(net, &content);
std::ofstream ofs(output.c_str());
ofs << content;