【WPF】提高InkAnalyer手写汉字识别的准确率

最近项目中需要用到一个手写键盘,我们使用了WPF的InkCanvas+InkAnalyer来开发。

按照文档,一般的代码写法如下:

            var analyzer = new InkAnalyzer();
            analyzer.AddStrokes(strokes, Constants.ChsLanguageId);
            analyzer.SetStrokesType(strokes, StrokeType.Writing);

            var status = analyzer.Analyze();
            if (status.Successful)
            {
                return analyzer.GetAlternates()
                    .OfType<AnalysisAlternate>()
                    .Select(x => x.RecognizedString)
                    .ToArray();
            }

            analyzer.Dispose();

不过,在实际跑起来之后,却发现识别精确度很低,经常会把一个字识别成好几个字,如果写的稍微远一点,则错误更多。

                              一个简单的人字会被识别成两个笔画

                             一个稍微写的开点的游字识别成了三个字

这让我们非常苦恼,在网上查阅资料也没有相关的方案。

经过我们仔细尝试后发现,如果我们把一个字连起来写一气呵成,识别率倒是上去了不少:

但是,我们不可能要求用户所有字都一气呵成吧?

就在这时,我们想到,既然不能要求用户把字一气呵成的写完,能不能通过程序让用户写的笔画“一气呵成”呢?

有了这个灵感,简单改动,将代码改成如下的写法:

        /// <summary>
        /// 识别
        /// </summary>
        /// <param name="strokes">笔迹集合</param>
        /// <returns>候选词数组</returns>
        public string[] Recognize(StrokeCollection strokes)
        {
            if (strokes == null || strokes.Count == 0)
                return Constants.EmptyAlternates;

            var stroke = GetCombinedStore(strokes);

            var analyzer = new InkAnalyzer();
            analyzer.AddStroke(stroke, Constants.ChsLanguageId);
            analyzer.SetStrokeType(stroke, StrokeType.Writing);

            var status = analyzer.Analyze();
            if (status.Successful)
            {
                return analyzer.GetAlternates()
                    .OfType<AnalysisAlternate>()
                    .Select(x => x.RecognizedString)
                    .ToArray();
            }

            analyzer.Dispose();

            return Constants.EmptyAlternates;
        }

        private static Stroke GetCombinedStore(StrokeCollection strokes)
        {
            var points = new StylusPointCollection();
            foreach (var stroke in strokes)
            {
                points.Add(stroke.StylusPoints);
            }
            return new Stroke(points);
        }

注意,在这种写法里面,我们并不直接使用InkCanvas给出的StrokeCollection,而是重新创建了一个Stroke,这个Stroke的StylusPoints是把所有Stroke的StylusPoints都添加进去了,多个Stroke变成了一个Stroke,这下我们再试试:

终于达到我们的要求了,呵呵

希望能给大家带来帮助

【附】如何启用手写识别:

1、在控制面板中选择 程序和功能->添加/删除Windows组件,选择TabletPC组件功能。

2、引用IACore.dll,IALoader.dll,IAWinFX.dll,Microsoft.Ink.Analysis.dll

3、App.config里面需要设置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup useLegacyV2RuntimeActivationPolicy="true">
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
  </startup>
</configuration>

代码下载:http://files.cnblogs.com/RMay/WpfRecognize.7z


<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
WPF 中,可以使用 System.Diagnostics 命名空间下的 PerformanceCounter 类和 System.Windows.Threading 命名空间下的 DispatcherTimer 类来获取系统 CPU 利用率,并实现每秒更新。具体步骤如下: 1. 引入 System.Diagnostics 和 System.Windows.Threading 命名空间: ``` using System.Diagnostics; using System.Windows.Threading; ``` 2. 创建 PerformanceCounter 对象: ``` PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); ``` 其中,第一个参数 "Processor" 表示 CPU 监视器,第二个参数 "% Processor Time" 表示 CPU 使用率,第三个参数 "_Total" 表示所有 CPU 核心的总体使用率。 3. 创建 DispatcherTimer 对象: ``` DispatcherTimer timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); ``` 其中,TimeSpan.FromSeconds(1) 表示每隔 1 秒触发一次 Tick 事件。 4. 绑定 Tick 事件处理方法: ``` timer.Tick += new EventHandler(OnTimerTick); ``` 5. 实现 Tick 事件处理方法,读取并更新 CPU 使用率: ``` void OnTimerTick(object sender, EventArgs e) { float cpuUsage = cpuCounter.NextValue(); Console.WriteLine("CPU 使用率:{0}%", cpuUsage); } ``` 注意,第一次调用 NextValue 方法获取的是 0,因为需要先获取一次初始值,之后才能获取正确的 CPU 使用率。 6. 启动 Timer: ``` timer.Start(); ``` 完整示例代码如下: ``` using System; using System.Diagnostics; using System.Windows; using System.Windows.Threading; public partial class MainWindow : Window { private PerformanceCounter cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); public MainWindow() { InitializeComponent(); // 获取初始值 cpuCounter.NextValue(); // 创建 Timer DispatcherTimer timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); timer.Tick += new EventHandler(OnTimerTick); timer.Start(); } void OnTimerTick(object sender, EventArgs e) { // 获取 CPU 使用率 float cpuUsage = cpuCounter.NextValue(); Console.WriteLine("CPU 使用率:{0}%", cpuUsage); } } ``` 注意,由于 WPF 应用程序是单线程的,因此不需要将 PerformanceCounter 对象定义为静态变量。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值