
这次给正在做课程设计、毕业设计或者数字图像处理课设的同学看一个非常典型的综合项目基于 MATLAB 数字图像处理的扑克牌图像识别系统。这类项目的核心不是“扑克牌”本身而是把图像预处理、边缘检测、形态学处理、区域分割、特征提取、模板匹配这一整套流程串起来。换句话说把扑克牌换成银行卡、身份证、货物标签技术路线几乎一样因此可迁移性很强。这个系统我是按“源码交付 可运行 可改参数”的标准去看的。整体偏向传统数字图像处理路线没有一上来就抛 CNN、YOLO而是先用灰度化、二值化、投影分割、模板匹配把流程跑通。对 MATLAB 图像处理工具箱还不熟的同学来说这种实现方式反而更容易看懂、更容易在答辩时讲清楚每一步原理。本文会从系统能力、技术流程、运行环境、源码启动方式、关键代码思路、功能测试、批量处理、性能优化和常见报错几个方向展开尽量让拿到源码的同学能快速跑通也让想自己从零实现的人有一条清晰的开发路径。1. 扑克牌图像识别系统核心能力速览能力项说明项目类型MATLAB 源码工程偏课程设计/毕设/图像处理综合实训核心功能识别图像中的扑克牌输出牌面点数和花色类别主要技术路线图像采集 → 预处理 → 牌面区域定位 → 角度校正 → 点数/花色分割 → 模板匹配或特征识别是否需要 GPU不需要普通 CPU 即可运行推荐 MATLAB 版本建议 R2018b 及以上需安装 Image Processing Toolbox输入方式本地图片路径、脚本内变量读取、GUI 选择文件取决于交付版本输出方式命令行打印识别结果、在工作区输出标签、GUI 显示结果、保存标记图像是否支持批量可扩展支持通过循环遍历文件夹实现批量识别是否带 GUI部分交付版带 MATLAB App Designer 或 GUIDE 界面具体看压缩包内容源码用途课程设计、毕业设计、算法复现、程序二次开发定制修改可按需求调整预处理阈值、识别区域、模板库、输出格式和界面布局这里先给一个结论这个项目最值得关注的不是“识别精度有多高”而是它把数字图像处理课程里最重要的几个知识点全部落地了。灰度化、中值滤波、边缘检测、二值化、形态学开闭运算、连通域标记、最小外接矩形、模板匹配这一套组合拳打完基本就能在答辩中把“图像识别系统”讲清楚。2. 系统整体技术流程设计传统扑克牌识别和自然场景物体识别不太一样。扑克牌是典型的“人造刚体目标”背景比较干净、颜色分明、边缘清晰尺寸也相对固定。这类问题用几何方法解决比用深度学习方法更可控而且不需要训练几十万张图片。一个完整的 MATLAB 扑克牌识别流程可以分为七个步骤图像读取使用imread读取图像必要时用rgb2gray转换成灰度图。图像预处理对灰度图进行中值滤波或高斯滤波去除噪声减少桌面纹理和光照不均的影响。牌面区域检测利用图像二值化、边缘检测Canny、Sobel和形态学操作提取扑克牌矩形区域。几何校正扑克牌在图像中可能带有旋转角度需要用regionprops提取最小外接矩形再进行仿射变换或旋转校正。牌面信息分割将左上角或右上角的牌值和花色区域裁剪出来作为识别子图。特征提取计算字符区域的特征或直接归一化尺寸后建立模板库花色则按颜色空间或形状特征区分。识别输出通过模板匹配或最近邻分类得到点数和花色再组合输出完整牌面例如红桃A、黑桃10、方块K。整个流程对应到 MATLAB 里最关键的是“区域定位”这一步。只要扑克牌区域定位得准后面的点数识别和花色识别就只是裁剪和模板比对的问题。拆开看各阶段的任务可以用下面这张表理解流程阶段输入关键操作输出图像读取摄像头截图或数码相机图像imread / rgb2gray灰度图预处理灰度图滤波、对比度增强平滑后的图像区域定位平滑图二值化、Canny、形态学闭运算、连通域标记牌面二值图及边框坐标角度校正牌面区域regionprops 外接矩形、imrotate摆正后的牌面点数/花色分割摆正后的牌面按固定比例裁剪左上角区域、颜色通道分离点数子图、花色子图模板匹配归一化后的子图与模板库做相关匹配或欧氏距离计算单张牌识别结果输出结果识别标签fprintf、imshow、label2rgb可视化识别图像有的版本会把“点数识别”直接交给 MATLAB 自带的ocr函数降低实现难度。但从数字图像处理课程设计的角度来说自己用模板匹配实现一次更能体现对图像处理原理的理解答辩老师也更认可。3. 适用场景与使用边界先说实话这个系统更适合实验环境、课程设计、算法学习不适合在赌场牌桌、复杂自然场景下做高精度实时识别。原因很简单真实牌桌背景复杂、光线不可控、存在遮挡、扑克牌可能严重形变传统图像处理方案会在定位环节出现较大误差。但作为一种教学项目和图像识别入门系统它的性价比非常高。适合的人群有四类正在选 MATLAB 课程设计题目的本科生需要一个完整可运行的图像识别项目。准备毕业设计的同学需要把某个识别算法作为基础再扩展准确率对比实验。初学数字图像处理的读者想弄清楚边缘检测、形态学、模板匹配怎么串联成应用。想接 MATLAB 程序定制和二次开发的开发者用这套框架改造成证件识别、卡片分类、物体计数系统。能解决的问题包括如何从一张照片里找到目标区域如何消除旋转和尺寸影响如何判断牌面花色如何把 MATLAB 图像处理算法封装成可调用的脚本或函数。必须注意的使用边界也很明确不要让系统处理模糊、严重遮挡、多张牌叠放重叠的图片预处理阶段会失效。花色识别如果只靠颜色阈值灯光偏色会直接导致错误建议颜色和形状特征双重判断。涉及图像采集时如果拍摄对象包含人脸、身份证件等人物隐私素材必须征得当事人授权。扑克牌图样和商标素材如果用于论文配图、课程报告仅限学习研究场景不得随意商用传播。一句话总结这套系统的边界不是“能不能识别”而是“在什么条件下识别稳定”。拿到源码后的第一件事就是搞清楚它在哪种光照、角度、分辨率下表现最好。4. MATLAB 本地开发环境准备运行基于 MATLAB 数字图像处理的源码前先确认 PC 上的 MATLAB 环境完整。这类图像识别项目对硬件要求很低不依赖 NVIDIA GPU不需要 CUDA也不需要安装 PyTorch 或 TensorFlow只需要一台能装 MATLAB 的普通电脑。4.1 版本与工具箱建议满足以下条件MATLAB R2018b 及以上R2020a-R2023b 兼容性更好。Image Processing Toolbox 必须安装代码中会用到rgb2gray、medfilt2、edge、im2bw、regionprops、imrotate、imresize、normxcorr2等函数。Computer Vision Toolbox 不是必须但如果有ocr函数版本需求可以额外安装。如果源码带 GUI需要确认当前版本支持 App Designer 或 GUIDE。检查工具箱是否安装可以在 MATLAB 命令行输入ver在输出中找到 Image Processing Toolbox 及其版本号即可。如果显示 Undefined function说明工具箱没有装全。4.2 硬件与系统普通办公笔记本电脑就能跑。识别单张图片时CPU 占用不高内存建议 8GB 以上。如果处理 4000×3000 的高分辨率照片MATLAB 会临时开辟较大数组16GB 内存会更从容。操作系统方面Windows 10/11 最方便macOS 和 Linux 版本 MATLAB 也可以运行但图片路径写法和中文字符编码需要注意。4.3 点按步骤走把源码解压到无中文路径、无空格的目录例如D:\card_recognition\尽量不要解压到“桌面\新建文件夹 (2)”这种路径MATLAB 旧版本偶尔会因为中文路径加载脚本出错。打开 MATLAB把当前路径切换到源码目录然后在命令行执行主函数名即可。具体主函数名以压缩包内说明为准常见命名是main.m、poker_recognition.m、identify_card.m。5. 源码目录与启动运行方式从交付物的通用结构来看这类 MATLAB 源码工程一般会包含以下内容card_recognition/ ├── main.m % 主运行脚本 ├── identify_card.m % 单张牌识别函数 ├── preprocess_img.m % 图像预处理函数 ├── locate_card.m % 定位牌面区域 ├── extract_rank_suit.m % 提取点数与花色子图 ├── match_template.m % 模板匹配识别 ├── create_template.m % 生成/加载模板库 ├── templates/ % 模板图片文件夹 ├── test_images/ % 测试图片文件夹 ├── result_images/ % 识别结果输出文件夹 └── README.txt % 使用说明如果压缩包里没有main.m而是直接给了一个识别系统.fig和识别系统.m则说明这是一个 GUI 版本需要先在当前目录打开.m文件点击“运行”按钮启动界面。5.1 无 GUI 版本运行方式命令行运行主脚本% 进入源码目录 cd D:\card_recognition % 运行主脚本 main也可以不带界面直接测试单张图img imread(test_images\card_01.jpg); result identify_card(img); disp(result);5.2 GUI 版本启动方式如果是 App Designer 版本直接在 MATLAB 中打开.mlapp文件点击运行如果是 GUIDE 版本打开.fig文件后点击绿色运行按钮。启动后界面上通常包含“打开图片”按钮原图显示区处理后图像显示区识别结果文本框批处理按钮5.3 遇到启动失败怎么办最常见的原因是当前路径没有包含函数文件。命令行运行which identify_card如果提示未找到说明需要把源码目录右键 → 添加到路径。addpath(genpath(pwd)); savepath;然后重新执行主程序。6. 扑克牌识别的关键实现思路虽然最终源码以实际交付为准但我可以按常规实现方案把核心代码逻辑梳理一遍。拿到源码后不建议先通读全部代码建议按“预处理 → 定位 → 识别”三段去理解。6.1 图像预处理预处理的目的是把彩色图转成更容易处理的灰度图和二值图同时压低噪声。扑克牌表面的纹理、桌面木纹、手指阴影都会干扰后续定位。function gray preprocess_img(img) % 输入彩色图像输出滤波后的灰度图 gray rgb2gray(img); % 中值滤波去掉椒盐噪声 gray medfilt2(gray, [3 3]); % 自适应提高对比度 gray imadjust(gray); end有时为了提高场景适应性也可以把灰度图再转成二值图bw imbinarize(gray, adaptive); bw imclose(bw, strel(rectangle, [15 15])); bw imfill(bw, holes);这里的闭运算是为了把牌面上分散的图案连通成一个完整矩形让白色区域成为一个大团块。这一步做得好后面regionprops才能准确找到扑克牌。6.2 区域定位与旋转校正在二值图中扑克牌是一个面积较大的白色连通区域。用regionprops提取所有连通域的包围盒和方向角再通过面积筛选出最大矩形。stats regionprops(bw, BoundingBox, Orientation, Area, Centroid); % 找出面积最大的连通域认为它是牌面 [~, idx] max([stats.Area]); box stats(idx).BoundingBox; angle stats(idx).Orientation; % 裁剪出牌面区域 card_img imcrop(img, box); % 如果旋转角度过大先转正 if abs(angle) 1 card_img imrotate(card_img, -angle, bilinear, crop); end注意imrotate的第三个参数是插值方法扩展参数crop表示旋转后保持原图尺寸。实际使用中如果角度过于接近 0 度不必旋转避免插值降低模板匹配准确率。6.3 左上角点数与花色提取扑克牌左上角通常是一个“点数 花色”的组合区域位置相对固定。把牌面区域裁出来后直接按比例取左上角一部分即可% 假设 card_img 是摆正后的牌面灰度图 [rows, cols] size(card_img); roi card_img(round(rows*0.05):round(rows*0.35), ... round(cols*0.02):round(cols*0.25)); % 对 roi 做二值化 bw_roi imbinarize(roi);如果识别右上角的点数镜像操作即可。6.4 模板匹配识别点数和花色模板匹配的思想非常简单把待识别子图缩放成固定尺寸和大小的模板求相似度。相关度最高的模板就是识别结果。function label match_template(roi_bw, templates, labels) roi_resized imresize(roi_bw, [64 64]); maxCorr -inf; label ; for i 1:length(templates) temp templates{i}; temp_resized imresize(temp, [64 64]); % 归一化相关系数匹配 c normxcorr2(temp_resized, roi_resized); corr max(c(:)); if corr maxCorr maxCorr corr; label labels{i}; end end end对花色识别也可以先用颜色分离快速区分红黑两类再用形状模板细分红桃、方块、黑桃、梅花。例如在 RGB 颜色空间下红色通道和蓝色通道的差可以快速判断红色系花色。6.5 主流程汇总整个识别函数可以整合为一个identify_card.m文件函数输入是图像路径或图像矩阵输出是形如Spade A的标签。function result identify_card(img) % 1. 预处理 gray preprocess_img(img); % 2. 二值化并定位牌面 bw imbinarize(gray, global); bw imclose(bw, strel(rectangle, [15 15])); stats regionprops(bw, BoundingBox, Orientation, Area); [~, idx] max([stats.Area]); card_img imcrop(img, stats(idx).BoundingBox); % 3. 转正并提取左上角 % 4. 分割出点数和花色区域 % 5. 调用模板库匹配返回结果 result finalLabel; end如果源码不是这个结构也可以按此逻辑去对照理解。数字图像处理的扑克牌识别系统本质上就是这几个模块的排列组合。7. 功能测试与效果验证拿到源码后不建议直接拿一张很复杂的牌桌照片做测试。先准备几张单牌、正角度、背景简单的图跑通流程再一步步增加难度。7.1 测试样本建议测试项输入图片要求预期输出判断标准基础识别单张扑克牌平放、光线均匀输出点数和花色10 张内识别准确率≥90%左/右上角识别单张牌有轻微旋转输出正确牌面旋转角度范围可稳定识别黑红花色分类黑桃、梅花、红桃、方块各一张颜色/花色不要混淆无花色错判低对比度测试桌面颜色和牌面接近能准确定位二值化阈值自适应程度背景干扰测试桌面上有花纹、杂物不误检杂物为牌regionprops 面积筛选生效摄像头实时帧测试摄像头对准桌面逐帧输出识别结果单帧处理时间小于 1-2 秒7.2 单张图片识别测试操作流程在命令行中先定义一组测试图片test_images { test_images\card_A.png test_images\card_K.png test_images\card_Q.png test_images\card_J.png test_images\card_10.png }; for i 1:length(test_images) img imread(test_images{i}); result identify_card(img); fprintf(图片 %s 识别结果%s\n, test_images{i}, result); end如果结果输出中有Undefined function优先检查工具箱如果输出结果是空优先打印中间二值图看定位环节是否失败。7.3 可视化中间结果识别系统出错的排查方式只有一个核心看到哪一步断了。可以在代码里临时插入figure; subplot(2,2,1); imshow(gray); title(灰度图); subplot(2,2,2); imshow(bw); title(二值图); subplot(2,2,3); imshow(card_img); title(定位裁切); subplot(2,2,4); imshow(roi); title(左上角提取);定位不出来就看二值图二值图不完整就看闭运算的结构元素尺寸裁切不对就看 ROI 的坐标比例。7.4 准确率评估如果需要写实验报告建议建立一份ground_truth.xlsx记录图片文件名和真实标签再用脚本批量识别并统计准确率。files dir(test_images\*.png); correct 0; total length(files); for i 1:total img imread(fullfile(files(i).folder, files(i).name)); res identify_card(img); if strcmp(res, expected_labels{i}) correct correct 1; end end fprintf(识别准确率%.2f%%\n, correct/total*100);这一步写进论文里非常加分因为很多同学只给了几个示例图没有量化评估。8. 批量处理与 MATLAB 程序扩展扑克牌识别系统除了单张测试更适合做批量识别实验。批量任务的核心逻辑是遍历文件夹逐个调用identify_card再把结果统一写入 Excel 或文本文件。8.1 批量遍历图片文件夹inputDir test_images; outputFile results.txt; files dir(fullfile(inputDir, *.jpg)); fid fopen(outputFile, w); for i 1:length(files) imgPath fullfile(inputDir, files(i).name); try img imread(imgPath); result identify_card(img); fprintf(fid, %s\t%s\n, files(i).name, result); fprintf(已处理%s - %s\n, files(i).name, result); catch ME fprintf(处理失败%s原因%s\n, files(i).name, ME.message); end end fclose(fid);8.2 按输出信息做分类整理批量识别完成后可以把不同牌面复制到对应文件夹实现自动分拣这也是很多同学想扩展的功能。resultDir sorted_results; if ~exist(resultDir, dir) mkdir(resultDir); end % 假设 result 是 Spade A解析花色并创建子文件夹 suit strtok(result, ); if ~exist(fullfile(resultDir, suit), dir) mkdir(fullfile(resultDir, suit)); end imwrite(img, fullfile(resultDir, suit, [result .jpg]));8.3 通过函数接口接出来如果想脱离 MATLAB 环境给别人做演示可以把识别函数编译成独立应用但需要 MATLAB Compiler 工具箱。常规课程设计不需要这一步把identify_card封装好就够了。9. 资源占用与性能观察MATLAB 求解这个问题时的计算热点不在“识别模板匹配”本身而在图像预处理和旋转校正。输入图片分辨率越大预处理耗时越高。想提高处理速度时应在读取图片后先做imresize缩放而不是保持 4000 万像素原图。9.1 分辨率与耗时关系可以从三个档位观察处理时间img_low imresize(img, [360 480]); img_mid imresize(img, [720 960]); img_high img; time_low timeit(() identify_card(img_low)); time_mid timeit(() identify_card(img_mid)); time_high timeit(() identify_card(img_high));通常分辨率降低后中值滤波、闭运算和连通域分析耗时明显下降但分辨率过低会让牌面左上角字符模糊模板匹配率下降。实际使用中可以找到一个“准确率可接受的最快分辨率”。9.2 模板匹配加速模板匹配阶段如果模板数量多normxcorr2的循环会很耗时。建议把所有模板提前预缩放并存入 .mat 文件运行时不重复缩放。load(template_library.mat, templates);也可以把每个模板栅格化成特征向量用pdist2批量计算距离替代循环相关匹配。9.3 观察 MATLAB 性能在 MATLAB 中可以用profile on和profile viewer查看各函数耗时占比是找性能瓶颈最直接的工具。profile on identify_card(img); profile off profile viewer如果imclose或imrotate占比过高先降低图幅如果模板匹配循环占比过高改用矩阵化匹配。10. 常见问题与排查方法问题现象可能原因排查方式解决方案打开.m文件中文乱码MATLAB 编码与文件不一致检查文件编辑器编码用 UTF-8 或 GBK 重存文件保持 MATLAB 字符编码一致Undefined function or variable当前目录未包含源码命令行输入which 函数名addpath(genpath(pwd))后保存路径imread 打不开图片图片路径含中文或空格检查dir输出复制到纯英文目录regionprops返回空二值图中没有连通域查看二值图是否为全黑调整imbinarize阈值或闭运算核大小识别出多张牌区域二值化后场景中有多个干扰块查看面积排序筛选面积最大的连通域或长宽比在扑克牌范围内的连通域花色总是认出红色颜色阈值受光照影响打印 ROI 颜色通道数值在 HSV 空间中增加饱和度阀值GUI 按钮无响应回调函数路径不对检查按钮回调名右键按钮查看 Callback识别 10 点错误十个点数与花色的两点区域被同时截图查看 ROI 子图调整 ROI 坐标或先分离字符连通域旋转牌识别误差大imrotate 插值后字符变形显示旋转后图像改用双线性插值或先检测四个角点做透视变换运行太慢图片过大查看 profile 结果先 imresize 再处理对这些图像处理问题判断标准很统一先检查每一步的中间输出不要只看最终结果。图像处理系统里 80% 的错误都发生在二值化和区域定位阶段。11. 最佳实践与 MATLAB 程序定制修改建议如果你手上这套源码准备用于课程答辩或毕业设计有一些工程经验值得提前知道。11.1 先跑通再谈精度第一步不要追求识别率 100%而是先把一套图跑通。准备 15 张牌验证两个核心结论区域定位是否正确模板匹配是否有效这两点确认后再根据错误样本调参数。11.2 保留参数可调入口建议把阈值、形态学结构元素尺寸、ROI 坐标都抽成变量。这样修改时不至于在几十行代码里反复找固定数字。config.closeSize 15; config.roiScale [0.05 0.35 0.02 0.25]; config.templateSize [64 64];11.3 把模板库单独管理把新的模板图片直接放到templates文件夹并保留统一的命名规则例如suit_spade.png、rank_10.png。模板命名混乱是程序定制修改里最消耗时间的因素。11.4 常见定制方向从实际需求来说这套系统的扩展方向大致有五个加摄像头实时识别用webcam对象获取视频帧循环调用现有识别流程。改成任意卡片识别替换模板库调整 ROI 比例即可识别身份证区域或银行卡卡号。加颜色直方图判断在模板匹配前先做一次颜色分类减少候选模板数量。用深度学习替换模板匹配使用 AlexNet、ResNet 提取特征再用 SVM 分类适合做传统方法和深度学习对比实验。做成 GUI 演示程序把identify_card接到 App Designer 按钮回调里降低使用门槛。11.5 合规提醒如果你打算上传识别图片到博客、论文或视频演示请注意涉及他人肖像、真实身份证件、银行卡、带有版权的扑克牌设计素材时先获得授权。技术演示建议用自己的纸质卡牌或自由版权图片在照片中避免包含任何无关私人物品。12. 后续调试与下一步建议扑克牌识别系统作为 MATLAB 数字图像处理综合项目最值得花时间的两个点是一是理解牌面定位为什么依赖形态学闭运算和连通域筛选二是理解模板匹配为什么要在统一尺寸后计算相关度。把这两点吃透整个系统的原理基本就通了。如果拿到源码后第一件事不知道做什么可以按这个优先级来先准备好 10-15 张单牌测试图确保能运行然后修改config参数观察 ROI 提取结果再插入中间图像代码打印每一步二值图的形态最后跑一遍批量识别统计准确率。这个过程走完无论是答辩还是改成论文实验部分都足够扎实了。