一、漢字識别簡介
漢字作為中華民族文化的資訊載體,與人們的日常學習和工作密不可分。在網絡資訊交流中,需要輸入大量的中文資訊 ,重複、單調的傳統鍵盤手工輸入方式效率低下,已逐漸不能滿足迅速發展的資訊化時代。而傳統的模闆比對法對于漢字的識别率不高,作者提出一種基于SVM的多特征手寫漢字識别技術,可大幅提高漢字的識别率以及錄入效率。
1 系統流程
首先對漢字圖像進行灰階化、二值化、形态學處理、傾斜校正、字元分割和歸一化、細化等圖像預處理操作,再對字元進行特征提取,最後采用SVM算法構造分類器。系統識别流程如圖1所示。
2 SVM原理
SVM(Support Vector Machines)是建立在統計學習理論的VC維理論和結構風險最小原理基礎上的,面對小樣本問題,其能表現出良好的學習能力,并能做到與資料的維數無關 。
圖1 漢字識别流程圖
SVM方法是從線性可分情況下的最優分類超平面提出的,所謂最優分類超平面就是要求分類平面不但能将兩類無錯地分開,且要使分類平面兩側樣本之間的間隔最大[4] 。過兩類樣本中離最優分類超平面最近的點,且平行于最優分類超平面的分類超平面上的訓練樣本稱為支援向量[3] 。設樣本集(xi,yi),xi∈Rd,yi∈{1,-1},i=1,…,n。線上性可分情況下,則可找到權向量w,使兩類間隔最大,即‖w‖2最小,同時滿足
其中,i=1,…,n,n表示分類樣本的數目。
為求解上述優化問題,引入拉格朗日函數
式中,α為拉格朗日乘子,αi≥0。
通過拉格朗日函數L分别對w,b求偏導,并令偏導數值為0,結果代入超平面方程得到最優分類函數
漢字識别的分類對象是非線性不可分的。對于不可分問題,可通過引入非負松弛變量ξi加以解決,則限制條件變為
式中,C是懲罰因子,用來調節分類的準确率與泛化能力[5] 。拉格朗日乘子α的取值範圍變為0≤αi≤C。對于低維空間的非線性可分問題,可通過引入核函數解決。原始資料的核函數變換為(xi·xj)→K(xi·xj),則非線性情況下,使用核函數之後對應的分類函數為
3 關鍵技術
3.1 質心特征的提取
質心特征是字元筆劃分布的展現。将二值圖像轉化成點陣形式,黑色像素點用“1”表示,白色像素點用“0”表示。設c(i,j)表示漢字點陣,質心計算如下:水準質心
垂直質心
式中,i表示該點陣的行;j表示該點陣的行。
3.2 筆劃特征的提取
漢字由橫、豎、撇、捺4種基本筆劃構成,筆劃的構成展現了漢字的基本形态[7] 。下面對4種基本筆劃進行提取。
(1)橫、豎筆劃的提取。橫筆劃中所有的像素點具有同一縱坐标,而豎筆劃中所有的像素點具有同一橫坐标[8] 。其特征明顯,提取算法也基本相同。本文提出一種将細化後圖像與原圖像相結合的筆劃提取方法,方法如下:1)對細化後圖像進行自上而下、從左往右的水準掃描,若同一縱坐标上連續的黑點個數大于或等于2,則記下這些黑點的坐标;2)對原圖像進行水準掃描,若這些黑點依然連續,則說明這些黑點構成一個橫筆劃,橫筆劃數量加1;3)重複第1、2步;4)當細化後圖像水準掃描全部完成時,記下橫筆劃數。同理,對細化後圖像進行自左向右而下、從上往下的豎直掃描,可得到豎筆劃數;
(2)撇、捺筆劃的提取。1)将細化後圖像中的橫、豎筆劃删除,降低圖像的複雜性;2)自上而下、從左往右的水準掃描細化後圖像,如果第i行掃描到黑點,記下該黑點的縱坐标yi;3)跳出對第i行的掃描,依次掃描第i+1,i+2,i+3,…,20行,記下首次掃描到黑點的縱坐标y2,y3,y4,…,y21-i;4)比較y2,y3,y4,…,y21-i,若滿足yj+1≤yj≤yj+1+1∪yj+2≤yj≤yj+2+2,j∈{1,2,3,…,20-i},則這些點構成一撇筆劃,撇筆劃數量+1,若滿足yj≤yj+1≤yj+1∪yj≤yj+2≤yj+2,j∈{1,2,3,…,20-i},則這些點構成一捺筆劃,捺筆劃數量+1;5)删除已提取的撇、捺筆劃,重複第2)~4)步;6)掃描結束後,記下撇、捺筆劃數。
3.3 特征點的提取
漢字筆劃特征點主要有端點、折點、歧點、交點[9] 。端點是筆劃的起點或終點(不與其他筆劃相接);折點是指筆劃方向出現顯著變化的點;歧點是三叉點,要求其中兩個筆端的分支方向相同;交點是四叉點,且有兩對等的對頂角。自左向右、自上而下的對二值圖像進行掃描,統計各筆劃特征點的個數。
3.4 構造分類器
分類器是整個字元識别系統的核心,作者采用SVM來構造分類器。SVM方法解決的是二分類問題,為使其能夠應用于10個漢字的分類,需構造多值分類器。将采用一對一方法構造分類器。對于10個不同的漢字,一對一方法需要構造(C210即45)個分類器,分類結束後選取得票數最多的類别作為最終的識别結果。
二、部分源代碼
function varargout = main(varargin)
% 開始初始化代碼 - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct(‘gui_Name’, mfilename, …
‘gui_Singleton’, gui_Singleton, …
‘gui_OpeningFcn’, @main_OpeningFcn, …
‘gui_OutputFcn’, @main_OutputFcn, …
‘gui_LayoutFcn’, [] , …
‘gui_Callback’, []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
endif nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% 結束初始化代碼
pause(1);
% 執行之前主要是可見的。
function main_OpeningFcn(hObject, eventdata, handles, varargin)
set(handles.process,‘enable’,‘on’)% 此函數沒有輸出參數,見 OutputFcn.
% main的選擇預設的指令行輸出
handles.output = hObject;
% 更新handles 結構
guidata(hObject, handles);
% UIWAIT 等待使用者響應 (see UIRESUME)
% uiwait(handles.figure1);% — 這個函數的輸出傳回到指令行。
function varargout = main_OutputFcn(hObject, eventdata, handles)
tic
% 獲得預設指令行輸出的把手結構
varargout{1} = handles.output;% — 執行按鈕在pushbutton1。
function pushbutton1_Callback(hObject, eventdata, handles)[filename pathname]=uigetfile({‘.jpg’;'.bmp’}, ‘File Selector’);
I = imread([pathname ‘’ filename]);
handles.I = I;
% 更新處理結構
guidata(hObject, handles);
axes(handles.axes1);
imshow(I);title(‘原始圖檔’)set(handles.process,‘enable’,‘on’)
% — 執行過程中按下按鈕。function process_Callback(hObject, eventdata, handles)
set(handles.edit3,‘string’,‘正在識别!請稍候…’);
I = handles.I;
I1=rgb2gray(I);;%rgb2gray轉換成灰階圖
guidata(hObject, handles);
axes(handles.axes2);
imshow(I1);title(‘灰階圖’);
axes(handles.axes3);
imhist(I1);title(‘灰階圖直方圖’);
%繼續
pause(2);
I2=edge(I1,‘roberts’,0.15,‘both’);
guidata(hObject, handles);
axes(handles.axes2);
imshow(I2);title(‘robert算子邊緣檢測’);
pause(2);
se=[1;1;1];
I3=imerode(I2,se);
guidata(hObject, handles);
axes(handles.axes3);
imshow(I3);title(‘腐蝕後圖像’);
%繼續
pause(2);
se=strel(‘rectangle’,[10,25]);%生成一個矩陣
I4=imclose(I3,se);%閉運算
guidata(hObject, handles);
axes(handles.axes2);
imshow(I4);title(‘平滑圖像的輪廓’);
%繼續
pause(2);
I5=bwareaopen(I4,2000);%小于2000的對象都被删除
guidata(hObject, handles);
axes(handles.axes2);
imshow(I5);title(‘從對象中移除小對象’);
%繼續
pause(2);
[PY2,PY1,PX2,PX1]=chepai_fenge(I5);%調用分割車牌
global threshold;
[PY2,PY1,PX2,PX1,threshold]=chepai_xiuzheng(PY2,PY1,PX2,PX1);%調用車牌校正
IY=I(PY1:PY2,:😅;
Plate=I5(PY1:PY2,PX1:PX2);%使用caitu_tiqu
global dw;
dw=Plate;
PX1=PX1-1;%對車牌區域的校正
PX2=PX2+1;
dw=I(PY1:PY2,PX1:PX2,:);
axes(handles.axes2);
imshow(dw),title(‘區域的校正’);
pause(2);
t=tic;
guidata(hObject, handles);
axes(handles.axes2);
imshow(IY),title(‘水準方向合理區域’);
axes(handles.axes3);
imshow(dw),title(‘定位剪切後的彩色圖像’);
pause(2);
imwrite(dw,‘New number plate.jpg’);
%[filename,filepath]=uigetfile(‘New number plate.jpg’,‘輸入一個定位裁剪後的車牌圖像’);
%jpg=strcat(filepath,filename);
a=imread(‘New number plate.jpg’);
b=rgb2gray(a);%對定位後的車牌灰階化
figure(3),subplot(3,2,1),imshow(b),title(‘灰階圖像’);
g_max=double(max(max(b)));
g_min=double(min(min(b)));
T=round(g_max-(g_max-g_min)/2); %T 為二值化的門檻值
[m,n]=size(b);
d=(double(b)>=T); % d:二值圖像
figure(3),subplot(3,2,2),imshow(d),title(‘二值圖像’);
figure(3),subplot(3,2,3),imshow(d),title(‘均值濾波前’);
pause(1);
h=fspecial(‘average’,3); %均值濾波器
d=im2bw(round(filter2(h,d)));
figure(3),subplot(3,2,4),imshow(d),title(‘均值濾波後’);
se=eye(2); % eye(n) returns the n-by-n identity matrix 機關矩陣
%字元面積與車牌面積之比在(0.235,0.365)之間
[m,n]=size(d); %如果大于0.365則對圖像進行腐蝕,如果小于0.235則對圖像進行膨脹
if bwarea(d)/m/n>=0.365%計算面積
d=imerode(d,se);%imerode 實作圖像腐蝕 d為待處理圖像,se是結構元素對象
elseif bwarea(d)/m/n<=0.235
d=imdilate(d,se);%imdilate 圖像膨脹
end
三、運作結果
四、matlab版本及參考文獻
1 matlab版本
2019b