iOS汉字识别改进算法

简介

前边一篇文章介绍了班讯通中新加的一个根据拼音写汉字功能的第一版本算法实现,今天说一说改进之后的算法。

班讯通3.2版本提交之后,我们对汉字识别算法进行了改进,并且将该模块抽离出来完善成了一个新的应用--写霸,现已经通过appstore审核上线, 欢迎大家下载体验。

进入正题

在第一版本中,我们将整个字拆为若干笔画存入数据库,每条笔画记录都对应若干条点记录,模板和用户记录均如此,在对比模板和用户数据的时候,根据笔画id对比相应的记录,最后根据匹配结果计算分数。新的版本里,我们在数据库中为所有笔画建立模型,然后每个字对应若干笔画模型。用户写字提交之后,分析用户输入的每一个笔画,在模板表中匹配出到若干笔画,再看与模板是否一致,从而得出分数。以下是详细过程

1.提炼笔画模型

在网上查到有三十一个笔画,于是将三十一个笔画一一录入,然后观察其特点。最后决定再将每一个笔画细分成几个线段,比如横折钩,拆成三段。具体做法是:写某一个笔画的时候,计算相邻两个点所成直线与水平直线的角度, 当这个角度与前两个点成直线的角度相差大于某个值(比如15度)的时候,就认为该笔画又多了一段。最后把该笔画所有线段id和线段平均角度存入数据库,这样一个笔画就对应若干个线段了。

// 解析笔画模型

- (void)featurePoints {

    NSArray *array = self.gridArray;

    if ([array count] < 4) {
        self.gridArray = self.pointArray;
        array = self.pointArray;
    }
    CGPoint point;
    CGPoint point0;
    CGPoint point1;
    CGPoint point2;
    int tag = 0;

    double angle0 = 0.0;
    double angle1 = 0.0;
    double angle3 = 0.0;
    for (int i=0; i<[array count]; i++) {
        if (i > 0) {
            point1 = [array[i-1] CGPointValue];
            point2 = [array[i] CGPointValue];

            angle1 = atan2(point2.y-point1.y, point2.x-point1.x)*180/M_PI;
            if (angle1 < -180) {
                angle1 += 360;
            }
            if (i > 1) {
                point0 = [array[i-2] CGPointValue];
                angle0 = atan2(point1.y-point0.y, point1.x-point0.x)*180/M_PI;
                if ((fabs(angle1-angle0)>180 && 360-fabs(angle1-angle0)>36) || fabs(angle1 - angle0) > 36) {
                    tag += 1;
                } else if(i > 2) {
                    point = [array[i-3] CGPointValue];
                    angle3 = atan2(point0.y-point.y, point0.x-point.x)*180/M_PI;
                    if (fabs(angle3-angle1)>36 || (fabs(angle3-angle1)>180 && 360-fabs(angle3-angle1)>36)) {
                        tag += 1;
                    }
                }
            }
        }
        [self.angleArray addObject:[NSNumber numberWithDouble:angle1]];
        [self.angleTagArray addObject:[NSNumber numberWithInt:tag]];
    }
}

2.录入模板

手工录入汉字模板,每录入一个字,按笔画进行比对,查找出相匹配的笔画,将笔画id存入该汉字记录,最后每个汉字就对应多个笔画了。

// 录入汉字模板

- (void)insertStandardStroke2:(CharacterModel *)model {

    NSMutableDictionary *dict = [NSMutableDictionary dictionary];// 记录重复的笔画的个数
    NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
    NSNumber *widthNumber = [userdefaults objectForKey:wtDefaultsCanvasViewWidth];
    NSNumber *heightNumber = [userdefaults objectForKey:wtDefaultsCanvasViewHeight];
    float canvasViewWidth = widthNumber.floatValue;
    float canvasViewHeight = heightNumber.floatValue;

    /****************插入字**************/
    [self.hanziDb executeUpdate:@"insert into s_character(chinese, pinyin) values(?,?)", model.chinese, model.pinyin];

    /****************获取字的id**************/
    FMResultSet* set0 = [self.hanziDb executeQuery:@"select max(id) as maxCharId from s_character"];
    int charid = -1;
    if([set0 next]) {
        charid = [set0 intForColumn:@"maxCharId"];
    } else {
        return;
    }

    NSArray *strokeModelArray = model.strokeModelArray;
    for (int strokeIndex=0; strokeIndex<strokeModelArray.count; strokeIndex++) {
        StrokeModel *strokeModel = strokeModelArray[strokeIndex];
        [self clearUserTable];

        /****************插入笔画**************/
        CGPoint minPoint = [model.minPointValue CGPointValue];
        CGPoint maxPoint = [model.maxPointValue CGPointValue];
        [self.hanziDb executeUpdate:@"insert into u_stroke(minX, minY, maxX, maxY) values(?,?,?,?)", minPoint.x, minPoint.y, maxPoint.x,maxPoint.y];

        /****************获取笔画的id**************/
        NSString *queryStrokeid = [NSString stringWithFormat:@"select max(id) maxid from u_stroke"];
        FMResultSet* setStrokeid = [self.hanziDb executeQuery:queryStrokeid];
        int strokeid = -1;
        if([setStrokeid next]) {
            strokeid = [setStrokeid intForColumn:@"maxid"];
        } else {
            return;
        }

        /****************插入点和角度**************/
        NSArray *pointsArray1 = strokeModel.gridArray;
        NSArray *angleArray1 = strokeModel.angleArray;
        NSArray *angleTagArray1 = strokeModel.angleTagArray;

        for (int i=0; i<pointsArray1.count; i++) {
            NSValue *pointValue = pointsArray1[i];
            NSNumber *angleTagNumber = angleTagArray1[i];
            CGFloat angle = [angleArray1[i] floatValue];
            CGPoint point = [pointValue CGPointValue];

            NSString *ss = [NSString stringWithFormat:@"insert into u_angle(strokeid, pointX, pointY, angle, angleTag) values(%d,%.2f,%.2f,%.2f,%d)", strokeid,point.x,point.y,angle, angleTagNumber.intValue];
            [self.hanziDb executeUpdate:ss];
        }

        // 提炼 把每个笔画分解成线段
        [self.hanziDb executeUpdate:@"insert into u_line (strokeid, pointcount, angle, angletag) select strokeid, count(*), sum(angle)/count(*),angletag from u_angle group by strokeid, angleTag"];
<span style="white-space:pre">	</span>// ......
}

3.判断用户输入

判断用户输入的时候只需要对比对应汉字模板的笔画id就可以了,具体代码就不再奉上(⊙﹏⊙b实在不敢公开)

结局

等待了一周多,写霸上线,结果刚上线,就被朋友们玩儿坏了……

有这样的:

竟然还有这样的

不多说了,回去接着改算法

时间: 2024-08-09 02:18:35

iOS汉字识别改进算法的相关文章

POJ 3155 Hard Life(最大密度子图+改进算法)

Hard Life Time Limit: 8000MS   Memory Limit: 65536K Total Submissions: 9012   Accepted: 2614 Case Time Limit: 2000MS   Special Judge Description John is a Chief Executive Officer at a privately owned medium size company. The owner of the company has

读论文《BP改进算法在哮喘症状-证型分类预测中的应用》

总结: 一.研究内容 本文研究了CAL-BP(基于隐层的竞争学习与学习率的自适应的改进BP算法)在症状证型分类预测中的应用. 二.算法思想 1.隐层计算完各节点的误差后,对有最大误差的节点的权值进行正常修正,  而对其它单元的权值都向相反方向修正,用 δ表示隐层节点的权值修正量, 则修正量的调整公式具体为 2.每次算法迭代完以后,计算误差函数的值并与前一次的值进行比较,如果误差函数的值增大,     则代表过调了学习率,应在下一次迭代时以一定比率下调学习率 ],若误差函数的i+1值减小,    

排序系列 之 简单选择排序及其改进算法 —— Java实现

简单选择排序算法: 基本思想: 在待排序数据中,选出最小的一个数与第一个位置的数交换:然后在剩下的数中选出最小的数与第二个数交换:依次类推,直至循环到只剩下两个数进行比较为止. 实例: 0.初始状态 3,1,5,7,2,4,9,6(共8个数) 1.n=8 个数中,最小数值为1,与第一个数交换:1,3,5,7,2,4,9,6 2.剩下 n-1=7 个数中,最小数值为2,与第二个数交换:1,2,5,7,3,4,9,6 3.剩下 n-2=6 个数中,最小数值为3,与第三个数交换:1,2,3,7,5,4

KMP及其改进算法

本文主要讲述KMP已经KMP的一种改进方法.若发现不正确的地方,欢迎交流指出,谢谢! KMP算法的基本思想: KMP的算法流程: 每当一趟匹配过程中出现字符比较不等时,不需回溯 i 指针,而是利用已经得到的部分匹配的结果将模式向右滑动尽可能远的一段距离后,继续进行比较. 设S为目标串,T为模式串,设 i 指针和 j 指针分别指示目标串和模式串中正待比较的字符. 开始时,令i=0,j=0.如果Si==Tj,则使i和j的值分别增加l:反之,i不变,j的值退回到j=next[j]的位置(即模式串右滑)

连通性问题改进算法

在上一篇“连通性问题”中已经对这个问题进行来介绍,在这一篇中给出针对以上问题的改进,在代码中已经对原理进行来注释. 加权快速合并算法 1 /** 2 * @file weightedquickunion.c 3 * @brief 加权快速合并算法 4 * 在合并操作中,不是任意把第二棵树连接到第一棵树上,而是记录每棵树中的节点数, 5 * 总是把较小的树连接到较大的树上.这个程序是对快速合并算法的改进,用另一个数组 6 * sz记录每个id[i]==i的对象所在树中的节点数,使得合并操作能够将较

无限极分类查找所有子孙节点的改进算法

在以前,遇到无限极分类返回一个节点的所有子孙节点时,我都是用递归计算的,后来发现时间复杂度和空间复杂度都太高了,后来自己研究了一下改进了算法. 节点数据如下:键值对分别是自己对应父亲节点 <?php $tree=array( 1=>0, 2=>1, 3=>2, 4=>3, 5=>4, 6=>5, 7=>6, 8=>7, 9=>8, 10=>9, 11=>10, ); ?> 以往算法如下: <?php function ge

KNN及其改进算法的python实现

一. 马氏距离 我们熟悉的欧氏距离虽然很有用,但也有明显的缺点.它将样品的不同属性(即各指标或各变量)之间的差别等同看待,这一点有时不能满足实际要求.例如,在教育研究中,经常遇到对人的分析和判别,个体的不同属性对于区分个体有着不同的重要性.因此,有时需要采用不同的距离函数. 如果用dij表示第i个样品和第j个样品之间的距离,那么对一切i,j和k,dij应该满足如下四个条件:    ①当且仅当i=j时,dij=0 ②dij>0 ③dij=dji(对称性) ④dij≤dik+dkj(三角不等式) 显

iOS 收款计算器算法

一个收款计算器算法,从之前高仿有赞Demo里面抽离的一个界面 demo 在这里 https://github.com/L-vinCent/calculView_function 显示计算记录 不能连续输入俩个计算符号 小数点的位数不能超过俩位 单个小数点的时候不能输入 00 点击 + ,直接显示计算结果,正则匹配计算 设置最大显示金额 - (IBAction)calculate:(UIButton *)sender { UIButton *btn=(UIButton *)sender; NSAr

iOS应用九宫格算法

1.框框横向间隔为:( "界面的总宽度"-"界面每行的控件的宽度" * "每行要现实的列数(这里是3)") / ("列数 + 1") 2.框框纵向间隔可以自定义写死 3.每个框框横向摆放的位置是:(框框宽度+间隔宽度)乘以(列号) 4.每个框框纵向摆放的位置为:(框框高度+间隔宽度)乘以(行号) + 顶端间隔[这里是30] 5.每个框框在第几行第几列的算法为: 行号为"框框的序号对列数取商", 列号为&qu