好久之前写的,一直没有发,现在整理一下发布了。
这是和我的第一篇MNIST数字手写识别的进阶,其实数字手写密码锁是17年五六月份左右的我们小组应该做的小组任务,但是带我们任务的学长比较忙,也由于其他原因,我们小组内没有人真正完成手写数字密码锁,只是实现了用kNN进行手写数字识别,关键是用kNN还没办法保存参数……后来断断续续开始学习深度学习,走了不少弯路,后来看了一部分吴恩达的视频,至今也就才算是摸到门槛。下面是我用单层的神经网络进行手写数字分类的代码,最近一周写的,快要考试了,越到考试我越浪……
本人是学自动化的,程序主要是面向过程,编写代码的质量也不高,请见谅!大神请另寻他路……
我的程序分为三个文件来写,一个文件是用openCV进行鼠标写数字,只做了一个很小的数据集,600张训练图片,30张测试图片。以下是用openCV进行鼠标写数字的代码,很简单,需要对openCV有一定了解,在此不进行详解。
import numpy as np
import cv2
drawing=False
def drawCircle(event,x,y,flags,param):
global drawing
if event==cv2.EVENT_LBUTTONDOWN:
drawing=True
if event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
cv2.circle(img,(x,y),10,(0,0,0),-1)
elif event==cv2.EVENT_LBUTTONUP:
drawing=False
img=np.zeros((280,280,3),np.uint8)+255
cv2.namedWindow('Image')
cv2.setMouseCallback('Image',drawCircle)
n=int(input("Input n:"))#因为写图片的时候可能要写好几次,在这里我用n记录应该从第几个图片开始储存,需要手动输入
print("c->clear s->save q->quit")
while(True): # 在写数字的时候,我的第一个图片名编号设为了1,从数字0开始写,最好把第一个图片名编号设为0
cv2.imshow('Image',img)
# k=cv2.waitKey(1)&0xFF
key=cv2.waitKey(1)&0xFF
if key==ord('s'):
print("Saving...")
cv2.imwrite(r"E:\WORK\Python3.6Files\openCV_about\pictures2\img"+str(n)+".png",img)
print("img"+str(n)+" OK!")
img=np.zeros((280,280,3),np.uint8)+255
n+=1
elif key==ord('q'):
break
elif key==ord('c'):
img = np.zeros((280, 280, 3), np.uint8) + 255
else:
pass
我用这个程序写了630张图片,600张用来训练,太少了,其实可以找人一起写呀~~~
下边是用Softmax激活函数进行分类的一个最简单的神经网络,目的其实就是得到参数。
import numpy as np
import cv2,re
from os import listdir
def savePicturesAndLabels(path):
name_list=listdir(path)#这里我掉进了一个大坑,我以为读进去图片是按照顺序img1,img2,img3...来的,但是,不是……
i=0 #导致我一开始训练出来的测试正确率是百分之十左右,跟瞎蒙差不多......
n=len(name_list)
LAB=np.zeros([10,n],dtype=np.uint8)
IMG=np.zeros([1225,n],dtype=np.uint8)
labs=[]
i=0
for name in name_list:
img_i=int(name[3:-4])#取文件名中的数字标签
LAB[(img_i-1)%10,i]=1 #第i列(即第i个图片)的j(=(img_i-1)%10)行(j就是对应的数字标签)设置为1
labs.append((img_i-1)%10)
img=cv2.imread(path+"\\"+name,0)
img2=cv2.pyrDown(cv2.pyrDown(cv2.pyrDown(img)))#由于我的图片原大小是280*280,所以我用了3次图像金字塔,把图
img2[img2<127]=1 #片大小缩小为35*35
img2[img2>=127]=0 # one-hot处理
img2.resize([1225,1])
IMG[:,i]=img2[:,0]
i+=1
np.save("testIMG.npy",IMG) #储存把图片处理后的矩阵,在分别储存训练集和测试集的矩阵的时候,直接执行两次本
np.save("testLAB.npy",LAB) #自定义函数,改一改文件名就可以啦,我是不是很懒…………
np.save("testLabels.npy",np.array(labs)) #储存测试用的的标签[1,n] n=600
if __name__=="__main__":
X = np.load("trainIMG.npy")
Y = np.load("trainLAB.npy")
k = 10 # 分类数 0~9
v = 1225 # 维度 35*35
n = X.shape[1] # 样本数 600
np.random.seed(13)#生成随机数种子
w = np.random.random([k, v]) # w[10,1225]
b = np.random.random([k, 1]) # b[10,1]
r = 0.1
#以下注释部分是训练的过程,训练的时候把注释去掉。
# for t in range(3000):
# z = (np.dot(w, X) + b)n # z[10,600]=w[10,1225] x X[1225,600]
# sum_a = ((np.exp(z)).sum(axis=0)).reshape([1, n]) # sum_a[1,600]
# a = np.exp(z) / sum_a # a[10,600]=z[10,600]/sum_a[1,600]
# # print(a[:,0])#这一句话是用来观察训练效果的
# w =w+ r * np.dot(Y - a, X.T) / n # 根据反向传播计算出 w 和 b 的参数更新公式,用道一点点简单的高数知识
# b =b+ r * ((np.dot(Y - a, np.ones([n, 1]))).reshape(k, 1)) / n #
# np.save("IMG_w.npy",w) # 训练完之后保存参数
# np.save("IMG_b.npy",b)
# tX=np.load("trainIMG.npy") # 这里后来注释掉了,因为一开始我需要测试训练集的训练效果
# tY=np.load("trainLabels.npy")
tX=np.load("testIMG.npy")#加载训练图片
tY=np.load("testLabels.npy")#加载训练标签
tn=tX.shape[1]
W=np.load("IMG_W.npy")
B=np.load("IMG_B.npy")
Z = (np.dot(W, tX) + B)
sum_A = ((np.exp(Z)).sum(axis=0)).reshape([1, tn])
A = np.exp(Z) / sum_A
predict = []
for i in range(tn):
#print((np.where(A[:, i] == np.amax(A[:, i])))[0][0])
predict.append((np.where(A[:, i] == np.amax(A[:, i])))[0][0])#找到每一列中最大值所在的位置,这样就能得到每
# print(predict) #一个图片的测试结果了,仔细体会......
errors = tY - np.array(predict) #这一步和下边的一步就是得到与正确标签不相等的错误结果标签
errors[errors != 0] = 1 #这样就可以统计错误个数了
print(np.where(errors[:]==1))
errors_num = errors.sum()
print("总测试数:", tn)
print("错误个数:", errors_num)
print("正确率:{}%".format(100 - 100 * errors_num / tn))
下边是主程序
# 其中一些图标或者矩阵数据文件我没有上传,可以根据自己写的数据制作
import numpy as np
import cv2
import easygui,re
from urllib import request
import urllib
drawing=False
import speech
def drawCircle(event,x,y,flags,param):
global drawing
if event==cv2.EVENT_LBUTTONDOWN:
drawing=True
if event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_FLAG_LBUTTON:
if drawing == True:
cv2.circle(img,(x,y),10,(0,0,0),-1)
elif event==cv2.EVENT_LBUTTONUP:
drawing=False
def checkPassword(password):
if password==[1,2,3,4]:
return True
else:
return False
def webSpider():
url='http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=tupian'#这里没有写网址链接
headers={
'User-Agent': 'Chrome/63.0.3239.84',
'Connection': 'keep-alive'
}
req=request.Request(url=url,headers=headers)
resp=request.urlopen(req)
text=(resp.read()).decode('utf-8')
cmpl=re.compile("http://\S+.jpg")
jpg_urls=re.findall(cmpl,text)
# keys_dic={}
speech.say("即将浏览网站图片,请确保已经连接网络。")
speech.say("按下 ESC 键退出程序,按下其他任意键浏览下一张图片!")
speech.say("浏览过程中因网络问题可能会有卡顿,请等待程序响应!")
for jpg_url in jpg_urls:
try:
request.urlretrieve(jpg_url,"E:\\Temp.jpg")
current_jpg = cv2.imread("E:\\Temp.jpg")
cv2.namedWindow("Temp.jpg",flags=cv2.WINDOW_AUTOSIZE) # WINDOW_NORMAL
cv2.imshow("Temp.jpg", cv2.pyrDown(current_jpg))
# print("+++++++++++++++"+jpg_url)
w_key=cv2.waitKey(0)
if w_key==27:
break
# except urllib.error.HTTPError:
except :
# print("---------------"+jpg_url)
pass
cv2.destroyAllWindows()
## speech.say("浏览结束!")
def customizedFunction():
# print("Log in!")
webSpider()
if __name__=="__main__":
# customizedFunction()
# easygui.buttonbox(
# msg="Press:\nq-->Quit the programme.\ns-->Save the number.\nc-->Clear the image without saving.\nr-->Retype the password.",
# title='', choices=["OK!"])
speech.say("按下“S”键确认当前输入的数字,按下 C 键清除当前画布,按下 R 键重新输入整个密码,按下 Q 键退出程序。")
img = np.zeros((280, 280, 3), np.uint8) + 255
cv2.namedWindow('Please input the password')
cv2.setMouseCallback('Please input the password', drawCircle)
W = np.load("IMG_W.npy")
B = np.load("IMG_B.npy")
# print("Press:\nq->quit the programme\ns->save and predict\nc->clear the image without saving ")
password=[]
while(True):
cv2.imshow("Please input the password",img)
key=cv2.waitKey(1)&0xFF
if key==ord('s'):
tX = cv2.pyrDown(cv2.pyrDown(cv2.pyrDown(cv2.cvtColor(img,cv2.COLOR_BGR2GRAY))))
tX[tX < 127] = 1
tX[tX >= 127] = 0
tX.resize([1225, 1])
Z = (np.dot(W, tX) + B)
sum_A = (np.exp(Z)).sum(axis=0)
A = np.exp(Z) / sum_A
predict = (np.where(A == np.amax(A)))[0][0]
# print(predict)
speech.say(str(predict))
password.append(predict)
if len(password)==4:
if checkPassword(password):
cv2.destroyWindow("Please input the password")
# easygui.buttonbox(msg="\n\n\t\t\t\t 密码正确!", title="提示", choices=[], image="right.gif")
speech.say("密码正确!")
break
else:
speech.say("密码错误!")
response=easygui.buttonbox(msg="",title='',choices=["重新输入","退出"],)
if response=="重新输入":
password=[]
elif response=="退出" or None:
cv2.destroyWindow("Please input the password")
exit()
img = np.zeros((280, 280, 3), np.uint8) + 255
elif key==ord('q'):
cv2.destroyWindow("Please input the password")
exit()
elif key==ord('c'):
img = np.zeros((280, 280, 3), np.uint8) + 255
elif key==ord('r'):
speech.say("重新输入密码。")
# easygui.buttonbox(msg="",title='提示',choices='',image='ok.gif')
img = np.zeros((280, 280, 3), np.uint8) + 255
password=[]
else:
pass
if checkPassword(password):
customizedFunction()
else:
exit()
speech.say("感谢使用!")
程序就是这样,小试牛刀,没什么技术含量的东西,大神勿喷。
对于神经网络一点也不懂的同学,建议去看一看吴恩达老师在网易云课堂的视频。