往期关于表格提取
简单总结下
- 前面写了些借助opencv实现表格的一些方法,但是内容识别我是用的paddleocr(我只是切割后识别,但是paddleocr其实识别结果是自带坐标的也就是说直接有表格识别的能力,但是这东西吧不能通用有些遇到问题还是需要个性化处理下)。
- opencv的win环境是官网下包就可以了,也可以自己编译。
- paddleocr的dll、so环境搭建文章前面也写了点(只不过win和linux都需要自己编译)。
- 借助于专业的模型处理有时候有时候也需要用opencv处理下的,另外paddleocr也有依赖opencv的地方。
- 如果是c++、python的话就可以直接开搞了,但是其他语言例如用java需要动态库,本篇简单说下dll代码吧(提前说下因为我碰到C++懵逼了,第一次我想到的是结果json序列化但是那个包引入有点麻烦我放弃了,然后我想的是直接返回识别结果JNA传递又没搞定,最后不想折腾了直接拼接字符串)。
- paddleocr也可以自己训练这个我不会。
- 生成dll还是其他一些操作可以借助AI给点实例参考。
cmake遇到得问题
- cmake我也不太熟悉但是好多需要编译的都需要用这个处理。
- cmake有些依赖github上的包clone不了,或者超时timeout(即使开了代理也不行)。然后把对应的makefile文件的https改为git,
java
# GIT_REPOSITORY https://github.com/LDOUBLEV/AutoLog.git
GIT_REPOSITORY git@github.com:LDOUBLEV/AutoLog.git
导出函数
写的有点啰嗦拼拼字符串只能说能跑
c++
__declspec(dllexport) char* VectorResult(char* image_dir);
char* VectorResult(char* image_dir) {
std::vector<cv::String> cv_all_img_names;
cv::glob(image_dir, cv_all_img_names);
std::vector<cv::Mat> img_list;
for (int i = 0; i < cv_all_img_names.size(); ++i) {
cv::Mat img = cv::imread(cv_all_img_names[i], cv::IMREAD_COLOR);
if (!img.data) {
std::cerr << "[ERROR] image read failed! image path: "
<< cv_all_img_names[i] << std::endl;
continue;
}
std::cerr << cv_all_img_names[i] << std::endl;
img_list.push_back(img);
}
//这里可以获取到所有结果
std::vector<std::vector<OCRPredictResult>> ocr_results = ocr.ocr(img_list, FLAGS_det, FLAGS_rec, FLAGS_cls);
int size = ocr_results[0].size();
std::string result;
std::cout << size << std::endl;
//OCRPredictResult* data = new OCRPredictResult [size];
for (size_t i = 0; i < size; ++i) {
std::string ret_str = (std::to_string(i)).append("|").append(ocr_results[0][i].text).append("|").append(std::to_string(ocr_results[0][i].score)).append("|").append(std::to_string(ocr_results[0][i].cls_label)).append("|").append(std::to_string(ocr_results[0][i].cls_score));
//data[i] = ocr_results[0][i];
for (auto j = 0; j != ocr_results[0][i].box.size(); ++j) {
std::cout << ocr_results[0][i].box[j][0] <<" "<< ocr_results[0][i].box[j][1] << std::endl;
ret_str.append("|").append(std::to_string(ocr_results[0][i].box[j][0])).append("|").append(std::to_string(ocr_results[0][i].box[j][1]));
}
//ret_str.append(";");
result.append(ret_str.append("\r\n"));
}
//OCRRESUTL sv = { size, data };
char* result2 = new char[result.size() + 1];
strcpy(result2, result.c_str());
return result2;
}
JNA复杂对象遇到的问题
- 我是直接用AI给的代码实例,但是里面有些头疼的问题就是这中间调用的过程不透明有些报错了摸不着头脑。
- 但是还有以下几个问题提前避免下。
- 复杂对象也就是对应c++里的结构体,但是里面给的类型需要注意例如vector我在网上看大部分也是处理为对应的结构体。
- java里面声明也很简单,但是注意属性应该用public不然参数指定顺序会报错的。
typescript
@Override
protected List<String> getFieldOrder() {
return Arrays.asList("box", "text", "score", "cls_score", "cls_label");
}
- 对象反序列化read/useMemory基类是protect类型的需要覆盖下,AI给的是直接调用方法的。
typescript
@Override
public void read() {
super.read();
}
@Override
public void useMemory(Pointer p) {
super.useMemory(p);
}
paddleocr主要是这个日志包,下面是路径。
读光表格模型
读光表格分为有线和无线,如果用python的可以试下。网上应该是作者出了个onnx的版本,这个导出的模型没有默认长和宽这个需要注意下,另外模型转onnx后运算处理逻辑还是太复杂了(主要一些数学函数处理)java没有这方面的类库不好处理也试着用AI翻译下但还是放弃了。
AI大部分能用,但对于一些专业化小众的可能会有点问题,例如我上面遇到的两个问题。