日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python3实现简单可学习的手写体识别

發(fā)布時間:2024/8/26 python 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python3实现简单可学习的手写体识别 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

0.目錄

1.前言

2.通過pymssql與數(shù)據(jù)庫的交互

3.通過pyqt與界面的交互

4.UI與數(shù)據(jù)庫的交互

5.最后的main主函數(shù)

1.前言

版本:Python3.6.1 + PyQt5 + SQL Server 2012

以前一直覺得,機器學(xué)習(xí)、手寫體識別這種程序都是很高大上很難的,直到偶然看到了這個視頻,聽了老師講的思路后,瞬間覺得原來這個并不是那么的難,原來我還是有可能做到的。

于是我開始順著思路打算用Python、PyQt、SQLServer做一個出來,看看能不能行。然而中間遇到了太多的問題,數(shù)據(jù)庫方面的問題有十幾個,PyQt方面的問題有接近一百個,還有數(shù)十個Python基礎(chǔ)語法的問題。但好在,通過不斷的Google,終于湊出了這么一個成品來。

最終還是把都湊在一個函數(shù)里的代碼重構(gòu)了一下,改寫成了4個模塊:
main.py、Learning.py、LearningDB.py、LearningUI.py
其中LearningDB實現(xiàn)python與數(shù)據(jù)庫的交互,LearningUI實現(xiàn)界面的交互,Learning繼承LearningUI類添加上了與LearningDB數(shù)據(jù)庫類的交互,最后通過main主函數(shù)模塊運行程序。
其中涉及數(shù)據(jù)庫的知識可參考之前的文章:Python3操作SQL Server數(shù)據(jù)庫,涉及PyQt的知識可參考:Python3使用PyQt5制作簡單的畫板/手寫板

手寫體識別的主要思路是將手寫的字,用一個列表記錄其所經(jīng)過的點,劃分為一個九宮格,然后數(shù)每個格子中點的數(shù)目,將數(shù)目轉(zhuǎn)化為所占總點數(shù)的百分比。然后兩兩保存的九維數(shù),求他們之間的距離,距離越近代表越接近。

2.通過pymssql與數(shù)據(jù)庫的交互

因為使用程序之前先需要建表,建表我就直接使用SQL語句執(zhí)行了:

create database PyLearningDBdrop table table0 create table table0 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table1 create table table1 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table2 create table table2 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table3 create table table3 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table4 create table table4 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table5 create table table5 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table6 create table table6 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table7 create table table7 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table8 create table table8 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)drop table table9 create table table9 (dim0 int not null, dim1 int not null, dim2 int not null, dim3 int not null, dim4 int not null, dim5 int not null, dim6 int not null, dim7 int not null, dim8 int not null)

LearningDB.py程序如下:

'''LearningDB類功能:定義數(shù)據(jù)庫類,包含一個學(xué)習(xí)函數(shù)learn_data和一個識別函數(shù)identify_data作者:PyLearn博客: http://www.cnblogs.com/PyLearn/最后修改日期: 2017/10/18 ''' import math import pymssqlclass LearningDB():def __init__(self):self.conn = pymssql.connect(host='127.0.0.1',user='sa',password='123',database='PyLearningDB',charset='utf8')self.cursor = self.conn.cursor()self.sql = ''self.distance = 0.0self.conn.close()def learn_data(self, table, dim):'''學(xué)習(xí)數(shù)據(jù),將數(shù)據(jù)存到對應(yīng)的數(shù)據(jù)庫table指定哪個表,dim是維度數(shù)組'''learn_result = Falsetry:if table < 0 or table > 9:raise Exception("錯誤!table的值為%d!" % table)for num in dim:if num < 0:raise Exception("錯誤!dim的值不能小于0!")self.conn = pymssql.connect(host='127.0.0.1',user='sa',password='123',database='PyLearningDB',charset='utf8')self.cursor = self.conn.cursor()self.sql = 'insert into table%d values(%d, %d, %d, %d, %d, %d, %d, %d, %d)' %(table, dim[0], dim[1], dim[2], dim[3], dim[4], dim[5], dim[6], dim[7], dim[8])self.cursor.execute(self.sql)self.conn.commit()learn_result = Trueexcept Exception as ex_learn:self.conn.rollback()raise ex_learnfinally:self.conn.close()return learn_resultdef identify_data(self, test_data):'''識別數(shù)據(jù),將數(shù)據(jù)一一對比,返回最接近的近似值'''try:table_data = []for i in range(10):table_data.append(self.__get_data(i, test_data))#返回table_data中最小值的索引return table_data.index(min(table_data))except Exception as ex_identify:raise ex_identifydef __get_data(self, table, test_data):'''取出table表中所有數(shù)據(jù)并與測試數(shù)據(jù)進行比較,返回最小值如果table表中無數(shù)據(jù),則全部取0'''try:if table < 0 or table > 9:raise Exception("錯誤!table的值不能為%d!" % table)self.conn = pymssql.connect(host='127.0.0.1',user='sa',password='123',database='PyLearningDB',charset='utf8')self.cursor = self.conn.cursor()self.sql = 'select * from table%d' % tableself.cursor.execute(self.sql)receive_sql = self.cursor.fetchall()if not receive_sql:new_receive_sql = [(0, 0, 0, 0, 0, 0, 0, 0, 0)]else:new_receive_sql = receive_sqlfinally:self.conn.close()#計算最小值dim_data = []for receive_data in new_receive_sql:dim_data.append(self.__distance_data(test_data, receive_data))#返回dimData中最小值return min(dim_data)def __distance_data(self, test_data, table_data):'''求九維空間中兩點之間的距離'''self.distance = 0.0for i in range(9):self.distance += (test_data[i] - table_data[i]) ** 2return math.sqrt(self.distance)

3.通過pyqt與界面的交互

LearningUI.py程序如下:

'''LearningUI類功能:生成UI界面,以及定義事件處理方法作者:PyLearn博客: http://www.cnblogs.com/PyLearn/最后修改日期: 2017/10/18 ''' from PyQt5.QtWidgets import (QWidget, QPushButton, QLabel, QComboBox, QDesktopWidget) from PyQt5.QtGui import (QPainter, QPen, QFont) from PyQt5.QtCore import Qtclass LearningUI(QWidget):def __init__(self):super(LearningUI, self).__init__()self.__init_ui()#設(shè)置只有鼠標按下時才跟蹤移動,否則不按的時候也在畫畫self.setMouseTracking(False)#self.pos_xy保存所有繪畫的點self.pos_xy = []#設(shè)置pos_x、pos_y方便計算self.pos_x = []self.pos_y = []#設(shè)置關(guān)聯(lián)事件self.btn_learn.clicked.connect(self.btn_learn_on_clicked)self.btn_recognize.clicked.connect(self.btn_recognize_on_clicked)self.btn_clear.clicked.connect(self.btn_clear_on_clicked)def __init_ui(self):'''定義UI界面:三個按鈕:學(xué)習(xí)、識別、清屏btn_learn、btn_recognize、btn_clear一個組合框:選擇0-9combo_table兩條標簽:請在屏幕空白處用鼠標輸入0-9中的某一個數(shù)字進行識別!2017/10/10 by PyLearn一條輸出識別結(jié)果的標簽label_output'''#添加三個按鈕,分別是學(xué)習(xí)、識別、清屏self.btn_learn = QPushButton("學(xué)習(xí)", self)self.btn_learn.setGeometry(50, 400, 70, 40)self.btn_recognize = QPushButton("識別", self)self.btn_recognize.setGeometry(320, 400, 70, 40)self.btn_clear = QPushButton("清屏", self)self.btn_clear.setGeometry(420, 400, 70, 40)#添加一個組合框,選擇0-9self.combo_table = QComboBox(self)for i in range(10):self.combo_table.addItem("%d" % i)self.combo_table.setGeometry(150, 400, 70, 40)#添加兩條標簽self.label_head = QLabel('請在屏幕空白處用鼠標輸入0-9中的某一個數(shù)字進行識別!', self)self.label_head.move(75, 50)self.label_end = QLabel('2017/10/10 by PyLearn', self)self.label_end.move(375, 470)#添加一條輸出識別結(jié)果的標簽'''setStyleSheet設(shè)置邊框大小、顏色setFont設(shè)置字體大小、形狀、加粗setAlignment設(shè)置文本居中'''self.label_output = QLabel('', self)self.label_output.setGeometry(50, 100, 150, 250)self.label_output.setStyleSheet("QLabel{border:1px solid black;}")self.label_output.setFont(QFont("Roman times", 100, QFont.Bold))self.label_output.setAlignment(Qt.AlignCenter)'''setFixedSize()固定了窗體的寬度與高度self.center()將窗體居中顯示setWindowTitle()設(shè)置窗體的標題'''self.setFixedSize(550, 500)self.center()self.setWindowTitle('0-9手寫體識別(機器學(xué)習(xí)中的"HelloWorld!")')def center(self):'''窗口居中顯示'''qt_center = self.frameGeometry()desktop_center = QDesktopWidget().availableGeometry().center()qt_center.moveCenter(desktop_center)self.move(qt_center.topLeft())def paintEvent(self, event):'''首先判斷pos_xy列表中是不是至少有兩個點了然后將pos_xy中第一個點賦值給point_start利用中間變量pos_tmp遍歷整個pos_xy列表point_end = pos_tmp判斷point_end是否是斷點,如果是point_start賦值為斷點continue判斷point_start是否是斷點,如果是point_start賦值為point_endcontinue畫point_start到point_end之間的線point_start = point_end這樣,不斷地將相鄰兩個點之間畫線,就能留下鼠標移動軌跡了'''painter = QPainter()painter.begin(self)pen = QPen(Qt.black, 2, Qt.SolidLine)painter.setPen(pen)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 = point_endcontinueif 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()def mouseReleaseEvent(self, event):'''重寫鼠標按住后松開的事件在每次松開后向pos_xy列表中添加一個斷點(-1, -1)然后在繪畫時判斷一下是不是斷點就行了是斷點的話就跳過去,不與之前的連續(xù)'''pos_test = (-1, -1)self.pos_xy.append(pos_test)self.update()def mouseMoveEvent(self, event):'''按住鼠標移動:將移動的點加入self.pos_xy列表'''#self.pos_x和self.pos_y總是比self.pos_xy少一到兩個點,還不知道原因在哪self.pos_x.append(event.pos().x())self.pos_y.append(event.pos().y())#中間變量pos_tmp提取當前點pos_tmp = (event.pos().x(), event.pos().y())#pos_tmp添加到self.pos_xy中self.pos_xy.append(pos_tmp)self.update()def btn_learn_on_clicked(self):'''需要用到數(shù)據(jù)庫,因此在在子類中實現(xiàn)'''passdef btn_recognize_on_clicked(self):'''需要用到數(shù)據(jù)庫,因此在在子類中實現(xiàn)'''passdef btn_clear_on_clicked(self):'''按下清屏按鈕:將列表賦值為空將輸出識別結(jié)果的標簽賦值為空然后刷新界面,重新繪畫即可清屏'''self.pos_xy = []self.pos_x = []self.pos_y = []self.label_output.setText('')self.update()def get_pos_xy(self):'''將手寫體在平面上分為9個格子計算每個格子里點的數(shù)量然后點的數(shù)量轉(zhuǎn)化為占總點數(shù)的百分比接著返回一個數(shù)組dim[9]橫軸依次是min_x、min2_x、max2_x、max_x縱軸依次是min_y、min2_y、max2_y、max_y'''if not self.pos_xy:return Nonepos_count = len(self.pos_x)max_x = max(self.pos_x)max_y = max(self.pos_y)min_x = min(self.pos_x)min_y = min(self.pos_y)dim = [0, 0, 0, 0, 0, 0, 0, 0, 0]dis_x = (max_x - min_x) // 3dis_y = (max_y - min_y) // 3min2_x = min_x + dis_xmin2_y = min_y + dis_ymax2_x = max_x - dis_xmax2_y = max_y - dis_yfor i in range(len(self.pos_x)):if self.pos_y[i] >= min_y and self.pos_y[i] < min2_y:if self.pos_x[i] >= min_x and self.pos_x[i] < min2_x:dim[0] += 1continueif self.pos_x[i] >= min2_x and self.pos_x[i] < max2_x:dim[1] += 1continueif self.pos_x[i] >= max2_x and self.pos_x[i] <= max_x:dim[2] += 1continueelif self.pos_y[i] >= min2_y and self.pos_y[i] < max2_y:if self.pos_x[i] >= min_x and self.pos_x[i] < min2_x:dim[3] += 1continueif self.pos_x[i] >= min2_x and self.pos_x[i] < max2_x:dim[4] += 1continueif self.pos_x[i] >= max2_x and self.pos_x[i] <= max_x:dim[5] += 1continueelif self.pos_y[i] >= max2_y and self.pos_y[i] <= max_y:if self.pos_x[i] >= min_x and self.pos_x[i] < min2_x:dim[6] += 1continueif self.pos_x[i] >= min2_x and self.pos_x[i] < max2_x:dim[7] += 1continueif self.pos_x[i] >= max2_x and self.pos_x[i] <= max_x:dim[8] += 1continueelse:pos_count -= 1continue#將數(shù)量轉(zhuǎn)化為所占百分比for num in dim:num = num * 100 // pos_countreturn dim

4.UI與數(shù)據(jù)庫的交互

Learning.py程序如下:

'''Learning類功能:重寫LearningUI類中的兩個用到了數(shù)據(jù)庫的方法:類中添加一個LearningDB類對象的數(shù)據(jù)成員self.learn_db作者:PyLearn博客: http://www.cnblogs.com/PyLearn/最后修改日期: 2017/10/18 ''' from PyQt5.QtWidgets import QMessageBox from LearningUI import LearningUI from LearningDB import LearningDBclass Learning(LearningUI):'''Learning實現(xiàn)btn_learn_on_clicked和btn_recognize_on_clicked兩個方法'''def __init__(self):super(Learning, self).__init__()#學(xué)習(xí)函數(shù)learn_data(table, dim)和一個識別函數(shù)identify_data(test_data)self.learn_db = LearningDB()def btn_learn_on_clicked(self):if not self.pos_xy:QMessageBox.critical(self, "注意", "請先寫入您要學(xué)習(xí)的數(shù)字!")return None#獲取要學(xué)習(xí)的數(shù)字learn_numlearn_num = self.combo_table.currentIndex()#彈出確認對話框qbox = QMessageBox()qbox.setIcon(QMessageBox.Information)qbox.setWindowTitle("請確認")qbox.setText("學(xué)習(xí)數(shù)字 %d ?" % learn_num)qbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)qbox.setDefaultButton(QMessageBox.No)qbox.button(QMessageBox.Yes).setText("是")qbox.button(QMessageBox.No).setText("否")reply = qbox.exec()#判斷對話框結(jié)果,執(zhí)行程序if reply == QMessageBox.Yes:learn_result = Falselearn_dim = self.get_pos_xy()if learn_dim:learn_result = self.learn_db.learn_data(learn_num, learn_dim)else:print('get_pos_xy()函數(shù)返回空值')return Noneif learn_result:QMessageBox.about(self, "提示", "學(xué)習(xí)成功!")else:QMessageBox.about(self, "提示", "學(xué)習(xí)失敗!")else:return Nonedef btn_recognize_on_clicked(self):#如果沒有進行繪畫,警告后退出if not self.pos_xy:QMessageBox.critical(self, "注意", "請先寫入您要識別的數(shù)字!")return Noneelse:recognize_num = 0recognize_dim = self.get_pos_xy()if recognize_dim:recognize_num = self.learn_db.identify_data(recognize_dim)else:print('recognize_dim為空')return Noneself.label_output.setText('%d' % recognize_num)

5.最后的main主函數(shù)

'''主函數(shù)main功能:生成Learning對象,進入主循環(huán)作者:PyLearn博客: http://www.cnblogs.com/PyLearn/最后修改日期: 2017/10/18 ''' import sys from PyQt5.QtWidgets import QApplication from Learning import Learningif __name__ == '__main__':app = QApplication(sys.argv)py_learning = Learning()py_learning.show()sys.exit(app.exec_())

將以上4個程序放在同一個目錄下,直接執(zhí)行main.py就行了。
運行界面如下:

學(xué)習(xí)數(shù)字4:

第一次運行需要全部學(xué)習(xí)至少一次才能有一點正確率。
識別3:

轉(zhuǎn)載于:https://www.cnblogs.com/PyLearn/p/7701476.html

總結(jié)

以上是生活随笔為你收集整理的Python3实现简单可学习的手写体识别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。