识别图片中的数字------基本思路
1. 读取矩阵 拿到一张带有数字的图片后,首先就是得到它的rgb矩阵。这对于bmp格式文件来说易如反掌,对于jpg的相对麻烦一些。假设我们现在已经得到了rgb矩阵M(m*n),每个点都有三个属性(r,g,b)。 2. 灰度化 将彩色图片转化为灰色图片,目的在于使图片颜色初步单调,便于第3步的进行。实现方法很多,可以将每个点的(r,g,b)设置为(a*r+b*g+c*b),其中a+b+c=1,即加权平均;也可以设置为(max(r,g,b))或者(min(r,g,b))。我采用的是加权法:0.11*blue+0.59*green+0.30*red。 3. 黑白化 将灰色图片转化为黑白图片。这一步是为了后期处理上的方便。大多数人会选择阈值法:设置一个(rx,gx,bx),逐点比较,将所有的点设置为黑色(0,0,0)或者白色(255,255,255)。我采用的方法是:
4. 腐蚀和膨胀 考虑到图片中的数字笔画可能比较细,同时有一些噪音斑点存在,需要进行腐蚀处理+膨胀处理。腐蚀处理就是把图片中线条变得更细,就像白色部分在腐蚀黑色部分一样;膨胀处理就是把线条变粗。在腐蚀的过程中,会把孤立的噪音点清除掉;在膨胀的过程中,会把原有的线条更圆润、清晰。所以需要先进行腐蚀,后进行膨胀。我实现的腐蚀算法很简单:遍历rgb矩阵,如果当前像素点为白色,则将其四周的像素点设置为白色。膨胀算法类似:遍历矩阵,如果当前点为黑色像素,则将其四周的点全部设置为黑色。我们不妨设想一下,如果先进行膨胀,后进行腐蚀,会有什么效果呢? 5.分割 这一步把图片分割为若干块,每一块中都是独立的一个数字,说的数学化一点,就是找到所有数字的外切矩形。如果各个数字没有粘连,则很容易分割;如果数字之间有粘连,则比较困难。常用的方法是检测粘连点(有点类似于图论中的连接两个连通块的桥),然后分割。我找的实验图片都是不粘连的,算是避过了这个难题 :) 6.离散化 第5步以后,我们得到若干矩形,每个矩形中有且仅有一个数字,现在针对每个矩形进行处理。常用的思路是将该矩形映射为一个二维矩阵。我的办法是映射为一个8*8的01矩阵,其中0代表白色块,1代表黑色块,实现方法比较无脑:将矩形分割为8*8的小矩形,然后统计每个小矩形中的黑色块数,如果超过小矩形面积的一半,则认为该小矩形全部为黑色,否则全为白色。下图是该8*8矩阵打印的结果,你能猜出来是哪个数字么?
7.训练 这时我情不自禁的想到了神经网络方法,输入是8*8=64,输出是0到9,共10个。事实上,很多人会采用神经网络方法来训练,可以很方便的得到识别结果的可信率。另一种方法是使用决策树,举个例子:如果8*8的矩阵的第一行有大于5个点为黑色,则该数字很有可能0、2、3、5、7、8、9,一般不会是1和4;如果第一行只有1到2个黑色,则很有可能是1和1;如果第一行有3到4个黑色,则很有可能是0和4(如果这些黑色连续,则很有可能是0;否则可能是4)。构造数十条此类的判断,也可以实现识别功能。如果为每个规则设置一个可信度,这样得到的识别结果也会附加一个可信度。 上面所说的,只是图像处理和模式识别中最最简单的东西,涉足以后,才发现博大精深呢 :) |