目录

前言

一、功能介绍

1.画板识别

2.图片识别

二、UI设计

1.整体设计思想

2.颜色设计

3.Logo 设计

4.按钮设计

三、算法介绍

1.图片预处理

2.数字分割和显示

3.识别算法

4.UI搭建

四、代码及架构

1.配置环境

2、代码结构

1、main

2、Tan

3、Run

4、predict

5、train

6、tarin_new

3、全部代码

1、main

2、Tan

3、Run

4、predict

5、train

6、tarin_new

总结

1.一些不足之处

2.界面和交互

3.网络搭建

4.深度学习算法设计与评估基本步骤总结


前言

这个其实是我上学期多媒体课的大作业(本文译自实验报告233),综合了网上一些零碎资料,谨以记录学习经历,如有错漏、不完善之处,请多多指正!

        ps:文章框架参考了两篇博客,但是写的时候有点找不到了ORZ,要是有人发现雷同,帮忙找到文章,我会标记到文末,感激!


一、功能介绍

1.画板识别

(1)可以选择算法,默认为 CNN

(2)在“画板”模块处可以进行鼠标绘制,绘制时接近画板中央会效果更好

(3)点击按钮“画板识别”即可进行识别,结果会显示在“结果”处

(4)点击按钮“画板擦除”即可清空“画板”模块。

2.图片识别

(1)可以选择算法,默认为 CNN
(2)点击按钮“图像识别”可选择需要上传的图片,点击确认后进行识别,结果会显
示在“结果”处

二、UI设计

1.整体设计思想

        画面简单干净,用户逻辑清晰。(划水)

2.颜色设计

        采用了白+ 蓝的基础设计思想,突出简单干净。(摸鱼)

3Logo 设计

        将猫咪和电脑结合,突出可爱和清爽。(某次PS课程作业)

4.按钮设计

        圆滑边角,略微阴影,突出舒适干净。(随便找的模板)

三、算法介绍

1.图片预处理

( 1 )调用 cv2 库读入图片,用插值的方法统一 resize 为 960:640 的比例
( 2 )灰度化
( 3 )二值化
( 4 )放大轮廓,再除去噪点。

代码如下:

image = cv2.resize(img, (960, 640), interpolation=cv2.INTER_LINEAR)
# 将这帧转换为灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 二值化
retval, binary = cv2.threshold(gray, 90, 255, cv2.THRESH_BINARY_INV)
# 放大所有轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):cv2.drawContours(binary, contours, i, (255, 255, 255), 5)
# 过滤噪声点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):perimeter = cv2.arcLength(contours[i], False)if perimeter < 100:# print(s)cv2.drawContours(binary, contours, i, (0, 0, 0), 15)# cv2.imshow('binary_f', binary)contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

2.数字分割和显示

( 1 )遍历每个查到的轮廓,得到中心距,并画出绿色框图
( 2 )读取框图内的图片进行预测
( 3 )将预测结果显示在已画框图的中上位置

代码如下:

for i in range(len(contours)):M = cv2.moments(contours[i])#  找到中心点if M['m00'] != 0:cx = int(M['m10'] / M['m00'])cy = int(M['m01'] / M['m00'])x, y, w, h = cv2.boundingRect(contours[i])pad = max(w, h) + 10#  画出绿色框图cv2.rectangle(image, (cx - pad // 2, cy - pad // 2), (cx + pad // 2, cy + pad // 2), (0, 255, 0), thickness=2)#  进行预测if cy - pad // 2 >= 0 and cx - pad // 2 >= 0:number_i = (binary[cy - pad // 2:cy + pad // 2, cx - pad // 2:cx + pad // 2])number_i = cv2.resize(number_i, (28, 28))if model_x == 1:number_i = np.reshape(number_i, (-1, 28, 28, 1)).astype('float')else:number_i = number_i.reshape(1, 784).astype('float32')#将结果红色显示在框上result = number_predict(number_i, model, model_x)cv2.putText(image, str(result[0]), org=(x, y), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1.2,color=(0, 0, 255), thickness=2)

3.识别算法

ps:除了CNN其实都是调的sklearn库保存的模型

(1)CNN:
        1 > 能够对数字图片的多层级特征进行自行构建和调参,是效果最好的算法,在
minist 集上准确率在 99%以上
        2 > 将 alex 网络的 5 层卷积变化为了 3 层,平坦化后的全连接变化为了卷积,可以在 gpu 更低级的设备上运行使用,初始 128 维特征减小为了 16 维开始,最后进行 10个特征的 one-hot 结果输出。网络架构和参数数量如下:

(2)RandomForest
        1 >使用投票方式,让多个弱分类器进行线性拟合,生成一个强分类器。
        2>算法思想图如下:

(3)KNN
        1 >利用距离进行最近邻居分类的迭代算法
        2>算法流程图如下:

(4)DecisionTree
        1 >对特征进行层层分支,用树的方式来进行分类
        2>算法流程图如下:

4.UI搭建

ps:因为做这个的时候第一次接触qt,所以没有用图形化界面而是找了个框架自己边学边改手撕的界面QAQ

1、Tan类,继承PYQT5的QWidget类

(1)设置主体框架大小和出现位置等基本参数,将l图标和背景置为自选图片

(2)添加logo、各个按钮、画板、结果显示、文字提示等控件,并copy模板略微美化界面

(3)图片识别和画板识别用同一个逻辑,截图或者直接选取图片,然后调用RUN函数用选中的模型进行预处理和预测得到结果,功能函数分别和两个按钮的鼠标点击事件连接

2、MyLabel类,继承PYQT5的QLabel类,主要是为了在背景图片上还能写字(可能方法比较蠢)

(1)定义一个事件函数,记录鼠标位置,用来写字

(2)定义一个擦除画板功能,和对应按钮鼠标点击事件连接

四、代码及架构

1.配置环境

keras 2.4.3     PyQt5 5.15.4

numpy 1.19.5   TensorFlow 2.5.0

opencv-python 4.5.2.52

pyscreenshot 3.0   joblib 1.0.1

sklearn 0.0

2、代码结构

1、main

调用界面

2、Tan

界面逻辑和交互

3、Run

图片预处理、预测及生成结果图片

4、predict

读入图片归一化、根据参数选择预测模型预测函数

5、train

CNN训练并保存模型

6、tarin_new

sklearn库函数模型训练、比较和保存

3、全部代码

1、main

import sys
from PyQt5.QtWidgets import QApplication
from Tan import Tanif __name__ == "__main__":app = QApplication(sys.argv)mymnist = Tan()  # 调用Tan中GUImymnist.show()app.exec_()

2、Tan

# --coding:utf-8--
from PyQt5.QtWidgets import (QWidget, QPushButton, QLabel, QComboBox, QFileDialog)
from PyQt5.QtGui import (QPainter, QPen, QFont)
from PyQt5.QtCore import Qt
from PyQt5 import QtGui
from PyQt5.Qt import QIcon
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.Qt import QDir, QIcon
from PyQt5.QtGui import QPixmap
import sys
from PIL import Image
import  osimport pyscreenshot as ImageGrab
import Run
import cv2
import numpydef is_chinese(string):"""检查整个字符串是否包含中文:param string: 需要检查的字符串:return: bool"""for ch in string:if u'\u4e00' <= ch <= u'\u9fff':return Truereturn Falseclass MyLabel(QLabel):pos_xy=[]def paintEvent(self, event):painter = QPainter()painter.begin(self)#pen = QPen(Qt.black, int(self.huabi.currentText()), Qt.SolidLine)  # 画笔尺寸 颜色painter.setPen(QPen(Qt.black, 2, Qt.SolidLine))if len(self.pos_xy) > 1:point_start = self.pos_xy[0]for pos_tmp in self.pos_xy:point_end = pos_tmpif point_end == (-1, -1):point_start = (-1, -1)continueif point_start == (-1, -1):point_start = point_endcontinuepainter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1])point_start = point_endpainter.end()# 记录鼠标点下的点,添加到pos_xy列表def mouseMoveEvent(self, event):pos_tmp = (event.pos().x(), event.pos().y())self.pos_xy.append(pos_tmp)self.update()# 鼠标释放,在pos_xy中添加断点def mouseReleaseEvent(self, event):pos_test = (-1, -1)self.pos_xy.append(pos_test)#绘制事件def btn_clear_on_clicked(self):self.pos_xy = []self.setText('')self.update()# 界面
class Tan(QWidget):def __init__(self):super(Tan, self).__init__()self.resize(654, 768)  # 外围边框大小self.move(550, 95)    # 设置位置self.setWindowTitle('手写数字识别')  # 标题self.setMouseTracking(False)  # False代表不按下鼠标则不追踪鼠标事件self.pos_xy = []  # 保存鼠标移动过的点# 添加控件#窗口图标self.setWindowIcon(QIcon('bluesky.jpg'))#窗口背景self.echoLabel = QLabel(self)self.echoLabel.setGeometry(160, 0, 903, 768)self.pixmap = QPixmap("bluesky.jpg")  # 按指定路径找到图片self.echoLabel.setPixmap(self.pixmap)  # 在label上显示图片self.echoLabel.setScaledContents(True)  # 让图片自适应label大小# logoself.logoLabel = QLabel(self)self.logoLabel.setGeometry(-80, -50, 319, 220)self.pixmap1 = QPixmap("logo.png")  # 按指定路径找到图片self.logoLabel.setPixmap(self.pixmap1)  # 在label上显示图片self.logoLabel.setScaledContents(True)  # 让图片自适应label大小# 画板文字self.label_draw_name = QLabel(('''<font color=#87F1E6 face='黑体' size=5>画板:<font>'''), self)self.label_draw_name.setGeometry(180, 15, 70, 30)# 画板区域self.label_draw = MyLabel('', self)self.label_draw.setGeometry(180, 45, 450, 300)self.label_draw.setStyleSheet("QLabel{border:1px solid white;background-color: #FFFFFF}")self.label_draw.setAlignment(Qt.AlignCenter)# 图片结果文字self.label_result_name = QLabel('''<font color=#87F1E6 face='黑体' size=5>结果:<font>''', self)self.label_result_name.setGeometry(180, 410, 70, 30)self.label_result_name.setAlignment(Qt.AlignCenter)# 图片结果区域self.label_result1 = QLabel(' ', self)self.label_result1.setGeometry(180, 440, 450, 300)self.label_result1.setStyleSheet("QLabel{border:1px solid white;background-color: #FFFFFF}")self.label_result1.setAlignment(Qt.AlignCenter)# 识别按钮,跳转到 reco 方法self.btn_recognize = QPushButton('画板识别', self)self.btn_recognize.setGeometry(6, 210, 60, 50)self.btn_recognize.setStyleSheet('''background-color: #87CEFA ;height:30px;border-style: outset;border-width: 2px;border-radius: 20px;border-color: beige;font: bold 12 px;min-width: 9em;padding: 5px;''')self.btn_recognize.clicked.connect(self.reco)# 选择上传图片self.btn_clear = QPushButton("图片识别", self)self.btn_clear.setGeometry(6, 510, 60, 50)self.btn_clear.clicked.connect(self.open_file)self.btn_clear.setStyleSheet('''background-color: #87CEFA ;height:30px;border-style: outset;border-width: 2px;border-radius: 20px;border-color: beige;font: bold 12 px;min-width: 9em;padding: 5px;''')# 清空所写数字self.btn_clear = QPushButton("擦除画板", self)self.btn_clear.setGeometry(6, 360, 60, 50)self.btn_clear.clicked.connect(self.label_draw.btn_clear_on_clicked)self.btn_clear.setStyleSheet('''background-color: #87CEFA ;height:30px;border-style: outset;border-width: 2px;border-radius: 20px;border-color: beige;font: bold 12 px;min-width: 9em;padding: 5px;''')# 识别模式self.moshi = QComboBox(self)self.moshi.addItems(['CNN', "RandomForest", "KNeighbors", "DecisionTree"])self.moshi.setGeometry(30, 650, 100, 30)self.moshi.setStyleSheet('''background-color: #87CEFA ;''')# 识别函数def reco(self):bbox = (self.x()+183, self.y()+83, 1180, 470)  # 设置截屏位置im = ImageGrab.grab(bbox)    # 截屏im.save("now.png")img = cv2.imread("now.png")if self.moshi.currentText() == "CNN":Run.Run(img, 1)  # 调用Run中'CNN'方法对所截图img进行处理if self.moshi.currentText() == "RandomForest":Run.Run(img, 2)  # 调用Run中'RandomForest'方法对所截图img进行处理if self.moshi.currentText() == "KNeighbors":Run.Run(img, 3)  # 调用Run中'KNeighbors'方法对所截图img进行处理if self.moshi.currentText() == "DecisionTree":Run.Run(img, 4)  # 调用Run中'DecisionTree'方法对所截图img进行处理self.label_result1.setPixmap(QtGui.QPixmap('img.png').scaled(self.label_result1.width(), self.label_result1.height()))  # 在label_result1中显示图片self.update()def open_file(self):imgName, imgType = QFileDialog.getOpenFileName(self, "选择一张图片", "", "*.jpg;;*.png;;All Files(*)")if imgName == "":returnif is_chinese(imgName):s = imgName.split('/')[-1]else:s = imgNameimg = cv2.imread(s)if self.moshi .currentText() == "CNN":Run.Run(img, 1)  # 调用Run中'CNN'方法对所截图img进行处理if self.moshi .currentText() == "RandomForest":Run.Run(img, 2)  # 调用Run中'RandomForest'方法对所截图img进行处理if self.moshi .currentText() == "KNeighbors":Run.Run(img, 3)  # 调用Run中'KNeighbors'方法对所截图img进行处理if self.moshi .currentText() == "DecisionTree":Run.Run(img, 4)  # 调用Run中'DecisionTree'方法对所截图img进行处理self.label_result1.setPixmap(QtGui.QPixmap('img.png').scaled(self.label_result1.width(), self.label_result1.height()))  # 在label_result1中显示图片self.update()

3、Run

import cv2
import numpy as np
import matplotlib.pyplot as plt
from keras.models import load_model
from predict import *
import joblibdef Run(img,model_x):""":param img: 输入图像矩阵:excute   将标注好的图片存入根目录,命名为“img.png”"""# 载入训练好的模型if model_x == 1:model = load_model('net1')if model_x == 2:model = joblib.load("RandomForest.pkl")if model_x == 3:model = joblib.load("KNeighbors.pkl")if model_x == 4:model = joblib.load("DecisionTree.pkl")image = cv2.resize(img, (960, 640), interpolation=cv2.INTER_LINEAR)# 将这帧转换为灰度图gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 二值化retval, binary = cv2.threshold(gray, 90, 255, cv2.THRESH_BINARY_INV)# 放大所有轮廓contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for i in range(len(contours)):cv2.drawContours(binary, contours, i, (255, 255, 255), 5)# 过滤噪声点contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for i in range(len(contours)):perimeter = cv2.arcLength(contours[i], False)if perimeter < 100:# print(s)cv2.drawContours(binary, contours, i, (0, 0, 0), 15)# cv2.imshow('binary_f', binary)contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#print(len(contours))# 遍历整个图片每个轮廓for i in range(len(contours)):M = cv2.moments(contours[i])#  找到中心点if M['m00'] != 0:cx = int(M['m10'] / M['m00'])cy = int(M['m01'] / M['m00'])x, y, w, h = cv2.boundingRect(contours[i])pad = max(w, h) + 10#  画出绿色框图cv2.rectangle(image, (cx - pad // 2, cy - pad // 2), (cx + pad // 2, cy + pad // 2), (0, 255, 0), thickness=2)#  进行预测if cy - pad // 2 >= 0 and cx - pad // 2 >= 0:number_i = (binary[cy - pad // 2:cy + pad // 2, cx - pad // 2:cx + pad // 2])number_i = cv2.resize(number_i, (28, 28))if model_x == 1:number_i = np.reshape(number_i, (-1, 28, 28, 1)).astype('float')else:number_i = number_i.reshape(1, 784).astype('float32')#将结果红色显示在框上result = number_predict(number_i, model, model_x)cv2.putText(image, str(result[0]), org=(x, y), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1.2,color=(0, 0, 255), thickness=2)cv2.imwrite('img.png', image)return 0#cv2.waitKey()#cv2.destroyAllWindows()

4、predict

def number_predict(img, model, k):# 图像处理img = img / 255.0# 预测if k == 1:result = model.predict_classes(img)else:result = model.predict(img)return result

5、train

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt
import numpy as np
from keras.utils import np_utilsbatch_size = 128
num_classes = 10
epochs = 10path = 'mnist_data/mnist.npz'
f = np.load(path)
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
f.close()x_train = x_train.reshape(60000, 28, 28, 1).astype('float32')
x_test = x_test.reshape(10000, 28, 28, 1).astype('float32')
x_train /= 255
x_test /= 255
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')# convert class vectors to binary class matrices
# label为0~9共10个类别,keras要求格式为binary class matricesy_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D# 卷积模型
model = Sequential()
model.add(Conv2D(filters=16,kernel_size=(5, 5),padding='same',input_shape=(28,28,1),activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(filters=36,kernel_size=(5, 5),padding='same',activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
#model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
#model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))model.summary()# 损失函数使用交叉熵
model.compile(loss='categorical_crossentropy',optimizer=RMSprop(),metrics=['accuracy'])
# 模型训练
model.fit(x_train, y_train,batch_size=batch_size,epochs=epochs,verbose=1,validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Total loss on Test Set:', score[0])
print('Accuracy of Testing Set:', score[1])# 模型保存
model.save('./net1.pkl')

6、tarin_new

import numpy as np
import pandas as pd
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.naive_bayes import MultinomialNB
from sklearn.naive_bayes import BernoulliNB
from sklearn.model_selection import StratifiedKFold
import joblibpath = 'mnist_data/mnist.npz'
f = np.load(path)
x_train, y_train = f['x_train'], f['y_train']
x_test, y_test = f['x_test'], f['y_test']
f.close()
x_train = x_train.reshape(60000, 784).astype('float32')
x_test = x_test.reshape(10000, 784).astype('float32')
x_train /= 255
x_test /= 255
clf5 = MultinomialNB()
clf5.fit(x_train, y_train)
joblib.dump(clf5, "MultinomialNB().pkl")classifierResult = clf5.predict(x_test)
mTest = len(x_test)errorCount = 0.0 ## 统计识别错误的样本个数
for i in range(mTest):if classifierResult[i] != y_test[i]:errorCount += 1.0print("\t 测试样本个数为: %d " % mTest)
print("\t 预测错误个数为: %d " % errorCount)
print("\t 预测错误率为: %2.2f%% " % (errorCount/float(mTest)*100))
print("\t 预测准确率为: %2.2f%%" % ((1-errorCount/float(mTest))*100))
'''
clf = KNeighborsClassifier(algorithm='kd_tree', n_neighbors=10)
clf.fit(x_train, y_train)
joblib.dump(clf, "KNeighbors.pkl")
clf2 = RandomForestClassifier()
clf2.fit(x_train, y_train)
joblib.dump(clf2, "RandomForest.pkl")
clf1 = DecisionTreeClassifier(criterion='entropy', random_state=0)
clf1.fit(x_train, y_train)
joblib.dump(clf1, "DecisionTree.pkl")
clf3 = GaussianNB()
clf3.fit(x_train, y_train)
joblib.dump(clf3, "GaussianNB.pkl")
clf4 = BernoulliNB()
clf4.fit(x_train, y_train)
joblib.dump(clf4, "BernoulliNB.pkl")
clf5 = MultinomialNB()
clf5.fit(x_train, y_train)
joblib.dump(clf5, "MultinomialNB().pkl")clf = joblib.load("RandomForest.pkl")
classifierResult = clf.predict(x_test)
mTest = len(x_test)errorCount = 0.0 ## 统计识别错误的样本个数
for i in range(mTest):if classifierResult[i] != y_test[i]:errorCount += 1.0print("\t 测试样本个数为: %d " % mTest)
print("\t 预测错误个数为: %d " % errorCount)
print("\t 预测错误率为: %2.2f%% " % (errorCount/float(mTest)*100))
print("\t 预测准确率为: %2.2f%%" % ((1-errorCount/float(mTest))*100))
'''


总结

1.一些不足之处

ps:有兴致和空闲再进行修改(估计是不会改了,滑稽.jpg

       另外我尝试了用pyinstaller进行打包,但是不知道是不是含有qt库,打包出来贼大(好几百M),.dll文件贼多,有兴趣的小伙伴可以自己尝试

( 1 )那个画板截图只能固定在屏幕某处,移动界面窗口会导致奇♂怪的画面出现。
(2)界面不够精美,质感可以提升,但是好的模块很多要钱(留下了菜且没钱的泪水π_π)
( 3 )不能将识别的数字按顺序保存文本,原因是多个数字按行截取容易出现奇怪的bug,而本文所用算法数字出现次序是:以预处理图片时目标识别的框最高处的坐标为标准,从高到低按顺序输出该处识别出来的数字(其实是cv库自带的轮廓识别结果的顺序),要实现按图片位置输出结果文本太麻烦,所以摸鱼(义正言辞^_^
(4 )图片识别时如果你的某个文件夹名字带中文或者不是根目录下的就会报错,因为用的是cv2的imread
(5)有不少冗余的库和实现,不够精简,希望coding能力越来越强!

2.界面和交互

( 1 )如果是在手机端,最好符合右手操作习惯(反正我不是)。
( 2 )在 PC 端不是功能越复杂越好,因为需要用户逻辑清晰(可以划水)。
( 3 )颜色的搭配还有 logo 、界面搭配等合理的设计会让用户体验大大提高(水字数)。

3.网络搭建

( 1 )学习和了解了 alex 、 vgg16 、 unet 等体系,在调整简单的 CNN 网络结构时进行了参考,但基于手写数字识别这个简单项目又进行了简化(摸鱼)。
(2 ) 在进行更高级的神经网络 图像处理中,运用多层金字塔特征,还有特征跨层连接可以获得更加准确的结果,例如 unet 网络:
        1         输入图片之后先经过卷积、最大池化下采样 5 层
        2         平坦化全连接
        3         上采样反卷积 5 层
        4         对应层进行跨层特征融合
        5         输出特征进行分割

4.深度学习算法设计与评估基本步骤总结

( 1 )确定问题目标:是监督、半监督还是无监督的学习,是目标识别还是分割等
( 2 )研究具体方案和思路:查阅文献确定范围,根据思路筛选文献,在现有基础上设计网络拓扑结构
( 3 )准备数据集,搭建网络,训练模型,测试准确率召回率和速度等进行评估和改进

ps:最近在考虑将抽空将正在学习的数据挖掘、深度学习、强化学习、计算机视觉等内容的基础知识整理来发博客,不过要准备考研估计得等很久以后了

PYQT5+CNN(TensorFlow-keras)做一个简单的手写数字识别PC端图形化小程序相关推荐

  1. TensorFlow笔记(3)——利用TensorFlow和MNIST数据集训练一个最简单的手写数字识别模型...

    前言 当我们开始学习编程的时候,第一件事往往是学习打印"Hello World".就好比编程入门有Hello World,机器学习入门有MNIST. MNIST是一个入门级的计算机 ...

  2. 神经网络和深度学习(二)——一个简单的手写数字分类网络

    本文转自:https://blog.csdn.net/qq_31192383/article/details/77198870 一个简单的手写数字分类网络 接上一篇文章,我们定义了神经网络,现在我们开 ...

  3. 用tensorflow.js实现浏览器内的手写数字识别

    原文 简介 Tensorflow.js是google推出的一个开源的基于JavaScript的机器学习库,相对与基于其他语言的tersorflow库,它的最特别之处就是允许我们直接把模型的训练和数据预 ...

  4. tensorflow应用:双向LSTM神经网络手写数字识别

    tensorflow应用:双向LSTM神经网络手写数字识别 思路 Python程序1.建模训练保存 Tensorboard检查计算图及训练结果 打开训练好的模型进行预测 思路 将28X28的图片看成2 ...

  5. AI常用框架和工具丨11. 基于TensorFlow(Keras)+Flask部署MNIST手写数字识别至本地web

    代码实例,基于TensorFlow+Flask部署MNIST手写数字识别至本地web,希望对您有所帮助. 文章目录 环境说明 文件结构 模型训练 本地web创建 实现效果 环境说明 操作系统:Wind ...

  6. 基于tensorflow2.0利用CNN与线性回归两种方法实现手写数字识别

    CNN实现手写数字识别 导入模块和数据集 import os import tensorflow as tf from tensorflow import keras from tensorflow. ...

  7. matlab 对mnist手写数字数据集进行判决分析_人工智能TensorFlow(十四)MINIST手写数字识别...

    MNIST是一个简单的视觉计算数据集,它是像下面这样手写的数字图片: MNIST 每张图片还额外有一个标签记录了图片上数字是几,例如上面几张图的标签就是:5.0.4.1. MINIST数据 MINIS ...

  8. Tensorflow 学习入门(二) 初级图像识别——手写数字识别

    初级图像识别--手写数字识别 背景知识储备 Softmax Regression MNIST 矩阵相乘 One Hot 编码 Cross Entropy(交叉熵) 代码实现 引入数据 设计数据结构 完 ...

  9. 莫烦keras学习代码二(手写数字识别MNIST classifier CNN版)

    知道了CNN的原理,同样是只要将之前用tensorflow写的几个建立网络的函数用keras的更简单的方法替换就行. 训练结果: 用Sequential().add()添加想要的层,添加卷积层就用Co ...

最新文章

  1. java开发用amd处理器_HBase1.x实战:协处理器Java开发实例--ObserverCoprocessor
  2. windows 映射文件会释放内存吗_Windows系统共享内存管理
  3. 黑苹果找不到触控板_猫和老鼠手游:好友位不足却找不到人开黑?玩家给好友系统支招...
  4. STM32的学习记录--单个模块开发思路
  5. CSDN-markdown编辑器的使用方法
  6. python简单圣诞树手工折纸_简单立体手工折纸圣诞树的视频教程
  7. java调用方法出现i 2a_性能-Java方法调用与使用变量
  8. java源代码反编译_XJad(Java源程序反编译软件)
  9. gps84转换gcj02公式_WGS84-GCJ-02坐标转化
  10. 新浪微博短网址t.cn 短链接生成9.28
  11. 多媒体呼叫中心技术、应用与发展前景
  12. 域名虚拟主机_域名和虚拟主机之间有什么区别(解释)
  13. 【重识云原生】第六章容器基础6.4.7.2节——CronJob
  14. 正则表达式课后练习题
  15. Word VBA自动排版(1)-新建窗口,并且设置并列分布
  16. 互联网无插件直播流媒体服务器方案EasyNVR下载新的软件执行程序,出现“invalid license”字样是什么意思?
  17. 亿图图示----流程图模块---样例展示
  18. [转载]中情局数千份机密文档泄露:各种0day工具、恶意程序应有尽有
  19. Win11,MySQL8 安装教程。
  20. Python多线程,大杂烩

热门文章

  1. java 接口 取消订单_java 商家取消订单流程
  2. android 事件失效,TouchEnd事件在Android上不起作用
  3. Android Battery 开发(三) BatteryService
  4. Excel中HLOOKUP函数实例(一):自动判断并获取数据
  5. C++学习笔记----allocator
  6. 我的英语学习经验与教训
  7. 黑马程序员 骑士飞行棋源码
  8. uniqid php 重复_在php使用隐藏字段和uniqid来实现表单的重复提交
  9. 港科夜闻|香港科技大学吴宏伟教授团队获国家自然科学奖二等奖
  10. 2019年一个程序员的回顾与成长计划