若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/86612009
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
Qt之手写识别开发笔记:Zinnia介绍、编译、使用以及Demo
前话
项目中有手写输入识别需求,转而研究手写输入算法。
Zinnia介绍
zinnia是一个开源的手写识别库,采用C++实现,具有手写识别,学习以及文字模型数据制作转换等功能,且该库拥有较好的可移植性。
zinnia手写输入为用户笔画坐标作为一系列坐标数据,并输出按SVM置信度排序的n个最佳字符。
zinnia库具备以下特点:
- 支持向量机的实用精度
- 便携紧凑的设计 - POSIX / Windows(取决于C ++ / STL)
- 线程安全的C / C ++ / Perl / Ruby / Python库
- 实用识别速度(50-100 /秒)
- 快速培训
Zinnia库下载
下载地址:https://github.com/taku910/zinnia
(zinnia主页所指下载地址已经404…)
提供csdn下载地址:https://download.csdn.net/download/qq21497936/10934234
使用VS2017编译Zinnia库
步骤一:打开VS2017命令行工具,切换到源码目录
步骤二:编译,使用指令”nmake -f Makefile.msvc”
就这么轻松愉快的编译完了,如下图:
将其模块化,参照jpeglib的模块化方法:https://blog.csdn.net/qq21497936/article/details/86155043
训练模型文件
为了给zinnia提供识别的基础数据,需要制作训练数据,训练数据用S表达式编写。一般而言,更多数据会产生更好的质量。到目前为止,百日草只支持批量训练,涉及到3个应用,如下:
- zinnia_learn.exe:用于对指定元数据进行学习;
- zinnia_convert程序将文本模型转换为二进制模型,可以压缩;
- zinnia.exe:我们用于测试模型识别文件;
模型文件格式
(character (value あ) (width 300) (height 300) (strokes ((54 58)(249 68)) ((147 10)(145 201)(182 252)) ((224 103)(149 230)(82 240)(53 204)(86 149)(182 139)(240 172)(248 224)(228 250)))) (character (value い) (width 300) (height 300) (strokes ((56 63)(43 213)(67 259)(94 243)) ((213 66)(231 171)(208 217)))) (character (value う) (width 300) (height 300) (strokes ((102 35)(187 45)) ((73 121)(167 105)(206 139)(198 211)(135 275)))) (character (value え) (width 300) (height 300) (strokes ((140 19)(162 38)) ((62 105)(208 100)(51 263)(128 205)(188 268)(260 252)))) (character (value お) (width 300) (height 300) (strokes ((64 94)(240 98)) ((148 35)(159 129)(140 199)(105 247)(64 228)(101 161)(192 161)(222 223)(189 257)) ((223 49)(253 89))))
训练模型(可进行压缩)
得到模型文件data.mode(二进制),至于多生成得data.mode.txt(文本文件)是一种独立于体系结构得格式,zinnia只能添加二进制文件,但是截图对比预留出来,以后也许用得到呢?
输入文件格式
实际与模型文件格式类似,只是少了“(value う)”这一段,如下:
(character (width 300) (height 300) (strokes ((54 58)(249 68)) ((147 10)(145 201)(182 252)) ((224 103)(149 230)(82 240)(53 204)(86 149)(182 139)(240 172)(248 224)(228 250)))) (character (width 300) (height 300) (strokes ((56 63)(43 213)(67 259)(94 243)) ((213 66)(231 171)(208 217)))) (character (width 300) (height 300) (strokes ((102 35)(187 45)) ((73 121)(167 105)(206 139)(198 211)(135 275)))) (character (width 300) (height 300) (strokes ((140 19)(162 38)) ((62 105)(208 100)(51 263)(128 205)(188 268)(260 252)))) (character (width 300) (height 300) (strokes ((64 94)(240 98)) ((148 35)(159 129)(140 199)(105 247)(64 228)(101 161)(192 161)(222 223)(189 257)) ((223 49)(253 89))))
测试识别(直接使用模型文件)
zinnia.exe -m data.model test.txt
使用模型”data.model”(二进制,非文本的),输入的文件为”test.txt”
由此,我们可以看出zinnia库识别的特点,应该是相似度,相似度越高越在前面,越低在越后面,那么风马牛不相及也有个相似度(负数),应该都能输出,我们取前面一部分(约5-10个)就好了,其实也可以取相似度,我们仔细查看识别出的数据特点,分析如下图:
所以根据数据特点,果断给这个下定义,认为就是相似度(阅读代码实际也是,相似得分)。
使用VS2017建立C++程序测试Demo
步骤一:建立VC++空工程
参照jpeglib测试demo:https://blog.csdn.net/qq21497936/article/details/86155043
步骤二:加入头文件路径,库路径,库命,在代码中添加引入库
参照jpeglib测试demo:https://blog.csdn.net/qq21497936/article/details/86155043
步骤三:拷贝代码 (注意运行代码,需要拷贝之前建立的模型data.model)
#include <iostream> #include "zinnia.h" static const char *input = "(character (width 1000)(height 1000)" "(strokes ((243 273)(393 450))((700 253)(343 486)(280 716)(393 866)(710 880))))"; #pragma comment(lib, "libzinnia.lib") int main(int argc, char **argv) { zinnia::Recognizer *recognizer = zinnia::Recognizer::create(); if (!recognizer->open("D:\\compile\\zinnia\\Demo\\Debug\\data.model")) { std::cerr << recognizer->what() << std::endl; return -1; } // 第一次识别(输入文件) zinnia::Character *character = zinnia::Character::create(); if (!character->parse(input)) { std::cerr << character->what() << std::endl; return -1; } { zinnia::Result *result = recognizer->classify(*character, 1); if (!result) { std::cerr << recognizer->what() << std::endl; return -1; } for (size_t i = 0; i < result->size(); ++i) { std::cout << "parse input i = " << i << " result = " << result->value(i) << "\t score = " << result->score(i) << std::endl; } delete result; } // 第二次识别(函数输入特征点) character->clear(); character->set_width(300); character->set_height(300); character->add(0, 51, 29); character->add(0, 117, 41); character->add(1, 99, 65); character->add(1, 219, 77); character->add(2, 27, 131); character->add(2, 261, 131); character->add(3, 129, 17); character->add(3, 57, 203); character->add(4, 111, 71); character->add(4, 219, 173); character->add(5, 81, 161); character->add(5, 93, 281); character->add(6, 99, 167); character->add(6, 207, 167); character->add(6, 189, 245); character->add(7, 99, 227); character->add(7, 189, 227); character->add(8, 111, 257); character->add(8, 189, 245); { zinnia::Result *result = recognizer->classify(*character, 1); if (!result) { std::cerr << recognizer->what() << std::endl; return -1; } for (size_t i = 0; i < result->size(); ++i) { std::cout << "parase input i = " << i << " result = " << result->value(i) << "\t score = " << result->score(i) << std::endl; } delete result; } delete character; delete recognizer; getchar(); return 0; }
Demo效果
如下图,模型只有5个,所以不准,框架搭好,下一步节主要研究数据模型:
Demo下载地址
https://download.csdn.net/download/qq21497936/10934243
拓展1:文本模型可转换为c/c++源文件
(略)
拓展2:模型可进一步压缩(损失识别精度)
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/86612009