记得前面(忘了是哪天写的,反正是前些天,请用力点击这里观看)老周讲了一个14393新增的控件,可以很轻松地结合InkCanvas来完成涂鸦。其实,InkCanvas除了涂鸦外,另一个大用途是墨迹识别,就是手写识别。

识别功能早在Win 8 App的API中就有了,到了UWP,同样使用,这叫传承,一路学过来,都是一个体系的,我不明白为什么某些人一遇到升级就说SDK变化太大,适应不了。我是不明白了,有什么适应不了的,该不会是你笨吧,或者学习方法不对。反正老周在以前的博客中都说过了,学习要学活,不要把知识学死了,把东西往死里学,就是古人所说的书呆子。

好了,不谈论书呆子的事了,因为“书呆子”在民间有太多的误解,咱们还是说正题。

处理数字墨迹有两种方式:

1、一种是脱离InkCanvas控件的方法,处理过程是面向笔触(Stroke)的,这就需要你手动去管理好你的墨迹数据了;

2、要是上一种方法太麻烦,与InkCanvas关联的做法较好,这样不用自己去搞UI部分的内容。

本着易用、久用、耐用、实用、妙用等伟大原则,我们实现手写识别还是不要脱离InkCanvas控件,这样的话实现起来会轻松很多,除非你要搞很高级的应用场景。

不讲过多的理论,免得大家看的头晕,老周简单说一个原理,大家懂了原理后,直接干活,这是学编程的万能招数。

先看看大致的步骤:

1、大家知道,InkCanvas有个关联的InkPresenter属性,引用的是InkPresenter实例,这个你得知道,不然后面的步骤就无法玩了。

2、InkPresenter类有个StrokeContainer属性,类型为InkStrokeContainer,它表示墨迹笔触的集合,被收集到的输入数据就存放到这个集合中。一个笔触通常是指你用笔/手指/鼠标按下时开始,直到你释放笔/手指/鼠标这一阶段中,所绘制出来的一段墨迹(从下笔到提笔)。一花一世界,一落一起一笔触。

3、实例化InkRecognizerContainer类,调用RecognizeAsync方法执行识别,上面为啥要提到InkStrokeContainer呢?因为执行识别需要它,你想啊,没有用户输入的墨迹(笔触)数据,一片空白,你识别个球。

4、识别后返回一个InkRecognitionResult列表,对于中文,通常只有一个InkRecognitionResult对象,但对于英文单词,可能会多个,一个InkRecognitionResult表示一个单词。对于一个InkRecognitionResult来说,访问GetTextCandidates方法返回一个字符串列表,即候选项,匹配度高的字符串排在前面。

5、也可以访问InkRecognizerContainer.GetRecognizers方法获取当前系统中已安装的语言识别引擎,中文系统至少会有一个简体中文的识别引擎。你可以到系统设置里面安装其他语言的引擎。

OK,基本思路有了,下面就可以做事情了。

首先,布置一下UI,XAML代码如下:

        <Grid Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="300"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox Name="cmbRecons" Header="选一个:" DisplayMemberPath="Name"/>
<Border Background="LightGray" Grid.Row="1" Margin="2,6">
<InkCanvas Name="inkcv" />
</Border>
<TextBlock Grid.Row="2" Name="tbresult" TextWrapping="Wrap" Foreground="Red" FontSize="24"/>
</Grid>

ComboBox控件用来显示当前系统中安装的手写识别引擎,TextBlock用来显示识别结果。

现在,切换到代码视图,首先在页面类级别声明一个InkRecognizerContainer变量,并且实例化。

        InkRecognizerContainer inkRecognContainer = new InkRecognizerContainer();

另外,还需要一个Timer,作用是在墨迹收集2秒钟后进行识别。

        DispatcherTimer timer = new DispatcherTimer();

       ……

            // 准备计时器
// 延迟2秒,应该不算慢吧
timer.Interval = TimeSpan.FromSeconds(2d);
timer.Tick += onTimerTick;
// 处理ink操作事件
inkcv.InkPresenter.StrokeInput.StrokeStarted += (k1, k2) =>
{
// 人家正要下笔呢,没有在此时识别的道理
timer.Stop();
};
inkcv.InkPresenter.StrokesCollected += (t1, t2) =>
{
// 墨迹已收集,可以进行识别
timer.Start();
};

当下笔开始书写时,会发生StrokeStarted事件,在此时,应该停止计时,你总不能人家一边写你就一边识别,没什么意思。但InkCanvas收集到输入笔触后,会发生StrokesCollected事件,这时候就可以开始计时了,2秒钟后进行识别。说白了就是在用户停止手写2秒钟后识别。

在ComboBox控件中显示系统已安装的识别引擎:

            // 获取已安装的识别引擎列表
var inkrecogs = inkRecognContainer.GetRecognizers();
// 将这些列表显示到ComboBox控件中
cmbRecons.ItemsSource = inkrecogs;
// 处理选项更改事件
cmbRecons.SelectionChanged += (s1, s2) =>
{
// 将选中的识别引擎设为默认
InkRecognizer currec = (InkRecognizer)cmbRecons.SelectedItem;
inkRecognContainer.SetDefaultRecognizer(currec);
};
if (cmbRecons.Items.Count > )
cmbRecons.SelectedIndex = ;

当ComboBox控件做出选择后,引发SelectionChanged事件,在事件处理代码中可以调用SetDefaultRecognizer方法设置默认的识别引擎。

还有一件事,不要忘了,让InkCanvas支持笔、手触、鼠标来书写。

            // 全能书写
inkcv.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse | Windows.UI.Core.CoreInputDeviceTypes.Touch | Windows.UI.Core.CoreInputDeviceTypes.Pen;

下面是核心代码,就是上面那个Timer的Tick事件处理,在处理代码中,执行手写识别,并显示识别的结果。

            // 如果InkStrokeContainer中没有收集笔触,那就没有识别的必要了
// 所以Count应大于0
if (inkcv.InkPresenter.StrokeContainer.GetStrokes().Count > )
{
IReadOnlyList<InkRecognitionResult> results = await inkRecognContainer.RecognizeAsync(inkcv.InkPresenter.StrokeContainer, InkRecognitionTarget.All);
// 处理结果
if (results.Count > )
{
StringBuilder strbd = new StringBuilder();
strbd.AppendLine("结果:");
// 每个InkRecognitionResult实例表示一个汉字/单词的识别结果
// 而单个结果中又包含候选列表,最接近的识别结果优先级更高
for(int x = ; x < results.Count; x++)
{
string s = string.Join(",", results[x].GetTextCandidates().ToArray());
strbd.AppendLine(s);
}
// 显示结果
tbresult.Text = strbd.ToString();
// 清理墨迹
inkcv.InkPresenter.StrokeContainer.Clear();
}
}

不是很复杂,代码你应该看得懂的,不然,学.NET这么多年,太对不起自己了。注意的是,识别后返回多个结果,对于中文,通常只返回一个,因为多个汉字是可以一起识别,并放到字符候选列表中。

在代码的最后面有这么一句:

 inkcv.InkPresenter.StrokeContainer.Clear();

这句代码的作用是清除所收集的所有墨迹,清除后,InkCanvas会变回空白。

运行一下程序,然后手写一些字,看看识别效果。

示例源代码下载

【Win 10 应用开发】手写识别的更多相关文章

  1. AI应用开发实战 - 手写识别应用入门

    AI应用开发实战 - 手写识别应用入门 手写体识别的应用已经非常流行了,如输入法,图片中的文字识别等.但对于大多数开发人员来说,如何实现这样的一个应用,还是会感觉无从下手.本文从简单的MNIST训练出 ...

  2. 10分钟搞懂Tensorflow 逻辑回归实现手写识别

    1. Tensorflow 逻辑回归实现手写识别 1.1. 逻辑回归原理 1.1.1. 逻辑回归 1.1.2. 损失函数 1.2. 实例:手写识别系统 1.1. 逻辑回归原理 1.1.1. 逻辑回归 ...

  3. 背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别

    [源码下载] 背水一战 Windows 10 (62) - 控件(媒体类): InkCanvas 保存和加载, 手写识别 作者:webabcd 介绍背水一战 Windows 10 之 控件(媒体类) ...

  4. 10分钟教你用python 30行代码搞定简单手写识别!

    欲直接下载代码文件,关注我们的公众号哦!查看历史消息即可! 手写笔记还是电子笔记好呢? 毕业季刚结束,眼瞅着2018级小萌新马上就要来了,老腊肉小编为了咱学弟学妹们的学习,绞尽脑汁准备编一套大学秘籍, ...

  5. win10下通过Anaconda安装TensorFlow-GPU1.3版本,并配置pycharm运行Mnist手写识别程序

    折腾了一天半终于装好了win10下的TensorFlow-GPU版,在这里做个记录. 准备安装包: visual studio 2015: Anaconda3-4.2.0-Windows-x86_64 ...

  6. Tensorflow之基于MNIST手写识别的入门介绍

    Tensorflow是当下AI热潮下,最为受欢迎的开源框架.无论是从Github上的fork数量还是star数量,还是从支持的语音,开发资料,社区活跃度等多方面,他当之为superstar. 在前面介 ...

  7. 使用PyTorch构建神经网络模型进行手写识别

    使用PyTorch构建神经网络模型进行手写识别 PyTorch是一种基于Torch库的开源机器学习库,应用于计算机视觉和自然语言处理等应用,本章内容将从安装以及通过Torch构建基础的神经网络,计算梯 ...

  8. (手写识别) Zinnia库及其实现方法研究

    Zinnia库及其实现方法研究 (转) zinnia是一个开源的手写识别库.采用C++实现.具有手写识别,学习以及文字模型数据制作转换等功能. 项目地址 [http://zinnia.sourcefo ...

  9. TensorFlow 入门之手写识别(MNIST) softmax算法

    TensorFlow 入门之手写识别(MNIST) softmax算法 MNIST flyu6 softmax回归 softmax回归算法 TensorFlow实现softmax softmax回归算 ...

随机推荐

  1. 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧

    记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...

  2. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  3. CSS float 浮动属性

    本篇主要介绍float属性:定义元素朝哪个方向浮动. 目录: 1. 页面布局方式:介绍文档流.浮动层以及float属性. 2. float:left :介绍float为 left 时的布局方式. 3. ...

  4. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  5. Performance Monitor4:监控SQL Server的IO性能

    SQL Server的IO性能受到物理Disk的IO延迟和SQL Server内部执行的IO操作的影响.在监控Disk性能时,最主要的度量值(metric)是IO延迟,IO延迟是指从Applicati ...

  6. 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

    之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...

  7. bash字符串操作

    参考 http://www.cnblogs.com/chengmo/archive/2010/10/02/1841355.html 问题:bash怎么提取字符串的最后一位?例如python中strin ...

  8. 【夯实PHP基础】UML序列图总结

    原文地址 序列图主要用于展示对象之间交互的顺序. 序列图将交互关系表示为一个二维图.纵向是时间轴,时间沿竖线向下延伸.横向轴代表了在协作中各独立对象的类元角色.类元角色用生命线表示.当对象存在时,角色 ...

  9. SMBus set up a 2-byte EEPROM address for read/write

    Sequencer Engine spec: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1260.pd ...

  10. sqlServer去除字符串空格

    说起去除字符串首尾空格大家肯定第一个想到trim()函数,不过在sqlserver中是没有这个函数的,却而代之的是ltrim()和rtrim()两个函数.看到名字所有人都 知道做什么用的了,ltrim ...