Code archives/Algorithms/Mouse Gestures Recogn

This code has been declared by its author to be Public Domain code.

Download source code

Mouse Gestures Recogn by Charrua2011
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

Charrua2011
Note
For the above code to work, a text file called: "Gestos.txt" is needed:



Juan


Code Archives Forum