Code archives/Algorithms/Mouse Gestures Recogn
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| The basic idea is: if MouseMoving Identify 8 Mouse Directions (like West, NorthWest, North And so on) And record a sequence of Directions if MouseStoppedMovement compare the sequence of movements recorded with a List of Sequences To compare strings is used the LevenshteinDistance, the selected pattern will be the one that has the minimum distance. | |||||
; --------------------------------------------------------------------------
;
; Mouse Gestures Recogn
; Autor: Juan Ignacio Odriozola
;
; Based on: http://www.bytearray.org/?p=91
;
; The basic idea is:
; if MouseMoving Identify 8 Mouse Directions (like West, NorthWest, North And so on) And record a sequence of Directions
; if MouseStoppedMovement compare the sequence of movements recorded with a List of Sequences
;
; to compare strings is used the LevenshteinDistance, the selected pattern will be the one that has the minimum distance.
;
; The Gestures are defined in the file "Gestos.txt"
; Each line started with a SPACE or a Semicolon (" ",";") will be skiped
; each line with a gesture definition will have 2 fields comma separeted like: A,71
; This indicates that the Gesture to construct the letter "A" (first field) is comprised by 2 mouse movements: 7 and then 1
; the mouse orientations are as follows:
;
; 5 6 7
; \ | /
; 4 <-- Start --> 0
; / | \
; 3 2 1
;
; for example East is 0, West is 4 and so on
;
; At first the code loads the "Gestos.txt" and generates an image based on the traces wich is Drawn as a helpper
; The first trace is green colored, all traces are lines ended with a dot
;
; there are some commented lines in the "Gestures.txt" with optional patterns for some Gestures
;
; for example the "8" could be: 4321234567654 (yes all that) but with some imagination the following is ok "8" : 3136
; like the 7 segment displays, it all depends how much simplification we are pretending
;
; I'm focused on few movements because the final version is for a kid with "so much motor problems"
; (donīt know the exact expression in english)
;
;---------------------------------------------------------------------------
Graphics 800,600, 0, 2
HidePointer()
Local InputString$
Local AcumTraces$
Local LastGesture$
Local MouseDirection, LikeThis$
Local State=2 ;valor aceptado
Local Moving=-1
Local Transition=-1
Local Count=0
Local LastMove=-1
Const TransitionThreshold = 1, StopThreshold = 15
Type tGestures
Field Gesture$
Field Pattern$
End Type
Type tHistory
Field Gesture$ ;"A"
Field Find$ ;"710"
Field Pattern$ ;"71"
Field Dist
End Type
LoadGestures()
Local Imagen = GenerarImagen()
Local h.tHistory
Local i, c
While Not(KeyHit(1))
Cls
Text 10, 10, "Accum Mouse Traces : "+AcumTraces
Text 10, 30, "Last Validated Trace : "+LastGesture
Text 10, 50, "Gesture Associated : "+LikeThis
Text 10, 90, "Input Text : "+InputString
i=30
c=1
Color 0,255,0
Text 430,10,"Pattern"
Text 560,10,"Traces"
Text 670,10,"Dif"
Text 700,10,"Gesture"
Color 255,255,255
For h=Each tHistory
Text 430,i,h\Pattern
Text 560,i,h\Find
Text 670,i,h\Dist
Text 700,i,h\Gesture
i=i+20
c=c+1
If c=14 Then
Delete First tHistory
Exit
End If
Next
DrawImage Imagen,0,GraphicsHeight()-ImageHeight(Imagen)
MouseDirection = EstimoOrientacion()
Select State
Case 1
If MouseDirection=Transition Then
Count=Count+1
If MouseDirection=-1 Then
If Count >= StopThreshold Then
State = 2
Moving = MouseDirection
End If
Else
If Count >= TransitionThreshold Then
State = 2
Moving = MouseDirection
End If
End If
Else
If MouseDirection=Moving Then
State=2
Else
Transition=MouseDirection
Count=0
End If
End If
Case 2
If MouseDirection<>Moving Then
State = 1
Count = 0
Transition=MouseDirection
End If
End Select
If Moving<>LastMove Then
If LastMove=-1 Then
AcumTraces=""
End If
LastMove = Moving ;recuerdo mi ultima tendencia
If Moving <> - 1 Then
AcumTraces = AcumTraces + Str(Moving) ;si me muevo anoto secuencia
End If
End If
If Moving=-1 Then
If AcumTraces<>"" Then
LikeThis = BuscarParecidos(AcumTraces)
If LikeThis<>"" Then
Select LikeThis
Case "SPACE"
InputString=InputString+" "
Case "DOT"
InputString=InputString+"."
Case "BACKSPACE"
If InputString<>"" Then InputString = Left(InputString,Len(InputString)-1)
Default
InputString=InputString+LikeThis
End Select
LastGesture=AcumTraces
End If
AcumTraces = ""
End If
End If
If KeyHit(57) Then
InputString=""
Delete Each tHistory
End If
MoveMouse(400,300)
Delay 20
Wend
End
Function EstimoOrientacion() ;Estimate mouse movement
Local x#, y#, r, Prueba#, Alfa#
Local strOut$
x = MouseXSpeed()
y = MouseYSpeed()
Alfa# = ATan2(y,x)
If Alfa < 0 Then Alfa = 360+Alfa
If x=0 And y=0 Then
r=-1
Else
r=0
Prueba#=22.5
If Alfa>22.5 And Alfa<337.5 Then
While Alfa>Prueba#
r = r + 1
Prueba# = Prueba#+45
Wend
End If
End If
Return r
End Function
Dim Ld(1,1)
Function Min#(a#, b#)
If a<b Then
Return a
Else
Return b
End If
End Function
Function Max#(a#, b#)
If a>b Then
Return a
Else
Return b
End If
End Function
Function AddGesture.tGestures(Gesture$, Pattern$)
Local g.tGestures=New tGestures
g\Pattern = Pattern
g\Gesture = Gesture
Return g
End Function
Function LevenshteinDistance(String1$, String2$)
;calculates the minimun amount of basic operations required to transmorm String1 into String2
;3 basic operations are considered: Character Delet, Insert, Substitution
Local Len1=Len(String1)
Local Len2=Len(String2)
Dim Ld(Len1, Len2)
Local i, j, Cost, s1$, s2$
If Len1 = 0 Then Return Len2
If Len2 = 0 Then Return Len1
For i=0 To Len1
Ld(i,0)=i
Next
For j=0 To Len2
Ld(0,j)=j
Next
For i=1 To Len1
For j=1 To Len2
s1$ = Mid(String1,i,1)
s2$ = Mid(String2,j,1)
If s1 = s2 Then
Cost=0
Else
Cost=1
End If
Ld(i,j) = Min( Min( Ld(i-1,j)+1 , Ld(i,j-1)+1 ), Ld(i-1,j-1)+Cost) ;deletion, insertion, substitution
Next
Next
Return Ld(Len1, Len2)
End Function
Function BuscarParecidos$(Buscar$) ;search match
Local Gesto.tGestures
Local MinDistance=1000
Local g$="", d, Pattern$
Local h.tHistory
;calculo la distancia de la cadena a buscar contra los gestos almacenados
;me quedo con la distancia menor. Luego evaluo que la distancia sea menor que el 30%
;respecto al largo de la cadena.
For Gesto = Each tGestures
d = LevenshteinDistance(Buscar, Gesto\Pattern)
If d<MinDistance Then
MinDistance = d
Pattern = Gesto\Pattern
g = Gesto\Gesture
End If
Next
If Float(MinDistance/Float(Len(Buscar))) < 0.3 Then
h=New tHistory
h\Gesture = g
h\Find = Buscar
h\Pattern = Pattern
h\Dist = MinDistance
Return g
Else
Return ""
End If
End Function
Function LoadGestures()
Local g.tGestures
Local Entrada = ReadFile("Gestos.txt")
Local StrEntrada$,Pos
While Not(Eof(Entrada))
StrEntrada = ReadLine(Entrada)
If Left(StrEntrada,1)<>";" And Left(StrEntrada,1)<>" " Then
Pos = Instr(StrEntrada,",")
g=New tGestures
g\Gesture = Mid(StrEntrada,1,Pos-1)
g\Pattern = Right( StrEntrada,Len(StrEntrada)-Pos)
End If
Wend
End Function
Function GenerarImagen(Create=True)
Local g.tGestures
Local i,j, txt$
Local Ancho=60, Alto=100
Local x, y, x1, y1, xDir, yDir, xDirOld, yDirOld
Local idx, Secuencia$
Local Imagen = CreateImage(800,Alto*3)
If Create=False Then
Return LoadImage("Patrones.bmp")
End If
SetBuffer ImageBuffer(Imagen)
ClsColor 0,0,0
Cls
Color 255,255,255
Local xMin, yMin, xMax, yMax
Local AnchoTrazado, AltoTrazado
Local Paso
For g = Each tGestures
Color 255,255,255
Rect i*Ancho,j*Alto,Ancho,Alto,False
Select g\Gesture
Case "SPACE"
txt = "SPC"
Case "DOT"
txt = "DOT"
Case "BACKSPACE"
txt = "<--"
Default
txt = g\Gesture
End Select
Color 255,255,255
Text i*Ancho+5,j*Alto+5,txt
Secuencia = g\Pattern
;primero calculo x,y minimas y maximas, para saber:
;a cuanto ajustar el paso (largo de cada linea)
;donde poner x,y iniciales para que el trazado quede centrado
x=0
y=0
xMax=-1000
xMin=+1000
yMax=-1000
yMin=+1000
xMax=0
xMin=0
yMax=0
yMin=0
For idx=1 To Len(Secuencia)
Select Mid(Secuencia,idx,1)
Case "0"
xDir=1
yDir=0
Case "1"
xDir=1
yDir=1
Case "2"
xDir=0
yDir=1
Case "3"
xDir=-1
yDir=1
Case "4"
xDir=-1
yDir=0
Case "5"
xDir=-1
yDir=-1
Case "6"
xDir=0
yDir=-1
Case "7"
xDir=1
yDir=-1
End Select
x = x + xDir
y = y + yDir
xMin = Min(x,xMin)
yMin = Min(y,yMin)
xMax = Max(x,xMax)
yMax = Max(y,yMax)
Next
AnchoTrazado = Max(xMax-xMin, 1)
AltoTrazado = Max(yMax-yMin, 1)
Paso = Min(Ancho/AnchoTrazado,Alto/AltoTrazado)/2
DebugLog Paso+" "+AnchoTrazado+" "+AltoTrazado
x = i*Ancho + (Ancho-Paso*AnchoTrazado)/2 - xMin*Paso/2 +5
y = j*Alto + (Alto-Paso*AltoTrazado)/2 - yMin*Paso/2
;ahora hago los trazados
For idx=1 To Len(Secuencia)
Select Mid(Secuencia,idx,1)
Case "0"
xDir=1
yDir=0
Case "1"
xDir=1
yDir=1
Case "2"
xDir=0
yDir=1
Case "3"
xDir=-1
yDir=1
Case "4"
xDir=-1
yDir=0
Case "5"
xDir=-1
yDir=-1
Case "6"
xDir=0
yDir=-1
Case "7"
xDir=1
yDir=-1
End Select
x1 = x + xDir*Paso
y1 = y + yDir*Paso
If idx=1 Then
Color 0,255,0
Else
Color 255,255,255
End If
Line x, y, x1, y1
x=x1
y=y1
Oval x-1,y-1,3,3,True
If xDir=0 And xDirOld=0 Then
x=x-yDirOld*4
End If
If yDir=0 And yDirOld=0 Then
y=y-xDirOld*4
End If
xDirOld = xDir
yDirOld = yDir
Next
i=i+1
If i > (GraphicsWidth()/Ancho)-1 Then
j=j+1
i=0
End If
Next
SaveImage Imagen,"Patrones.bmp"
SetBuffer FrontBuffer()
Return Imagen
End Function
;~IDEal Editor Parameters:
;~C#Blitz3D |
Comments
| ||
| Note For the above code to work, a text file called: "Gestos.txt" is needed: Juan |
Code Archives Forum