在《图片文字识别》项目中,有两个模块:文本检测和字符识别,为充分利用机器性能,我们单独封装了两个模块的SDK,由服务层根据机器性能设置各个模块的实例数量。文本检测模块需要输出多个文本框,包括文本框的图像数据,文本框宽高,文本框在图像中位置。最开始SDK的预测接口设计如下:
/// @brief 文本框检测接口
/// @param[in] handle 已初始化句柄
/// @param[in] data 输入图像文件的二进制流数据(没有解码)
/// @param[in] length 二进制流数据的长度
/// @param[out] p_texts_array 预测的文本框结构体信息
/// @param[out] p_texts_count 预测的文本框数目
/// @return 成功返回DY_OK,失败返回其他错误码,错误码定义在dy_common.h 中,如DY_E_FAIL等
DY_SDK_API dy_result_t
dy_east_text_detect_process(dy_handle_t handle,
const char* data,
int length,
dy_text_detect_t **p_texts_array,
int *p_texts_count);
接口输出文本框的个数和文本框信息,文本框结构体信息如下;
/// 图像中的坐标点信息
typedef struct {
float x; ///< 点的水平方向坐标,为浮点数
float y; ///< 点的竖直方向坐标,为浮点数
} dy_pointf_t;
/// @brief 检测后的文本框信息
typedef struct {
char*textImageData; ///< 文本框图像数据
int textImageWidth; ///< 文本框图像宽度
int textImageHeight; ///< 文本框图像高度
dy_pointf_t startPoint; ///< 文本框左上坐标点
dy_pointf_t endPoint; ///< 文本框右下坐标点
} dy_text_detect_t;
与wsd对接后,对方反馈go语言中无法接收指针的指针结构体,包括int、float等类型指针的指针,只能接收char类型指针的指针,所以需要寻找其他的解决方案。protobuf在多个深度学习框架Caffe、Tensorflow、Pytorch中作为数据流转模块,可以解决我们遇到的问题,所以我们准备使用protobuf来进行数据传输。
protobuf是由谷歌开源的对象序列化和反序列化的工具,protobuf和Xml类似,都是数据描述工具。可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。甚至可以在无需重新部署程序的情况下更新数据结构。
protc编译器就在当前目录下,protobuf头文件在 /home/ImageLab/protobuf/include目录下,protobuf.a在 /home/ImageLab/protobuf/lib目录下
syntax = "proto2"; //proto版本
package mod_east_text_detect_cpp; //包名
message dy_text_detect_t //结构体信息
{
required bytes text_image_data= 1; // 文本框图像数据
required int32 text_image_width= 2; // 文本框图像宽度
required int32 text_image_height= 3; // 文本框图像高度
required float text_left_top_point_x = 4; // 文本框在原始图像中的左上点x坐标
required float text_left_top_point_y = 5; // 文本框在原始图像中的左上点y坐标
required float text_right_bottom_point_x = 6; // 文本框在原始图像中的右下角x坐标
required float text_right_bottom_point_y = 7; // 文本框在原始图像中的右下角y坐标
}
message text_infor
{
repeated dy_text_detect_t text_info = 8; // 文本框信息
}
required:必须赋值的字段
optional:可有可无的字段
repeated:可重复字段(变长字段),类似于数组
使用protoc可执行程序,执行以下命令:
protoc所在目录 mod_east-text_detect_cpp.text_infor.proto所在目录 --cpp_out=./src/
示例如下:
/home/protobuf/bin/protoc mod_east-text_detect_cpp.text_infor.proto --cpp_out=./src/
其中protoc为编译器,mod_east-text_detect_cpp.text_infor.proto为编写的proto文件。
生成的c++文件 mod_east-text_detect_cpp.text_infor.pb.h和 mod_east-
text_detect_cpp.text_infor.pb.cc存放在当前目录下src文件夹中,对象的序列化和反序
列化就可以通过这两个文件完成操作了。
/// @brief 文本检测接口
/// @param[in] handle 已初始化句柄
/// @param[in] data 输入图像文件的二进制流数据
/// @param[in] length 二进制流数据的长度
/// @param[out] protobuffer 返回序列化后的protobuffer字符串
/// @param[out] protobuffer_len 返回序列化后的protobuffer字符串长度
/// @return 成功返回DY_OK,失败返回其他错误码,错误码定义在dy_common.h 中,如DY_E_FAIL等
DY_SDK_API dy_result_t
dy_east_text_detect_process(dy_handle_t handle,
const char* data,
int length,
char **protobuffer,
int *protobuffer_len);
/// @brief 数据调用及解析如下
char *res_pb = NULL; //输出的protobuf字符串指针
int len_pb; //输出的protobuf字符串长度
dy_result_t res = dy_east_text_detect_process(my_data->text_handle, dataBuf, fileLen, &res_pb, &len_pb);
std::string str_pb; //接收probobuf字符串的对象
str_pb.assign(res_pb, len_pb); //根据字符串长度获取字符串的内容
mod_east_text_detect_cpp::text_infor text; //probobuf对象
bool ret = text.ParseFromString(str_pb); //反序列化,从字符串获取文本框数据信息
if (ret)
{
for (int i = 0; i < text.text_info_size(); i ++)
{
//获取文件框坐标
std::cout << text.text_info(i).text_left_top_point_x() << std::endl;
std::cout << text.text_info(i).text_left_top_point_y() << std::endl;
std::cout << text.text_info(i).text_right_bottom_point_x() << std::endl;
std::cout << text.text_info(i).text_right_bottom_point_y()<< std::endl;
//获取文本框宽度
std::cout << text.text_info(i).text_image_width() << std::endl;
//获取文本框高度
std::cout << text.text_info(i).text_image_height() << std::endl;
//获取文本框图像数据
const char * image = text.text_info(i).text_image_data().c_str();
}
}
else
{
std::cout << "parse fail" << std::endl;
}
_text.clear_text_info();
cv::Mat _text_img[10];
for(int i = 0; i < 10; ++i)
{
mod_east_text_detect_cpp::dy_text_detect_t* msg = _text.add_text_info();
msg->set_text_image_width(_text_img[i].cols);
msg->set_text_image_height(_text_img[i].rows);
msg->set_text_image_data((char*)_text_imgp[i].data,_text_img[i].cols*_text_img[i].rows*3);
}
_text.SerializeToString(&_proboBuffer);
const char* buf = _proboBuffer.c_str();
*protobuffer_len = _proboBuffer.length();
*protobuffer = (char*)buf;
SET(LIB_H ${CMAKE_SOURCE_DIR}/mod_east-text_detect_cpp.text_infor.pb.h)
SET(LIB_SRC ${CMAKE_SOURCE_DIR}/mod_east-text_detect_cpp.text_infor.pb.cc)
ADD_LIBRARY(DyETD SHARED ${LIB_H} ${LIB_SRC})
target_link_libraries(DyETD libprotobuf.a)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W85D6Jsq-1675326921638)(null)]
如上图所示, protobuf编译时出现了与zlib的冲突问题,解决方案是重新编译zlib,并加上-fPIC编译参数,具体如下: