一不小心入了图像处理的大坑,我要一步一步向上爬~
因为本文是直接调用sklearn库中已封装好的KNN,所以对KNN算法就不作介绍了
###1、MNIST数据集转化为图片
#####这部分代码直接从http://blog.csdn.net/qq_32166627/article/details/52640730找的
我们只需要训练集
import numpy as np
import struct
from PIL import Image
import os
data_file = 'somePath/train-images.idx3-ubyte' #需要修改的路径
# It's 47040016B, but we should set to 47040000B
data_file_size = 47040016
data_file_size = str(data_file_size - 16) + 'B'
data_buf = open(data_file, 'rb').read()
magic, numImages, numRows, numColumns = struct.unpack_from(
'>IIII', data_buf, 0)
datas = struct.unpack_from(
'>' + data_file_size, data_buf, struct.calcsize('>IIII'))
datas = np.array(datas).astype(np.uint8).reshape(
numImages, 1, numRows, numColumns)
label_file = 'somePath/train-labels.idx1-ubyte' #需要修改的路径
# It's 60008B, but we should set to 60000B
label_file_size = 60008
label_file_size = str(label_file_size - 8) + 'B'
label_buf = open(label_file, 'rb').read()
magic, numLabels = struct.unpack_from('>II', label_buf, 0)
labels = struct.unpack_from(
'>' + label_file_size, label_buf, struct.calcsize('>II'))
labels = np.array(labels).astype(np.int64)
datas_root = '/somePath/mnist_train' #需要修改的路径
if not os.path.exists(datas_root):
os.mkdir(datas_root)
for i in range(10):
file_name = datas_root + os.sep + str(i)
if not os.path.exists(file_name):
os.mkdir(file_name)
for ii in range(numLabels):
img = Image.fromarray(datas[ii, 0, 0:28, 0:28])
label = labels[ii]
file_name = datas_root + os.sep + str(label) + os.sep + \
'mnist_train_' + str(ii) + '.png'
img.save(file_name)
转换后的目录结构
###2、获取KNN训练所需数据
#####为了省事这里直接将图片二值化并转为行向量
def imgtoVect(filename):#filename:图片路径
f = cv2.imread(filename,0)
a,b=f.shape
Vect=np.array(f).reshape(a*b)#将灰度图转为行向量
#二值化操作
for i in range(a*b):
if Vect[i]>127:
Vect[i]=1
else:
Vect[i]=0
return Vect
def createtrainMat(filename):#filename:图片文件夹路径
trainMat=[]
labels=[]
root_list=os.listdir(filename)
for i in root_list:
img_list=os.listdir(filename+'/'+i)
for j in img_list:
labels.append(str(i))#标签和图片上级目录名一致
trainMat.append(imgtoVect(filename+'/'+i+'/'+j))
return trainMat,labels
trainMat和labels大概就是这样
#trainMat
#每一行代表一张图片的所有特征,每一列代表一类特征
[[1,0,1,1,...1,0,0],
[1,1,0,1,...1,1,0],
[1,0,0,0,...0,0,0],
...
[1,0,1,1,...1,0,0]]
#labels
#labels的每一列是trainMat对应行的分类标签
[0,0,0,...1,1,1...,...9,9,9]
因为训练集太大,每次准备训练数据时间太长,所以我们先将trainMap,labels存储下来,第二次执行的时候可以直接load数据,跳过准备阶段
if os.path.exists('C:/Users/53121/Desktop/Mat.npy'):
Mat=np.load('C:/Users/53121/Desktop/Mat.npy')
labels=np.load('C:/Users/53121/Desktop/labels.npy')
else:
Mat,labels=createtrainMap("C:/Users/53121/Desktop/mnist_train")
np.save('C:/Users/53121/Desktop/Mat.npy', Mat)
np.save('C:/Users/53121/Desktop/labels.npy',labels)
###3、获取KNN测试所需数据
利用opencv的鼠标事件写数字
3.1、得到手写数字图片
import cv2
#draw鼠标事件的回掉函数
def draw(event,x,y,flags,param):
global en
if event==cv2.EVENT_LBUTTONDOWN:
en=True
elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_LBUTTONDOWN:
if en:
cv2.circle(img,(x,y),7,255,-1)
elif event==cv2.EVENT_LBUTTONUP:
en=False
img=np.zeros((280,280),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(10)&0xFF==27:
break
cv2.destroyAllWindows()
这样就可以得到280*280的手写体
- 3.2、将图片变为特征矩阵
#首先是尺寸变化,因为mnist图片尺寸为28*28的
input=cv2.resize(img,(28,28),interpolation=cv2.INTER_CUBIC)
#转为行向量+二值化
def imgtoVect2(f):#f:即上面的input
a,b=f.shape
Vect=np.array(f).reshape(a*b)
for i in range(a*b):
if Vect[i]>127:
Vect[i]=1
else:
Vect[i]=0
return Vect
4、引入并训练KNN
- 训练
from sklearn import neighbors
mode = neighbors.KNeighborsClassifier()#创建KNN
Mat,labels=createtrainMap("C:/Users/53121/Desktop/mnist_train")#获取训练数据
data = np.array(Mat)
labels=np.array(labels)
print '训练mode...'
mode.fit(data,labels)
print 'mode训练完成'
- 分类
print '分类结果:',mode.predict([input])
print '可能性:' ,mode.predict_proba([input])
5、完整代码
# -*- coding: utf-8 -*-
"""
Created on Sun Nov 05 13:23:21 2017
@author: 53121
"""
import cv2
import numpy as np
from sklearn import neighbors
import os
from sklearn import tree
from sklearn.naive_bayes import GaussianNB
en=False
def draw(event,x,y,flags,param):
global en
if event==cv2.EVENT_LBUTTONDOWN:
en=True
elif event==cv2.EVENT_MOUSEMOVE and flags==cv2.EVENT_LBUTTONDOWN:
if en:
cv2.circle(img,(x,y),7,255,-1)
elif event==cv2.EVENT_LBUTTONUP:
en=False
def imgtoVect2(f):
a,b=f.shape
Vect=np.array(f).reshape(a*b)
for i in range(a*b):
if Vect[i]>127:
Vect[i]=1
else:
Vect[i]=0
return Vect
def imgtoVect(filename):
f = cv2.imread(filename,0)
Vect=np.array(f).reshape(784)
for i in range(784):
if Vect[i]>127:
Vect[i]=1
else:
Vect[i]=0
return Vect
def createtrainMap(filename):
trainMap=[]
labels=[]
root_list=os.listdir(filename)
for i in root_list:
img_list=os.listdir(filename+'/'+i)
for j in img_list:
labels.append(str(i))
trainMap.append(imgtoVect(filename+'/'+i+'/'+j))
return trainMap,labels
method=raw_input('please input method name: ')
if method=='knn':
mode = neighbors.KNeighborsClassifier()
elif method=='tree':
mode = tree.DecisionTreeClassifier(criterion='gini')
elif method=='bayes':
mode=GaussianNB()
def classifiy(Mat,labels):
data = np.array(Mat)
labels=np.array(labels)
print '训练mode...'
mode.fit(data,labels)
print 'mode训练完成'
img=np.zeros((280,280),np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw)
if os.path.exists('C:/Users/53121/Desktop/Mat.npy'):
Mat=np.load('C:/Users/53121/Desktop/Mat.npy')
labels=np.load('C:/Users/53121/Desktop/labels.npy')
else:
Mat,labels=createtrainMap("C:/Users/53121/Desktop/mnist_train")
np.save('C:/Users/53121/Desktop/Mat.npy', Mat)
np.save('C:/Users/53121/Desktop/labels.npy',labels)
classifiy(Mat,labels)
mode.fit(Mat,labels)
while(1):
cv2.imshow('image',img)
if cv2.waitKey(10)&0xFF==27:
break
elif cv2.waitKey(10)&0xFF==115: #按‘s’进行分类
input=cv2.resize(img,(28,28),interpolation=cv2.INTER_CUBIC)
input=imgtoVect2(input)
print '分类结果:',mode.predict([input])
print '可能性:' ,mode.predict_proba([input])
elif cv2.waitKey(10)&0xFF==99:
img=np.zeros((280,280),np.uint8)
cv2.destroyAllWindows()
代码里还有决策树和贝叶斯分类方法(写的太乱,可是不想改)
其实最后效果不太好,找了个预测对的就贴上来了,哈哈