1 没有意料的的问题
上回通过机器学习算法已经能够很好地找到那些图片里完整地存在数字,选择出这张图片有助于下一步识别图片中的数字,如果数字包含得都不完整,就不用说识别图片里的数字了。
红色边框表示算法判断存在数字
正如人有时很难在一小片图片中判断哪个图片里的数字最完整,算法会找到一小片包含数字的小方块,这些小方块都是彼此相邻的。因此下一步要做的事就是把一片判断包含数字的小方块组成一个组。
2 组成一组
必须保证是自左向右地去寻找,这样才能保证验证码里数字的顺序不会错乱。
def groupParts(predicted): """Assume predicted a boolean 2D array of representing a rectangle Group: area made up of adjacent Trues values Groups: all the group finding from left to the right""" partShape = predicted.shape looked = np.zeros(partShape,dtype=bool) nexts = [(1,0),(0,1),(-1,0),(0,-1)] groups = [] for l in range(partShape[1]): for c in range(partShape[0]): if not looked[c,l]: looked[c,l] = True if predicted[c,l]: group = [] fifo = [(c,l)] while len(fifo)!=0: tmp = fifo.pop(0) looked[tmp[0],tmp[1]] = True if predicted[tmp[0],tmp[1]]: group.append((tmp[0],tmp[1])) for n in nexts: nextPos = (n[0]+tmp[0],n[1]+tmp[1]) if 0<=nextPos[0]<partShape[0] and 0<=nextPos[1]<partShape[1]: if not looked[nextPos[0],nextPos[1]]: looked[nextPos[0],nextPos[1]] = True fifo.append(nextPos) groups.append(group) return groups
写得非常糟糕的一段程序。思路大致是这样的,在没有找到存在数字的小方块时,从左向右一列一列地寻找。查看过的小方块在looked数组里标记,以免重复查看。
一旦找到了存在数字的小方块,将上下左右的小方块保存在待查看的fifo列表里,每一次循环弹出一个小方块查看,如果包含数字就加入group列表,同时将上下左右的小方块保存在待查看的列表里,直至fifo为空。借鉴了一下图的广度优先搜索。
结果会是这样的:
Group 1:[(5, 3), (6, 3), (7, 3), (8, 3), (7, 4)]
Group 2:[(4, 8), (5, 8), (6, 8), (5, 9), (6, 9)]
Group 3:[(2, 13), (3, 13), (4, 13), (5, 13), (4, 14)]
Group 4:[(8, 13)]
Group 5:[(3, 18), (4, 18), (5, 18), (6, 18)]
Group 6:[(0, 23), (1, 23), (2, 23), (3, 23), (4, 23), (5, 23)]
3 对付误判
预测的算法精度不够,通常有一些误判,这样组Group有可能超过验证码数字的个数5。解决办法很简单,真正包含数字的组一般长度更长,找到长度最长的5个组就可以了。又是一段nasty的代码。
groups = groupParts(partImgs,predict_contain.reshape(img.partNum)) num_threshold = sorted(map(len,groups),reverse=True)[4] groups_filtered = filter(lambda x:len(x)>=num_threshold,groups)
一组相互毗邻的小方块代表一个数字,可以简单地选择出现最多的数字(众数),作为预测的结果。