我有三个手写数字(0、1、8)的1024位二进制表示。这些数字在32×32的位图中,通过连接各行形成了一个二进制向量。
每个数字有50个这样的二进制向量。当我们对每个数字应用最近邻算法时,可以使用汉明距离或其他度量方法,然后应用算法来区分这些向量。现在我想使用另一种技术,不是查看向量的每一位,而是希望在比较向量时分析更少的位数。
例如,我知道当比较数字‘8’和‘0’的位图(大小:1024位)时,数字‘8’的向量中间必须有1,因为数字8在视觉上看起来像是两个零叠加在列中。因此,我们的算法会寻找两个零的交点(这将是数字的中间部分)。
这就是我想做的方式。我想将低级表示(查看1024位位图向量)转换为高级表示(从位图中提取的两个特征组成)。
有什么建议吗?我希望这个问题对观众来说是清楚的。
回答:
想法1:洪水填充
这个想法不使用你每个数字拥有的50个模式:它基于这样的想法,即通常“1”周围的所有0位是连通的,而“0”将里面的0位与外面的0位分开,“8”则有两个这样的封闭区域。因此,计算连通的0位区域的数量可以识别出这是三个数字中的哪一个。
因此,你可以使用洪水填充算法,从向量中的任何一个0位开始,将所有连通的0位设为1。在一维数组中,你需要正确识别连通的位(要么是水平方向的,相距1位,但不跨越32的边界;要么是垂直方向的,相距32位)。当然,这种洪水填充会破坏图像——所以请确保使用副本。如果一次这样的洪水填充后仍然有0位(这些位因此与你转为1的位不连通),那么选择其中一个并从那里开始第二次洪水填充。如果需要,重复此操作。
当所有位都以这种方式被设为1后,根据你执行的洪水填充次数,使用以下方法:
- 一次洪水填充?这是“1”,因为所有0位是连通的。
- 两次洪水填充?这是“0”,因为零的形状将两个区域(内/外)分开。
- 三次洪水填充?这是“8”,因为这个形状将三个连通的0位区域分开。
当然,这个过程假设这些手写数字是格式良好的。例如,如果8的形状有一个小缺口,像这里这样:
…那么它不会被识别为“8”,而是“0”。这个特定问题可以通过识别1位的“松散末端”(停止的“线”)来解决。当你有两个这样的末端在短距离内,那么将洪水填充计数得到的数字增加1(好像这两个末端是连通的)。
同样,如果“0”意外地有一个小的第二个环,像这里这样:
…它会被识别为“8”而不是“0”。你可以通过要求每次洪水填充找到最少数量的0位(比如至少10个0位)来计数来防止这种特定问题。
想法2:概率向量
对于每个数字,添加你拥有的50个示例向量,使得每个位置的计数介于0到50之间。你将为每个数字得到一个这样的“概率”向量,因此有prob0、prob1和prob8。如果prob8[501] = 45,这意味着“8”向量在索引501处有1位的概率很高(45/50)。
现在按以下方式转换这三个概率向量:不是按位置存储计数,而是按递减的计数(概率)顺序存储位置。因此,如果prob8[513]具有最高值(比如49),那么新数组应该像[513, …]这样开始。我们称这些新向量为A0、A8和A1(对应相应的数字)。
最后,当你需要匹配给定的输入向量时,同时遍历A0、A1和A8(始终查看三个向量中的相同索引)并保持3个分数。当输入向量在A0[i]指定的位置有1时,则向score0加1。如果它也在A1[i]指定的位置有1(相同的i),则向score1加1。对于score8也是如此。增加i,并重复。只要最高分(score0、score1和score8中的最高分)与第二高分之间的差异超过阈值,就停止此迭代。此时你就知道表示的是哪个数字了。