手写数字识别小demo-按列计算均值提特征

文章讲述了使用均值向量方法进行数字识别的局限性,如特征不足、难以区分相似数字等,并提出通过图像预处理(如字体粗细标准化和边界框裁剪)来提取更丰富的特征,以提高识别准确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import os
import cv2
import numpy as np

train_path = './minist_train'
file_train = os.listdir(train_path)

mean_vectors = np.zeros((10, 50))  # 用于存储每个数字的均值向量

for file_name in file_train:
    file_path = os.path.join(train_path, file_name)
    data = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE) / 255.0  # 归一化

    digit = int(file_name[0])  # 获取图片所代表的数字

    # 计算每列的均值,并将结果累加到均值向量中
    column_means = np.mean(data, axis=0)
    mean_vectors[digit] += column_means

# 完成均值向量的计算,除以5以获取均值
mean_vectors /= 5

# for digit, mean_vector in enumerate(mean_vectors):
#     print(f"Digit {digit}: {mean_vector}")

new_image_path = 'minist_val/9-7.JPG'
new_image = cv2.imread(new_image_path, cv2.IMREAD_GRAYSCALE) / 255.0
new_mean_vector = np.mean(new_image, axis=0)

# 计算新图片的均值向量与每个数字均值向量的距离
distances = np.linalg.norm(mean_vectors - new_mean_vector, axis=1)

# 预测最接近的数字
predicted_digit = np.argmin(distances)

print(f"模型预测数字为: {predicted_digit}")

使用均值向量方法进行数字预测的错误率较高的原因可能有以下几个:

  1. 特征不足: 均值向量方法仅使用了每张图片的列均值作为特征,这可能会丢失很多有用的信息。数字识别通常需要更多的特征来更准确地区分不同的数字。

  2. 差异不明显: 不同的数字在均值向量上可能有相似之处,导致难以区分。特别是当数字之间有相似的形状或结构时,均值向量方法可能无法很好地区分它们。

  3. 样本不足: 如果每个数字仅有5个样本,这可能不足以捕获数字的多样性和变化。更多的样本通常会有助于提高模型的性能。

  4. 模型选择: 均值向量方法是一种非常简单的方法,可能不适用于复杂的数字识别任务。深度学习模型等更复杂的模型通常可以在数字识别任务中表现得更好。

下面是改进后的代码,对数字特征大小进行归一化以及按照数字位置裁剪大小相同的候选框

import os
import cv2
import numpy as np

train_path = './minist_train'
file_train = os.listdir(train_path)

# 初始化均值向量
mean_vectors = np.zeros((10, 50))

for file_name in file_train:
    file_path = os.path.join(train_path, file_name)
    data = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE) / 255
    data = (data * 255).astype(np.uint8)
    digit = int(file_name[0])  # 获取图片所代表的数字

    # 字体粗细标准化(示例使用形态学操作来增加粗细)
    kernel = np.ones((3, 3), np.uint8)
    data = cv2.dilate(data, kernel, iterations=1)

    # 使用边缘检测或轮廓检测来找到数字的边界框
    _, thresholded = cv2.threshold(data, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    if len(contours) > 0:
        # 找到数字区域的边界框
        x, y, w, h = cv2.boundingRect(contours[0])

        # 裁剪数字区域并调整大小为50x50像素
        digit_region = data[y:y+h, x:x+w]
        digit_resized = cv2.resize(digit_region, (50, 50))

        # 计算数字区域的均值并将结果累加到均值向量中
        column_means = np.mean(digit_resized, axis=0)
        mean_vectors[digit] += column_means

# 完成均值向量的计算,除以样本数以获取均值
# 这里假设每个数字的样本数均相等,如果不是,需要除以实际的样本数
mean_vectors /= 5

# 预测图片的路径
new_image_path = 'minist_val/9-8.JPG'
new_image = cv2.imread(new_image_path, cv2.IMREAD_GRAYSCALE) / 255
new_image = (new_image * 255).astype(np.uint8)

# 字体粗细标准化(示例使用形态学操作来增加粗细)
kernel = np.ones((3, 3), np.uint8)
new_image = cv2.dilate(new_image, kernel, iterations=1)

# 使用边缘检测或轮廓检测来找到数字的边界框
_, thresholded = cv2.threshold(new_image, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

if len(contours) > 0:
    # 找到数字区域的边界框
    x, y, w, h = cv2.boundingRect(contours[0])

    # 裁剪数字区域并调整大小为50x50像素
    digit_region = new_image[y:y+h, x:x+w]
    digit_resized = cv2.resize(digit_region, (50, 50))

    # 计算新图片的均值向量
    new_mean_vector = np.mean(digit_resized, axis=0)

    # 计算新图片的均值向量与每个数字均值向量的距离
    dis = np.linalg.norm(mean_vectors - new_mean_vector, axis=1)

    predicted_digit = np.argmin(dis)  # 预测特征向量距离最小的

    print(f"模型预测数字为: {predicted_digit}")

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值