代码和报告均为本人自己实现(实验满分),只展示任务实验结果,如果需要报告或者代码可以私聊博主

有任何疑问或者问题,也欢迎私信博主,大家可以相互讨论交流哟~~求点赞+关注

后续持续更新机器学习专栏

一、案例简介

java车牌识别离线sdk java车牌号识别算法_人工智能

图像的智能处理一直是人工智能领域广受关注的一类技术,代表性的如人脸识别与 CT 肿瘤识别,在人工智能落地的进程中发挥着重要作用。其中车牌号识别作为一个早期应用场景,已经融入日常生活中,为我们提供了诸多便利,在各地的停车场和出入口都能看到它的身影。车牌号识别往往分为字符划分和字符识别两个子任务,本案例我们将关注字符识别的任务,尝试用 K-NN 的方法对分割好的字符图像进行自动识别和转化。

二、作业说明

基本要求

  • 完成数据的读入和表示,将图片表示成向量并和 label 对应上;
  • 构建 K-NN 模型(可调库)对测试集中的图片进行预测并计算准确率;
  • 分析当 K 取不同值时测试准确率的变化。

扩展要求

  • 分析不同距离度量方式对模型效果的影响;
  • 对比平权和加权 K-NN 的效果;
  • 分析训练集大小对测试结果的影响。

实验结果

 三、数据概览

本次我们使用已经分割好的车牌图片作为数据集,包括数字 0-9、字母 A-Z(不包含 O 和 I)以及省份简称共 65 个类,编号从 0 到 64。数据已经分成了训练集和测试集,里面的文件夹用 label 编号命名,一个文件夹下的所有图片都属于该文件夹对应的类,每个图片都是 20 * 20 的二值化灰度图。

下面演示一下如何借助 PIL 库将图片转化为向量:

java车牌识别离线sdk java车牌号识别算法_人工智能_02

四、模型构建 

读取数据

import os
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt

def load_data(data_path):
    images = []
    labels = []

    for label_dir in os.listdir(data_path):
        if label_dir.startswith('.'):
            continue
        label = int(label_dir)
        label_path = os.path.join(data_path, label_dir)
        for image_file in os.listdir(label_path):
            image_path = os.path.join(label_path, image_file)
            image = Image.open(image_path)
            image_array = np.array(image).flatten()
            images.append(image_array)
            labels.append(label)

    return np.array(images), np.array(labels)

train_images, train_labels = load_data(data_path='./data/train')
test_images, test_labels = load_data(data_path='./data/test')

构建模型并且预测图像计算准确率 

from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import warnings
warnings.filterwarnings("ignore", category=FutureWarning)


# 构建K-近邻分类器
knn = KNeighborsClassifier(n_neighbors=1)

# 训练模型
knn.fit(train_images, train_labels)

# 预测测试集
y_pred = knn.predict(test_images)

# 计算准确率
accuracy = accuracy_score(test_labels, y_pred)
print('Accuracy: {:.2f}%'.format(accuracy * 100))

 Accuracy: 71.68%

通过对k的不同取值发现,当k=1的时候正确率最高,结果最优 

k_values = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for k in k_values:
    knn_model = KNeighborsClassifier(n_neighbors=k)
    knn_model.fit(train_images, train_labels)
    pred_labels = knn_model.predict(test_images)
    accuracy = accuracy_score(test_labels, pred_labels)
    print("K =", k, "时的准确率:", accuracy)

java车牌识别离线sdk java车牌号识别算法_人工智能_03

不同的距离度量方式可以对K-NN模型的效果产生影响。在K-NN算法中,常用的距离度量方式包括欧氏距离(Euclidean distance)、曼哈顿距离(Manhattan distance)、闵可夫斯基距离(Minkowski distance)等,通过运行发现欧式距离和闵可夫斯基距离的结果是一样的。

关于我这里为什么取值k=5,因为我发现k=1的时候,结果差距真的很小,不容易看到影响。

# 定义不同的距离度量方式
distance_metrics = ['euclidean', 'manhattan', 'minkowski']

# 初始化结果列表
accuracy_results = []

# 遍历距离度量方式
for metric in distance_metrics:
    # 创建K-NN模型
    knn = KNeighborsClassifier(n_neighbors=5, metric=metric)
    
    # 使用训练集拟合模型
    knn.fit(train_images, train_labels)
    
    # 使用测试集进行预测
    y_pred = knn.predict(test_images)
    
    # 计算准确率并添加到结果列表
    accuracy = accuracy_score(test_labels, y_pred)
    accuracy_results.append(accuracy)

# 输出不同距离度量方式的准确率结果
for metric, accuracy in zip(distance_metrics, accuracy_results):
    print(f"{metric}: {accuracy}")

对比平权和加权knn的效果发现,加权后效果更好一点。 

# 对比平权和加权K-NN的效果
knn_model_uniform = KNeighborsClassifier(n_neighbors=5, weights='uniform')  # 平权K-NN
knn_model_uniform.fit(train_images, train_labels)
pred_labels_uniform = knn_model_uniform.predict(test_images)
accuracy_uniform = accuracy_score(test_labels, pred_labels_uniform)
print("平权K-NN的准确率:", accuracy_uniform)

knn_model_distance = KNeighborsClassifier(n_neighbors=5, weights='distance')  # 加权K-NN
knn_model_distance.fit(train_images, train_labels)
pred_labels_distance = knn_model_distance.predict(test_images)
accuracy_distance = accuracy_score(test_labels, pred_labels_distance)
print("加权K-NN的准确率:", accuracy_distance)

 平权K-NN的准确率: 0.6928188638799572

加权K-NN的准确率: 0.7016077170418007

 通过不同训练集大小训练模型时,我决定使用欧式距离和加权的方式进行,通过运行发现并不是训练集越大越好,反而是训练集为原来训练集0.6的情况下最优,再增加正确率就会递减。

# 训练集大小比例
train_sizes = [i / 10 for i in range(1, 10)]

# 保存每个训练集大小比例下的准确率
accuracy_results = []

for size in train_sizes:
    # 按照指定的比例划分训练集
    X_train, _, y_train, _ = train_test_split(train_images, train_labels, train_size=size,random_state=42)
    
    # 创建K-NN模型
    knn = KNeighborsClassifier(n_neighbors=1,weights='distance', metric='euclidean')
    
    # 拟合训练数据
    knn.fit(X_train, y_train)
    
    # 预测测试数据
    predictions = knn.predict(test_images)
    
    # 计算准确率
    accuracy = accuracy_score(test_labels, predictions)
    
    # 将准确率添加到结果列表
    accuracy_results.append(accuracy)

plt.figure(figsize=(8, 6))
plt.plot(train_sizes, accuracy_results,marker='o')
plt.title('Training Set Size vs Accuracy')
plt.xlabel('Training Set Size Ratio')
plt.ylabel('Accuracy')
plt.show()

java车牌识别离线sdk java车牌号识别算法_机器学习_04