zoukankan      html  css  js  c++  java
  • 基于OpenCV.Net连通域分析进行文本块分割

    上一次通过投影的方式进行了文本块分割,(见 https://www.cnblogs.com/BoyTNT/p/11812323.html )但这种方法有很大的局限性,要求分行清晰、不能有字符跨多行、不能倾斜,而且对噪声比较敏感。还是拿上一回的图片,但是我在上面加了一个比较大的字,得出的结果就有问题了:

    可以看到,由于右下角大大的“测”字跨了多行,导致水平投影分行时就出错了。

     本次换一种方法,基于连通性分析来做。简单讲,就是把图像做一定的膨胀操作,使得同一个字符的不同部分以及相邻字符相互重叠到一起,变成一个整体,然后再通过分析找到每一个独立的块,排除掉噪声,剩下的基本就是符合条件的结果了。

    直接上代码,后面再分析:

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
     
    using OpenCvSharp;
    using OpenCvSharp.Extensions;
    using OpenCvSharp.Utilities;
     
    namespace OpenCvTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                //读入源文件
                var src = IplImage.FromFile("source.jpg");
                    
                //转换到灰度图
                var gray = Cv.CreateImage(src.Size, BitDepth.U8, 1);
                Cv.CvtColor(src, gray, ColorConversion.BgrToGray);
                    
                //做一下膨胀,x与y方向都做,但系数不同
                //使用了Erode方法,腐蚀操作,针对白色区域,所以等效于对文字进行了膨胀
                var kernal = Cv.CreateStructuringElementEx(5, 2, 1, 1, ElementShape.Rect);
                Cv.Erode(gray, gray, kernal, 2);
                    
                //二值化
                Cv.Threshold(gray, gray, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);
                    
                //检测连通域,每一个连通域以一系列的点表示,FindContours方法只能得到第一个域
                var storage = Cv.CreateMemStorage();
                CvSeq<CvPoint> contour = null;
                Cv.FindContours(gray, storage, out contour, CvContour.SizeOf, ContourRetrieval.CComp, ContourChain.ApproxSimple);
                var color = new CvScalar(0, 0, 255);
                    
                //开始遍历
                while (contour != null)
                {
                    //得到这个连通区域的外接矩形
                    var rect = Cv.BoundingRect(contour);
                        
                    //如果高度不足,或者长宽比太小,认为是无效数据,否则把矩形画到原图上
                    if(rect.Height > 10 && (rect.Width * 1.0 / rect.Height) > 0.2)
                        Cv.DrawRect(src, rect, color);
                            
                    //取下一个连通域
                    contour = contour.HNext;
                }
                Cv.ReleaseMemStorage(storage);
                    
                //显示
                Cv.ShowImage("Result", src);
                Cv.WaitKey();
                Cv.DestroyAllWindows();
            }
        }
    }

    下面来一步一步分析。读入的原图是这样的:

    转换到灰度图并膨胀处理后,已经可以大致看出同一文本块的多个字符已经连到一起了:

    二值化后的图像:

    做连通性分析后,原始分析出的结果是这样的:

    Cv.DrawContours(src, contour, color, color, 1);

    对每个连通域取外接矩形,得到的最终结果是这样的:

    可以看到效果比之前好了很多,比较大的字可以作为独立的文本块被检测出来了。另外即使是同一行的文本块,也会有轻微的上下浮动,不再是绝对按行对齐了。

    未经许可严禁转载。

  • 相关阅读:
    C#_Assembly-Reflection_程序集与反射
    C#_event_事件
    C#_扩展方法
    C#_Delegate_泛型
    C#_正则表达式
    C#_序列化
    Unity_ClickToShow_FadeInAndOut
    RecordToday
    写作技巧
    高效休息法
  • 原文地址:https://www.cnblogs.com/BoyTNT/p/11812562.html
Copyright © 2011-2022 走看看