【超详细】python实现手写识别 基于距离的分类方法

目录

一,问题背景

二,实验过程

1.原理及简要思路:

(1)原理:

(2)简要思路:

2.数据准备:

(1)数据获取

(2)将图像转化为灰度图像

(3)将图片数据和标签分别存储在两个列表中

(4) 编写函数,便于批量处理标准图片及测试图片

3.计算相似度(距离)并判断

编写函数,通过计算欧式距离并判断其最小值,得到数字类型

三,实验结果及分析

1.完整代码及输出结果

2.结果分析

一,问题背景

        在做人智学科基础的期末考察作业,虽然老师说可以网上找代码,但搜了一圈发现啥都看不懂(不是大佬写得不好,而是我们Python还在学基础语法,实在太菜),无法完成论文撰写。

        尝试文心一言,并结合所学,从头到尾(伪)手搓代码,获益匪浅。故写下人生第一篇博文,从32*32像素的图片开始,

        涉及内容:图片处理、Python代码详细注释、相似度计算判断等

        期待路过的好心大佬指点!❤

二,实验过程

1.原理及简要思路:

(1)原理:

灰度图像像素的值与像素点的亮度有关。

在灰度图像中,每个像素点的值只有一个,表示其亮度级别,范围从0到255(0表示黑色,255表示白色)。

灰度值越高,像素点越亮,反之则越暗。

(2)简要思路:

①图片处理:将图像转为灰度图像——对图像进行归一化(灰度值/255,使每个像素点的值都在0和1之间,个人觉得这步可以跳过)——得到32*32的二维数组

②相似度计算思路:从0-9的图片中,分别挑一张图片作为标准,并处理得到其二维数组,设名为A——将测试图片同样处理成二维数组,设名为B——对于每个B,计算其与10个A的距离,距离最小的,即为测试图片所属数字

③距离计算:欧几里得距离,是在n维空间中两个点之间的真实距离。在二维中体现为直角坐标系中两点距离的计算。会通过numpy来直接实现。

2.数据准备:

(1)数据获取

老师给的,包含许多32*32像素的手写图片

链接:https://pan.baidu.com/s/1VBBaGNsbXjzI7BUkY_xiuw?pwd=dspc 
提取码:dspc

我在学写代码的时候,为了方便搞懂,新建了“测试数据”和“训练数据”两个文件夹,每个里面只挑了3张0和1,(1)到(3)的代码会先基于此情况编写

(2)将图像转化为灰度图像

from PIL import Image
import numpy as np
import glob
import os

#遍历图片文件夹,获取图片路径和对应的标签
image_folder = r'E:\桌面\期末\代码\尝试时所用数据\训练数据\零'  # 替换为你的图片文件夹路径
for image_path in glob.glob(os.path.join(image_folder, '*.bmp')):  # 假设图片为bmp格式,如有其他格式请相应修改
    with open(image_path, 'rb') as f:
        # 读取图像文件
        image = Image.open(f)
        # 将彩色图像转换为灰度图像
        gray_image = image.convert('L')

        # 将灰度图像转换为NumPy数组,并重塑为一维数组
        pixel_values = np.array(gray_image).flatten()

        # 将一维数组重塑为32x32的二维数组
        reshaped_image = pixel_values.reshape((32, 32))

(3)将图片数据和标签分别存储在两个列表中

(仅代码片段,帮助理解。融合后有变量名、删除二进制信息等部分改动。完整版见末尾代码)

import os
import glob

image_data = [] # 创建一个空列表来存储图片数据
labels = [] # 创建一个空列表来存储标签

# 遍历图片文件夹,获取图片路径和对应的标签
image_folder = 'E:\桌面\期末\代码\尝试时所用数据\训练数据\零'  # 替换为你的图片文件夹路径
for image_path in glob.glob(os.path.join(image_folder, '*.bmp')):  # 假设图片为bmp格式,如有其他格式请相应修改
    with open(image_path, 'rb') as f:
        image_data.append(f.read())  # 将图片数据读取到列表中
    label = int(list(os.path.basename(image_path))[-5])  # 假设图片名称代表数字,例如0.png、1.png等,根据实际情况修改提取标签的方式
    labels.append(label)  # 将标签添加到列表中

#print(image_data)
#print(labels) 

其中,关于“list(os.path.basename(image_path))[-5]”的解释:

  • os.path.basename() 是一个Python的os模块函数,用于返回指定路径的基本文件名。
  • image_path 是一个包含图片完整路径的字符串。例如:'E:\桌面\期末\代码\尝试时所用数据\训练数据\零\001-0.bmp'
  • 当我们调用 os.path.basename(image_path),它会返回基本文件名,即 ’001-0.bmp'。
  • 转列表后去第-5个元素,得到“0”作为图片标签。
  • 为什么不用split()而是要转列表操作?不知道的话,建议实操一下+文心一言

(4) 编写函数,便于批量处理标准图片及测试图片

def get_32D_and_labels(path):
    data = [] # 创建一个空列表来存储图片数据
    labels = []  # 创建一个空列表来存储图片标签

    # 遍历图片文件夹,获取图片路径和对应的标签
    image_folder = path  #
    for image_path in glob.glob(os.path.join(image_folder, '*.bmp')):  # 假设图片为bmp格式,如有其他格式请相应修改
        with open(image_path, 'rb') as f:
            # 读取图像文件
            image = Image.open(f)
            # 将彩色图像转换为灰度图像
            gray_image = image.convert('L')

            # 将灰度图像转换为NumPy数组,并重塑为一维数组
            pixel_values = np.array(gray_image).flatten()

            # 将一维数组重塑为32x32的二维数组
            reshaped_image = pixel_values.reshape((32, 32))

            reshaped_image = reshaped_image / 255.0  # 归一化到[0, 1]范围

            data.append(reshaped_image)  # 将归一化后的图片数据添加到列表中

            if '标准数据' in path:
                label = int(list(os.path.basename(image_path))[-5])  # 得到数字标签
                labels.append(label)  # 将标签添加到列表中
            else:
                pass
    return labels,data

3.计算相似度(距离)并判断

编写函数,通过计算欧式距离并判断其最小值,得到数字类型

def get_kind(array1):
    dist_data= []
    # 遍历标准数据,计算其与测试数据的欧式距离,并用列表记录
    for array2 in stan_data:
        dist = np.linalg.norm(array1 - array2)
        dist_data.append(dist)
      
    dist_min=min(dist_data) # 得到最小距离的值

    kind_index = dist_data.index(dist_min) #类型在标签列表中的索引==最小距离值在距离列表中的索引
    kind = stan_labels[kind_index]

    return kind

三,实验结果及分析

1.完整代码及输出结果

from PIL import Image
import numpy as np
import glob
import os

def get_32D_and_labels(path):
    data = [] # 创建一个空列表来存储图片数据
    labels = []  # 创建一个空列表来存储图片标签

    # 遍历图片文件夹,获取图片路径和对应的标签
    image_folder = path  #
    for image_path in glob.glob(os.path.join(image_folder, '*.bmp')):  # 假设图片为bmp格式,如有其他格式请相应修改
        with open(image_path, 'rb') as f:
            # 读取图像文件
            image = Image.open(f)
            # 将彩色图像转换为灰度图像
            gray_image = image.convert('L')

            # 将灰度图像转换为NumPy数组,并重塑为一维数组
            pixel_values = np.array(gray_image).flatten()

            # 将一维数组重塑为32x32的二维数组
            reshaped_image = pixel_values.reshape((32, 32))

            reshaped_image = reshaped_image / 255.0  # 归一化到[0, 1]范围

            data.append(reshaped_image)  # 将归一化后的图片数据添加到列表中

            if '标准数据' in path:
                label = int(list(os.path.basename(image_path))[-5])  # 得到数字标签
                labels.append(label)  # 将标签添加到列表中
            else:
                pass
    return labels,data

def get_kind(array1):
    dist_data= []
    # 遍历标准数据,计算其与测试数据的欧式距离,并用列表记录
    for array2 in stan_data:
        dist = np.linalg.norm(array1 - array2)
        dist_data.append(dist)

    dist_min=min(dist_data) # 得到最小距离的值

    kind_index = dist_data.index(dist_min) #类型在标签列表中的索引==最小距离值在距离列表中的索引
    kind = stan_labels[kind_index]

    return kind


stan_labels,stan_data = get_32D_and_labels('E:\桌面\期末\代码\尝试时所用数据\标准数据')
test_labels,test_data = get_32D_and_labels('E:\桌面\期末\代码\尝试时所用数据\测试数据')
#得到标准数字的32维数组列表及对应标签列表、测试数字的32维数组列表及空标签列表,空标签列表将用于记录数字类别

for test_32D in test_data:

    test_kind = get_kind(test_32D)
    test_labels.append(test_kind)
    
print(stan_labels)
print(test_labels) # 根据我的数据库,打印内容应与stan_labels一致

输出结果:

2.结果分析

根据我的数据库,两个列表应该一致。但2、5、8没能成功识别,正确率只有70%

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值