如何写一个简单的手写识别算法?



可以精准快速的识别出自定义的简单图形。
类似于下面这种?
Magic Touch - A Free Game by Nitrome
Magic Touch: Wizard for Hire on the App Store on iTunes

吐槽第一名答案, @Vinjn张静 回答的 $1 gesture recognizer 是比较好的解法。

洒家也有一个类似的算法,借鉴了原始手写ocr的思路来实现的。其实是写在 $1 gesture recognizer 之前的,但没有 $1 gesture recognizer 归纳得好,作者jacob还是我偶像。

Realtime Gesture recognition

把所有的笔画定义了个8个方向,然后将B的笔画可以分解成一个字符串。然后当人在触摸屏上画出一个符号时,也将它分解成8个方向的字符串,最后比较两个字符串的距离就能判断出和不同符号的近似度。
<img src="https://i-blog.csdnimg.cn/blog_migrate/eb0f63812d8b51833df65833fd52221a.png" data-rawwidth="527" data-rawheight="167" class="origin_image zh-lightbox-thumb" width="527" data-original="http://pic1.zhimg.com/5c8f99d6dfe803d783e215e131cb9f10_r.jpg">
实现起来也很简单,第一步去噪,因为不同触摸屏的采样频率不同。
<img src="https://i-blog.csdnimg.cn/blog_migrate/acf45ab24643aef7367c4b6684cdc7b5.png" data-rawwidth="376" data-rawheight="188" class="content_image" width="376">

第二步把去噪后的数据转换成方向序列,把之前得到的点换成方向序列,并把方向序列归纳到之前定义的8个方向中去。
<img src="https://i-blog.csdnimg.cn/blog_migrate/acf45ab24643aef7367c4b6684cdc7b5.png" data-rawwidth="376" data-rawheight="188" class="content_image" width="376">
第三步把连续一致的方向合并。
<img src="https://i-blog.csdnimg.cn/blog_migrate/ece91fce50e9d1c37c6693c286c12f76.png" data-rawwidth="263" data-rawheight="156" class="content_image" width="263">
第四步把小片段的移动略去,最后就能得出其实是画了一个凹的形状。
<img src="https://i-blog.csdnimg.cn/blog_migrate/725d2d96112a229eed923bf420700927.png" data-rawwidth="470" data-rawheight="170" class="origin_image zh-lightbox-thumb" width="470" data-original="http://pic4.zhimg.com/e8f5c7238045c508d42c0341bf860483_r.jpg">
这个算法的厉害之处是可以实时识别,画到一半也能判断出来。
Realtime Gesture recognition 源代码和demo都在上面了。



===============
吐槽时间。。。。
刚写完论文累死了,来吐槽。。。。
原来大家都觉得第一名不靠谱,怎么木有人把我顶上去!我眼红着那300多票呢!

我来告诉你为什么第一名不靠谱,

首先ocr拿来做gesture recognition是不对滴!
ocr是一个比gesture recognition更难的问题,因为ocr得到的是一张图片,所有点并没有时间戳,而手势识别时,每一下移动是有时间戳的,所以是知道“怎么画出来”这个额外信息的。

其次ocr不是这么解释的。
ocr问题的重点是怎么选择特征,比如知名的uci 数据集就有以下这些特征量:

     1.	lettr	capital letter	(26 values from A to Z)
     2.	x-box	horizontal position of box	(integer)
     3.	y-box	vertical position of box	(integer)
     4.	width	width of box			(integer)
     5.	high 	height of box			(integer)
     6.	onpix	total # on pixels		(integer)
     7.	x-bar	mean x of on pixels in box	(integer)
     8.	y-bar	mean y of on pixels in box	(integer)
     9.	x2bar	mean x variance			(integer)
    10.	y2bar	mean y variance			(integer)
    11.	xybar	mean x y correlation		(integer)
    12.	x2ybr	mean of x * x * y		(integer)
    13.	xy2br	mean of x * y * y		(integer)
    14.	x-ege	mean edge count left to right	(integer)
    15.	xegvy	correlation of x-ege with y	(integer)
    16.	y-ege	mean edge count bottom to top	(integer)
    17.	yegvx	correlation of y-ege with x	(integer)

我不懂deep learning,别和我讲什么ocropus....

最后贝叶斯讲得也不好。

感觉挑小朋友刺也挺不要脸的,其实我就是眼红那300多票。。。

不请自来,终于有个能答的了。
用贝叶斯分类器做,四五十行Matlab代码足以搞定。
先占座,容我缓缓道来,保准看完大家都会做模式识别。
------------------------------
以手写阿拉伯数字识别为例,我们需要设计一个系统,其输入为一个M*N像素的图片,输出为的0~9的数字。对于M*N像素的图片输入,可将其视为一个M*N的矩阵,矩阵的每个元素代表其对应像素位置上的的灰度值。

我们需要大量的手写样本来训练分类器,样本越多越好,自己采集样本当然很累啦,网上有现成的数据库 MNIST Database sam roweis : data
把数据库中的一部分画出来,大概是这样子的:
<img src="https://i-blog.csdnimg.cn/blog_migrate/f0844b8be8a391601b47af72a8aeaa5e.png" data-rawwidth="913" data-rawheight="334" class="origin_image zh-lightbox-thumb" width="913" data-original="http://pic1.zhimg.com/6bdccf8a6dc0f8998adf24c430579fc4_r.jpg">--
先讲正态分布。

单个变量x的正态分布,众所周知,大概是这样的
<img src="https://i-blog.csdnimg.cn/blog_migrate/3c7a7967cb51f1d63154d163f4717acf.png" data-rawwidth="422" data-rawheight="300" class="origin_image zh-lightbox-thumb" width="422" data-original="http://pic4.zhimg.com/79f621189519523b42b93951f6bbd393_r.jpg">
函数式也很简单&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/2a32f7e1d9a3174c40f37e568bcd3ea0.png" data-rawwidth="232" data-rawheight="58" class="content_image" width="232"&gt;两个变量&amp;lt;x,y&amp;gt;的联合分布,大概是这样子的两个变量<x,y>的联合分布,大概是这样子的
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/3df4bbff6e52fb8272b86d0f9067013a.png" data-rawwidth="300" data-rawheight="227" class="content_image" width="300"&gt;
那么对于k个变量的输入,\emph{x} = [x_1, x_2, x_3,...,x_k]
应该是什么样子呢~
我也不知道,但是有公式描述它:
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/295ead3ef98d0fc80807267d10f2777e.png" data-rawwidth="569" data-rawheight="58" class="origin_image zh-lightbox-thumb" width="569" data-original="http://pic2.zhimg.com/071cccf42ac95f91441636904b7a6835_r.jpg"&gt;跟单变量函数式是不是很像啊~~跟单变量函数式是不是很像啊~~
其中,u 是 x 的期望值:
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/db20d3119907372fbb6892280528e000.png" data-rawwidth="291" data-rawheight="32" class="content_image" width="291"&gt;\Sigma 是 x 的协方差矩阵,大小为 k*k:
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/fd64c8004fcc2e4c91ee17a5976a395a.png" data-rawwidth="758" data-rawheight="197" class="origin_image zh-lightbox-thumb" width="758" data-original="http://pic4.zhimg.com/b0856458cd49232aea2467b2b4f85823_r.jpg"&gt;
嗯,这就是对k维随机变量的正态分布的描述,简单吧。
------------------------------
再讲贝叶斯分类。

看一维的例子。
假设有两种鱼A,B,各自的长度都呈正态分布,但期望方差不同,如下图,蓝色为B的长度的正态分布,红色为A的长度的正态分布。
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/99271804a9d20f66321f6e7b156dca33.jpeg" data-rawwidth="561" data-rawheight="420" class="origin_image zh-lightbox-thumb" width="561" data-original="http://pic4.zhimg.com/818851373fbacf832cd8539d812cf7f7_r.jpg"&gt;
问题来了,是我逮到一条鱼,告诉你量出来长度为25,别的你都不知道,让你猜猜到底这鱼是A还是B,你会怎么答啊?

答A么,错啦!!

这是A,B的长度的正态分布,又不是A,B的概率分布!!!
假如逮上来1000100条鱼,其中100条是A,剩下的1000000条是B;你答A就二了么!

那该怎么答哇~
把各自的正态分布乘以其概率,再画画看~
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/0e4136866e41147a194e9532e61a2b50.jpeg" data-rawwidth="561" data-rawheight="420" class="origin_image zh-lightbox-thumb" width="561" data-original="http://pic2.zhimg.com/c1c5adf8bff164333a5ce14a63a2d089_r.jpg"&gt;我去,x=25的地方B比A不知道高到哪里去了!!!所以你们不要见的风是的雨啊,懂了没有!!!我去,x=25的地方B比A不知道高到哪里去了!!!所以你们不要见的风是的雨啊,懂了没有!!!

原理是什么呢?贝叶斯老爷子告诉我们这个定理:

P(\omega_j|x) = \frac{p(x|\omega_j)P(\omega_j)}{p(x)}

就是说啊:要是你知道某种鱼\omega_j的长度x的正态分布p(x|\omega_j),也知道这种鱼在鱼群中的概率P(\omega_j)p(x)是所有鱼的长度分布。逮上来一条鱼的长度为25,套这个公式就知道这条鱼是\omega_j的概率是多少了不是~

刚那个问题不就好答了么,肯定要比较P(A|x=25)P(B|x=25) 的大小啊,哪个大选哪个啊~~

这是一维的问题,x的纬度高了的话,套用上面的正态分布的高纬度公式啊,一样算得出来

so easy~~
------------------------------
正式步入主题。

我们刚说了,对于M*N的矩阵输入,直接把它转化成一个有M*N个元素的数组,这个数组就是前面的x啦,即x = [x_1, x_2, x_3,..., x_{M*N}],对于x中的每一个元素x_k,我们都视之为呈正态分布。

我们有很多不同手写数字的样本哒~算出这些样本对应的参数,比如对于数字 3:
1. 算出其在样本库中的出现的概率P(\omega_3)
2. 算出数字3对应的所有样本矩阵转换成的向量x的正态分布:p(x|\omega_3) = N(\mu_3,\Sigma_3)
3. 根据贝叶斯公式算出 P(\omega_3|x),这里忽略掉 p(x)因为它对于所有数字都一样,而且我们只是要比较P(\omega_3 | x) 的大小而已啊~

这不就把贝叶斯分类器设计好了么,剩下的就简单啦~
比如我们现在有一张图片,转化成矩阵再转化成向量x, 然后你就开始算啊,
P(\omega_0|x)一直到P(\omega_9|x)的大小,最后比较谁大就认为这个图片上画的是谁~
------------------------------
Matlab代码和数据库附上,大家有兴趣可以下了试试看:
Bayes.m_免费高速下载
识别正确率高达95.3%啊有木有!!!
手写数字都能识别了,三角形什么的识别起来不是太简单啦~就是要大量的样本而已嘛。
------------------------------
感谢大家的热情,如果有兴趣自学模式识别的话 @欧阳尘曦@黄升球 ,推荐大家这本书:
Pattern Classification (豆瓣)
网上中英文pdf都有,大家自己找啦。有人问到需要的数学基础,其实本科的基础数学就足够用了,遇到不懂的去网上搜,再不行就找人问。
------------------------------
关于不同分类器选择的问题,楼下匿名用户已经讲的很好啦,我再补充几点 @用心阁

贝叶斯分类器的好处是,简单易懂,无迭代,运行速度快,准确率尚可,但是在某些情况下会表现不好,而且需要大量样本来估算其正态分布参数。

KNN分类器的原理也很简单,比贝叶斯更容易懂,实现简单,需要样本数少,但是其迭代次数多,运行速度比贝叶斯要慢个几十甚至上百倍,而且根据k的取值,运行结果准确率不是很稳定。

支持向量机,前几年非常火的,需要较好的数学基础才能理解实现,准确率较前两者都好,速度跟贝叶斯在一个级别,也不需要迭代,缺点在于,对于两个以上的类别,你需要设计不止一个支持向量机来分类,而且,你需要针对特定的情况设置特定的kernal,以达到满意的效果。

最近比较火的是神经网络啦,准确率超高,表现惊人;但是训练需要迭代,运行时间很长,大规模的神经网络一般的PC运行起来很吃力的。
------------------------------
关于样本多少的问题 @波纹,你可以这么理解,假如告诉你,某种鱼的长度呈正态分布,但是其长度的方差和均值都未知,那你需要逮几条鱼出来量,才敢有把握估算这种鱼长度的正态分布呢?当然是越多越好啦,具体的证明,你可以搜下:最大似然估计。我们采集样本,就是为了估算这种鱼的长度的正态分布的参数。
------------------------------
@chivalry
1. 贝叶斯是假定各个特征间是独立的,代码中看到用到了协方差,是不是只要保留协方差矩阵的对角线的值?
答:可以看我前面讲的多为正态分布。需要计算样本的协方差矩阵,才能估算样本的正态分布。样本的各个特征之间是否独立,不影响我们对样本的正态分布的估算。
2. 没看到乘以先验概率的地方?
答:在样本中,各个数字出现的概率是一样的(现实中大多也是如此),要比较后验概率的大小,乘不乘都一样,你看我就把p(x)给省去了。事实上,我比较后验概率时的计算更加简化了:
对后验概率取对数,称之为discriminant function:
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/94abd332fecd22b82c52327d902a4493.png" data-rawwidth="297" data-rawheight="44" class="content_image" width="297"&gt;
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/61e1fbb7b1fdb1bc7fec9272b878e3b1.png" data-rawwidth="591" data-rawheight="55" class="origin_image zh-lightbox-thumb" width="591" data-original="http://pic1.zhimg.com/c4e80d23fa41f64cb70c953f29d18fc8_r.jpg"&gt;
省去对各个数字一样的项和影响小的项,最后只剩下
&lt;img src="https://i-blog.csdnimg.cn/blog_migrate/8571bdd535f6e0d62c586375636bfa6c.png" data-rawwidth="298" data-rawheight="54" class="content_image" width="298"&gt;甚至连二分之一也不乘了。甚至连二分之一也不乘了。
------------------------------
@黄升球 对于高像素的图片,即高纬度的输入,一般需要做降维处理提取特征向量,PCA和LDA是比较基础的,也能提高分类器的准确率,这部分确实需要一点数学才好理解。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值