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);

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

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

    未经许可严禁转载。

  • 相关阅读:
    bzoj 4012: [HNOI2015]开店
    POJ 1054 The Troublesome Frog
    POJ 3171 Cleaning Shifts
    POJ 3411 Paid Roads
    POJ 3045 Cow Acrobats
    POJ 1742 Coins
    POJ 3181 Dollar Dayz
    POJ 3040 Allowance
    POJ 3666 Making the Grade
    洛谷 P3657 [USACO17FEB]Why Did the Cow Cross the Road II P
  • 原文地址:https://www.cnblogs.com/BoyTNT/p/11812562.html
Copyright © 2011-2022 走看看