经过之前的迁移训练,其实在某些方面会比通用的模型要好一些,但是直接投入实际生产使用还是差一些,所以这里读一下paddleocr的源代码去了解一下现有的预处理和后处理情况。
1. 预处理
预处理也分为cls分类
,db检测
,east检测
,rec识别
这几种情况,没有在FAQ文件中搜到统一的文件夹,自己去手动找找。根据PaddleOCR 的整体目录结构-tree结构可知,与预处理相关的内容
\PaddleOCR\tools
- 读了一下源码,其中,
predict_cls.py
文件中只有一个类class TextClassifier(object)
,其中有两个比较重要的函数 - resize_norm_img(self, img) ,对图像做padding/缩放,对小的图片就做padding,对大的图片就缩小,将所有输入的batch的图像控制在一个相似的范围
__call__()
函数,返回img_list
(图片列表),cls_res
(分类结果,包括标签和得分), elapse(耗时,时间流逝elapse += time.time() - starttime
)
predict_det.py
文件
可以看到,其实就是一个类,其中有6个函数,
order_points_clockwise
函数(按照顺时针对点排序),其实也都是一些关于检测的控制函数。
predict_rec.py
文件,也主要是确定不同种类的解码方式涉及的字符集,重新变换图像的尺寸。不涉及什么传统CV领域的模糊,腐蚀,膨胀,边缘提取等操作。
- 另外,还有
PaddleOCR\deploy\cpp_infer\include\preprocess_op.h
,不过这里的预处理也是很基础的。与这个文件配套的还有对应的.cpp
文件,这里的预处理和后处理都属于部署之后的(推理时使用的预处理和后处理) - 不过这里的预处理和日常所想象的预处理,不太一样——这里的预处理,主要是来自配置文件,与我以为的图片送入模型之前的一些预处理方式不太一样。
PaddleOCR的deploy
文件夹中的预处理主要包括以下内容(为了加速,都是C++
语言写的):
-
void Permute::Run
(重新排列),这个函数的功能是将输入图片的像素点(主要是channel)进行重排,使之符合opencv的格式。
双冒号是域操作符,参考:c语言的双冒号是什么意思::
-
void Normalize::Run
(归一化),将像素点除以255,再进行归一化,缩小数值,控制在同一个量级。 -
void ResizeImgType0::Run
,当图像的长度或者宽度超过了max_size_len
,就要对图形进行的尺寸进行重新缩放 void CrnnResizeImg::Run
void ClsResizeImg::Run
2. 后处理
有的检测的后处理在
ppocr/postprocess
路径下
查看这个文件夹可以看到,主要就是cls分类
,db检测
,east检测
,rec识别
这几种情况的后处理
其中,
-
cls分类
的后处理文件中只有一个类:class ClsPostProcess(object)
,作用是:文本标签和文本索引之间的转换。 -
db检测
的后处理文件也是一个类,class DBPostProcess(object)
,类中有几个函数:
boxes_from_bitmap()
从二值化图像中获取boxes,返回标记框的坐标和得分;unclip()
,控制标记框与文字之间的距离,这个函数返回一个扩展因子(boxes要扩大的数量)get_mini_boxes()
返回最小的boxesbox_score_fast
返回boxes的score_call_()
函数 返回所有的boxes列表
-
rec识别
的后处理文件就比较多,有四个类,
class BaseRecLabelDecode(object)
,这个类主要就是判断字符集,规定了支持的字符集(中文/英文等),特殊字符,文本序号和文本索引的转换class CTCLabelDecode(BaseRecLabelDecode)
,和上面的基类差不多,都是涉及文本解码,将文本序号和文本索引转换,确定字符集/特殊字符/忽略字符等,其余下面两个类似。class AttnLabelDecode(BaseRecLabelDecode)
,class SRNLabelDecode(BaseRecLabelDecode)
,
其实上面的db检测
的后处理措施和部署中使用c++
写的后处理方式差不多。
部署的后处理
文件位于PaddleOCR\deploy\cpp_infer\src\postprocess_op.cpp
这个文件夹中,主要包含以下函数:
-
void PostProcessor::GetContourArea
获取轮廓区域 cv::RotatedRect PostProcessor::UnClip
-
float **PostProcessor::Mat2Vec
,将图像的矩阵转换为float类型的array数组返回 -
std::vector<std::vector<int>>PostProcessor::OrderPointsClockwise
对点进行顺时针方向的排序(从左到右,从上到下) (order points clockwise[顺时针方向]) -
std::vector<std::vector<float>> PostProcessor::Mat2Vector
将图像的矩阵转换为float类型的vector数组返回 -
bool PostProcessor::XsortFp32(std::vector<float> a, std::vector<float> b)
判断元素为浮点数float的vector的精度,如果a中元素的精度不等于b中元素的精度,则返回false -
bool PostProcessor::XsortInt(std::vector<int> a, std::vector<int> b)
和上面的很像,只是浮点数变成了整数 -
std::vector<std::vector<float>> PostProcessor::GetMiniBoxes
没看懂这个函数,就知道作用是返回最小的boxs -
float PostProcessor::BoxScoreFast(std::vector<std::vector<float>> box_array,cv::Mat pred)
返回score -
std::vector<std::vector<std::vector<int>>> PostProcessor::BoxesFromBitmap(const cv::Mat pred, const cv::Mat bitmap, const float &box_thresh, const float &det_db_unclip_ratio)
这个应该是DB(差分二值化)相关的内容,涉及到box_thresh
(低于这个阈值的boxs不予显示)和det_db_unclip_ratio
(文本框扩张的系数,关系到文本框的大小) std::vector<std::vector<std::vector<int>>> PostProcessor::FilterTagDetRes(std::vector<std::vector<std::vector<int>>> boxes, float ratio_h, float ratio_w, cv::Mat srcimg)