采用 K 近邻执行手写数字识别任务

以下 Python 代码是“人工智能与计算科学”课程的配套示例。程序将手写数字图像转换为文本向量,并采用 K 近邻(KNN)模型识别数字。数据集为 data.zip(点击下载)。

# Convert an image to a text file
import os
from PIL import Image

def imgtotext(imgfile,txtfile,size=(32,32)):
    # Resize the image to 32x32 and convert it to text
    image_file = Image.open(imgfile)
    image_file = image_file.resize(size,Image.LANCZOS)
    image_file=image_file.convert('L')
    width,height = image_file.size
    f =open(txtfile,'w')
    ascii_char = '10'
    for i in range(height):
        pix_char='';
        for j in range(width):
            pixel = image_file.getpixel((j,i))
            pix_char+=ascii_char[int(pixel/128)]
        pix_char+='\n'
        f.write(pix_char)
    f.close()

imgtotext(r'test.jpg', r'test.txt')

from os import listdir
from numpy import *
import numpy as np
import operator

def KNN(test_data,train_data,train_label,k):
    # Number of training samples
    dataSetSize = train_data.shape[0]
    # Tile the input vector and compute the distances
    all_distances = np.sqrt(np.sum(np.square(tile(test_data,(dataSetSize,1))-train_data),axis=1))
    print("All distances:", all_distances)
    # Sort by distance
    sort_distance_index = all_distances.argsort()
    # Select the k nearest samples
    classCount = {}
    for i in range(k):
        voteIlabel = train_label[sort_distance_index[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0)+1
    sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)
    return sortedClassCount[0][0]

# Convert 32x32 text to a 1x1024 vector
def img2vector(filename):
    returnVect = []
    fr = open(filename)
    for i in range(32):
        lineStr = fr.readline()
        for j in range(32):
            returnVect.append(int(lineStr[j]))
    return returnVect

# Read the class label from the filename
def classnumCut(fileName):
    # Example filename: 0_3.txt
    fileStr = fileName.split('.')[0]
    classNumStr = int(fileStr.split('_')[0])
    return classNumStr

# Load the training set
def trainingDataSet():
    train_label = []
    trainingFileList = listdir('data/trainingDigits')
    m = len(trainingFileList)
    train_data = zeros((m,1024))
    # Read the label
    for i in range(m):
        fileNameStr = trainingFileList[i]
        train_label.append(classnumCut(fileNameStr))
        train_data[i,:] = img2vector('data/trainingDigits/%s' % fileNameStr)
    return train_label,train_data

# Set the number of neighbors and run the test
Nearest_Neighbor_number = 3
train_label,train_data = trainingDataSet()
test_data = img2vector('test.txt')
# Predict
classifierResult = KNN(test_data, train_data, train_label, Nearest_Neighbor_number)
print("Recognition result:", classifierResult)

下图为待识别的手写数字:

KNN 的识别结果为:

识别结果为:6