用Python和sklearn给人民币‘看相’:从240张纸币图片到颜色矩分类模型实战

发布时间:2026/6/3 15:19:37

用Python和sklearn给人民币‘看相’:从240张纸币图片到颜色矩分类模型实战 用Python给人民币看相从图像处理到SVM分类实战每次从钱包里掏出现金时你有没有想过手机摄像头也能像人眼一样快速识别纸币面额这个看似神奇的功能其实用Python和基础机器学习就能实现。本文将带你用240张纸币图片从零构建一个能看相识别的智能系统整个过程就像教电脑认识不同面额人民币的长相特征。1. 项目准备与环境搭建在开始之前我们需要明确这个项目的核心目标通过分析人民币图像的颜色特征自动识别其面额。这听起来像是专业的图像识别任务但我们将用生活化的方式来理解和实现它。首先准备开发环境。推荐使用Anaconda创建独立的Python环境避免包版本冲突conda create -n money_classifier python3.8 conda activate money_classifier pip install pillow numpy scikit-learn matplotlib项目所需的库各有其职Pillow处理图像加载和基础操作NumPy高效计算颜色特征scikit-learn构建和训练分类模型Matplotlib可视化分析结果数据集方面我们收集了6种面额1元、5元、10元、20元、50元、100元的人民币图片每种包含正反面不同角度的40张图片总计240张。这些图片已经按照面值_序号.png的格式命名例如5_23.png表示第23张5元纸币图片。提示实际项目中建议将图片按面额分文件夹存放这样既方便管理也能快速验证数据完整性。2. 图像特征提取颜色矩的秘密要让计算机认识不同面额的人民币首先需要教会它如何描述纸币的视觉特征。颜色矩Color Moments是一种简单有效的图像特征表示方法它通过统计颜色分布的三个关键指标来刻画图像特征。2.1 理解颜色三兄弟RGB通道每张彩色图像都由红(R)、绿(G)、蓝(B)三个颜色通道组成。我们可以把这想象成三张叠在一起的单色照片每张记录一种颜色的强度信息。以100元人民币为例from PIL import Image import matplotlib.pyplot as plt img Image.open(100_1.png) r, g, b img.split() plt.figure(figsize(15,5)) plt.subplot(131); plt.imshow(r, cmapReds); plt.title(Red Channel) plt.subplot(132); plt.imshow(g, cmapGreens); plt.title(Green Channel) plt.subplot(133); plt.imshow(b, cmapBlues); plt.title(Blue Channel) plt.show()运行这段代码你会看到同一张纸币在三个通道下的不同表现——这正是我们提取特征的基础。2.2 计算颜色矩图像的DNA对于每个颜色通道我们计算三个关键指标一阶矩均值颜色的平均强度二阶矩标准差颜色变化的剧烈程度三阶矩偏度颜色分布的不对称性计算公式如下import numpy as np def calculate_moments(channel): # 将通道数据转换为0-1范围的浮点数 channel np.array(channel) / 255.0 # 一阶矩均值 mean np.mean(channel) # 二阶矩标准差 std np.std(channel) # 三阶矩偏度 skewness np.mean((channel - mean)**3) ** (1/3) return mean, std, skewness这样每个通道产生3个特征三个通道共9个特征构成描述图像的颜色指纹。2.3 优化特征提取聚焦核心区域纸币边缘可能因拍摄角度产生干扰我们应聚焦中心区域def extract_center(image, size100): 提取图像中心区域 width, height image.size left (width - size)/2 top (height - size)/2 right (width size)/2 bottom (height size)/2 return image.crop((left, top, right, bottom))3. 构建分类模型SVM的实战应用有了特征提取方法接下来就是构建分类模型。支持向量机(SVM)特别适合我们这种中小规模、特征明确的分类问题。3.1 数据准备与划分首先批量处理所有图片构建特征矩阵和标签向量import os from sklearn.model_selection import train_test_split def load_dataset(image_folder): features [] labels [] for filename in os.listdir(image_folder): if not filename.endswith(.png): continue # 从文件名解析面额标签 denomination int(filename.split(_)[0]) # 加载并预处理图像 img_path os.path.join(image_folder, filename) img Image.open(img_path) img extract_center(img) # 计算颜色矩特征 r, g, b img.split() r_features calculate_moments(r) g_features calculate_moments(g) b_features calculate_moments(b) # 合并所有特征 all_features r_features g_features b_features features.append(all_features) labels.append(denomination) return np.array(features), np.array(labels) # 加载数据并划分训练测试集 X, y load_dataset(money_images) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42)3.2 SVM模型训练与评估选择线性核SVM作为我们的基础模型from sklearn.svm import SVC from sklearn.metrics import classification_report # 创建并训练模型 model SVC(kernellinear, class_weightbalanced) model.fit(X_train, y_train) # 评估模型 train_acc model.score(X_train, y_train) test_acc model.score(X_test, y_test) print(f训练集准确率: {train_acc:.2%}) print(f测试集准确率: {test_acc:.2%}) # 详细分类报告 y_pred model.predict(X_test) print(classification_report(y_test, y_pred))典型输出可能如下训练集准确率: 92.71% 测试集准确率: 89.58%3.3 模型优化技巧如果初始准确率不理想可以尝试以下优化策略特征工程添加颜色通道间的比值特征引入HSV颜色空间的特征计算图像纹理特征如LBP模型调参from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10], kernel: [linear, rbf], gamma: [scale, auto] } grid_search GridSearchCV(SVC(), param_grid, cv5) grid_search.fit(X_train, y_train) print(最佳参数:, grid_search.best_params_) print(最佳得分:, grid_search.best_score_)数据增强对训练图像进行轻微旋转、平移调整亮度和对比度添加少量噪声增强鲁棒性4. 从原型到应用构建完整识别系统有了训练好的模型我们可以将其封装成完整的识别系统。以下是一个简单的实现框架class MoneyClassifier: def __init__(self, model_pathNone): if model_path: self.model joblib.load(model_path) else: self.model SVC(kernellinear) def train(self, image_folder, save_pathNone): X, y self.load_dataset(image_folder) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42) self.model.fit(X_train, y_train) if save_path: joblib.dump(self.model, save_path) return self.evaluate(X_test, y_test) def predict_image(self, image_path): img Image.open(image_path) img self.extract_center(img) features self.extract_features(img) return self.model.predict([features])[0] # 其他辅助方法...这个类封装了完整的训练和预测流程可以方便地集成到各种应用中。例如开发一个Flask web应用from flask import Flask, request, jsonify import werkzeug app Flask(__name__) classifier MoneyClassifier(money_classifier.pkl) app.route(/predict, methods[POST]) def predict(): if image not in request.files: return jsonify({error: No image uploaded}), 400 image_file request.files[image] filename werkzeug.utils.secure_filename(image_file.filename) temp_path os.path.join(/tmp, filename) image_file.save(temp_path) try: denomination classifier.predict_image(temp_path) return jsonify({ denomination: int(denomination), currency: CNY }) finally: os.remove(temp_path) if __name__ __main__: app.run(host0.0.0.0, port5000)在实际部署时还需要考虑以下优化点使用更高效的图像处理库如OpenCV添加输入验证和错误处理实现批处理API提高吞吐量加入模型版本管理和A/B测试5. 扩展思路与项目进阶完成基础版本后这个项目还有许多值得探索的扩展方向5.1 多模态特征融合除了颜色特征还可以引入纹理特征使用LBP、Haralick等算法形状特征边缘检测后的几何特征局部特征SIFT、SURF等关键点特征from skimage.feature import local_binary_pattern def extract_lbp(image, radius3, n_points24): gray image.convert(L) lbp local_binary_pattern(np.array(gray), n_points, radius) hist, _ np.histogram(lbp, bins256, range(0, 256)) return hist / hist.sum() # 归一化5.2 深度学习方案对比与传统方法对比可以尝试CNN特征提取from keras.applications import MobileNetV2 from keras.models import Model base_model MobileNetV2(weightsimagenet, include_topFalse) model Model(inputsbase_model.input, outputsbase_model.get_layer(block_6_expand_relu).output) def extract_cnn_features(image): img image.resize((224, 224)) x np.array(img)[np.newaxis, ...] return model.predict(x).flatten()端到端分类模型from keras.models import Sequential from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense model Sequential([ Conv2D(32, (3,3), activationrelu, input_shape(100,100,3)), MaxPooling2D(2,2), Conv2D(64, (3,3), activationrelu), MaxPooling2D(2,2), Flatten(), Dense(128, activationrelu), Dense(6, activationsoftmax) ])5.3 实际应用中的挑战与解决方案在真实场景中你会遇到光照变化使用色彩恒常性算法或数据增强遮挡问题引入注意力机制新旧版人民币作为不同类别处理或特征工程区分实时性要求模型轻量化或边缘计算# 光照归一化示例 def normalize_illumination(image): lab cv2.cvtColor(np.array(image), cv2.COLOR_RGB2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit3.0, tileGridSize(8,8)) l_norm clahe.apply(l) lab_norm cv2.merge((l_norm, a, b)) return Image.fromarray(cv2.cvtColor(lab_norm, cv2.COLOR_LAB2RGB))在开发过程中我遇到一个有趣的现象新版和老版100元人民币在颜色特征上差异明显最初导致模型将它们误认为不同面额。这提醒我们实际应用中必须考虑货币版本更新带来的影响最好的解决方案是在数据收集阶段就包含不同版本样本。

相关新闻