用 Scikit-learn 和 SVM 实现验证码识别系统

在这篇文章中,我们将使用 Scikit-learn 中的 支持向量机(SVM) 来实现一个验证码识别系统。虽然支持向量机(SVM)通常用于二分类问题,但我们可以通过调整其多类分类支持来解决验证码识别问题。本示例通过简单的图像预处理和特征提取,使用 SVM 来识别图像中的字符。

  1. 环境准备
    首先,我们需要安装以下必要的库:

pip install scikit-learn opencv-python numpy matplotlib pillow
scikit-learn:一个广泛使用的机器学习库,用于实现 SVM 和其他分类算法。

opencv-python:用于图像处理。

numpy:用于数值计算。

matplotlib:用于结果可视化。

pillow:用于图像加载和预处理。

  1. 数据集准备与图像预处理
    我们假设数据集中的验证码图像已经准备好了,且每个图像的标签是包含的字符。我们将对图像进行一些预处理操作,包括:将图像转为灰度图、应用二值化、调整图像大小以及将图像展平为一维特征向量。

(1) 图像预处理

import cv2
import numpy as np
import os
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split

def preprocess_image(img_path, img_size=(64, 64)):
# 读取图像
img = cv2.imread(img_path)

# 转换为灰度图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 使用 Otsu 的方法进行二值化
_, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# 调整图像大小
resized_img = cv2.resize(binary, img_size)

# 展平图像为一维数组
flattened_img = resized_img.flatten()

return flattened_img

加载图像数据

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

for filename in os.listdir(image_dir):
    if filename.endswith('.png'):
        img_path = os.path.join(image_dir, filename)
        img = preprocess_image(img_path)

        images.append(img)

        # 提取标签(假设标签为文件名的前几个字符)
        label = filename.split('.')[0]
        labels.append(label)

images = np.array(images)
labels = np.array(labels)

return images, labels

加载数据集

image_dir = 'captcha_images'
images, labels = load_data(image_dir)
在上述代码中,我们读取图像并将其转换为灰度图,进行二值化处理,并将图像调整为统一的尺寸。最后,使用 flatten() 方法将每张图像展平为一维数组,这样可以直接用于 SVM 模型的训练。

  1. 标签编码与数据拆分
    因为 SVM 是一种分类算法,我们需要对标签进行编码。我们可以使用 LabelEncoder 来将标签(字符)转换为数值。此外,我们还会将数据集拆分为训练集和测试集,以便评估模型的性能。

(1) 标签编码与数据拆分

标签编码

label_encoder = LabelEncoder()
labels_encoded = label_encoder.fit_transform(labels)

拆分训练集和测试集

X_train, X_test, y_train, y_test = train_test_split(images, labels_encoded, test_size=0.2, random_state=42)
在这段代码中,我们使用 LabelEncoder 将字符标签转换为数值标签。然后,使用 train_test_split 将数据集分为训练集和测试集,其中 80% 用于训练,20% 用于测试。

  1. 构建 SVM 模型
    接下来,我们使用 Scikit-learn 中的 SVC(支持向量分类器) 来构建模型。由于验证码的字符识别是一个多分类问题,我们将使用 SVC 的多分类策略。

(1) 构建并训练 SVM 模型

from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler

标准化数据

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

构建 SVM 模型

svm_model = SVC(kernel='linear', C=1.0, random_state=42, decision_function_shape='ovr')

训练模型

svm_model.fit(X_train_scaled, y_train)

预测并评估模型

y_pred = svm_model.predict(X_test_scaled)
accuracy = accuracy_score(y_test, y_pred)

print(f'测试集上的准确率: {accuracy * 100:.2f}%')
在这段代码中,我们使用 StandardScaler 对数据进行标准化,以便 SVM 更好地进行训练。然后,我们使用 线性核函数(kernel='linear')构建了一个 SVM 模型,并训练它。最后,我们使用测试集评估模型的准确率。

  1. 模型评估与可视化
    通过训练完模型后,我们可以计算模型的性能并进行可视化。除了准确率,我们还可以绘制 混淆矩阵 来查看模型在每个类别上的表现。

(1) 混淆矩阵可视化

import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
import seaborn as sns

混淆矩阵

cm = confusion_matrix(y_test, y_pred)

可视化混淆矩阵

plt.figure(figsize=(10, 7))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=label_encoder.classes_, yticklabels=label_encoder.classes_)
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.show()
在这里,我们使用 confusion_matrix 计算混淆矩阵,并通过 seaborn 库绘制热图。通过混淆矩阵,我们可以更直观地了解模型在哪些字符上做得好,在哪些字符上做得差。

  1. 对新的验证码进行预测
    训练完成后,我们可以用模型对新的验证码图像进行预测。以下是如何对一张新图像进行预测的代码。

(1) 对新验证码进行预测

def predict_captcha(model, scaler, img_path):
# 预处理图像
img = preprocess_image(img_path)

# 标准化图像数据
img_scaled = scaler.transform([img])

# 预测
predicted_label_encoded = model.predict(img_scaled)

# 解码标签
predicted_label = label_encoder.inverse_transform(predicted_label_encoded)

return predicted_label[0]

预测新的验证码

new_image_path = 'captcha_images/test1.png'
predicted_label = predict_captcha(svm_model, scaler, new_image_path)
print(f'预测结果: {predicted_label}')
这段代码首先会预处理图像,然后使用训练好的 SVM 模型进行预测,最后将预测的数值标签转换为原始的字符标签。

posted @ 2025-04-06 13:53  ttocr、com  阅读(56)  评论(0)    收藏  举报