码迷,mamicode.com
首页 > 移动开发 > 详细

iOS简单的手写汉字识别

时间:2015-06-13 17:12:17      阅读:1207      评论:0      收藏:1      [点我收藏+]

标签:数据库   算法   手写   汉字   识别   

简介

前一阵在班讯通上边加了一个小的功能:根据拼音提示写出汉字,提交之后软件会打出分数,其界面如下:

技术分享

下面简单介绍一下第一个版本识别算法的实现:

  • 记录汉字录入轨迹

iOS中UIView视图继承了UIResponder类,该类中的四个方法是我们需要调用的:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; 
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; 
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

  1. 在前三个方法中,我们记录一个笔画的起始点、过程点和结束点,将点添加到保存点的数组中,在touchesEnded方法里,将保存点的数组添加到保存笔画的数组。这样,写完一个字之后,保存笔画的数组就是我们要的整个字的点集。
  2. 将该点集保存在数据库模板表中,用做模板。
  3. 模板完成之后,开始记录用户输入的点集,并将数据记录在用户表。
// 采集点集
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
        for (UITouch *touch in touches) {
            NSMutableArray *newStackOfPoints = [NSMutableArray array];
            [newStackOfPoints addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]];
            [self.strokes addObject:newStackOfPoints];
        }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
        for (UITouch *touch in touches) {
            [[self.strokes lastObject] addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]];
        }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
        for (UITouch* touch in touches) {
            [[self.strokes lastObject] addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]];
        }
}


// 插入数据库
- (int)insertChar:(CharacterModel *)model {
    int charId = 0;
    [self.hanziDb executeUpdate:@"insert into characters(chinese, pinyin, pointsString) values(?,?,?)", model.chinese, model.pinyin, model.pointsString];
    
    NSString *queryString = [NSString stringWithFormat:@"select id from characters where chinese = '%@'", model.chinese];
    FMResultSet* set = [self.hanziDb executeQuery:queryString];
    
    if([set next]) {
        charId = [set intForColumn:@"id"];
    }
    for (int i=0; i<model.inputPointGrids.count; i++) {
        NSArray *aStroke = model.inputPointGrids[i];
        for (NSValue *aPointValue in aStroke) {
            CGPoint aPoint = [aPointValue CGPointValue];
            [self.hanziDb executeUpdate:@"insert into points(id, pointX, pointY, strokeid) values(?,?,?,?)", [NSNumber numberWithInt:charId],[NSNumber numberWithInt:(int)aPoint.x],[NSNumber numberWithInt:(int)aPoint.y], [NSNumber numberWithInt:i+1]];
        }
    }
    return charId;
}


  • 对比用户输入数据和模板数据
  1. 有了数据,剩下的就是利用数据库的select语句来对比了。但是在实际对比时候会发现~~根本没几个点能匹配的上,原因很简单:在第一步中,记录的是点的绝对坐标。比如我们写个“一”,录入模板的时候,记录的坐标集是{(50, 200), (100, 200), (150, 200), (200, 200), (250, 200)},用户输入的时候记录的是{(60, 220), (90, 220), (130, 220), (160, 220), (200, 220), (230, 220)}, 结果就是零匹配。另外一点很重要,就是屏幕的分辨率......
  2. 鉴于这种情况, 将输入区域划分为50个格子,每经过一个格子,便将其记录下来作为相对坐标,这样上边的两条数据就成了{(10, 40), (20, 40 ), (30, 40), (40, 40), (50, 40)}和{(10, 40), (20, 40 ), (30, 40), (40, 40), (50, 40), (60, 40)}, 匹配程度就提高了(当然,这只是举例数据,并不准确)。
  3. 改为相对坐标存储之后,虽然匹配程度提高不少,但是当笔画上下或者左右位置偏差比较大的时候仍然识别不准确, 比如一个横的模板数据是{(10, 40), (20, 40 ), (30, 40), (40, 40), (50, 40)}, 用户输入的数据是{(10, 41), (20, 41 ), (30, 41), (40, 41), (50, 41)},这样在查询的时候就匹配不到。所以在查询的时候需要将用户输入的笔画做一个偏移,将{(10, 40), (20, 40 ), (30, 40), (40, 40), (50, 40)}和{(10, 41), (20, 41 ), (30, 41), (40, 41), (50, 41)}匹配起来。
// 取相对坐标
- (void)turnToGrids {
    self.strokeCount = self.inputStrokes.count;
    // 格子宽度
    float gridWidth = kScreenWidth/10;
    for (int k=0; k<self.inputStrokes.count; k++) {
        // 存储一个笔画的所有点到一个数组
        NSMutableArray *strokPointGrids = [NSMutableArray array];
        NSArray *inputStrokesArray = self.inputStrokes[k];
        for (int l = 0; l<inputStrokesArray.count; l++) {
            NSValue *value = inputStrokesArray[l];
            if (l == 0) {
                [self.strokeStartPoints addObject:value];
            }
            if (l == self.inputStrokes.count-1) {
                [self.strokeEndPoints addObject:value];
            }
            CGPoint point = [value CGPointValue];
            CGPoint grid = CGPointMake(ceil(point.x/gridWidth), ceil(point.y/gridWidth));
            BOOL shouldAdd = NO;
            if (strokPointGrids.count == 0) {
                shouldAdd = YES;
            } else {
                NSValue *lastValue = strokPointGrids.lastObject;
                CGPoint lastGrid = [lastValue CGPointValue];
                if (lastGrid.x != grid.x || lastGrid.y != grid.y) {
                    shouldAdd = YES;
                }
            }
            if (shouldAdd) {
                [strokPointGrids addObject:[NSValue valueWithCGPoint:grid]];
                if (![self.pointsString isEqualToString: @""] && ![self.pointsString hasSuffix:@"*"]) {
                    [self.pointsString appendString:[NSString stringWithFormat:@"|"]];
                }
                [self.pointsString appendString:[NSString stringWithFormat:@"%d,%d", (int)grid.x, (int)grid.y]];
            }
        }
        if (k != self.inputStrokes.count-1) {
            [self.pointsString appendString:@"*"];
        }
        [self.inputPointGrids addObject:strokPointGrids];
    }
}


// 最终的查询语句
                NSString *queryString4 = [NSString stringWithFormat:@"select a.strokeid as strokeid,a.samecount as samecount,a.ucount as ucount,a.pcount as pcount from ( select strokeid, count(*) as samecount, (select count(*) from input_points where id=p.id and strokeid= %d ) as ucount, (select count(*) from points where id=p.id and strokeid=p.strokeid) as pcount from points p where exists(select * from input_points u where u.id=p.id and u.strokeid=%d and (abs(u.pointX-p.pointX) + abs(u.pointY-p.pointY))<2 ) and p.strokeid not in (%@) and p.id=%d group by strokeid ) a order by abs(a.pcount - a.samecount) asc", j, j, hasStrokeid, model.charID];


至此, 该功能模块就可以简单识别从手机屏幕写入的汉字了,只不过这样很鸡肋,因为如果模板录入和用户输入风格相差比较大或者用户写的偏上(偏下,左右都有可能)的话,识别率就直线下降,所以,我们在第二版本中彻底改变了识别算法,极大程度地提高了识别率。

关于手写识别的第二个版本,请看下一篇博文

iOS简单的手写汉字识别

标签:数据库   算法   手写   汉字   识别   

原文地址:http://blog.csdn.net/zwf_apple/article/details/46482585

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!