用 Scikit-learn 和 SVM 实现验证码识别系统
在这篇文章中,我们将使用 Scikit-learn 中的 支持向量机(SVM) 来实现一个验证码识别系统。虽然支持向量机(SVM)通常用于二分类问题,但我们可以通过调整其多类分类支持来解决验证码识别问题。本示例通过简单的图像预处理和特征提取,使用 SVM 来识别图像中的字符。
- 环境准备
首先,我们需要安装以下必要的库:
pip install scikit-learn opencv-python numpy matplotlib pillow
scikit-learn:一个广泛使用的机器学习库,用于实现 SVM 和其他分类算法。
opencv-python:用于图像处理。
numpy:用于数值计算。
matplotlib:用于结果可视化。
pillow:用于图像加载和预处理。
- 数据集准备与图像预处理
我们假设数据集中的验证码图像已经准备好了,且每个图像的标签是包含的字符。我们将对图像进行一些预处理操作,包括:将图像转为灰度图、应用二值化、调整图像大小以及将图像展平为一维特征向量。
(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 模型的训练。
- 标签编码与数据拆分
因为 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% 用于测试。
- 构建 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) 混淆矩阵可视化
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) 对新验证码进行预测
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 模型进行预测,最后将预测的数值标签转换为原始的字符标签。
浙公网安备 33010602011771号