源地址:http://blog.csdn.net/rushkid02/article/details/9242415
本文介紹3種基本的字符形狀歸一化算法(Character Shape Normalization)。字符歸一化是光學字符識別中的一個子步驟,給定一個字符區域,我們要做的就是將該區域內的字符歸一化到一個標准模板大小,然后才能提取特征,並送給分類器做具體的識別。好的歸一化算法可以盡量提高后續特征提取在同一類內的一致性。
先來看一個例子,假如上帝擁有一個完美的字符歸一化算法,那么他將可以做到如下所示的效果:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
圖1,完美的歸一化:左邊為原始字符區域,右邊為歸一化后的結果。
如果說我們能做到上述結果,那么也就無需再做特征提取,也無需再做訓練,而只需簡單的模板匹配即可得到100%准確的分類結果。可以看到,上述算法的能力在於:
1. 歸一化到標准模板大小
2. 傾斜校正
3. 筆畫寬度歸一化
4. 字形歸一化
可惜的是,今天介紹的幾種常見算法僅能保證第1點的實現,而2,3則只能實現部分。至於4,就讓后續的特征提取去彌補吧。言歸正傳,3個算法分別是:線性歸一化算法,基於圖像矩的歸一化以及非線性歸一化算法。
按慣例,3個算法的標准c實現可在:
https://github.com/UnilVision/visionbase/tree/master/ocr/baseline/normalization找到。希望對大家有所幫助。
線性歸一化:線性歸一化算法就是一個標准的線性采樣過程,采用線性插值獲得最終的圖像結果。在我們的實現中,使用反向計算的方式:
對應代碼中的函數為:
- void backward_linear(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
- void backward_linear(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
圖像矩歸一化: 我們可以通過圖像矩來預先校正字符的傾斜度,並通過矩來獲得字體的實際大小[w1, h1]及中心位置[xc, yc]。歸一化的原始區域被修改為
[xc-w1/2, xc+w1/2, yc-h1/2, yc+h1/2]。其計算方法為:
其中圖像矩的計算方法:
在找到新的區域[xc-w1/2, xc+w1/2, yc-h1/2, yc+h1/2]后,后續即調用線性歸一化算法即可。對應代碼中的實現為:
- void backward_moment(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
- void backward_moment(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
采樣計算方式為:
注意這里我們僅調整x的位置以保證圖像的中心仍然處於原始的xc,yc。其實現對於:
- // slant correction
- // Note>> (dst_wid, dst_hei) must equal to (region.width, region.height)
- void backward_moment_slantcorrection(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep);
- // slant correction
- // Note>> (dst_wid, dst_hei) must equal to (region.width, region.height)
- void backward_moment_slantcorrection(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep);
通常傾斜校正會放在歸一化之前,已獲得更好的效果。
非線性歸一化:這里實現的是Jun Tsukumo在1988年提出的一個經典算法(原論文名稱為Classification of Handprinted Chinese Characters Using Non-linear Normalization and Correlation Methods)。作者的思路是希望每一行,每一列的背景區域都可以平均分布。
為此,他首先為每個像素在x,y方向分別定義了個概率密度函數:以及
。這兩個函數的計算方法是:
如果(x,y)是一個屬於字符區域的像素,那么都取一個極小值(在我們的實現中,這個值是0.001f,調整這個參數可以引起歸一化后筆畫的粗細變化)。
如果(x,y)是背景區域像素,那么:
其中和
分別是當前像素所處x方向背景像素的run-length和y方向的run-length。有了這兩個密度函數,定義:
這里px和py就是歸一化后的投影直方圖了,為了在歸一化后的圖像中讓px和py平均分布,引入兩個函數hx,hy:
通過前向映射采樣即可實現歸一化操作:
注意這里與前兩個算法的不同之處,前向映射是將當前圖像的某個像素映射到歸一化的圖像中。而反向映射則是將歸一化的圖像中的某個像素位置映射到原圖像中。
非線性歸一化的實現對應:
- void forward_nonlinear_1d(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
- void forward_nonlinear_1d(unsigned char* src, int src_wid, int src_hei, int src_widstep,
- CHARECT_t* region,
- unsigned char* dst, int dst_wid, int dst_hei, int dst_widstep,
- int ratio_preserve_func);
參考結果:
最后看下各個算法的結果:
圖2,參考結果。從左到右依次:1. 原始扣取的圖像通過OpenCV的resize函數縮放。2. 線性歸一化。3.基於矩的歸一化。4.先傾斜校正再基於矩的歸一化。5.非線性歸一化。
[原創文章,轉載請注明出處:http://blog.csdn.net/unilvision/article/details/8624606]