OpenCV + EAST 文字检测模型需预处理图像:输入必须缩放至宽高均为32整数倍且长边≤1024,等比缩放后padding,归一化用scalefactor=1.0/127.5和mean=(123.68,116.78,103.94)。

OpenCV + EAST 文字检测模型能直接用,但必须预处理图像
OpenCV 自带的 cv::dnn::readNet 可加载预训练的 EAST 检测模型(frozen_east_text_detection.pb),它输出的是旋转矩形(RBOX)坐标,不是像素级分割。但模型对输入有硬性要求:图像必须被缩放到宽度和高度均为 32 的整数倍,且长边不超过 1024(否则显存溢出或推理失败)。常见错误是直接喂入原始截图,结果 net.forward() 返回全零或 shape 不匹配的 blob。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
cv::resize先等比缩放,再 padding 到最近的 32 倍尺寸(别用INTER_NEAREST插值,文字边缘会锯齿化) - 归一化时用
scalefactor=1.0/127.5、mean=(123.68,116.78,103.94)—— 这是 EAST 训练时用的 ImageNet 均值,不是 OpenCV 默认的 [0,0,0] - 如果图像中文字极小(cv::pyrUp 上采样 1–2 级再送入,但别超过原图 2 倍,否则模糊失真
cv::findContours 在二值图上容易把连笔字切成多块
纯传统方法(如 OTSU + 膨胀 + cv::findContours)适合印刷体、高对比度场景,但对中文行文尤其危险:汉字笔画粘连(如「口」「吕」「品」)、标点紧贴文字、或者手写体轻微倾斜,都会让 cv::findContours 把一个词框成三四个碎片矩形。更糟的是,cv::boundingRect 输出的是轴对齐矩形(AABB),无法表达倾斜文本行。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先用
cv::morphologyEx做横向闭运算(MORPH_CLOSE+cv::getStructuringElement(CV_SHAPE_RECT, {30,1})),把同一行文字“粘”成一个连通域 - 对每个轮廓调用
cv::minAreaRect而非cv::boundingRect,拿到带角度的RotatedRect,再用cv::boxPoints转成四顶点坐标 - 过滤掉宽高比
aspect_ratio 或面积 <code>area 的轮廓——它们大概率是噪点或标点
Python cv2.dnn 推理快但 C++ 版本要手动管理内存和 blob 维度
C++ 调用 EAST 时,cv::dnn::blobFromImage 输出的 cv::Mat 是 NCHW 格式(batch=1, channel=3, height, width),而 OpenCV 4.5+ 的 cv::dnn::Net::forward 默认返回 NHWC,容易导致 outputBlob.size[2] 访问越界。另外,C++ 没有 Python 的自动内存回收,blob 生命周期必须严格匹配 net 推理周期。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- forward 后立刻用
outputBlob.reshape(1, outputBlob.total()/4)拉平成 [N, 4] 形状,其中每行是 [x1,y1,x2,y2](EAST 输出的是 4 点坐标,不是中心+宽高) - 用
cv::dnn::NMSBoxes做后处理时,传入的scores必须是std::vector<float></float>,不能是cv::Mat;否则编译通过但运行时崩溃 - 若集成到 Qt 或 Android NDK,记得在
cv::dnn::Net构造前调用cv::dnn::setPreferableTarget(net, cv::dnn::DNN_TARGET_CPU),GPU 后端(如 DNN_BACKEND_INFERENCE_ENGINE)在移动端兼容性差
定位结果坐标必须映射回原始图像尺寸,缩放系数别算反
EAST 输出的坐标是基于缩放后图像的归一化值(0~1),很多人直接乘以缩放后尺寸,却忘了原始图可能被 padding 过。典型错误是:原始图 1920×1080 → 缩放为 736×416 → padding 到 768×448,结果把坐标乘了 768 和 448,导致框偏移几十像素。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 记录缩放过程中的两个比例:
scale_x = resized_width / original_width,scale_y = resized_height / original_height;padding 部分不参与缩放,只影响输入 blob,不影响坐标映射 - 对每个检测框的 4 个顶点,先除以 blob 输入尺寸(如 768×448),再分别除以
scale_x和scale_y,得到原始图坐标 - 用
cv::rectangle可视化前,务必用cv::Point2f构造并cv::round()取整——浮点坐标直接转cv::Point会截断,造成 0.9 像素偏移累积
最易忽略的是:不同来源的模型(如自己训的 CRNN 检测头 vs 官方 EAST)输出坐标格式完全不同,有的给中心点+wh,有的给左上+右下,有的给四点顺时针顺序——不看模型文档直接套用后处理逻辑,框就永远对不上。


















