$1 Unistroke Recognizer( lua )
来源:互联网 发布:护理优化服务流程 编辑:程序博客网 时间:2024/06/05 20:52
最近在做一个游戏,里面涉及到了手势识别(比较复杂的手势),由于自身数学并不好。。去网上搜了一番,找到了这个$1识别算法,http://depts.washington.edu/aimgroup/proj/dollar/ 这是官网,发现这是目前网上比较好的一种手势识别算法,而且可以添加自定义手势模板。然后发现源码下载里面没有Lua的版本T_T,,,无奈之下,把js版本的大概翻译了一下,现在发上来好了。
local Recognizer = class("Recognizer")----- Point --local function Point(x,y)-- local pt = { X=0,Y=0 }-- pt.X = x-- pt.Y = y return { X=x,Y=y }end----- Rectangle--local function Rectangle(x,y,width,height) local rectangle = {} rectangle.X = x rectangle.Y = y rectangle.Width = width rectangle.Height = height return rectangle end----- deglocal function Deg2Rad(d) return (d * math.pi / 180.0)endlocal NumUnistrokes = 16;local NumPoints = 64;local SquareSize = 250.0;local Origin = Point(0,0);local Diagonal = math.sqrt(SquareSize * SquareSize + SquareSize * SquareSize);local HalfDiagonal = 0.5 * Diagonal;local AngleRange = Deg2Rad(45.0);local AnglePrecision = Deg2Rad(2.0);local Phi = 0.5 * (-1.0 + math.sqrt(5.0)) -- Golden Ratio----- distancelocal function Distance(p1, p2) local dx = p2.X - p1.X; local dy = p2.Y - p1.Y; return math.sqrt(dx * dx + dy * dy);end----- pathLengthlocal function PathLength(points) local d = 0.0; for i = 2 ,#points,1 do d = d + Distance(points[i - 1], points[i]) end return dend----- pathDistancelocal function PathDistance(pts1, pts2) local d = 0.0 for i = 1,#pts1,1 do -- assumes pts1.length == pts2.length d = d + Distance(pts1[i], pts2[i]) end return d / #pts1;end----- boundingboxlocal function BoundingBox(points) local minX = math.huge local maxX = -math.huge local minY = math.huge local maxY = -math.huge for i = 1,#points, 1 do minX = math.min(minX, points[i].X) minY = math.min(minY, points[i].Y) maxX = math.max(maxX, points[i].X) maxY = math.max(maxY, points[i].Y) end return Rectangle(minX, minY, maxX - minX, maxY - minY)end----- centroid 矩心❤local function Centroid(points) local x = 0.0 local y = 0.0 for i = 1,#points,1 do x = x + points[i].X y = y + points[i].Y end x = x / #points y = y / #points return Point(x, y)endlocal function RotateBy(points, radians) -- rotates points around centroid local c = Centroid(points) local cos = math.cos(radians) local sin = math.sin(radians) local newpoints = {} for i = 1,#points,1 do local qx = (points[i].X - c.X) * cos - (points[i].Y - c.Y) * sin + c.X local qy = (points[i].X - c.X) * sin + (points[i].Y - c.Y) * cos + c.Y; newpoints[#newpoints+1] = Point(qx, qy); end return newpoints;end-----distanceAtanglelocal function DistanceAtAngle(points, T, radians) local newpoints = RotateBy(points, radians) return PathDistance(newpoints, T.Points)end-----DistanceAtBestAnglelocal function DistanceAtBestAngle(points, T, a, b, threshold) local x1 = Phi * a + (1.0 - Phi) * b; local f1 = DistanceAtAngle(points, T, x1); local x2 = (1.0 - Phi) * a + Phi * b; local f2 = DistanceAtAngle(points, T, x2); while math.abs(b - a) > threshold do if (f1 < f2) then b = x2; x2 = x1; f2 = f1; x1 = Phi * a + (1.0 - Phi) * b; f1 = DistanceAtAngle(points, T, x1); else a = x1; x1 = x2; f1 = f2; x2 = (1.0 - Phi) * a + Phi * b; f2 = DistanceAtAngle(points, T, x2); end end return math.min(f1, f2);end-----OptimalCosineDistancelocal function OptimalCosineDistance(v1, v2) -- for Protractor local a = 0.0; local b = 0.0; for i = 1,#v1,2 do-- print(" "..i.." "..#v1.." "..#v2) a = a + v1[i] * v2[i] + v1[i + 1] * v2[i + 1] b = b + v1[i] * v2[i + 1] - v1[i + 1] * v2[i] end local angle = math.atan(b / a) return math.acos(a * math.cos(angle) + b * math.sin(angle));end-----Vectorizelocal function Vectorize(points) -- for Protractor local sum = 0.0; local vector ={} for i = 1,#points,1 do vector[#vector+1] = points[i].X; vector[#vector+1] = points[i].Y; sum = sum + points[i].X * points[i].X + points[i].Y * points[i].Y; end local magnitude = math.sqrt(sum); for i = 1,#vector,1 do vector[i] = vector[i] / magnitude; end return vector;end-----TranslateTolocal function TranslateTo(points, pt) -- translates points' centroid local c = Centroid(points) local newpoints = {} for i = 1,#points,1 do local qx = points[i].X + pt.X - c.X; local qy = points[i].Y + pt.Y - c.Y; newpoints[#newpoints+1] = Point(qx, qy); end return newpoints;end-----ScaleTolocal function ScaleTo(points, size) -- non-uniform scale; assumes 2D gestures (i.e., no lines) local B = BoundingBox(points) local newpoints = {} for i = 1,#points,1 do local qx = points[i].X * (size / B.Width) local qy = points[i].Y * (size / B.Height) newpoints[#newpoints+1] = Point(qx, qy); end return newpoints;end-----RotateBylocal function RotateBy(points, radians) -- rotates points around centroid local c = Centroid(points); local cos = math.cos(radians); local sin = math.sin(radians); local newpoints = {} for i = 1,#points,1 do local qx = (points[i].X - c.X) * cos - (points[i].Y - c.Y) * sin + c.X local qy = (points[i].X - c.X) * sin + (points[i].Y - c.Y) * cos + c.Y newpoints[#newpoints+1] = Point(qx, qy) end return newpoints;end-----IndicativeAnglelocal function IndicativeAngle(points) local c = Centroid(points) return math.atan2(c.Y - points[1].Y, c.X - points[1].X)end----- Private helper functions from this point down--local function Resample(points, n) local I = PathLength(points) / (n - 1) -- interval length local D = 0.0 local newpoints = { points[1] }-- print(" ijjhhhhhhh local k = 2 while k<= #points do local d = Distance(points[k - 1], points[k])-- print(" "..I) if D + d >= I then-- print(" "..points[k - 1].X + ((I - D) / d) * (points[k].X - points[k - 1].X)) local qx = points[k - 1].X + ((I - D) / d) * (points[k].X - points[k - 1].X); local qy = points[k - 1].Y + ((I - D) / d) * (points[k].Y - points[k - 1].Y);-- print(" "..points[k - 1].X.." "..I.." "..D.." "..d.." "..points[k].X.." "..points[k - 1].X) local q = Point(qx, qy)-- print(" "..q.X.." "..q.Y.." "..k-1) newpoints[#newpoints+1] = q; -- append new point 'q'-- print(" "..#newpoints.." "..k.." "..#points) table.insert(points,k,q) -- points.splice(k, 0, q) -- insert 'q' at position k in points s.t. 'q' will be the next k D = 0.0; else D = D + d;-- print(" "..#newpoints.." "..k.." "..#points) end k = k + 1 end if #newpoints == n - 1 then -- somtimes we fall a rounding-error short of adding the last point, so add it if so newpoints[#newpoints+1] = Point(points[#points].X, points[#points].Y) end return newpoints;end----- Unistroke class: a unistroke template--local function Unistroke(name, points) -- constructor local uni = {} uni.Name = name; uni.Points = Resample(points, NumPoints); local radians = IndicativeAngle(uni.Points); uni.Points = RotateBy(uni.Points, -radians); uni.Points = ScaleTo(uni.Points, SquareSize); uni.Points = TranslateTo(uni.Points, Origin); uni.Vector = Vectorize(uni.Points); -- for Protractor return uniend----- Result class--local function Result(name, score) --constructor local re = {} re.Name = name; re.Score = score; return reendlocal tbSign = { "Heng" } -- 手势的名称----- DollarRecognizer class--function Recognizer:DollarRecognizer() -- constructor local mUnis = { Unistrokes={} } -- -- one built-in unistroke per gesture type -- mUnis.Unistrokes = {} --模板 mUnis.Unistrokes[1] = Unistroke(tbSign[3],{ Point(80,304),Point(82,297),Point(87,281),Point(95,261),Point(102,236),Point(117,197),Point(128,173),Point(137,152),Point(140,146),Point(144,138),Point(145,134),Point(148,128),Point(149,126),Point(150,123),Point(151,121),Point(152,121),Point(153,117),Point(157,112),Point(159,109),Point(162,106),Point(162,105),Point(165,114),Point(173,131),Point(184,143),Point(197,164),Point(205,180),Point(213,200),Point(223,220),Point(228,242),Point(234,258),Point(238,271),Point(240,278),Point(243,285),Point(247,292),Point(251,297),Point(251,298),Point(251,298)}); -- -- The $1 Gesture Recognizer API begins here -- 3 methods: Recognize(), AddGesture(), and DeleteUserGestures() ---- mUnis.Recognize = function(points, useProtractor) function mUnis:Recognize(points,useProtractor) local tbResult = {} points = Resample(points, NumPoints); local radians = IndicativeAngle(points); points = RotateBy(points, -radians); points = ScaleTo(points, SquareSize); points = TranslateTo(points, Origin); local vector = Vectorize(points); -- for Protractor local b = math.huge local u = -1 for i = 1,#mUnis.Unistrokes,1 do -- for each unistroke local d; if (useProtractor) then -- for Protractor d = OptimalCosineDistance(mUnis.Unistrokes[i].Vector, vector); else -- Golden Section Search (original $1) d = DistanceAtBestAngle(points, mUnis.Unistrokes[i], -AngleRange, AngleRange, AnglePrecision) end if (d < b) then b = d; -- best (least) distance u = i; -- unistroke end end if u == -1 then return Result("No match.",0.0) else if useProtractor == true then return Result( mUnis.Unistrokes[u].Name,1.0 / b ) else return Result( mUnis.Unistrokes[u].Name,1.0 - b / HalfDiagonal ) end end-- return (u == -1) ? new Result("No match.", 0.0) : new Result(this.Unistrokes[u].Name, useProtractor ? 1.0 / b : 1.0 - b / HalfDiagonal); end---- this.AddGesture = function(name, points)-- function mUnis:AddGesture(name,points)-- mUnis.Unistrokes[#mUnis.Unistrokes+1] = Unistroke(name, points) -- append new unistroke-- local num = 0;-- for i = 1,#mUnis.Unistrokes,1 do-- if mUnis.Unistrokes[i].Name == name then-- num = num + 1-- end-- end-- return num;-- end---- this.DeleteUserGestures = function()-- function mUnis:DeleteUserGestures()---- #mUnis.Unistrokes = NumUnistrokes; -- clear any beyond the original set-- for i=#mUnis.Unistrokes ,NumUnistrokes,-1 do-- table.remove(mUnis.Unistrokes,i)-- end-- return NumUnistrokes;-- end return mUnisendreturn Recognizer
ps:模板可以自定义,按照上面的格式添加进数组就可以,亲测可用。但是对于某些简单的手势识别概率不是太大,而且模板太多的话执行效率貌似也不高,求来个大大给优化一下。。
0 0
- $1 Unistroke Recognizer( lua )
- kaggle 训练赛(1)Digit Recognizer
- Recognizer API
- Recognizer API
- TargetAction&&Recognizer
- Face Recognizer
- Recognizer API
- Kaggle项目实战1——Digit Recognizer——排名Top10%
- Recognizer & FS & Filter
- Recognizer & FS & Filter
- Recognizer & FS & Filter
- POJ 3561 Pseudographical recognizer
- Digit Recognizer (Kaggle)
- Gesture Recognizer(添加手势)
- Kaggle | Digit Recognizer
- kaggle入门digits Recognizer
- Kaggle入门:Digit Recognizer
- Digit Recognizer by LightGBM
- 队列的简单学习
- NavigationBar 添加、标题/左右按钮/颜色
- Anko for Android
- Android ,TextView 设置onClick 没反应
- SVN执行清理时乱码
- $1 Unistroke Recognizer( lua )
- iOS9 新特性
- CSDN-markdown编辑器使用规范
- 什么是JavaScript?
- [Java] Java中的可变参数方法
- Linux多线程基础学习(八)私有数据
- 判断某个时间是否在某个时间范围内
- 大型网站服务器架构
- 用Redis存储Tomcat集群的Session