使用zinnia库进行中文手写识别

        研究手写识别的时候看到了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/8741772

zinnia的使用

编译zinnia

从git上下载源码https://github.com/taku910/zinnia

打开VS2017命令行工具,进入zinnia源码文件目录

编译,使用指令”nmake -f Makefile.msvc”

使用zinnia库进行中文手写识别_第1张图片

生成 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 
#include 

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 result);

public slots:

private:
    QImage *m_pCanvas = nullptr;
    QPainter *m_pPainter = nullptr;//临时画布的painter
    QPoint m_posLast;

    QMap m_result;
    QRect m_rect;
    std::vector m_vecPoints; //一个笔画所含的点,目前是把
    std::vector> m_vecPointsList; // 里面的vector为一个笔画,外面一层为所有笔画集合
};

#endif // PAINTWIDGET_H

.cpp文件:

#include "paintwidget.h"
#include 
#include 
#include 
#include 
#include 
#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()<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__<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()<set_width(m_rect.width());
    character->set_height(m_rect.height());
    adjustPoints();

    for ( unsigned int i = 0 ; i < m_vecPointsList.size() ; i++ )
    {
        std::vector 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()<pos();
    qInfo()<<"mouse press"<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__<pos();
    m_vecPointsList.push_back( m_vecPoints );
    m_vecPoints.clear();
}

bool PaintWidget::event(QEvent *event)
{
    switch(event->type()){
    case QEvent::TouchBegin:
        mousePressEvent(static_cast(event));
        break;
    case QEvent::TouchUpdate:
        mouseMoveEvent(static_cast(event));
        break;
    case QEvent::TouchEnd:
        mouseReleaseEvent(static_cast(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(xm_rect.right()){
            m_rect.setRight(x);
        }

        if(ym_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 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);
        }
    }
}


 

你可能感兴趣的:(Qt)