Python knn 对手写数字分类

一不小心入了图像处理的大坑,我要一步一步向上爬~

因为本文是直接调用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()

代码里还有决策树和贝叶斯分类方法(写的太乱,可是不想改)
这里写图片描述
其实最后效果不太好,找了个预测对的就贴上来了,哈哈

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值