OpenCVsharp实现提取文本区域检测 来提取图片中的文本区域坐标 提到OCR识别这块,就想提一下站长早几年从事的开发医疗自助打印系统的工作。
医疗自助打印应用
早前从事医疗自助打印系统的时候 ,胶片自助打印这一块时很核心的一块,胶片这块业务流程有两大难点 对接放射设备、图片的ocr识别。
DICOM C-PrintSCP
对接各类放射打印设备(不多说 有这块烦恼的又想偷懒买成品的可以看看)
FO-DICOM胶片C-PrintSCP 虚拟打印服务端实现源码
医疗胶片ocr识别归档
二、业务流程最核心的功能 自动化ocr识别系统
对于整个系统来说最大的利益点就是胶片打印,基本软件系统就是附赠品 耗材费用才是盈利点,但胶片打印识别这块也是最麻烦的,不同设备, 不同医院 ,不同医生,甚至于不同患者都有可能导致胶片上的字体位置、大小、字体的变化,最终就可能影响识别效果最终导致识别结果错误。
为了解决这个问题,站长围绕着谷歌的开源ocr组件tesseract-ocr做了一系列辅助ocr识别的工具 ,文本区域检测工具就是其中一项 节省了胶片整张识别的效率问题 核心代码也是整合修改自网络上分享的一些代码。
文本区域检测的逻辑就是 通过对图片二值化处理再通过反复腐蚀膨胀得到一个接近矩形的方块 然后将这些矩形框选出来就得到了文本所在区域 再根据一系列过滤规则提取到我们所需要的区域 进行识别减少不必要的图像识别 以提升系统整体效率
文本检测核心代码
- 文字区域处理
public void FindText(string imgPath)
{
Mat dilation2 = new Mat();
//读取灰度图
using (Mat src = new Mat(imgPath, ImreadModes.Grayscale))
{
Cv2.ImShow("原始图像", src);
//1.Sobel算子,x方向求梯度
Mat sobel = new Mat();
Cv2.Sobel(src, sobel, MatType.CV_8U, 1, 0, 3);
//2.二值化
Mat binary = new Mat();
Cv2.Threshold(sobel, binary, 0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
//3. 膨胀和腐蚀操作的核函数
Mat element1 = new Mat();
Mat element2 = new Mat();
OpenCvSharp.Size size1 = new OpenCvSharp.Size(20, 20);
OpenCvSharp.Size size2 = new OpenCvSharp.Size(16, 10);
element1 = Cv2.GetStructuringElement(MorphShapes.Rect, size1);
element2 = Cv2.GetStructuringElement(MorphShapes.Rect, size2);
//4. 膨胀一次,让轮廓突出
Mat dilation = new Mat();
Cv2.Dilate(binary, dilation, element2);
//5. 腐蚀一次,去掉细节,如表格线等。注意这里去掉的是竖直的线
Mat erosion = new Mat();
Cv2.Erode(dilation, erosion, element1);
//6. 再次膨胀,让轮廓明显一些
Cv2.Dilate(erosion, dilation2, element2, null, 3);
Cv2.ImShow("文本处理效果", dilation2);
}
this.FindTextRegion(dilation2, imgPath);
}
- 将处理过的图像里的文字区域框选出来
public void FindTextRegion(Mat dilation,string film) { Mat mat = new Mat(film); // 1. 查找轮廓 OpenCvSharp.Point[][] contours; HierarchyIndex[] hierarchly; Rect biggestContourRect = new Rect(); Cv2.FindContours(dilation, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple); // 2. 筛选那些面积小的 int i = 0; foreach (OpenCvSharp.Point[] contour in contours) { double area = Cv2.ContourArea(contour); //面积小的都筛选掉 if (area < 1000) { continue; } //轮廓近似,作用很小 double epsilon = 0.001 * Cv2.ArcLength(contour, true); //找到最小的矩形 biggestContourRect = Cv2.BoundingRect(contour); if (biggestContourRect.Height > (biggestContourRect.Width * 1.2)) { continue; } //画线 mat.Rectangle(biggestContourRect, new Scalar(0, 255, 0), 2); } Cv2.ImShow("文字区域框选", mat); }
- 调用方法得到文本区域结果
string film = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "测试胶片.jpg"); FindText(film);
代码运行效果图
面对不同大小或者间隔不同的图片需要针对性的设置算子参数 来提升准确度,这样就拿到了文字区域的具体位置然后配合ocr做识别效果还是挺不错的