1. 准备工作

下载MNIST数字集 : http://yann.lecun.com/exdb/mnist/

使用python将数据集提取出来,转换成图片,转化后图片像这样的

数据集解读和保存如下(代码以测试文件为例):

import numpy as np
import struct
import matplotlib
import matplotlib.pyplot as pltsavePath = r'pictures\NumberRecgonize\TestImage'#测试集文件
t10kImages = r'pictures\NumberRecgonize\t10k-images.idx3-ubyte'
t10kILabels = r'pictures\NumberRecgonize\t10k-labels.idx1-ubyte'#训练集文件
trainImages = r'pictures\NumberRecgonize\train-images.idx3-ubyte'
trainLabels = r'pictures\NumberRecgonize\train-labels.idx1-ubyte'f=open(savePath+ r"\imgpathAndLabel.csv","w+")#读取bin文件
bin_image_data = open(t10kImages, 'rb').read()
bin_label_data = open(t10kILabels, 'rb').read()
#文件偏移和image、label的头文件格式
image_offset = 0
label_offset = 0
fmt_image_header = '>iiii'
fmt_label_header = '>ii'magic_number, num_images, num_rows, num_cols = struct.unpack_from(fmt_image_header, bin_image_data, image_offset)
print('魔数:%d, 图片数量: %d张, 图片大小: %d*%d' % (magic_number, num_images, num_rows, num_cols))
#magic_number, num_images, num_rows, num_cols = struct.unpack_from(fmt_label_header, bin_label_data, label_offset)
#print('魔数:%d, 图片数量: %d张, 图片大小: %d*%d' % (magic_number, num_images, num_rows, num_cols))image_size = num_rows * num_cols
image_offset += struct.calcsize(fmt_image_header)
label_offset += struct.calcsize(fmt_label_header)
print(image_offset)
#文件占用多少存储空间 , 一张图片28*28 = 784;  数字标签 1
fmt_image = '>' + str(image_size) + 'B'
fmt_lable = '>B'
print(fmt_image, image_offset, struct.calcsize(fmt_image))
print(fmt_lable, label_offset, struct.calcsize(fmt_lable))
images = np.empty((num_images, num_rows, num_cols))  #大内存申请尽量避免呢,不过MNIST不是很大
labels = np.empty(num_images)for i in range(num_images):#num_imagesif(i + 1) % 1000 == 0 :print('已解析 %d' % (i+1) + '张')print(image_offset)images[i] = np.array(struct.unpack_from(fmt_image, bin_image_data, image_offset)).reshape(num_rows, num_cols)#黑色背景转换为黑色背景 白字,当然根据自己的需要调整 黑纸白字也可以images[i] = 255 - images[i]labels[i] = np.array(struct.unpack_from(fmt_lable, bin_label_data, label_offset))[0]#保存图片路径imageSavePath = savePath+r'\num%d\numPic_%d'%(int(labels[i]),i) + '.png'matplotlib.image.imsave(imageSavePath, images[i], cmap='gray')#写入图片路径和标签f.write(imageSavePath+';%d\n'%(int(labels[i])))#print(int(labels[i]))image_offset += struct.calcsize(fmt_image)label_offset += struct.calcsize(fmt_lable)
f.close()

2.  KNN数字识别

2.1. 原理: 每一张图片是28 * 28大小的图片, 如果训练数据有500张图片,其中每一个阿拉伯数字出现的次数大致相同(叫训练图片可能不太妥当,没有训练过程可以叫“已知标签的图片”), 待测图片的大小也为28*28的大小, 测试时候计算 待检测图片和每一张训练图片的距离,这样就得到了待测图片与所有训练图片的距离(一个500的数组), 找到前K个距离最短的图片,K个图片中标签出现次数最多的就可以假设为这一张待测图片中的标签。 比如 算出K个最近图片中标签为3的图片出现超过K/2,则可以认为待检测图片中的数字为3。

2.2 OpenCV代码


#include <math.h>
#include <opencv2/opencv.hpp>using namespace std;
using namespace cv;
using namespace cv::ml;int main()
{string filename = string("NumberRecgonize/TestImage/imgpathAndLabel.csv");string modelPath = string("NumberRecgonize/TestImage/testData.xml");ifstream file(filename.c_str(), ifstream::in);if (!file){cout << "could not load file correctlly ..." << endl;getchar();return -1;}bool trainSelect = false; // 已经生成好模型就不用训练了Ptr<KNearest> knn = KNearest::create();knn->setDefaultK(10);knn->setIsClassifier(true);if (trainSelect){string line, path, label;Mat images, labels;char separator = ';';Mat readImg, grayImg, reshapImg;while (getline(file, line)){stringstream liness(line);getline(liness, path, separator);getline(liness, label);if (!path.empty() && !label.empty()){//cout << "path : " << path << endl;readImg = imread(path, 0);//int tmp = readImg.channels();// 读取的图片本身是gray的grayImg = readImg;//cvtColor(readImg, grayImg, CV_BGR2GRAY);threshold(grayImg, grayImg, 0, 255, CV_THRESH_OTSU);reshapImg = grayImg.reshape(1, 1);reshapImg.convertTo(reshapImg, CV_32FC1);images.push_back(reshapImg);//labels.push_back(path);labels.push_back(atoi(label.c_str()));}}// 训练数据和标签 进行训练Ptr<TrainData> trainData = TrainData::create(images, ROW_SAMPLE, labels);// 训练生成模型knn->train(trainData);knn->save(modelPath);}else{// 模型保存下来了,下一次进行训练后可以直接加载//   knn->read(modelPath); --- no functionknn = StatModel::load<KNearest>(modelPath);}Mat src = imread("NumberRecgonize/numPic_97.png");Mat grayImg, input;cvtColor(src, grayImg, CV_BGR2GRAY);threshold(grayImg, grayImg, 0,255, CV_THRESH_OTSU);imshow("train src", grayImg);input = grayImg.reshape(1,1);input.convertTo(input, CV_32FC1);float r = knn->predict(input);cout << r << endl;waitKey(0);return 0;
}

2.3 结果展示 可以看出这一种方法还是有一定计算错误,毕竟需要大量的数据去测试,而且一张图片数字可能出现再不同的位置,这样计算距离的时候可能也有很大的差异。

2.4. KNN 数字识别Python 代码,使用tensorflow计算,python代码如下

# -*- coding: utf-8 -*-
"""
Created on Mon Apr 13 16:36:18 2020@author: Administrator
"""import tensorflow as tf
import numpy as np
import random
from tensorflow.examples.tutorials.mnist import input_data#load pictures
mnist = input_data.read_data_sets('MNIST_data', one_hot = True)trainNum = 55000
testNum = 10000
trainSize = 5000
testSize = 5k = 4 #KNN 中与哪几个图片相似,这几张图片中属于哪一个标签更多,就属于哪一个类别
#数据获取和分解,将数据全部分解
trainIdx = np.random.choice(trainNum, trainSize, replace=False)
testIdx = np.random.choice(testNum, testSize, replace=False)
trainData = mnist.train.images[trainIdx]
trainLabel = mnist.train.labels[trainIdx]
testData = mnist.test.images[testIdx]
testLabel = mnist.test.labels[testIdx]print('trainData.shape=',trainData.shape)
print('trainLabel.shape=',trainLabel.shape)
print('testData.shape=',testData.shape)
print('testLabel.shape=',testLabel.shape)# tf input  tensorflow里对于暂时不进行赋值的元素有一个称呼叫占位符。所谓占位符,顾名思义,先占着茅坑不拉屎,等需要时再赋值。所需要的命令为tf.placeholder
# feed_dict就是用来赋值的,格式为字典型
trainDataInput = tf.placeholder(shape=[None, 784], dtype=tf.float32)
trainLabelInput = tf.placeholder(shape=[None,10], dtype = tf.float32)
testDataInput = tf.placeholder(shape=[None, 784], dtype=tf.float32)
testlableInput = tf.placeholder(shape=[None,10], dtype=tf.float32)#knn distance 5*784
f1 = tf.expand_dims(testDataInput,1)
f2 = tf.subtract(trainDataInput,f1)
f3 = tf.reduce_sum(tf.abs(f2),reduction_indices=2)f4 = tf.negative(f3) ## 取反# f55 存放最近的距离, f6存放数组的下标与最近四个样本对应
f5,f6 = tf.nn.top_k(f4,k=4)#f7 收集最近标签信息
f7 = tf.gather(trainLabelInput, f6)#f8 数据的累加,将可能数据进行累加; f9 num的获取,为预测结果
f8 = tf.reduce_sum(f7, reduction_indices=1)
f9 = tf.argmax(f8,dimension=1)#获取测试数据真是的结果
f10 = tf.argmax(testlableInput,dimension=1)with tf.Session() as sess:#f1 <- testData p1 = sess.run(f1,feed_dict={testDataInput:testData[0:5]})print('p1=', p1.shape)p2 = sess.run(f2,feed_dict={trainDataInput:trainData, testDataInput:testData[0:5]})print('p2=', p2.shape)p3 = sess.run(f3,feed_dict={trainDataInput:trainData, testDataInput:testData[0:5]})print('p3=',p3.shape)print('p3[0,0]=',p3[0,0])p4 = sess.run(f4, feed_dict={trainDataInput:trainData, testDataInput:testData[0:5]})print('p4=', p4.shape)p5,p6 = sess.run((f5,f6),feed_dict={trainDataInput:trainData, testDataInput:testData[0:5]})print('p5.shape=', p5.shape)print('p6.shape=', p6.shape)print('p5[0,0]=',p5[0,0])print('p6[0,0]=',p6[0,0])p7 = sess.run(f7,feed_dict={trainDataInput:trainData, testDataInput:testData[0:5], trainLabelInput:trainLabel})print('p7.shape=',p7.shape)p8 = sess.run(f8,feed_dict={trainDataInput:trainData, testDataInput:testData[0:5], trainLabelInput:trainLabel})print('p8.shape = ', p8.shape)print('p8[]', p8)p9 = sess.run(f9,feed_dict={trainDataInput:trainData, testDataInput:testData[0:5], trainLabelInput:trainLabel})#print('p9.shape = ', p9.shape)print('p9[]', p9)p10 = sess.run(f10, feed_dict={testlableInput:testLabel})#print('p10.shape = ', p10.shape)print('p10[]', p10)

结果展示 python代码中  trainSize = 5000,训练样本足够,得到的结果准确率够高

p9[]  [8 0 3 1 1]
     p10[] [8 0 3 1 1]

如果将 trainSize 更改更小一些,trainSize = 500,有时候还是会出现识别错误的

p9[]  [4 1 6 4 6]
    p10[] [4 1 6 4 0]

ps:代码中下载 mnist 如果没有网络可能会出现错误,可以事先下载好放在工程目录/MNIST_data下面(不用解压出来),下载MNIST数字集 : http://yann.lecun.com/exdb/mnist/

3.  神经网络数字识别 tensorflow2.1版本

具体代码讲解见大牛的:  简单粗暴 TensorFlow 2

迭代进行以下步骤:

  • 从 DataLoader 中随机取一批训练数据;

  • 将这批数据送入模型,计算出模型的预测值;

  • 将模型预测值与真实值进行比较,计算损失函数(loss)。这里使用 tf.keras.losses 中的交叉熵函数作为损失函数;

  • 计算损失函数关于模型变量的导数;

  • 将求出的导数值传入优化器,使用优化器的 apply_gradients 方法更新模型参数以最小化损失函数

import numpy as np
import tensorflow as tfclass MNISTLoader():def __init__(self):mnist = tf.keras.datasets.mnist(self.train_data, self.train_label), (self.test_data, self.test_label) = mnist.load_data()self.train_data = np.expand_dims(self.train_data.astype(np.float32) / 255.0, axis=-1)self.test_data = np.expand_dims(self.test_data.astype(np.float32) / 255.0, axis=-1)self.train_label = self.train_label.astype(np.int32)self.test_label = self.test_label.astype(np.int32)self.num_train_data, self.num_test_data = self.train_data.shape[0], self.test_data.shape[0]def get_batch(self, batch_size):index = np.random.randint(0, self.num_train_data, batch_size)return self.train_data[index, :], self.train_label[index]class MLP(tf.keras.Model):def __init__(self):super().__init__()self.flatten = tf.keras.layers.Flatten()self.dense1 = tf.keras.layers.Dense(units=100, activation=tf.nn.relu)self.dense2 = tf.keras.layers.Dense(units=10)def call(self, inputs):x = self.flatten(inputs)x = self.dense1(x)x = self.dense2(x)output = tf.nn.softmax(x)return outputclass CNN(tf.keras.Model):def __init__(self):super().__init__()self.conv1 = tf.keras.layers.Conv2D(filters=32,kernel_size=[5,5],padding='same',activation=tf.nn.relu)self.pool1 = tf.keras.layers.MaxPool2D(pool_size=[2,2], strides=2)self.conv2 = tf.keras.layers.Conv2D(filters=64,kernel_size=[5,5],padding='same',activation=tf.nn.relu)self.pool2 = tf.keras.layers.MaxPool2D(pool_size=[2,2], strides=2)self.flatten = tf.keras.layers.Reshape(target_shape=(7*7*64, ))self.dense1 = tf.keras.layers.Dense(units=1024, activation=tf.nn.relu)self.dense2 = tf.keras.layers.Dense(units=10)def call(self, inputs):x = self.conv1(inputs)x = self.pool1(x)x = self.conv2(x)x = self.pool2(x)x = self.flatten(x)x = self.dense1(x)x = self.dense2(x)output = tf.nn.softmax(x)return outputnum_epochs = 5
batch_size = 50
learning_rate = 0.001model = CNN() # or model = MLP()
data_loader = MNISTLoader()
optimizer = tf.keras.optimizers.Adam(learning_rate = learning_rate)num_batches = int(data_loader.num_train_data // batch_size * num_epochs)
for batch_index in range(num_batches):X,y = data_loader.get_batch(batch_size)with tf.GradientTape() as tape:y_pred = model(X)loss = tf.keras.losses.sparse_categorical_crossentropy(y_true=y, y_pred=y_pred)loss = tf.reduce_mean(loss)print("batch %d; loss %f" %(batch_index, loss.numpy()))grads = tape.gradient(loss, model.variables)optimizer.apply_gradients(grads_and_vars=zip(grads, model.variables))sparse_categorical_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
num_batches = int(data_loader.num_test_data // batch_size)
for batch_index in range(num_batches):start_index, end_index = batch_index * batch_size, (batch_index + 1) * batch_sizey_pred = model.predict(data_loader.test_data[start_index : end_index])sparse_categorical_accuracy.update_state(y_true=data_loader.test_label[start_index: end_index],y_pred=y_pred)
print("test accuracy: %f" % sparse_categorical_accuracy.result())

4.

opencv手写数字识别(未完待续...)相关推荐

  1. pyTorch入门(六)——实战Android Minist OpenCV手写数字识别(附源码地址)

    学更好的别人, 做更好的自己. --<微卡智享> 本文长度为4239字,预计阅读12分钟 前言 前面几篇文章实现了pyTorch训练模型,然后在Windows平台用C++ OpenCV D ...

  2. 手写数字识别【QT+OpenCV】

    手写数字识别[QT+OpenCV] [说明] 手写数字识别的实现方式很多. 本文尽量将其简化,以让大家能够快速了解怎样实现一个动起来的系统. [截图] [思路] 1.特征提取 将图像划分为5*5大小的 ...

  3. python opencv数字识别_基于模板匹配的手写数字识别(python+opencv)

    智能计算课第一周的实验是做基于模板匹配的手写数字识别,光听见就很感兴趣,于是决定认真做做这个实验,本实验基于python3+opencv的python版本,所用到的知识都比较简单,基本上边学边做,技术 ...

  4. linux手写数字识别opencv,opencv实现KNN手写数字的识别

    人工智能是当下很热门的话题,手写识别是一个典型的应用.为了进一步了解这个领域,我阅读了大量的论文,并借助opencv完成了对28x28的数字图片(预处理后的二值图像)的识别任务. 预处理一张图片: 首 ...

  5. 在OpenCV里使用机器学习库sklearn 实现手写数字识别1

    前面学习过KNN的方式来实现手写数字识别,不过效果一般,那么有没有别的方法来试一试,或许可以改进一点呢.在本文里将要介绍使用SVM和HOG的方式来实现手写数字识别,比如最终结果如下图: 在这个例子里与 ...

  6. 手把手教你使用LabVIEW OpenCV DNN实现手写数字识别(含源码)

    文章目录 前言 一.OpenCV DNN模块 1.OpenCV DNN简介 2.LabVIEW中DNN模块函数 二.TensorFlow pb文件的生成和调用 1.TensorFlow2 Keras模 ...

  7. 现在论文用手写还是用计算机写,毕业论文计算机手写数字识别技术完整版.docx...

    HEN system office room [HEN16H-HENS2AHENS8Q8-HENH1688] HEN system office room [HEN16H-HENS2AHENS8Q8- ...

  8. 监督学习:KNN(K-近邻)算法实现手写数字识别的三种方法

    没人会看的开场白:本来觉得自己从数据建模转人工智能方向应该问题不大(自我感觉自己算法学的不错).结果一个K-邻近实现手写数字识别的代码就让我改了三四天.虽然网上这方面的代码是很多,但是我运行了好几个, ...

  9. pytorch 预测手写体数字_深度学习之PyTorch实战(3)——实战手写数字识别

    如果需要小编其他论文翻译,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/DeepLearningNote 上一节,我们已经 ...

最新文章

  1. oracle 有则更新,oracle 存在则更新不存在则插入-方案
  2. h5实现手机端等级进度条
  3. MySQL 错误对照表
  4. 【OpenCV3】角点检测——cv::goodFeaturesToTrack()与cv::cornerSubPix()详解
  5. SSM中通过Json做前后端分离
  6. Android中onInterceptTouchEvent、dispatchTouchEvent及onTouchEvent的调用顺序及内部原理
  7. 正确解读PHP获取时间错误原因
  8. 【转】如何写出让同事无法维护的代码
  9. Python全栈开发记录_第三篇(linux(ubuntu)的操作)
  10. 9-n个人中选k个人的选择方法种类
  11. Python进行websocket接口测试
  12. Java Swing中国象棋AI(人机和人人对战)
  13. 搜索网络所有计算机快捷键,实用电脑快捷键使用大全(图文)
  14. 传苹果将采用:夏普IGZO技术面板量产
  15. Nginx 关于 Rewrite 执行顺序详解
  16. lol服务器维护补偿,LOL官方:服务器崩溃补偿!全服再次免费赠送皮肤一款!
  17. 家居装修选购:挑选家用沙发的8个禁忌
  18. 算力网络发展中的若干关键技术问题分析
  19. 通过EFI安装Ubantu+Win7双系统教程
  20. 日本大型移动支付软件 PayPay 的 TiDB 迁移实践

热门文章

  1. 前端学习第一天--编程软件vscode使用、HTML标签
  2. SpringBoot核心技术
  3. System.Diagnostics.Stopwatch
  4. JSON--JSON学习入门(了解什么是JSON)
  5. 简练网软考知识点整理-项目风险审计及风险评估
  6. 苹果ios APP怎么打包?
  7. 关于PyCharm比较高效率的使用技巧,学习Python的小伙伴别错过!
  8. Neo4j:SLM群集算法的过程
  9. 揭秘香港房地产,未来中国之我见
  10. HEIF HEVC 你知道多少?