<<实例4:简单的触摸手势识别>>
在Ubuntu中创建一个文件夹,命名为pka04,在pka04文件夹中创建一个名称为main.py的Python文件,写入代码如下:
#-*-coding:utf-8-*-
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
Builder.load_file('gesture.kv')
class myLayout(FloatLayout):
pass
class pkaApp04(App):
def build(self):
return myLayout()
if __name__=='__main__':
pkaApp04().run()
在pka04文件夹中创建一个名称为mygestures.py的Python文件,写入代码如下:
from kivy.gesture import GestureDatabase
gdb = GestureDatabase()
cross = gdb.str_to_gesture(
'eNq1l9tu3DYQhu/1It6bLjicE+cFtrcF/ACBYwv2Iqkt7G7a5u1DDqlT0lZ7I2Mxsj5JP2f4k'
'xR1OH85//X9+Npfb98uffd7Ow6hO7wM0D0+vD/92T90Q8z/5gN218eH6+3y8aW/5lPqDl8H7g'
'7/KvLot3WDFCnNzw8f5/dbeSyVx+w/Hvuj3NUNUDMoKXzPj0DsTuGIGiRJGCOVbP4pV7E7/Ra'
'ORJZMwhS1u35++v9WyFvh7rU2ENEMJI1RuLu+NnEEgyhpjEG2xb1y0H3Ek4vbKA6kEmyKEWdx'
'WPaJsaVN8eidH2Ef8ejiOIqHdbeQLvolaLTFLxlty7ulsVlaNBKChCnmEpp+uRSSIozRBLbl3'
'dSoe8m7rdF2kkc3FmGSB1FVphYT6qSejY2sOsXtyYRuLOIkHgEtGrZIKJP4Spk13ZG524qzrX'
'FWLlHmfok/9UvcFndTUe8Rz8OVA7RIYXtAoluKdke3hJU42j0dQ24pwV7ybiptm1oGE+Rz4il'
'u9w25q8R3qQtnZ2WKd+TutpLeox4pZmt1jHlh3VR3X8nuUceFdIm4qc5uKy9mapCY339jXKb+'
'08tjewlmN5VxH3H3lBcLcASZfzGv4osFPiVk5SnmCb6p766y7qbvvvL0Zg2GKtHGCDjPJ2FKi'
'cfI2wuNuKsCu2i7qYLzdiP3BXGLYIs1DEAo0hh1eyaJeyq8i7b7KdM26ddNXpPO7SCSTnHbSn'
'ErxXaQVndSJyeJGQOMMe+RJm1aLrk5bku7kYp7SLuPOvlI6/FHs4+87hH2Fats/p8vff8+beV'
'Vyl5etTucMA/a7kSE+XAbNHVPmcGK2ZKBsxSciTPUyqAwUmdRKouFCToDqgwLU3MWQmVUmDnD'
'1O7jwsCfOuXFt0JxGKNDaS1rhVwhV5gqpBW0CnEJLaw0G4QKwwrGmlJaQaxw1bp5QRBsBb2iZ'
'MvczQtSWjGvx09m5uXwmnk1tNKDEGYbZli94TX0aqg1nRrE5Z3WoFdDtWyFBr0aqR2URljLqa'
'1bbNDrsToywth69QfqGIrcaDVoPSoBqkNtbDE1Wi3iqsAtV6gesSdL0vKCalLNdqa5rjpB3vr'
'z69utfJTmz8qTFclM/z6/3N4cSteSyvT28bW/PL0/935Ffdsd1n9Q7muT+dNw+Xj59lzFU+6W'
'Y5L8ug5qwTR/PFH5bDz+AM/6Dqo=')
circle = gdb.str_to_gesture(
'eNq1WNtyGzcMfd8fiV+iIS4EyB9QXzuTD+g4icbxpLU1ttI2f18QoHa5jpy12qlGAyUw9hA4B'
'yQh3dx/vf/z++7u8Hz69nSYfumfxzTdfD7C9OHdw+0fh3fTEe2f9kHT84d3z6enx6+HZ/svTz'
'e/H/N0cxHkg4dNR2lQas8fH+8fTu2x0h6rrzz2a4uajhAZtBS+2yOA0z7tCDMkqjk1y0W1pfN'
'3+zNN+/dpl0pGqmdLJcv0/PH25+uwr5Onu74EMxErVLeGMT3fNXQDT4C1kopbLVBhG92LB91G'
'h6RJinRb5A2ZF8euM/aP5JyxhVVShbBiJW9ho7OPcMZG1YTzWzTP2LgAm8XyBmx0bJqxsfSkm'
'8UqMzaRluVduW5ju5o4qwkKmFWruM28cGLNcW3eriXOWi5kv8zbNK7GcwmbabtP0LXEWcuB7M'
'Y3pSVxVuRMiGFJaBOcXEzqYrZtwglLEsluBdOSen7R5LiN7nISzehAwsQZwC3yfwJ3PSnP4FZ'
'31fnNrZX/PS8uKOkCvpBiFkfSF2Sz3PpoC9wVpTqDExXKmkvYmoc274S8nRZ2RXlR1B5u5xGG'
'1bKcK7a5rtz77ILyIihVSVzL2bb8zuB4LefsgnJ+AzjQtTuUXVBeBCVRTKSMbq1HA/u9b7DMo'
'hpWSLbPFnZFuf4/6NklzYOki57N1rzAQ8YV/HY3Ztc0L5piXR0BMqAj1GItLmELb/OeXdQ87F'
'KB8QhIOKDXOXGzOb2BGVc1D9sUaNxJNiPM6LQkbpbS9lbKrmpeVAXluRtTTloXdDs2B95z3UY'
'XV1UWVe2aPydutqAO6HIt7+KqCm0f7A2+Fk1JkNyiTQ+b8C6rzJdpyrkoQUlhUx6IZ61XEi8u'
'qyzXKSODTSphAcsAjnBlz4irKvN9CjVxsXEwu2UZ9iopXcmLuqgKWwOMb2JJNoh2y284B9Q11'
'WU6En2NFuRrFVVXVJdhN71QdDhjBIe3a/3xtg3/n54Oh4d5lFdps7zNmjd7Rt2laY9ad3V88X'
'Q6apluW0TxiAL2Yc7qTkqjs6RwSjgxnOBOhpUTw6krJ7kz06up2D3iETUiNB7L7pT+WLZhf3h'
'Ji5CIiLyU4zENZ5SlPYWoVSNZTeGMWv25vWnqzhq1amBKYNaotcTjuUdGrSXy8+rMGbWW7E6u'
'66SpRUStJRbgvGZDW0QUXqICjgqqjE6q4dSVM19Yrawi4MJqwUIJyTBqg5TGOpC6F1be9ON6t'
'tdGVkB+XNA2ZYREjwFfCgmSNJKC8/JBjMbyAN0bzLjS5k3dG9RoLJJK95axY9K52KBAohGShB'
'eCAgncdIFcABj79nJI8JHzT0L6/kg/CQk+mFd5Q/BBtKoRZNzXZz4g+MC0YhSCD+hqXWhGgCA'
'n1dcFxWAqdV0uND1gMJWCTIyeBnRy7CtZeLl7KbxRLPaykMObXu1k+1rpIb2VL20Hm9siJFKl'
'TiTqylu7t4SXx31o35ZW3p4zpZVXLyxNsAq5xBIFH/1syH1FCj76Hs69PSn4KHU8k2w+D5aCZ'
'+lbhKLqGvVJF5+i6hp0yRk3WiLFWSedfepdQOMBCtyFl/GsBe5a9xO4r8axESCNh7UNo+GFVw'
'95YB57VHuaHL0Pebwy7DYPb79IevLcex/W3n7/0dobhWI+X1buzVEoytprhcYN/OVwf/fl1H7'
'0sql+ry83CbbfxP66/3z64iF2m9sJZxjmPT3+fni6ffh08L9w/IixfkGL68PDb8enx8/fPsVS'
'edrnnc05diDYoIA2CpbUvu7t/gFuoPx3')
line = gdb.str_to_gesture(
'eNq1l8tSKzcQhvfzIrCJS62+v4CzTRUPkCLgAtc5AZfxSXLePq0eIJ7UYGljbwZ6fn0j9a9L6'
'3b/bf/Xz83T7u3047ibfn1/Hsp0+3iA6e7m5f7P3c10qPFnPHB6u7t5Ox1fv+3e4l+abr8feL'
'pdhdylbDpIQ2m0P7zuX06tmbVm/kWz35pqOsDcg9aFn9EE6rT9pWxKYfDiXB2KEDBmh/5pAkw'
'BO2G8KFbFiCRe/3F/+TuU3+Hp6cInnj7oZGhaXFQJHLlPz8GDjtEBvRCiRZgL9eGWcB+CkzpV'
'YHXGakBFuviaDlQYwxfSYpESY5L4RJ9ek45Xoqerla9ET1frmKtIWlFFgUwMdcDXmr7WMV+rc'
'8ybCDGzlWjao2PainAletqKY7ZWtEK1ioOpm0KfnrYiX4metuKYrcBgkRitglKlUn89YdqKfi'
'U8pa8E18KnsTRmLABIic1SWSP3ULSPT2dpzNmiCrVqNWeDEptaH5/W0pi1BQGIFTTOD2uD6C9'
'ZSm9pwNv2CrHtAwAcZxSAQ7//nOYyXI2f7jIO8VENXN1VlbGI99PD6S6/u9vohVlAkavEWYQk'
'+omP76kxghaw6MFA39Nb1uvA01j2IXgcI8C11KLSDvH+QSJpq8AQ3bQSl9jIokLgkSUraargE'
'D12SHSk0ERpE8u2T09P5cxTwYLV3aV6VBryyY6lSkquNaYixq7cny+SlooOsKNQkjhi1YPLMf'
'X77HRUfIDtMbkxNkh3jjfWz7imnwp9NkKUYxZgiLMpTtk+Os1UHECzC5vFcY2KZaDe0HRSB5x'
'EM3RiqFFK1iiZGrpdCB6Ou93LZ3mv0up71el2GxNqU6ZtLRyP0yGm1X0L4iLoc9DOg1YyyLQI'
'QgZlwbSaQV0wDTNoyyBl0OsiyC1IBTZ+/qMzhaQCdNFMM1iX/cvhES7753NwMTzP4RFRW5T//'
'eRMkWONKb1olmMleR+BLFtjU+Cs8BXwmjxTQipfA+f8qH2tmPNj5UOxSKQ2xZysDzfWFHPmjF'
'ZcWJPPOTX9EghlzrDZGDHKiNQ7rSZuRT9b4X6hC+kFr06tVT3Neh7VpzUMMNplmfV4ocs6S+i'
'CJKyal/3zbv/0fGp37+LT9n+j1Lj6hubv/ePpuUniPr+Niiq4ET29ft8d718edvkG8gBq8ff9'
'6ffD8fXxx0Oi25ZUN3HtNlaOLa1obZvl5l8HGD4O')
square = gdb.str_to_gesture(
'eNq1mEluIzcYRvd1EXsT4Z+HC6i3AXyAwG0LttEdW7DUSfr2YZHVEgk4KQGCtZH8RD4OH4eSb'
'1++vfz1c/O0Oxx/vO+mL8v7Hqbbxz1Odzev93/ubqY9lY/ljafD3c3h+P72bXcof8p0+32v0+'
'2HkrtabNrbrPJSf//28nqcq8VcLf+j2u9zqWmPrQdzF36WKkjTFjasKZKMaJwqGTp355/5a56'
'2v8FGREAVLIINymebDl/v/78Zqc3o9LS04EgogK6ECeSlhadFTomIHElsKqoS6/I6dPQL5JiW'
'aSTKYMZEuS6PKs8L5DD03DB11U51+gnX7EVuGOQUgqDIxHGBnKqc1+XkJXLMyAyXUFkPlGqgp'
'J/irnmSr7s5kThBIhAB5RJ3jZPOcYpbiIG6elkc81Je3DL222TVzTVMPoVJggFESoEGBIJndy'
'irWWpYRonyAnfNkk9ZQkQYghuLSlnI7tfIa5i8hDmvZFBSUwdH5ixDgKv6XvNkP+mxbDxgo1S'
'2JIhr3DVPzpOb0IGQ3DTVhTPP8nEH+bpcaqCCJzkHOjlqpISFAp/lZMqMZqIBLnCBvCYqfJKL'
'EqNyCgkFFNlZjt0qJaD1rS81UTknKuEGqYgRGUZdnsxlnapilrkiKafjurzmKec8Sy12KTPvT'
'mWn5lle9mS/B2z9MJcaqOSqvC7TflRlkZZ7bM2vNVPFT/PXWJUv8ZO5hkiAQVkz5Wpat9dcVT'
'/JXoNVv8Quoz3Wl43WZDU/x241V1vfq+UrRTFhLicyAxpecG1YTdXOqVLXP4XSRmcHCg/NIPG'
'AcnOs22uqdk4Vx777dfaaqp2uU+jPWGdkvcpeU7X8HLvXVP10pWJKOdSFksIMSgNXyWuofrpT'
'yyUKaewgxuCJeJW8ZuqnB6TxIATspkXGJ16r8vkHwMP7bvd6epx3m5/ny0V/uy1X4wamLaWVt'
'+PeY7qfoQ8wG8wGvcKACjMGiDMsj/EDpApRB8gV0lhdKpSxulaoI7QKDQfoDfIAY4Cyyf4lc4'
'lsJaSV4FotYYDzCd69bC6BfYloU5XUQ88GeYBLA9JD+6BfqX0J1VZtGThVKD72i+cS3k+NUKv'
'WZkFbhMwfVMu+BOXYHy8lENqcaMuM2vyWp+WB2kJpoLrQNhOqI21Toa3HJAttw5c2fOKFtvGz'
'jrSNmWikbdAAI11WMw8U23L2HCkOdBkxUk8/msyyCVsj0IeAKAP9aI5R+yJ1+mZqPXVYqPc0f'
'jUSA82FZk9zmWNqo45hG5WfSB1lWOaCqDMwLDkTD/SXoQy0nTzPu5en52P9f4BO25jbLfTvl8'
'fjc4VWoDZ4fPu+e79/fdjVL7we0jC+cC63nJJ/7N/fHn88NHdM29xw+VUXOp+Mzm7FcPi6+Re'
'GcFi7')
在以上的mygestures.py文件中我们预定义了四个常用的手势:cross、circle、line、square,分别对应叉子手势、圆圈手势、直线手势和方形手势。
在pka04文件夹中创建一个名称gesture.kv的Kv文件,写入代码如下:
#-*-coding:utf-8-*-
#:import gesture_board gesture_board
<mylayout>:
orientation:'vertical'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
size_hint_x:.3
font_name:'simhei.ttf'
text:'叉子图形相似度:'
Button:
id:text1
text:'cross'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
size_hint_x:.3
font_name:'simhei.ttf'
text:'横线图形相似度:'
Button:
id:text2
text:'line'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
size_hint_x:.3
font_name:'simhei.ttf'
text:'圆圈图形相似度:'
Button:
id:text3
text:'circle'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
size_hint_x:.3
font_name:'simhei.ttf'
text:'方形图形相似度:'
Button:
id:text4
text:'square'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
size_hint_x:.3
font_name:'simhei.ttf'
text:'大于0.7的手势:'
Button:
id:text5
text:'gesture'
BoxLayout:
orientation:'horizontal'
size_hint_y:.1
Button:
font_name:'simhei.ttf'
text:'手势图形为:'
Button:
id:text6
font_name:'simhei.ttf'
text:'gesture'
GestureBoard:
id:gestureboard1
atext1:text1
atext2:text2
atext3:text3
atext4:text4
atext5:text5
atext6:text6
以上Kv文件描述窗口的布局,如下图:
接下来在pka04文件夹中创建一个名称gesture_board.py的Python文件,写入代码如下:
#-*-coding:utf-8-*-
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Ellipse, Line
from kivy.gesture import Gesture, GestureDatabase
from mygestures import cross, circle,line, square
def simplegesture(name, point_list):
"""
将点集合转换为手势
"""
g = Gesture()
g.add_stroke(point_list)
g.normalize()
g.name = name
return g
class GestureBoard(BoxLayout):
def __init__(self, *args, **kwargs):
super(GestureBoard, self).__init__()
self.gdb = GestureDatabase()
#将已定义的手势添加到手势库
self.gdb.add_gesture(cross)
self.gdb.add_gesture(line)
self.gdb.add_gesture(circle)
self.gdb.add_gesture(square)
def on_touch_down(self, touch):
# 开始收集点到touch.ud
# 创建线显示这些点
userdata = touch.ud
with self.canvas:
Color(1, 1, 0)
d = 10.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
userdata['line'] = Line(points=(touch.x, touch.y))
return True
def on_touch_move(self, touch):
# 存储触摸移动的点
try:
touch.ud['line'].points += [touch.x, touch.y]
return True
except (KeyError) as e:
pass
def on_touch_up(self, touch):
# 触摸结束,显示信息,检测是否有匹配,确认手势
g = simplegesture('', list(zip(touch.ud['line'].points[::2],
touch.ud['line'].points[1::2])))
#命令行输出手势字符串
print("gesture representation:", self.gdb.gesture_to_str(g))
#输出与所有已知手势的匹配得分
self.atext1.text=str(g.get_score(cross))
self.atext2.text=str(g.get_score(line))
self.atext3.text=str(g.get_score(circle))
self.atext4.text=str(g.get_score(square))
# 在数据库中查找最匹配的手势
g2 = self.gdb.find(g, minscore=0.70)
print str(g2)
#输出手势数据v
self.atext5.text=str(g2)
if g2: #如果g2不为空
if g2[1] == circle:
self.atext6.text="圆圈"
if g2[1] == square:
self.atext6.text="方形"
if g2[1] == line:
self.atext6.text="直线"
if g2[1] == cross:
self.atext6.text="叉子"
else:
self.atext6.text="无"