上一次經過投影的方式進行了文本塊分割,但這種方法有很大的侷限性,要求分行清晰、不能有字符跨多行、不能傾斜,並且對噪聲比較敏感。仍是拿上一回的圖片,可是我在上面加了一個比較大的字,得出的結果就有問題了:c#
能夠看到,因爲右下角大大的「測」字跨了多行,致使水平投影分行時就出錯了。ide
本次換一種方法,基於連通性分析來作。簡單講,就是把圖像作必定的膨脹操做,使得同一個字符的不一樣部分以及相鄰字符相互重疊到一塊兒,變成一個總體,而後再經過分析找到每個獨立的塊,排除掉噪聲,剩下的基本就是符合條件的結果了。spa
直接上代碼,後面再分析:blog
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(); } } }
下面來一步一步分析。讀入的原圖是這樣的:圖片
轉換到灰度圖並膨脹處理後,已經能夠大體看出同一文本塊的多個字符已經連到一塊兒了:get
二值化後的圖像:string
作連通性分析後,原始分析出的結果是這樣的:it
Cv.DrawContours(src, contour, color, color, 1);
對每一個連通域取外接矩形,獲得的最終結果是這樣的:
io
能夠看到效果比以前好了不少,比較大的字能夠做爲獨立的文本塊被檢測出來了。另外即便是同一行的文本塊,也會有輕微的上下浮動,再也不是絕對按行對齊了。class
未經許可嚴禁轉載。