OpenCV實現基於傅里葉變換的旋轉文本校訂

代碼html

        先給出代碼,再詳細解釋一下過程:ios

 


過程
讀取圖片git

 

        srcImg.empty()用來判斷是否成功讀進圖像,若是srcImg中沒有數據,在後面的步驟會產生內存錯誤。
        因爲處理的是文本,彩色信息不會提供額外幫助,因此要用CV_LOAD_IMAGE_GRAYSCALE代表以灰度形式讀進圖像。
        假定讀取的圖像以下:github

english-rotation

旋轉原圖像(可選)算法

 

        若是手頭沒有這樣的傾斜圖像,能夠選擇一張正放的文本圖像,再把第12行#define DEGREE那行前的註釋符號去掉。而後這部分代碼就會把所給的圖像旋轉你規定的角度,再交給後面處理。app

圖像延擴ide

 

        OpenCV中的DFT採用的是快速算法,這種算法要求圖像的尺寸是二、3和5的倍數時處理速度最快。因此須要用getOptimalDFTSize()找到最適合的尺寸,而後用copyMakeBorder()填充多餘的部分。這裏是讓原圖像和擴大的圖像左上角對齊。填充的顏色若是是純色對變換結果的影響不會很大,後面尋找傾斜線的過程又會徹底忽略這一點影響。函數

DFT測試

 

        DFT要分別計算實部和虛部,把要處理的圖像做爲輸入的實部、一個全零的圖像做爲輸入的虛部。dft()輸入和輸出應該分別爲單張圖像,因此要先用merge()把實虛部圖像合併,分別處於圖像comImg的兩個通道內。計算獲得的實虛部仍然保存在comImg的兩個通道內。ui

得到DFT圖像

 

        通常都會用幅度圖像來表示圖像傅里葉的變換結果(傅里葉譜)。
        幅度的計算公式:magnitude = sqrt(Re(DFT)^2 + Im(DFT)^2)。
        因爲幅度的變化範圍很大,而通常圖像亮度範圍只有[0,255],容易形成一大片漆黑,只有幾個點很亮。因此要用log函數把數值的範圍縮小。

 

        dft()直接得到的結果中,低頻部分位於四角,高頻部分位於中間。習慣上會把圖像作四等份,互相對調,使低頻部分位於圖像中心,也就是讓頻域原點位於中心。

 

fft-mag

        雖然用log()縮小了數據範圍,但仍然不能保證數值都落在[0,255]以內,因此要先用normalize()規範化到[0,1]內,再用convertTo()把小數映射到[0,255]內的整數。結果保存在一幅單通道圖像內:

 

english-mag

Hough直線檢測
        從傅里葉譜能夠明顯地看到一條過中心點的傾斜直線。要想求出這個傾斜角,首先要在圖像上找出這條直線。
        一個很方便的方法是採用霍夫(Hough)變換檢測直線。

 

        Hough變換要求輸入圖像是二值的,因此要用threshold()把圖像二值化。
        二值化的一種結果:

english-binary

 

        這一部分用HoughLines()檢測圖像中可能存在的直線,並把直線參數保存在向量組lines中,而後繪製出找到的直線。
        兩個參數GRAY_THRESH和HOUGH_VOTE須要手動指定,不一樣的圖像須要設置不一樣的參數,同一段文本旋轉不一樣的角度也須要不一樣的參數。GRAY_THRESH越大,二值化的閾值就越高;HOUGH_VOTE越大,霍夫檢測的投票數就越高(須要更多的共線點來肯定一條直線)。說白了,若是發現二值化圖像中直線附近有不少散點,就要適當提升GRAY_THRESH;若是發現從二值圖像的一條直線上檢測到了幾條角度相差很小的直線,就須要適當提升HOUGH_VOTE。咱們但願獲得的結果時恰好檢測到三條直線(有時只能檢測到一條直線,後面會給出一個例子)。
        檢測到的直線:

english-line

計算傾斜角
        上面獲得了三個角度,一個是0度,一個是90度,另外一個就是咱們所須要的傾斜角。要把這個角找出來,並且要考慮偏差。

 

        因爲DFT的特色,只有輸入圖像是正方形時,檢測到的角纔是文本真正旋轉的角度。但咱們的輸入圖像不必定是正方形的,因此要根據圖像的長寬比改變這個角度。
        還有一個須要注意的細節,雖然HoughLines()輸出的傾斜角在[0,180)之間,但在[0,90]和(90,180)之間這個角的含義是不一樣的。請看圖示:

 

hough-transformation

        當傾斜角大於90度時,(180-傾斜角)纔是直線相對豎直方向的偏離角度。在OpenCV中,逆時針旋轉,角度爲正。要把圖像轉回去,這個角度就變成了(傾斜角-180)。
校訂圖像
        最後一步,固然是把圖像轉回去

 

 

        先用getRotationMatrix2D()得到一個2*3的仿射變換矩陣,再把這個矩陣輸入warpAffine(),作一個單純旋轉的仿射變換。warpAffine()的最後一個參數Scalar(255,255,255)是把因爲旋轉產生的空白用白色填充。
        校訂的結果:

english-correction


一個檢測單條直線的例子
原始圖像:

single-english-rotation

傅里葉譜:

single-english-mag

        只有一條明顯的直線。還好僅有的這條直線正是咱們所須要的。
檢測直線:

single-english-line

校訂結果:

single-english-correction


對中文的效果
        咱們來試試看這段程序對中文的校訂效果。
輸入圖像:

chinese-rotation

傅里葉譜:

chinese-mag

        能夠發現有許多條平行的亮線,其中過頻域原點的那條長度最長,最容易檢測出來。
檢測直線:

chinese-line

校訂結果:

chinese-correction

        雖然中文和英文在文字上有很大的不一樣,但字母(或者文字)的高度比較一致,使得行與行之間的分隔很明顯。因此它們的頻域特徵是類似的。


對其餘語言文字的效果
        我從IMDB.com摘取影片《教父》的英文介紹,而後用谷歌翻譯成其餘文字進行測試。
阿拉伯語

arabic-rotation

arabic-mag

arabic-line

一枚反例
老撾語:

lao-rotation

傅里葉譜:

lao-mag

一種二值化的結果:

lao-binary

直線檢測:

lao-line

        這種文字的不少字母的上下方多了不少「筆畫」(我不知道該怎麼稱呼那些小曲線),讓行與行之間的分離變得不明顯,使得頻域特徵變得不明顯。
        雖然用肉眼能夠看出傅里葉譜中存在一條傾斜的直線,但它的亮度過低,二值化過程很難排除噪聲,致使直線檢測會首先檢出噪聲產生的直線。這也是個人程序目前受限之處。須要增長一個過濾散點噪聲的步驟以增長程序的適用範圍。


參考:Discrete Fourier Transform — OpenCV 2.4.7.0 documentation

代碼還能夠在這裏下載:https://github.com/johnhany/textRotCorrect

原文:http://johnhany.net/2013/11/dft-based-text-rotation-correction/

相關文章
相關標籤/搜索