1. 程式人生 > >字元識別OCR研究一(模板匹配&BP神經網路訓練)

字元識別OCR研究一(模板匹配&BP神經網路訓練)

摘 要

在MATLAB環境下利用USB攝像頭採集字元影象,讀取一幀儲存為影象,然後對讀取儲存的字元影象,灰度化,二值化,在此基礎上做傾斜矯正,對矯正的影象進行濾波平滑處理,然後對字元區域進行提取分割出單個字元,識別方法一是採用模板匹配的方法逐個對字元與預先製作好的字元模板比較,如果結果小於某一閾值則結果就是模板上的字元;二是採用BP神經網路訓練,通過訓練好的net對待識別字符進行識別。最然後將識別結果通過MATLAB下的串列埠工具輸出51微控制器上用液晶顯示出來。

關鍵字: 傾斜矯正,字元分割,模板匹配,BP神經網路,液晶顯示

Abstract

In the MATLAB environmentusing USB camera capture the character images, saved as an image reading, thenread the saved character images, grayscale, binary, on this basis do tilt correction,the correction image smoothing filter, and then extract the character regionsegmentation of a single character, and then one by one using a templatematching method of character with good character template is a pre-production,if the result is less than a certain threshold, the result is a template of thecharacter. Second, the BP neural network trained by the trained net to identifythe character towards recognition The results will identify the most and thenthe serial port through the MATLAB tool output 51 under microcontroller withLCD display.

Keyword: Tilt correction, character segmentation,template matching, liquid crystal display

一 引言:

光學字元識別(OCR,Optical Character Recognition)是指對文字資料進行掃描,然後對影象檔案進行分析處理,獲取文字及版面資訊的過程。已有30多年曆史,近幾年又出現了影象字元識別(image character recognition,ICR)和智慧字元識別(intelligent character recognition,ICR),實際上這三種自動識別技術的基本原理大致相同。

關於字元識別的方法有很多種,最簡單的就是模板匹配,還有根據採集到的字元用BP神經網路或者SVM來訓練得到結果的方式。本文主要針對模板匹配的方式,在MATLAB環境下程式設計實現。

二 字元影象獲取:

在MATLAB下利用image acquisition toolbox獲取視訊幀,並儲存影象在工程資料夾內。攝像頭採用普通的USB攝像頭,由於這種攝像頭拍攝的照片延時比較大,所以先用image acquisition toolbox下的對視訊進行預覽,調整出最佳的效果來,採集的影象效果越好則識別率越高。 根據測試,實驗選擇640*480的視訊獲取視窗,顏色空間選取為RGB空間,獲取一幀後儲存為jpg的儲存格式。


三 字元預處理

3.1字元矯正

由於攝像頭拍攝的影象存在一定存在的傾斜度,在分割字元區域時,應先對字元進行矯正。過程如下:

將通過攝像頭獲取的儲存幀影象灰度化,然後對其進行邊緣提取,再在1到180度角內對影象進行旋轉,記錄下邊緣提取後的影象在x軸方向上的投影,當x軸方向上的投影最小的時候即表示影象中字元平行於y軸,已經完成矯正,此時記錄下旋轉的傾斜角。然後利用imrotate函式實現對字元影象的矯正。

3.2 字元區域分割:

在第三步完成對字元影象的傾斜矯正後,將影象分別做x軸和y軸方向上的投影既可以知道字元區域在x軸上的畫素分佈範圍和y軸上的畫素分佈範圍,然後對根據這個範圍對影象做分割,在MATLAB中表示為:

goal=I(ix1:iy1,jx1:jy1);

其中goal為分割後的影象,I為分割前的影象,ix1和ix2分別為x軸上投影的畫素範圍的起始座標值和終止座標值,iy1和iy2分別為y軸上投影的畫素範圍的起始座標值和終止座標值。

3.3 單個字型分割:

在分割得到的字元區域影象上,只需要做y軸上的投影就可以知道每個字元在y軸上的分佈區間,然後利用這個分佈區間就可以分割出單個字元。


3.4 單個字型裁剪

在第五步分割出來的字元基礎上進一步對字元的畫素區域進行裁剪,原理也是分別做x軸,y軸方向上的投影,求的字元的區間再做剪裁。

四 模板字元識別

4.1字元模板製作:

模板的要求是與要識別的字元的字型格式一致,實驗中採用word上的標準字元,通過截圖軟體截圖後按照3-6步的處理過程製作出需要的字元模板,從0到9共10個數字,A到Z共26個字母。

4.2 字元模板歸一化

在滿足識別率的條件下,儘量採用小模板識別可以提神運算速度,具體的模板大小,可以根據後面的與待識別字符的比較中調節。

4.3識別過程:

將待識別字符與字元模板做同樣的歸一化處理,然後遍歷與字元模板比較,處理方法為先和字元模板做差,然後計算做差後的影象的總畫素值,如果小於每一個閾值,則表示該待識別字符和該模板是同一個字元,這樣就完成了一次識別。

迴圈對要識別的字元做同樣的處理就可以識別出所有的字元,將結果儲存在字串中。

五 BP神經網路字元識別

BP(Back Propagation)網路是1986年由Rumelhart和McCelland為首的科學家小組提出,是一種按誤差逆傳播演算法訓練的多層前饋網路,是目前應用最廣泛的神經網路模型之一。BP網路能學習和存貯大量的輸入-輸出模式對映關係,而無需事前揭示描述這種對映關係的數學方程。它的學習規則是使用最速下降法,通過反向傳播來不斷調整網路的權值和閾值,使網路的誤差平方和最小。BP神經網路模型拓撲結構包括輸入層(input)、隱層(hide layer)和輸出層(outputlayer)。

BP (Back Propagation)神經網路,即誤差反傳誤差反向傳播演算法的學習過程,由資訊的正向傳播和誤差的反向傳播兩個過程組成。輸入層各神經元負責接收來自外界的輸入資訊,並傳遞給中間層各神經元;中間層是內部資訊處理層,負責資訊變換,根據資訊變化能力的需求,中間層可以設計為單隱層或者多隱層結構;最後一個隱層傳遞到輸出層各神經元的資訊,經進一步處理後,完成一次學習的正向傳播處理過程,由輸出層向外界輸出資訊處理結果。當實際輸出與期望輸出不符時,進入誤差的反向傳播階段。誤差通過輸出層,按誤差梯度下降的方式修正各層權值,向隱層、輸入層逐層反傳。周而復始的資訊正向傳播和誤差反向傳播過程,是各層權值不斷調整的過程,也是神經網路學習訓練的過程,此過程一直進行到網路輸出的誤差減少到可以接受的程度,或者預先設定的學習次數為止。

  BP神經網路模型BP網路模型包括其輸入輸出模型、作用函式模型、誤差計算模型和自學習模型。

  (1)節點輸出模型

  隱節點輸出模型:Oj=f(∑Wij×Xi-qj) (1)

  輸出節點輸出模型:Yk=f(∑Tjk×Oj-qk) (2)

  f-非線形作用函式;q -神經單元閾值。

  圖1 典型BP網路結構模型

  (2)作用函式模型

  作用函式是反映下層輸入對上層節點刺激脈衝強度的函式又稱刺激函式,一般取為(0,1)內連續取值Sigmoid函式: f(x)=1/(1+e) (3)

  (3)誤差計算模型

  誤差計算模型是反映神經網路期望輸出與計算輸出之間誤差大小的函式:

  Ep=1/2×∑(tpi-Opi) (4)

  tpi- i節點的期望輸出值;Opi-i節點計算輸出值。

  (4)自學習模型

  神經網路的學習過程,即連線下層節點和上層節點之間的權重拒陣Wij的設定和誤差修正過程。BP網路有師學習方式-需要設定期望值和無師學習方式-只需輸入模式之分。自學習模型為

  △Wij(n+1)= h ×Фi×Oj+a×△Wij(n) (5)

h -學習因子;Фi-輸出節點i的計算誤差;Oj-輸出節點j的計算輸出;a-動量因子。

5.1 訓練樣本製作:

在不同解析度和不同傾斜角度下分別採集幾組圖片作為訓練樣本,本實驗為了節省計算時間,根據需要只做12345ABCDE這10個字元的識別,因此只各採集了10組資料。不同解析度下5組,不同傾斜角度下5組。然後按照2-4上的操作過程的對字元進行處理,獲得32*32大小的訓練樣本共100個。

5.2設計BP神經網路

利用MATLAB下的神經網路工具設計一個,以字元影象的x軸y軸畫素值為輸入特徵作為輸入層的輸入;以logsig函式作為隱含層,隱含層設計節點25個,輸出層就是預期的結果,共十種可能,所以有輸出層有十種輸出。

net=newff(pr,[25 1],{'logsig' 'purelin'},'traingdx', 'learngdm');

net.trainParam.epochs=250;%訓練步數

net.trainParam.goal=0.001;%目標誤差

net.trainParam.show=10;%系統每10步顯示一次訓練誤差的變化曲線

net.trainParam.lr=0.05; %學習速度

net=train(net,p,t)%訓練

並儲存訓練結果save name net

5.3 BP訓練

首先對待識別字符預處理,然後讀取讀取訓練好的網路load name net,通過sim函式對字元進行識別,結果輸出,儲存在一個字串內。

六 識別結果傳送下位機

利用MTLAB下的串列埠工具傳送識別出的結果給下位機,下位機為51核的微控制器,然後在微控制器內經過程式處理驅動LM1602液晶顯示結果。

5.1 MATLAB下的串列埠工具:

在Matlab6.0以上版本中新增的裝置控制工具條(instrument control toolbox)具備支援計算機與其它具有串列埠的外部裝置之間的通訊的功能。其特點如下:

a、支援基於序列介面(RS-232、RS-422、RS-485)的通訊;

b、通訊資料支援二進位制和文字(ASCII)兩種方式;

c、支援非同步通訊和同步通訊;

d、支援基於事件驅動的通訊(亦稱中斷方式)。

5.2 下位機處理

5.2.1主控電路

主控晶片採用基於51核的STC12A50S8,51微控制器是對目前所有相容Intel 8031指令系統的微控制器的統稱。

·8位CPU·4kbytes 程式儲存器(ROM)(52為8K)

  ·256bytes的資料儲存器(RAM)(52有384bytes的RAM)

  ·32條I/O口線·111條指令,大部分為單位元組指令

  ·21個專用暫存器

  ·2個可程式設計定時/計數器·5箇中斷源,2個優先順序(52有6個)

  ·一個全雙工序列通訊口

  ·外部資料儲存器定址空間為64kB

  ·外部程式儲存器定址空間為64kB

  ·邏輯操作位定址功能·雙列直插40PinDIP封裝

  ·單一+5V電源供電

  CPU:由運算和控制邏輯組成,同時還包括中斷系統和部分外部特殊功能暫存器;

  RAM:用以存放可以讀寫的資料,如運算的中間結果、最終結果以及欲顯示的資料;

  ROM:用以存放程式、一些原始資料和表格;

  I/O口:四個8位並行I/O口,既可用作輸入,也可用作輸出;

  T/C:兩個定時/記數器,既可以工作在定時模式,也可以工作在記數模式;

  五個中斷源的中斷控制系統;

  一個全雙工UART(通用非同步接收發送器)的序列I/O口,用於實現微控制器之間或微控制器與微機之間的序列通訊;

  片內振盪器和時鐘產生電路,石英晶體和微調電容需要外接。最高振盪頻率為12M。

5.2.2 液晶顯示電路

實驗中顯示模板採用1602字元型液晶,它是工業字元型液晶,能夠同時顯示16x02即32個字元。602液晶模組內部的字元發生儲存器(CGROM)已經儲存了160個不同的點陣字元圖形,這些字元有:阿拉伯數字、英文字母的大小寫、常用的符號、和日文假名等,每一個字元都有一個固定的程式碼,比如大寫的英文字母“A”的程式碼是01000001B(41H),顯示時模組把地址41H中的點陣字元圖形顯示出來,我們就能看到字母“A”。

因為1602識別的是ASCII碼,試驗可以用ASCII碼直接賦值,在微控制器程式設計中還可以用字元型常量或變數賦值,如'A’。

5.2. 3 串列埠通訊圖:

由於微控制器的串列埠輸出為TTL電平,與PC機通訊是需要採用轉換為RS232電平,實驗中使用美信公司的MAX232晶片。它是美信公司專門為電腦的RS-232標準串列埠設計的單電源電平轉換晶片,使用+5v單電源供電。

七 總結:

本實驗完成了usb攝像頭的視訊幀影象採集,並對採集影象進行了數字影象處理,採用模板匹配和BP神經網路訓練的方式對字元進行識別,並利用MATLAB下的串列埠工具和下位機微控制器通訊,傳送識別結果顯示在字元液晶上。

試驗中存在的問題:一是,對影象字元進行分割的時候,如果影象採集的解析度過低的話會出現字元斷裂的情況,這時候要做的就是對字元進行連通域檢測。二是在做本實驗的程式都是針對特定字元進行處理的,沒有做自適應的字元個數檢測。三是BP訓練樣本數太少,所以訓練後的網路對字元的識別結果並不好。這些都需要後續的改進。

八參考文獻:

[ 1]  王鵬.基於神經網路的手寫體字元識別 北京工業大學 , 2002

[ 2]  閆雪梅 ,王曉華 ,夏興高. 基於 PCA和 BP神經網路演算法的車牌字元識別 北京理工大學資訊科學技術學院 2007

[ 3]  金城 二維影象特徵研究 浙江大學博士論文 2006

[ 4]  MATLAB2010R image processing tools

附錄:

MATLAB程式:

一、模板匹配:

%%%%%%%%%%%%%%%%%模板字元識別1.0%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%朱本福
%利用usb攝像頭在MATLAB中通過image acquisition toolbox
%獲取一幀圖片並儲存為ocr.jpg在讀取圖片進行處理,採用模板匹配的
%方式進行識別,模板為根據操作製作的,最後將結果通過串列埠傳送出去顯示在微控制器上
%MATLAB2010下開發
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
clc;
clear all;
close all;
vid = videoinput('winvideo', 1, 'YUY2_640x480');%視訊獲取字元影象
src = getselectedsource(vid);
vid.FramesPerTrigger = 1;
preview(vid);%預覽
start(vid) ;
vid.ReturnedColorspace = 'rgb';
vid.FramesPerTrigger =1;
imaqmem(10000000);
frame = getsnapshot(vid) ;%獲取一幀
figure(1);
imshow(frame)
imwrite(frame,'ocr.jpg','jpg');%儲存該幀圖片

stop(vid);
delete(vid);


I=imread('ocr.jpg');%讀取測試圖片
[m,n,z]=size(I)
figure(1);
imshow(I);title('測試圖片')
I1=rgb2gray(I);
    imwrite(I1,'I1.jpg');%儲存二值化影象
figure(2);
imshow(I1);%顯示二值化影象
%figure(3);
%imhist(I1);


Ic = imcomplement(I1);%取反
    imwrite(Ic,'Ic.jpg');
figure(33);imshow(Ic);
BW = im2bw(Ic, graythresh(Ic));%二值化
    imwrite(BW,'BW.jpg');
figure(5), imshow(BW); 


bw=edge(I1,'prewitt');%邊緣提取
    imwrite(bw,'bw.jpg');
figure(32);imshow(bw);
theta=1:180;
[R,xp]=radon(bw,theta);
[I0,J]=find(R>=max(max(R)));%J記錄了傾斜角
qingxiejiao=90-J
goal1=imrotate(BW,qingxiejiao,'bilinear','crop');
    imwrite(goal1,'goal1.jpg');
figure,imshow(I1);title('correct image');



%中值濾波
goal3=medfilt2(goal1,[3,3]);
figure(19), imshow(goal3);


goal3=medfilt2(goal3,[3,3]);
    imwrite(goal3,'goal3.jpg');
figure(19), imshow(goal3);


%求解X方向的投影畫素範圍
[ix1,iy1]=xfenge(goal1)


%求解y方向的投影畫素範圍
[jx1,jy1]=yfenge(goal1)


%字元區域分割:
goal4=goal3(ix1:iy1,jx1:jy1);
    imwrite(goal4,'goal4.jpg');
figure(21);imshow(goal4);
[m,n]=size(goal4)
%[L,num] = bwlabel(goal4,8);%區域標記,1,2,3,4


ysum(n-1)=0;
for y=1:n-1
ysum(y)=sum(goal4(:,y));
end
%y=1:n-1;
%figure(12)
%plot(y,ysum)%畫出y方向上的畫素分佈


%找出ysum分佈的幾個與y軸交點就是單個字元在y軸上分佈的區間
i=1;j=1;
for y=1:n-2
    if (ysum(y)==0)&(ysum(y+1)~=0)
        yy(i)=y
        i=i+1;
    end
    
    if (ysum(y)~=0)&(ysum(y+1)==0)
        yx(j)=y
        j=j+1;
    end
end
[m_yy,n_yy]=size(yy);%求出字元的分佈並分割
if n_yy==3 %根據n_yy和n_yx的個數及分佈區間,選擇分割區間
%segment
num1=goal4(1:m , 1:yx(1));%分割出字元1
figure(23);imshow(num1);


num2=goal4(1:m ,yy(1):yx(2));%分割出字元2
figure(24);imshow(num2);


num3=goal4(1:m ,  yy(2):yx(3));%分割出字元3
figure(25);imshow(num3);


num4=goal4(1:m ,  yy(3):n);%分割出字元4
figure(26);imshow(num4);


%[m1,n1]=size(num1)%求出各個字元的大小
%[m2,n2]=size(num2)
%[m3,n3]=size(num3)
%[m4,n4]=size(num4)
%對單個字元細分,避免字型出現大小不一致的情況,也就是再在x軸上進行分割
[ix1,iy1]=xfenge(num1)
[ix2,iy2]=xfenge(num2)
[ix3,iy3]=xfenge(num3)
[ix4,iy4]=xfenge(num4)
num1=goal4(ix1:iy1 , 1:yx(1));
figure(23);imshow(num1);



num2=goal4(ix2:iy2 ,yy(1):yx(2));
figure(24);imshow(num2);


num3=goal4(ix3:iy3 ,  yy(2):yx(3));
figure(25);imshow(num3);


num4=goal4(ix4:iy4 ,  yy(3):n);
figure(26);imshow(num4);


imwrite(num1, 'nnum1.bmp'); 
imwrite(num2, 'nnum2.bmp'); 
imwrite(num3, 'nnum3.bmp'); 
imwrite(num4, 'nnum4.bmp'); 
end


if n_yy==4 %根據n_yy和n_yx的個數及分佈區間,選擇分割區間
    %segment
num1=goal4(1:m , yy(1):yx(1));
figure(23);imshow(num1);


num2=goal4(1:m ,yy(2):yx(2));
figure(24);imshow(num2);


num3=goal4(1:m ,  yy(3):yx(3));
figure(25);imshow(num3);


num4=goal4(1:m ,  yy(4):n);
figure(26);imshow(num4);
%[m1,n1]=size(num1)
%[m2,n2]=size(num2)
%[m3,n3]=size(num3)
%[m4,n4]=size(num4)
%對單個字元細分
[ix1,iy1]=xfenge(num1)
[ix2,iy2]=xfenge(num2)
[ix3,iy3]=xfenge(num3)
[ix4,iy4]=xfenge(num4)
num1=goal4(ix1:iy1 , yy(1):yx(1));
figure(23);imshow(num1);


num2=goal4(ix2:iy2 ,yy(2):yx(2));
figure(24);imshow(num2);


num3=goal4(ix3:iy3 ,  yy(3):yx(3));
figure(25);imshow(num3);


num4=goal4(ix4:iy4 ,  yy(4):n);
figure(26);imshow(num4);
imwrite(num1, 'nnum1.bmp'); 
imwrite(num2, 'nnum2.bmp'); 
imwrite(num3, 'nnum3.bmp'); 
imwrite(num4, 'nnum4.bmp'); 
end




for i=1:36 %將模板歸一化
    imageName=strcat(num2str(i),'.bmp');
    I = imread(imageName);
   % figure;imshow(imageName);
   M{i}=imresize(I,[16,12],'nearest');
   %figure;imshow(M{i});
end



Rchar(4)='0';
for i=1:4 
    imagenum=strcat('nnum',num2str(i),'.bmp');
    J=imread(imagenum);
     [m,n]=size(J)
    num{i}=imresize(J,[16,12],'nearest');  %待識別字符歸一化
    [m,n]=size(num{i})
    figure;imshow(num{i});
 for j=1:36   
    MM{j}=xor(num{i} , M{j});  %差分比較
   % figure;imshow(MM{j});
    dist(j)=sum(sum(MM{j}))
    
        if dist(j)<=28  %這個可以根據dist的具體情況選取,這裡去18分割效果不錯
        char(i)=j
        end
    end

      
    
switch char(i)%遍歷比較
         case 1 
             Rchar(i)='1' ;
         case 2 
             Rchar(i)='2';
         case 3 
             Rchar(i)='3';
         case 4
             Rchar(i)='4' ;
         case 5 
             Rchar(i)='5';
         case 6 
             Rchar(i)='6';
         case 7 
             Rchar(i)='7';
         case 8 
             Rchar(i)='8';
         case 9 
             Rchar(i)='9';
         case 10 
             Rchar(i)='0';
         case 11 
             Rchar(i)='A' ;
         case 12 
             Rchar(i)='B';
         case 13 
             Rchar(i)='C';
         case 14 
             Rchar(i)='D' ;
         case 15 
             Rchar(i)='E';
         case 16 
             Rchar(i)='F';
         case 17
             Rchar(i)='G' ;
         case 18 
             Rchar(i)='H';
         case 19 
             Rchar(i)='I';
         case 20 
             Rchar(i)='J' ;
         case 21 
             Rchar(i)='K';
         case 22 
             Rchar(i)='L';
         case 23 
             Rchar(i)='M' ;
         case 24 
             Rchar(i)='N';
        case 25 
            Rchar(i)='O';
         case 26 
             Rchar(i)='P' ;
         case 27 
             Rchar(i)='Q';
         case 28 
             Rchar(i)='R';
         case 29 
             Rchar(i)='S' ;
         case 30 
             Rchar(i)='T';
         case 31 
             Rchar(i)='U';
         case 32 
             Rchar(i)='V' ;
         case 33 
             Rchar(i)='W';
         case 34
             Rchar(i)='X';
         case 35 
             Rchar(i)='Y' ;
         case 36 
             Rchar(i)='Z';
         otherwise 
             Rchar(i)='false'   ;
     end
 end
 schar=[Rchar(1),Rchar(2),Rchar(3),Rchar(4)]
 
%schar=['4','5','A','B'] 


sport1=serial('COM4');%串列埠輸出字元
sport1.BaudRate=9600;
fopen(sport1);
fwrite(sport1,schar);
INSTRFIND
fclose(sport1);
delete(sport1);
clear sport1;
INSTRFIND

子函式:

%對分割出的單個字元進行分割x方向的再分割
function [ix,iy]=xfenge(goal1)
[m,n]=size(goal1);
ix(m)=0;
xx=0;j=1;
for  x=1:m
    for y=1:n
        if goal1(x,y)==1;
            xx=1;
        end
    end
    if xx==1
        ix(j)=x;
        j=j+1;
    end
end
ix=ix(1);


iy(m)=0;
xx=0;j=1;
for  x=m:-1:1
    for y=n:-1:1
        if goal1(x,y)==1;
            xx=1;
        end
    end
    if xx==1
        iy(j)=x;
        j=j+1;
    end
end
iy=iy(1);

子函式:

%對分割出的單個字元進行分割y方向的再分割
function [jx,jy]=yfenge(goal1)
[m,n]=size(goal1);
jx(m)=0;
xx=0;j=1;
for  y=1:n
    for x=1:m
        if goal1(x,y)==1;
            xx=1;
        end
    end
    if xx==1
        jx(j)=y;
        j=j+1;
    end
end
jx=jx(1)


jy(m)=0;
xx=0;j=1;
for  y=n:-1:1
    for x=m:-1:1
        if goal1(x,y)==1;
            xx=1;
        end
    end
    if xx==1
        jy(j)=y;
        j=j+1;
    end
end
jy=jy(1)

二、BP神經網路訓練後識別:

clc;
clear all;
close all;




for kk = 0:99
    p1=ones(16,16);
    m=strcat('muban3\',int2str(kk),'.bmp');
    x=imread(m,'bmp');


    [i,j]=find(x==1);
    imin=min(i);
    imax=max(i);
    jmin=min(j);
    jmax=max(j);
    bw1=x(imin:imax,jmin:jmax);%words segmentation
    
    bw1=imresize(bw1,[16,16],'nearest');
    [i,j]=size(bw1);
    i1=round((16-i)/2);
    j1=round((16-j)/2);
    p1(i1+1:i1+i,j1+1:j1+j)=bw1;
    
    for m=0:15
        p(m*16+1:(m+1)*16,kk+1)=p1(1:16,m+1);
    end
    
    switch kk
        case{0,10,20,30,40,50,60,70,80,90}
            t(kk+1)=1;
        case{1,11,21,31,41,51,61,71,81,91}
            t(kk+1)=2;
        case{2,12,22,32,42,52,62,72,82,92}
            t(kk+1)=3;
        case{3,13,23,33,43,53,63,73,83,93}
            t(kk+1)=4;
        case{4,14,24,34,44,54,64,74,84,94}
            t(kk+1)=5;
        case{5,15,25,35,45,55,65,75,85,95}
            t(kk+1)=6;
        case{6,16,26,36,46,56,66,76,86,96}
            t(kk+1)=7;
        case{7,17,27,37,47,57,67,77,87,97}
            t(kk+1)=8;
        case{8,18,28,38,48,58,68,78,88,98}
            t(kk+1)=9;
        case{9,19,29,39,49,59,69,79,89,99}
            t(kk+1)=10;
    end
end


% 建立和訓練BP網路 
pr(1:256,1)=0;
pr(1:256,2)=1;
net=newff(pr,[25 1],{'logsig' 'purelin'}, 'traingdx', 'learngdm');
net.trainParam.epochs=250;
net.trainParam.goal=0.001;
net.trainParam.show=10;
net.trainParam.lr=0.05;
net=train(net,p,t)



save E52net net;



% 識別 
I=imread('ocr.jpg');%讀取測試圖片
[m,n,z]=size(I)
figure(1);
imshow(I);title('測試圖片')
I1=rgb2gray(I);
 %   imwrite(I1,'I1.jpg');%儲存二值化影象
figure(2);
imshow(I1);%顯示二值化影象
%figure(3);
%imhist(I1);


Ic = imcomplement(I1);%取反
  %  imwrite(Ic,'Ic.jpg');
figure(33);imshow(Ic);
BW = im2bw(Ic, graythresh(Ic));%二值化
  %  imwrite(BW,'BW.jpg');
figure(5), imshow(BW); 


bw=edge(I1,'prewitt');%邊緣提取
 %   imwrite(bw,'bw.jpg');
figure(32);imshow(bw);
theta=1:180;
[R,xp]=radon(bw,theta);
[I0,J]=find(R>=max(max(R)));%J記錄了傾斜角
qingxiejiao=90-J
goal1=imrotate(BW,qingxiejiao,'bilinear','crop');
  %  imwrite(goal1,'goal1.jpg');
figure,imshow(I1);title('correct image');


%中值濾波
goal3=medfilt2(goal1,[3,3]);
figure(19), imshow(goal3);


goal3=medfilt2(goal3,[3,3]);
  %  imwrite(goal3,'goal3.jpg');
figure(19), imshow(goal3);


%求解X方向的投影畫素範圍
[ix1,iy1]=xfenge(goal1)


%求解y方向的投影畫素範圍
[jx1,jy1]=yfenge(goal1)


%字元區域分割:
goal4=goal3(ix1:iy1,jx1:jy1);
  %  imwrite(goal4,'goal4.jpg');
figure(21);imshow(goal4);
[m,n]=size(goal4)
%[L,num] = bwlabel(goal4,8);%區域標記,1,2,3,4


ysum(n-1)=0;
for y=1:n-1
ysum(y)=sum(goal4(:,y));
end
%y=1:n-1;
%figure(12)
%plot(y,ysum)%畫出y方向上的畫素分佈


%找出ysum分佈的幾個與y軸交點就是單個字元在y軸上分佈的區間
i=1;j=1;
for y=1:n-2
    if (ysum(y)==0)&(ysum(y+1)~=0)
        yy(i)=y
        i=i+1;
    end
    
    if (ysum(y)~=0)&(ysum(y+1)==0)
        yx(j)=y
        j=j+1;
    end
end
[m_yy,n_yy]=size(yy);%求出字元的分佈並分割
if n_yy==3 %根據n_yy和n_yx的個數及分佈區間,選擇分割區間
%segment
num1=goal4(1:m , 1:yx(1));%分割出字元1
figure(41);imshow(num1);


num2=goal4(1:m ,yy(1):yx(2));%分割出字元2
figure(42);imshow(num2);


num3=goal4(1:m ,  yy(2):yx(3));%分割出字元3
figure(43);imshow(num3);


num4=goal4(1:m ,  yy(3):n);%分割出字元4
figure(44);imshow(num4);
%[m1,n1]=size(num1)%求出各個字元的大小
%[m2,n2]=size(num2)
%[m3,n3]=size(num3)
%[m4,n4]=size(num4)
%對單個字元細分,避免字型出現大小不一致的情況,也就是再在x軸上進行分割
[ix1,iy1]=xfenge(num1)
[ix2,iy2]=xfenge(num2)
[ix3,iy3]=xfenge(num3)
[ix4,iy4]=xfenge(num4)


num1=goal4(ix1:iy1 , 1:yx(1));
figure(51);imshow(num1);


num2=goal4(ix2:iy2 ,yy(1):yx(2));
figure(52);imshow(num2);


num3=goal4(ix3:iy3 ,  yy(2):yx(3));
figure(53);imshow(num3);


num4=goal4(ix4:iy4 ,  yy(3):n);
figure(54);imshow(num4);


imwrite(num1, '1.bmp'); 
imwrite(num2, '2.bmp'); 
imwrite(num3, '3.bmp'); 
imwrite(num4, '4.bmp'); 
end


if n_yy==4 %根據n_yy和n_yx的個數及分佈區間,選擇分割區間
    %segment
num1=goal4(1:m , yy(1):yx(1));
figure(61);imshow(num1);


num2=goal4(1:m ,yy(2):yx(2));
figure(62);imshow(num2);


num3=goal4(1:m ,  yy(3):yx(3));
figure(63);imshow(num3);


num4=goal4(1:m ,  yy(4):n);
figure(64);imshow(num4);


%[m1,n1]=size(num1)
%[m2,n2]=size(num2)
%[m3,n3]=size(num3)
%[m4,n4]=size(num4)
%對單個字元細分
[ix1,iy1]=xfenge(num1)
[ix2,iy2]=xfenge(num2)
[ix3,iy3]=xfenge(num3)
[ix4,iy4]=xfenge(num4)


num1=goal4(ix1:iy1 , yy(1):yx(1));imwrite(num1, '1.bmp'); 
figure(71);imshow(num1);


num2=goal4(ix2:iy2 ,yy(2):yx(2));imwrite(num2, '2.bmp'); 
figure(72);imshow(num2);


num3=goal4(ix3:iy3 ,  yy(3):yx(3));imwrite(num3, '3.bmp'); 
figure(73);imshow(num3);


num4=goal4(ix4:iy4 ,  yy(4):n);imwrite(num4, '4.bmp'); 
figure(74);imshow(num4);
end


for i=1:4
    imagenum=strcat(num2str(i),'.bmp');
    J=imread(imagenum);
     [m,n]=size(J)
    num{i}=imresize(J,[32,32],'nearest');  %待識別字符歸一化
    [m,n]=size(num{i})
    figure;imshow(num{i});
    imwrite(num{i}, [num2str(i),'.bmp']);
    
end
   
 clear all;
  for i=1:4  
    p(1:256,1)=1;
    p1=ones(16,16);
    load E52net net;
   % test=input('FileName:', 's');
    %x=imread(test,'bmp');
    m=strcat(num2str(i),'.bmp');
    x=imread(m,'bmp');


    [i,j]=find(x==1);
    imin=min(i);
    imax=max(i);
    jmin=min(j);
    jmax=max(j);
    bw1=x(imin:imax,jmin:jmax);%words segmentation
    
    bw1=imresize(bw1,[16,16],'nearest');
    [i,j]=size(bw1);
    i1=round((16-i)/2);
    j1=round((16-j)/2);
    p1(i1+1:i1+i,j1+1:j1+j)=bw1;
    
    for m=0:15
        p(m*16+1:(m+1)*16,1)=p1(1:16,m+1);
    end
    [a,Pf,Af]=sim(net,p);
    figure;imshow(p1);
    a=round(a)
    
        switch a
        case 1
            Rchar(i)='1'
        case 2
            Rchar(i)='2'
        case 3
            Rchar(i)='3'
        case 4
            Rchar(i)='4'
        case 5
            Rchar(i)='5'
        case 6
           Rchar(i)='A'
        case 7
           Rchar(i)='B'
        case 8
            Rchar(i)='C'
        case 9
           Rchar(i)='D'
        case 10
           Rchar(i)='E'
         otherwise 
            Rchar(i)='false'   ;
    end
end


 schar=[Rchar(1),Rchar(2),Rchar(3),Rchar(4)]