C++版本
参考链接protobuf repeated类型的使用
repeated类型设置值的方法是add
optional,required类型设置值得方法是set,下面用开源的目标检测框架SSD里的数据层代码举例,注意最后添加plate_valid成员变量的方式。
message PlateValid {
repeated int32 valid = 1;
optional int32 length = 2;
}
message Annotation {
optional int32 instance_id = 1 [default = 0];
optional NormalizedBBox bbox = 2;
optional PlateValid plate_valid = 3;
}
// Parse MSCOCO detection annotation.
bool ReadJSONToAnnotatedDatum(const string& labelfile, const int img_height,
const int img_width, const std::map<string, int>& name_to_label,
AnnotatedDatum* anno_datum) {
ptree pt;
read_json(labelfile, pt);
// Get image info.
int width = 0, height = 0;
try {
height = pt.get<int>("image.height");
width = pt.get<int>("image.width");
} catch (const ptree_error &e) {
LOG(WARNING) << "When parsing " << labelfile << ": " << e.what();
height = img_height;
width = img_width;
}
LOG_IF(WARNING, height != img_height) << labelfile <<
" inconsistent image height.";
LOG_IF(WARNING, width != img_width) << labelfile <<
" inconsistent image width.";
CHECK(width != 0 && height != 0) << labelfile <<
" no valid image width/height.";
// Get annotation info.
int instance_id = 0;
BOOST_FOREACH(ptree::value_type& v1, pt.get_child("annotation")) {
Annotation* anno = NULL;
bool iscrowd = false;
ptree object = v1.second;
// Get category_id.
string name = object.get<string>("category_id");
if (name_to_label.find(name) == name_to_label.end()) {
LOG(FATAL) << "Unknown name: " << name;
}
int label = name_to_label.find(name)->second;
bool found_group = false;
for (int g = 0; g < anno_datum->annotation_group_size(); ++g) {
AnnotationGroup* anno_group =
anno_datum->mutable_annotation_group(g);
if (label == anno_group->group_label()) {
if (anno_group->annotation_size() == 0) {
instance_id = 0;
} else {
instance_id = anno_group->annotation(
anno_group->annotation_size() - 1).instance_id() + 1;
}
anno = anno_group->add_annotation();
found_group = true;
}
}
if (!found_group) {
// If there is no such annotation_group, create a new one.
AnnotationGroup* anno_group = anno_datum->add_annotation_group();
anno_group->set_group_label(label);
anno = anno_group->add_annotation();
instance_id = 0;
}
anno->set_instance_id(instance_id++);
// Get iscrowd.
iscrowd = object.get<int>("iscrowd", 0);
// Get bbox.
vector<float> bbox_items;
BOOST_FOREACH(ptree::value_type& v2, object.get_child("bbox")) {
bbox_items.push_back(v2.second.get_value<float>());
}
CHECK_EQ(bbox_items.size(), 4);
float xmin = bbox_items[0];
float ymin = bbox_items[1];
float xmax = bbox_items[0] + bbox_items[2];
float ymax = bbox_items[1] + bbox_items[3];
CHECK_NOTNULL(anno);
LOG_IF(WARNING, xmin > width) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, ymin > height) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, xmax > width) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, ymax > height) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, xmin < 0) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, ymin < 0) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, xmax < 0) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, ymax < 0) << labelfile <<
" bounding box exceeds image boundary.";
LOG_IF(WARNING, xmin > xmax) << labelfile <<
" bounding box irregular.";
LOG_IF(WARNING, ymin > ymax) << labelfile <<
" bounding box irregular.";
// Store the normalized bounding box.
NormalizedBBox* bbox = anno->mutable_bbox();
bbox->set_xmin(xmin / width);
bbox->set_ymin(ymin / height);
bbox->set_xmax(xmax / width);
bbox->set_ymax(ymax / height);
bbox->set_difficult(iscrowd);
// valid是从json文件里读取的标注字符串string类型
// std::string valid = object.get<string>("valid");
PlateValid *plate_valid = anno->mutable_plate_valid();
int plate_length = 0;
for (int j = 0; j < valid.size(); j++) {
std::sring valid_elem(1, valid[j]);
int chrlabel = name_to_chrlabel.find(valid_elem)->second;
plate_valid->add_valid(chrlabel);
plate_valid->set_length(++plate_length);
}
return true;
}
Python版本
python protobuf repeated类型的使用方法参考Python序列化protobuf中的repeated数据。自定义类型和基本类型添加实例的方法不一样,一个用add(),一个用append()。
ValueError: ‘\xe5\x94\x90\xe6\x9e\x9c‘ has type bytes, but isn‘t in 7-bit ASCII encoding. Non-ASCII strings must be converted to unicode objects before being added.
原因分析,参考这里在Python中使用protobuf2.6.1 string format utf-8 and unicode error
解决方法:message中赋值时 都带上 decode(“utf-8”)
其他
proto中的数据类型和c++,Python中的数据类型对应规则如下:
.proto | C++ | Python | 介绍 |
---|---|---|---|
double | double | float | |
float | float | float | |
int32 | int32 | int | 可变长编码,对负数效率不高 |
int64 | int64 | int/long | |
uint32 | uint32 | int/long | |
uint64 | uint64 | int/long | |
sint32 | int32 | int | 可变长编码,对负数效率较高 |
sint64 | int64 | int/long | |
fixed32 | uint32 | int/long | 32位定长编码 |
fixed64 | uint64 | int/long | |
sfixed32 | int32 | int | |
sfixed64 | int64 | int/long | |
bool | bool | bool | |
string | string | str/unicode | UTF-8编码或者7-ASCII编码 |
bytes | string | str |