svm手写数字识别_Qt+OpenCV+SVM+KNN的MNIST手写字符识别

手写字符识别: - 使用Qt/C++/Linux实现手写字符(主要是界面) - 使用MNIST手写字符集作为训练源 - 使用OpenCV/SVM/KNN训练MNIST数据集

MNIST字符集读取与训练

MNIST介绍:SVM+MNIST

将代码简单修改就是本文使用的训练测试源码,在这里就不赘述了,具体可看源码。

手写字符界面

所谓手写其实是模拟手写,毕竟一般开发的笔记本和PC没有手写功能,就是用鼠标画图。

先定义两个点lastpoint,endpoint。

鼠标拖动的时候更新两个点数据

void Drawing::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton){
        lastPoint = event->pos();
    }
    endPoint = lastPoint;
}

而Qt会自动调用paintEvent绘图,我们使用lastpoint,endpoint划线,同时两个点数据一直在更新,这样就模拟出手写的效果。

void Drawing::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    //qDebug()<<this->size();

    QPainter pp(&pix);
    pp.setPen(pen);
    pp.setFont(font);
    pp.drawLine(lastPoint,endPoint);
    pp.setRenderHint(QPainter::HighQualityAntialiasing,true);

    lastPoint = endPoint;
    QPainter painter(this);
    painter.drawPixmap(0,0,pix);
}

这里为了效果使用缓冲技术,先将线画在一张图片上,在将图片绘制在界面上。

手写字符处理

鼠标模拟手写结束之后,需要将我们绘制的图片处理一下。我们绘制的图片显示是黑白的,但是实际上他是彩色的。而且训练的数据是1* 784的向量,我们的图片也要转换成这个尺寸,否则会报错。

处理流程为:

保存界面图片
图片缩放至28*28(这是字符集的尺寸)
灰度化图片
二值化图片
将28*28转换为1*784(28*28)
将图片的数据转换为CV_32F
得到结果

源码为:

QImage drawImg = ui->wgtDrawing->getImage();
    QImage scaleImg = drawImg.scaled(28,28);
    cv::Mat img = toMat(scaleImg);
    //cv::imshow("drawImg",img);//correct
    cv::Mat gray = getGrayImg(img);
    //cv::imshow("gray",gray);//correct
    cv::Mat bin = getBinImg(gray);
    //cv::imshow("bin",bin);//correct

    cv::Mat temp(1,28* 28, CV_8UC1);
    for(int i=0;i<bin.rows;i++){
        for(int j=0;j<bin.cols;j++){
            uchar a=bin.at<uchar>(i,j);
            temp.at<uchar>(0,i*28+j)=a;
        }
    }
    temp.convertTo(temp,CV_32F);

然后就可以是这个图片进行识别了

结果预测

预测流程是:

检查xml文件是否存在
加载xml文件
预测
结果显示

代码为:

std::cout << "svm预测开始" << std::endl;
        file.open("svm.xml");
        if (!file.is_open())
        {
            std::cout << "->SVM训练结果文件svm.xml不存在" << std::endl;
        }

        std::cout << "->开始加载svm模型" << std::endl;
        cv::Ptr<cv::ml::SVM> svm = cv::Algorithm::load<cv::ml::SVM>("svm.xml");
        std::cout << "->svm模型加载完毕" << std::endl;

        predicted = svm->predict(temp);
        result = static_cast<int>(predicted);
        std::cout << "svm预测结束" << std::endl;

源码使用

本文源码地址为:HandWriting

源码有三个文件夹:

data
src
tools

data是已经解压的mnist数据集,src是QT的手写字符识别软件,tools里面是SVM/KNN/OpenCV训练测试MNIST工具。

先到tools文件夹下,可以看到:

bb7815b5ed787bc1e424334eeafbb59e.png

将data文件夹中的数据集复制到此文件夹下:

3ad4ccbde6ffe4713e3ae921700bea86.png

然后编译:

cmake .
make

1a9954576912d5a874d4c544658de57e.png

knnttsvmtt就是训练和测试工具(svmtraintest)。

训练SVM,执行:

./svmtt

输出为:

f29ed0b6ff35a28d2b363f4d12ae22fe.png

svm.xml就是训练结果文件,将其复制到手写字符软件编译可执行文件文件夹下。

同理可得knn结果文件:

44b074f5d5668c1fe9ff53910b15aa03.png

编译运行手写字符软件:

de22d8420430cb6df9b0d6538584b39b.png

使用鼠标绘制字符(相当于手写),点击Type下拉框选择SVM/KNN模型(暂时只有这两个)点击GO就会从软件文件夹加载之前训练的*.xml文件然后预测结果:

9ab28732084e0f5c73dc9993b5fcd2a0.png

到此结束,源码注释都有,可自行优化。

SVM和KNN的原理在这,准确率不会太高。可能使用pytorch或者TensorFlow会更好。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值