在本次流程說明中,我們會利用威盛Pixetto 的手寫字母辨識功能,實作一個能辨識英文單字的 Python 程式。
在手寫字母識別功能裡,威盛Pixetto不僅能偵測英文字母,它也能告訴使用者各個字母的出現位置。透過以上資訊,我們可以精確地辨識使用者提供的手寫單字。接下來我們一步一步介紹如何匯入威盛Pixetto 所需函式庫、如何讀取並利用威盛Pixetto的回傳數據,達成本次實作目標。
若您尚未建立 Python 編程環境,請先參考 “Python 環境設置流程說明”。
步驟 1
將威盛Pixetto連結至電腦後,開啟 Pixetto Utility。在右方選單中選擇 “手寫字母辨識”。由於我們需要同時辨識多個字母,請將 “最大顯示物件數量” 設為5。
完成後即可測試 威盛Pixetto 是否能正確辨識字母。


步驟 2
開啟 Jupyter Notebook,並建立一份“ipynb”檔案。

在第一格 code cell 裏,匯入 pixetto 以及 collections 等函式庫。
from pixetto import Pixetto
from collections import defaultdict, Counter
在 Python 程式裏,我們會將威盛 Pixetto 視為一個 “類別” ( Class )。在後續的步驟中,我們可以直接呼叫類別中的 “方法” ( Method ),以開啟、關閉、或讀取威盛 Pixetto。
第二行的 “defaultdict” 以及 “Counter” 是處理資料時常用的工具。在之後的步驟,我們會對這兩種工具進行更詳盡的介紹。
步驟 3
在本次實作中,我們需要建立一個單字庫,讓程式認識英文單字。之後的步驟,我們會讓程式在偵測到正確的英文單字後停止。
在這個步驟中,我們需要用到 “Counter” 函式。 “Counter” 會讀取傳入的陣列,並以陣列中的元素為鍵 ( Key ),各元素在陣列中出現的次數為值( Value ),轉換為字典 ( Dictionary )。
請先到網站 ( https://norvig.com/big.txt ) 下載文字檔至您的資料夾下。接著,讓 Python 讀取檔案,將所有文字以空格作為區隔後,存入 “words” 陣列。最後利用 “Counter”,將陣列 “words” 轉換為字典 ( Dictionary ) “WORDS”。
import re
text = open('big.txt').read()
words = re.findall(r'\w+', text.lower())
WORDS = Counter(words)
完成後,我們可以得到任意單字在 “text” 的出現次數。

步驟 4
接下來,我們會宣告三個 “defaultdict”,分別為 “confidence”, “x_position”,以及 “candidates”。
“defaultdict” 是一個能賦予預設值的字典 (Dictionary )。宣告時,可以利用“lambda” 為每個鍵 ( Key ) 賦予預設的值 ( Value )。
例:若要宣告一個預設值皆為 0 的 “defaultdict”,可以輸入以下程式碼
example_dictionary = defaultdict(lambda: 0)
本次實作中,我們需要將 “confidence”, “x_position”, 以及“candidates” 三個字典 ( Dictionary ) 的預設值設為 0。
confidence, x_position, candidates = defaultdict(lambda: 0), defaultdict(lambda: 0), defaultdict(lambda: 0)
“confidence” 總共有 26 個鍵,分別為 26 個英文字母,各自記錄著它被 Pixetto 偵測到的信心程度。每當 Pixetto 偵測到某字母時,該字母在“confidence” 中的值便會上升。您可以將其理解為每個字母被偵測到的次數。經過多次偵測,“confidence” 中擁有最高值的幾個鍵 ( Key ),即為手寫單字中出現的字母。
“x_position” 記錄著各個字母在影像中的 X 座標。數值越小代表它位於單字的左方,越大則代表位於右方。
創建完 “defaultdict” 後,宣告一個包含所有字母的字串,以便之後對各個字母進行操作。
alphabets = 'abcdefghijklmnopqrstuvwxyz'
為了讓程式更容易理解,我們可以讓使用者提供單字的長度。
word_len = int(input('Input the length of the word: '))
步驟 5
接下來,宣告一個 Pixetto Class,並連接指定的 Pixetto 視覺感測器 ( COM3 )。
pix = Pixetto()
pix.open("COM3")
連接威盛 Pixetto 視覺感測器後,我們可以先嘗試讀取威盛 Pixetto 的偵測資料。
while True:
if pix.is_detected() == True:
print(pix.get_data_list())
pix.close()


利用 “get_data_list()” 讀取威盛 Pixetto 回傳資料。每一筆資料都由兩個數字以及一個陣列所組成。第一個數字代表威盛Pixetto 目前的功能代號 ( 手寫字母辨識 ),第二個數字代表 Pixetto 偵測到之字母數量。最後的陣列則是由每個偵測到的字母的詳細資料所組成,除了字母 ( label ),亦包含了威盛 Pixetto 的辨識信心程度 ( confidence )、字母寬度高度 ( w, h ),以及 XY 座標 ( x, y )。
步驟 6
現在我們可以接收並記錄威盛 Pixetto 的回傳資料。
首先以 “objs” 紀錄回傳的陣列。由於我們只需陣列中的資料,無需第一及第二個回傳數字,因此可以先以底線 “_” 帶過。
while True:
if pix.is_detected() == True:
_, _, objs = pix.get_data_list()
for item in objs:
letter = item['label'][1] # 取小寫字母
x_pos = item['x']
conf = item['confidence']
變數 “objs” 是一個記錄偵測到之字母的陣列。我們可以利用 “for” 迴圈對陣列中每個元素做處理。
在迴圈裏,宣告三個變數,分別記錄偵測到之字母 ( letter )、字母之 X 座標( x_pos )、以及威盛Pixetto 的信心程度 (conf)。
在字典 “confidence” 中,將偵測到的字母對應到的值 ( Value ) 依據信心程度加上一定比例的值。為了不讓數值過高,可以使用 “min” 函式,將其上限設為100。
在字典 “x_position” 中,將偵測到的字母 ( letter ) 對應到的值 ( Value ) 更新。
for item in objs:
letter = item['label'][1]
x_pos = item['x']
conf = item['confidence']
confidence[letter] += 10 * conf
confidence[letter] = min(confidence[letter], 100)
x_position[letter] = x_pos
conf = item['confidence']
字典 “confidence” 的資料處理完後,請在 “for” 迴圈外,依據 “confidence”中的各個值 ( Value ) ,由大到小做排序,並由 “result_1” 紀錄前 “word_len”名 ( “word_len” 為單字字母個數 )。
result_1 = sorted(confidence.items(), key=lambda item: -
item[1])[0:word_len]
“result_1” 記錄了威盛 Pixetto 所偵測到的字母。但我們仍需依據各個字母的 X座標進行排列。
result_1 = sorted(confidence.items(), key=lambda item: -
item[1])[0:word_len]
result_2 = []
for item in result_1:
result_2.append([item[0], x_position[item[0]]])
result_2 = sorted(result_2, key=lambda item: item[1])
為了防止誤判的字母在字典 “condifence” 中的值居高不下,我們可以在每次讀取威盛 Pixetto 後,將所有字母的信心程度下降。
for i in alphabets:
if confidence[i] >= 2:
confidence[i] -= 2
else:
confidence[i] = 0
現在,我們可以對程式碼進行測試。

步驟 7
在這個步驟中,我們要讓程式在偵測到正確單字後停止。
首先,我們必須確認單字出現在單字庫中,並且長度必須等於使用者在前面步驟輸入的 “word_len”。
若是上述條件都符合,將該單字在字典 “candidates” 中的值加一。
if WORDS[word] != 0 and len(word) == word_len:
candidates[word] += 1
當偵測到的單字在字典 “candidates” 中的值超過十,便暫停程式,顯示該單字於螢幕上,並且詢問使用者是否繼續偵測。
if WORDS[word] != 0 and len(word) == word_len:
candidates[word] += 1
if candidates[word] > 10:
print('\nFinished detecting!')
print('Word detected: ', word)
correct_word = input('Continue detecting? (y/n)\n')
若是使用者輸入 “n”,則跳出 “while” 迴圈,結束程式。
若是輸入 “y”,則將 “candidates” , “confidence”, 以及 “x_position” 重製,並詢問下一個欲偵測單字的長度。
correct_word = input('Continue detecting? (y/n)\n')
if correct_word == 'n':
break
elif correct_word == 'y':
word_len = int(input('Input the length of the word:'))
candidates.clear()
confidence.clear()
x_position.clear()

我們已經完成了所有的程式碼了。現在,您可以在白紙上寫下五個字母以下的英文單字,並試著讓威盛 Pixetto 視覺感測器辨識。
結束辨識後,別忘了關閉威盛 Pixetto。
pix.close()
恭喜您完成了!
祝您玩得愉快,別忘了分享自己的創作至社群並標註 #VIAPixetto!