基於模板匹配的手寫數字識別


【實驗項目名稱】

手寫數字特征提取方法與實現

【實驗目的】

通過手寫數字特征的提取,了解數字的特征提取方法,掌握特征匹配准則。

【實驗原理】

讀取標准化后的數字0~9,二值化,對每個數字進行等分區域分割,統計每個區域內的黑色像素點的個數,即為特征初值。采用歐式距離的模板匹配法判斷數字。

【實驗要求】

給定數字0-9的原始樣本集合,每個數字都有100個大小為28*28的樣本圖像。要求如下:

1、將上述圖像切分成標准圖像庫,存儲為文件。

2、對每個數字進行等分區間分割。

3、給出統計結果:每個區域內的黑色像素點個數值以及占總量的百分比,顯示出計算結果。

4、采用歐氏距離模板匹配法,給出識別結果。

5、從統計意義上,給出每個數字的識別率。


1.Python庫的相關配置:OpenCV 

2.實驗流程圖:

3.實驗步驟分析(包含有train圖片集、test圖片集):

  1.圖片預處理,該實驗使用圖片均已做過預處理,均為二值化的圖像(0 和 255),黑底白字,28*28大小,如下圖所示;

                  

  2.對所有train圖片進行數據壓縮,設計為28*28->7*7,也就是,每一個小方塊中含有4*4=16個像素點,通過統計小方塊中的像素值,分別給小方塊標記為0或1(其中當白點超過16/2 = 8 個時,記該小方塊為1,反之,記為0。可以知道,每一張圖片可以被49個0_1字符串刻畫。

  3.對train圖片集中所有圖片進行上述處理,並將其字符串數據進行存儲(可以設計為存儲在一個txt文檔,,稱為模板庫)。然后對test圖片集中的每一張圖片進行字符串轉化,同樣可以得到49個字符串的0_1數據,然后將其與模板庫中的字符串數據進行對比,其中,歐氏距離最小的即認為是和該測試圖片是同一類數字。以此分辨手寫數字圖片。

  4.關於各種統計率的計算:[正確率]--(最小距離唯一,且兩個圖片數字屬於同一類)或者(存在多個最小距離,但是均屬於同一類數字);

              [拒絕識別率]--(存在多個最小距離,並且不全部屬於同一類數字,無法正常分類);

              [錯誤率]--(最小距離唯一,並且兩個圖片不屬於同一類數字);

  5.為了更好地判斷兩個圖片是否屬於同一類數字,故一般在其49個字符數據前加上一些標記符號,用來表示該字符串屬於哪個數字。

4.Python實現(其中路徑絕對方式給出

one_test.py文件:(該文件中代碼復雜主要在於三種識別率的計算,其中關於每類識別得統計判斷有點繁雜,需耐心)

Function.Image_Compression(root_dir) -------圖像壓縮,返回壓縮數據流

Function.Distance(test_str, train_str)--------計算樣本間距

 1 # 基於模板的手寫數字識別
 2 import os
 3 import cv2
 4 import Function     # 關於該實驗中需要調用的函數
 5 # 1.樣本特征,不需預處理
 6 # 2.圖像壓縮表示,28*28——7*7,存儲於(E:\PatternRecognition\picture7_7.txt)
 7 root_dir = "E:/train-images"           # 訓練數據集
 8 file7_7 = open("E:/PatternRecognition/picture7_7.txt", 'w')     # 覆蓋寫模式
 9 for fl in os.listdir(root_dir):      # 循環處理所有train圖片
10     img_str = fl[0:-4] + ":" + Function.Image_Compression(root_dir + '/' + fl)      # 圖像壓縮,返回壓縮數據流
11     file7_7.write(img_str + '\n')      # 壓縮后的圖像數據寫入文本存儲
12 file7_7.close()
13 # 3.待測樣本的相似性比較,根據最近距離判斷
14 # 4.根據相似性比較給出識別結果,並給出統計意義上的正確率,錯誤率,拒絕識別率
15 file7_7 = open("E:/PatternRecognition/picture7_7.txt", 'r')     # 只讀模式
16 root_dir = "E:/test-images"          # 測試test-images數據集
17 Correct_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
18 Error_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
19 Rejection_rate = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
20 ############
21 for fl in os.listdir(root_dir):      # 循環處理所有test圖片
22     # 一些必備的基礎數據變量
23     Same_dist_number = 0    # 用於記錄最小距離時,是否存在多個標准樣本,並標記個數
24     Same_class = -1         # 當有多個相同距離時,如果他們均為同一類別,則標記為該類別;-1表示可直接判斷。
25     min_dist = 7            # 用於存儲判斷最小距離
26     dist_img = ""           # 用於標記當前最小距離時,屬於哪個數字圖片
27     # 開始處理test圖片的匹配識別
28     test_img_str = Function.Image_Compression(root_dir + '/' + fl)      # test圖片數據
29     while True:
30         line = file7_7.readline()
31         if not line:        # 已讀完整個文檔,光標返回開頭,結束此次匹配
32             file7_7.seek(0)
33             break
34         train_str = line[-50:-1]        # train圖片數據
35         temp_dist = Function.Distance(test_img_str, train_str)      # 計算樣本間距
36         if temp_dist < min_dist:        # 更新min_dist/dist_img/Same_dist_number
37             min_dist = temp_dist
38             dist_img = line[0:-51]      # 提取最小距離的圖片名稱,即屬於哪個數字
39             Same_dist_number = 0        # 出現最小距離,個數歸零
40             Same_class = -1             # 出現最小距離,不需要類別判斷
41         elif temp_dist == min_dist:
42             Same_dist_number += 1       # 表示具有相同距離的數字
43             if dist_img[0:1] == line[0:1]:      # 樣本間距相等,同時是同一類的樣本
44                 Same_class = eval(line[0:1])    # 記錄同一類別
45             else:
46                 Same_class = -1         # 表明,同時具有不同類的數字樣本與測試數字距離相等
47     # 識別結果 以及 識別結果的數據統計
48     # a.Same_dist_number = 0 ,表明可以直接識別出來,但不保證正確率
49     # b.Same_dist_number != 0 and Same_class = -1 ,拒絕識別,同時有不同數字與其距離相等
50     # c.Same_dist_number != 0 and Same_class ,可以識別,表示同一類數字中多個樣本與其距離相等
51     if Same_dist_number == 0:           # 該數字可以識別
52         print("測試數字:", fl[0:-4], "  --  識別出來的結果:", dist_img)    # 數字的識別結果
53         if fl[0] == dist_img[0]:
54             Correct_rate[eval(fl[0])] += 1        # 正確識別
55         else:
56             Error_rate[eval(fl[0])] += 1          # 識別錯誤
57     elif Same_class == -1:              # 拒絕識別
58         print("測試數字:", fl[0:-4], "  --  該數字拒絕識別!")
59         Rejection_rate[eval(fl[0])] += 1      # 拒絕識別
60     else:                               # 同一類數字中多個樣本與其距離相等
61         print("測試數字:", fl[0:-4], "  --  識別出來的結果(類):", Same_class)
62         if eval(fl[0]) == Same_class:
63             Correct_rate[eval(fl[0])] += 1  # 正確識別
64         else:
65             Error_rate[eval(fl[0])] += 1  # 識別錯誤
66 file7_7.close()
67 print("------------------------------------------------")
68 for i in range(10):
69     print("數字 {:d} 識別的正確率 = {:.2f}% ,錯誤率 = {:.2f}% ,拒絕識別率 = {:.2f}%".format(i, Correct_rate[i]*5, Error_rate[i]*5, Rejection_rate[i]*5))
70 print("success!")
View Code

  <<----------------------數據流顯示

5.兩個函數:

Function.py文件:(包含兩個需要常調用的函數)

Image_Compression(img_path)

 1 import cv2
 2 
 3 #######################
 4 # 實現圖像壓縮,28*28——7*7,並以49數據流返回,img_path--圖片路徑
 5 # 划分為4*4的像素矩陣,其中八個及以上的像素點超過127即記為1,反之為0
 6 # 參數img_path,必須為完成的圖片路徑
 7 #######################
 8 def Image_Compression(img_path):
 9     # 數據按行存儲
10     img_str = ""        # 存數據流
11     img = cv2.imread(img_path)
12     # print("圖像的形狀,返回一個圖像的(行數,列數,通道數):", img.shape)
13     x = y = 0           # img像素點坐標表示img[x][y]
14     for k in range(1, 50):      # k的范圍1-49
15         totle_img = 0           # 統計滿足要求的像素點數目
16         for i in range(4):
17             for j in range(4):
18                 if img[x + i - 1][y + j - 1][0] > 127:
19                     totle_img += 1
20         y = (y + 4) % 28
21 # 一個矩形陣中包含16個像素點,其中像素值大於127的點超過八個記為1,反之記為0
22         if totle_img >= 8:
23             img_str += '1'
24         else:
25             img_str += '0'
26         if k % 7 == 0:      # 控制x,y的變化
27             x = x + 4
28             y = 0
29     return img_str
View Code

 Distance(test_str, train_str)

 1 #######################
 2 # 計算測試樣本與標准樣本之間的距離,返回以距離,test_str--測試,train_str--標准
 3 # 其中test_str,train_str均必須保證為49個字符串形式的數字
 4 # 返回一個double類型的數據
 5 #######################
 6 def Distance(test_str, train_str):
 7     len_str = len(train_str)        # 數據長度
 8     dist = 0.0
 9     for i in range(len_str):        # 計算距離
10         dist += (eval(test_str[i:i+1]) - eval(train_str[i:i+1]))**2
11     dist **= 0.5
12     return dist
View Code

6.1匹配結果:(test是從train里面提取出來的若干圖片合集)

     

數字 0 識別的正確率 = 100.00% ,錯誤率 = 0.00% ,拒絕識別率 = 0.00%

數字 1 識別的正確率 = 45.00% ,錯誤率 = 0.00% ,拒絕識別率 = 55.00%

數字 2 識別的正確率 = 85.00% ,錯誤率 = 0.00% ,拒絕識別率 = 15.00%

數字 3 識別的正確率 = 80.00% ,錯誤率 = 0.00% ,拒絕識別率 = 20.00%

數字 4 識別的正確率 = 90.00% ,錯誤率 = 0.00% ,拒絕識別率 = 10.00%

數字 5 識別的正確率 = 80.00% ,錯誤率 = 0.00% ,拒絕識別率 = 20.00%

數字 6 識別的正確率 = 90.00% ,錯誤率 = 0.00% ,拒絕識別率 = 10.00%

數字 7 識別的正確率 = 95.00% ,錯誤率 = 0.00% ,拒絕識別率 = 5.00%

數字 8 識別的正確率 = 100.00% ,錯誤率 = 0.00% ,拒絕識別率 = 0.00%

數字 9 識別的正確率 = 85.00% ,錯誤率 = 0.00% ,拒絕識別率 = 15.00%

6.2匹配結果:(其他方式構建的圖片)

 

 暫無

7.總結:

  實驗可以通過特征壓縮的方式來適當減少特征值的數量,然后再進行模板匹配,需要注意的是,特征值得壓縮需要處於適當的范圍。特征值過多會導致計算數據多大,匹配速度較慢,反之,特征值過少,對數據的判別存在較大的誤差。總的來說,對於模板匹配識別方式,計算量較大,匹配速度較慢。

2021-04-29


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM