作品欣赏

首页 资讯中心 作品欣赏 干货分享 | 教你辨识手写英文单字

干货分享 | 教你辨识手写英文单字

869    2021-04-29 08:43:26   

在本次流程说明中,我们会利用威栗camera 的手写字母识别功能,实作一个能识别英文单字的Python程序。


在手写字母识别功能里,威栗camera不仅能侦测英文字母,它也能告诉使用者各个字母的出现位置。通过以上资讯,我们可以精确地识别使用者提供的手写单字。


接下来,我们一步一步介绍如何汇入威栗camera 所需函数库、如何读取并利用威栗camera的回传数据,达成本次实作目标。


若您尚未建立Python 编程环境,请先参考“Python 环境设置流程说明(https://pixetto.ai/tw/2020/08/python-environment-setup-tw/)”。



步骤 1


威栗camera连接至电脑后,开启CZL智能传感器工具。在右方选单中选择“手写字母辨识”。由于我们需要同时识别多个字母,请将“最大显示物件数量” 设为5。


完成后,即可测试威栗camera 是否能正确识别字母。


2688_86ow_9511.png

2689_vdw9_5662.png



步骤 2


开启Jupyter Notebook,并建立一份“ipynb”档案。


2689_nwqi_4562.png

在第一栏code cell 里,汇入威栗camera 以及collections 等函数库。


from pixetto import Pixetto
from collections import defaultdict, Counter

在Python 程序里,我们会将威栗camera 视为一个“类别” ( Class )。在后续的步骤中,我们可以直接呼叫类别中的“方法” ( Method ),以开启、关闭、或读取威栗camera


第二行的“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 个英文字母,各自记录着它被威栗camera 侦测到的信心程度。每当威栗camera 侦测到某字母时,该字母在“confidence” 中的值便会上升。您可以将其理解为每个字母被侦测到的次数。经过多次侦测,“confidence” 中拥有最高值的几个键( Key ),即为手写单字中出现的字母。


“x_position” 记录着各个字母在影像中的X 座标。数值越小代表它位于单字的左方,越大则代表位于右方。


创建完“defaultdict” 后,宣告一个包含所有字母的字串,以便之后对各个字母进行操作。

alphabets = 'abcdefghijklmnopqrstuvwxyz'

为了让程序更容易理解,我们可以让使用者提供单字的长度。

word_len = int(input('Input the length of the word: '))



步骤 5


接下来,宣告一个威栗camera Class,并连接指定的威栗camera 视觉传感器( COM3 )。


pix = Pixetto()
pix.open("COM3")

连接威栗camera 视觉传感器后,我们可以先尝试读取威栗camera 的侦测资料。



while True:
    if pix.is_detected() == True:
        print(pix.get_data_list())

pix.close()




利用“get_data_list()” 读取威栗camera 回传资料。每一笔资料都由两个数字以及一个阵列所组成。第一个数字代表威栗camera 目前的功能代号( 手写字母辨识),第二个数字代表威栗camera 侦测到之字母数量。最后的阵列则是由每个侦测到的字母的详细资料所组成,除了字母( label ),亦包含了威栗camera 的辨识信心程度( confidence )、字母宽度高度( w, h ),以及XY 座标( x, y )。



步骤 6


现在我们可以接收并记录威栗camera 的回传资料。

首先以“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 )、以及威栗camera 的信心程度(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” 记录了威栗camera 所侦测到的字母。但我们仍需依据各个字母的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” 中的值居高不下,我们可以在每次读取威栗camera 后,将所有字母的信心程度下降。


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()

图片


我们已经完成了所有的程序码了。现在,您可以在白纸上写下五个字母以下的英文单字,并试着让威栗camera 视觉传感器辨识。


结束识别后,别忘了关闭威栗camera

pix.close()

恭喜您完成了!