研究手写识别的时候看到了zinnia,就进行了测试,存在问题是zinnia书写依赖笔画顺序,而且没有找到更多的可以用于训练的数据。
zinnia介绍
zinnia是一个基于svm的开源的手写识别库。zinnia简单地接收用户笔划作为一系列坐标数据,并输出按SVM置信度排序的n个**字符。为了保持可移植性,Zinnia没有任何渲染功能。此外,Zinnia还提供训练模块,使我们能够以低成本创建任何手写识别系统。
特点
- 支持向量机的实用精度
- 便携紧凑的设计 - POSIX / Windows(取决于C ++ / STL)
- 线程安全的C / C ++ / Perl / Ruby / Python库
- 实用识别速度(50-100字符 /秒)
- 快速训练
参考 zinnia的介绍:http://taku910.github.io/zinnia/
zinnia属于联机文字识别,包含预处理、特征提取和分类识别过程。
https://blog.csdn.net/stellar0/article/details/
zinnia的使用
编译zinnia
从git上下载源码https://github.com/taku910/zinnia
打开VS2017命令行工具,进入zinnia源码文件目录
![]()
编译,使用指令”nmake -f Makefile.msvc”

生成 zinnia.lib,zinnia.dll文件。
使用zinnia:
1.创建zinnia::Recognizer,加载model文件
2.创建zinnia::Character,把书写的点坐标传进来
3.zinnia::Recognizer进行识别,得到一组包含识别的字和对应相似度的结果
注意点:
1.书写顺序会影响识别的结果,导致结果特别不准确
2.zinnia::Character需要设置字符的高宽,当只在一个小的区域书写,设置高宽很大时,相当于拿这个小的区域去和一个字的一部分去比较,取出最相近的。所以代码里面有根据点来确定一个区域,根据此区域设置zinnia::Character的高宽。
代码
.h文件:
#ifndef PAINTWIDGET_H #define PAINTWIDGET_H #include <QWidget> #include <QMap> class PaintWidget : public QWidget { Q_OBJECT public: explicit PaintWidget(QWidget *parent = nullptr); void clear(); void init(); void recignize(); protected: void paintEvent(QPaintEvent *event); void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent * e); void mouseReleaseEvent(QMouseEvent * e); bool event(QEvent *event); private: void resizeRect(QPoint p); void adjustPoints(); signals: void sigResult(QMap<QString, float> result); public slots: private: QImage *m_pCanvas = nullptr; QPainter *m_pPainter = nullptr;//临时画布的painter QPoint m_posLast; QMap<QString, float> m_result; QRect m_rect; std::vector<QPoint> m_vecPoints; //一个笔画所含的点,目前是把 std::vector<std::vector<QPoint>> m_vecPointsList; // 里面的vector为一个笔画,外面一层为所有笔画集合 }; #endif // PAINTWIDGET_H
讯享网
.cpp文件:
讯享网#include "paintwidget.h" #include <QPainter> #include <QDebug> #include <QImage> #include <QMouseEvent> #include <QApplication> #include "zinnia/zinnia.h" PaintWidget::PaintWidget(QWidget *parent) : QWidget(parent) { } void PaintWidget::init() { m_pCanvas = new QImage(this->size(),QImage::Format_ARGB32_Premultiplied); m_pCanvas->fill(Qt::transparent); qInfo()<<this->size(); m_pPainter = new QPainter(m_pCanvas); // m_pPainter->setPen(Qt::black); m_pPainter->setRenderHint(QPainter::Antialiasing, true); m_pPainter->setCompositionMode(QPainter::CompositionMode_Source); m_pPainter->setPen(QPen(Qt::red,3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); } void PaintWidget::clear() { m_vecPointsList.clear(); m_pCanvas->fill(Qt::transparent); update(); } void PaintWidget::recignize() { // 汉字识别 zinnia::Recognizer *recognizer = zinnia::Recognizer::create(); QString strPath = QApplication::applicationDirPath()+"/handwriting-zh_CN.model"; qInfo()<<__FUNCTION__<<strPath; /*初始化汉字库*/ if (!recognizer->open( strPath.toStdString().data() )){ qInfo()<<__FUNCTION__<<"open model fail"; return; } zinnia::Character *character = zinnia::Character::create(); if(m_vecPointsList.size()<=0){ qInfo()<<__FUNCTION__<<"no points"; return; } character->clear(); // character->set_width(this->width()); // character->set_height(this->height()); qInfo()<<m_rect; character->set_width(m_rect.width()); character->set_height(m_rect.height()); adjustPoints(); for ( unsigned int i = 0 ; i < m_vecPointsList.size() ; i++ ) { std::vector<QPoint> vecTmp = m_vecPointsList[i]; for ( unsigned int j = 0 ; j < vecTmp.size() ; j++ ) { character->add( i , vecTmp[j].x() , vecTmp[j].y() ); } } zinnia::Result *result = recognizer->classify( *character , m_vecPointsList.size()/*m_vecPoints.size() / 2 +1*/ ); if ( !result ) return; m_result.clear(); for ( size_t i = 0 ; i < result->size() ; ++i ) { std::string str1 = result->value(i); float score = result->score(i); QString qs = str1.c_str(); qInfo()<<qs<<score; m_result.insert(qs, score); } emit sigResult(m_result); delete result; delete character; delete recognizer; m_vecPoints.clear(); m_vecPointsList.clear(); } void PaintWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawImage(0,0,*m_pCanvas); } void PaintWidget::mousePressEvent(QMouseEvent *event) { QPoint pos = event->pos(); qInfo()<<"mouse press"<<pos; m_posLast = pos; m_pPainter->drawPoint(pos); resizeRect(pos); m_vecPoints.push_back(pos); } void PaintWidget::mouseMoveEvent(QMouseEvent *event) { QPoint pos = event->pos(); m_pPainter->drawLine(m_posLast, pos); m_vecPoints.push_back(pos); m_posLast = pos; resizeRect(pos); update(); } void PaintWidget::mouseReleaseEvent(QMouseEvent *event) { qInfo()<<__FUNCTION__<<event->pos(); m_vecPointsList.push_back( m_vecPoints ); m_vecPoints.clear(); } bool PaintWidget::event(QEvent *event) { switch(event->type()){ case QEvent::TouchBegin: mousePressEvent(static_cast<QMouseEvent*>(event)); break; case QEvent::TouchUpdate: mouseMoveEvent(static_cast<QMouseEvent*>(event)); break; case QEvent::TouchEnd: mouseReleaseEvent(static_cast<QMouseEvent*>(event)); break; } return QWidget::event(event); } void PaintWidget::resizeRect(QPoint p) { if(m_vecPointsList.size() == 0 && m_vecPoints.size()==0){ m_rect.setTopLeft(p); m_rect.setBottomRight(p); qInfo()<<__FUNCTION__<<"first point"; } else{ int x = p.x(); int y = p.y(); if(x<m_rect.left()){ m_rect.setLeft(x); } else if(x>m_rect.right()){ m_rect.setRight(x); } if(y<m_rect.top()){ m_rect.setTop(y); } else if(y>m_rect.bottom()){ m_rect.setBottom(y); } } } void PaintWidget::adjustPoints() { int x = m_rect.left(); int y = m_rect.top(); for (unsigned int i = 0 ; i < m_vecPointsList.size() ; i++) { std::vector<QPoint> vecTmp = m_vecPointsList[i]; for (unsigned int j = 0 ; j < vecTmp.size() ; j++) { QPoint p = m_vecPointsList[i][j]; m_vecPointsList[i][j] = QPoint(p.x()-x, p.y()-y); } } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/27492.html