资讯动态

MATLAB曲线图片识别程序:从截图到数据表的完整还原

发布时间:2026/10/21 13:02:26 来源:尧图企业网站定制
简介这是一份面向科研人员与图像处理学习者的MATLAB曲线识别工具包用于从论文截图或实验图像中自动提取曲线坐标省去手工描点或重写绘图代码的麻烦。压缩包共14个文件约459KB包含12个png示例图片、1个mat数据文件和1个m脚本文件图片用于测试识别效果脚本与数据文件则承载核心算法与结果存储。内容覆盖图像预处理、边缘检测、轮廓追踪、曲线拟合、数据绘图、文件读写及GUI交互等环节并涉及算法优化思路可帮助读者理解从灰度化、二值化到坐标提取的完整流程。已有2019人学习下载适合需要对比分析不同论文曲线、快速复现图形数据的中高级MATLAB用户参考也可作为图像处理课程的实践素材。1. 曲线图片识别程序从截图到数据表的完整还原手里拿到一张论文截图或者实验报告照片上面画着几条曲线想把数据点抠出来重新画图或者做拟合这事我干过不止一次。手动描点几十个点还能忍几百个点纯属折磨。这个基于 MATLAB 的曲线图片识别程序就是解决这个问题的输入一张包含曲线的图片输出曲线对应的坐标数据。它适合做实验数据分析的学生、需要复现文献图表的工程师以及任何手里只有图片没有原始数据的人。整个项目不依赖深度学习工具箱纯图像处理加坐标映射MATLAB 基础版本就能跑对新手相当友好。下面从架构到代码逐层拆开讲。2. 项目架构与运行准备文件结构、依赖与启动流程2.1 目录结构与模块划分这个项目的代码量不大但模块划分清晰。拿到源码后先看目录结构心里有个数再动手跑。curve_recognition/ ├── main.m % 主入口串联整个流程 ├── preprocess.m % 图像预处理灰度化、二值化、去噪 ├── extract_curve.m % 曲线提取分离曲线像素与坐标轴 ├── calibrate_axis.m % 坐标轴校准像素坐标到数据坐标的映射 ├── output_data.m % 数据输出保存为 mat 或 csv ├── utils/ │ ├── remove_grid.m % 去除网格线 │ └── smooth_curve.m % 曲线平滑处理 └── samples/ ├── sample1.png % 示例图片 └── sample2.png主入口main.m负责按顺序调用各模块每个模块只做一件事。这种设计的好处是如果你只想替换其中某一步——比如用自己的二值化算法——直接改对应文件就行不会牵一发动全身。常见做法是把所有逻辑塞进一个脚本但那样后期维护会很痛苦这个项目的拆分方式值得借鉴。2.2 环境要求与依赖检查运行前确认 MATLAB 版本。项目用到的主要函数包括imread、rgb2gray、imbinarize、bwareaopen、regionprops这些在 R2016b 及以上版本都支持。如果用的是更早的版本imbinarize需要换成im2bw注意一下就行。不需要额外工具箱。Image Processing Toolbox 是必须的但大多数 MATLAB 安装都自带。在命令行输入ver可以查看已安装的工具箱列表确认里面有 Image Processing Toolbox 即可。启动方式很简单在 MATLAB 中把当前文件夹切换到项目根目录然后运行% 启动主程序传入图片路径 main(samples/sample1.png);如果一切正常命令窗口会输出识别到的曲线数量和数据点个数同时在当前目录生成result.csv。第一次跑建议用自带的示例图片确认流程通了再换自己的图。2.3 主流程代码逐段解析main.m是整个项目的骨架理解它就理解了整个处理链路。下面逐段拆解。function main(imagePath) % 读取图片并转为灰度图 img imread(imagePath); if size(img, 3) 3 gray rgb2gray(img); else gray img; end % 预处理二值化 去噪 bw preprocess(gray); % 提取曲线像素排除坐标轴和网格 [curvePixels, axisInfo] extract_curve(bw); % 坐标轴校准建立像素到数据的映射 calibration calibrate_axis(axisInfo); % 将像素坐标转换为数据坐标 dataPoints cell(length(curvePixels), 1); for i 1:length(curvePixels) px curvePixels{i}(:, 1); py curvePixels{i}(:, 2); [dx, dy] pixel2data(px, py, calibration); dataPoints{i} [dx, dy]; end % 输出结果 output_data(dataPoints, result.csv); end这段代码的逻辑链条是读图 → 预处理 → 提取曲线 → 校准坐标轴 → 坐标转换 → 输出。每一步的输出是下一步的输入数据流单向传递没有循环依赖。参数说明imagePath是图片路径支持 png、jpg、bmp 等常见格式。curvePixels是一个 cell 数组每个元素对应一条曲线的像素坐标集合。calibration结构体存储了坐标轴原点和缩放比例后面坐标转换要用。有个细节值得注意代码里判断了图片是否为三通道如果是彩色图先转灰度。这一步看似简单但如果跳过后续二值化处理彩色图会出问题。我见过有人直接对 RGB 图做imbinarize结果报错都不知道为什么。3. 核心模块拆解预处理、曲线提取与坐标校准3.1 图像预处理二值化阈值怎么选预处理的目标是把曲线从背景中分离出来变成黑白分明的二值图。核心是阈值选择。function bw preprocess(gray) % 使用 Otsu 方法自动确定阈值 level graythresh(gray); bw imbinarize(gray, level); % 反转让曲线为白色背景为黑色 bw ~bw; % 去除小面积噪点小于 30 像素的连通区域 bw bwareaopen(bw, 30); % 填充曲线内部可能出现的空洞 bw imfill(bw, holes); endgraythresh用的是 Otsu 算法它会自动找到一个让前景和背景类间方差最大的阈值。对于大多数曲线图这个自动阈值够用了。但如果图片光照不均——比如手机拍屏幕产生的反光——自动阈值可能翻车这时候需要手动指定% 手动指定阈值适用于光照不均的情况 bw imbinarize(gray, 0.6);bwareaopen去除小面积连通区域参数 30 是面积阈值。如果你的图片分辨率很高噪点面积也大这个值要相应调大。反过来如果曲线本身很细调太大会把曲线也去掉。我一般会先跑一遍看看二值化结果用imshow(bw)确认曲线完整、噪点干净再继续往下走。imfill填充空洞是为了处理曲线较粗时二值化后内部出现空心的情况。如果曲线本身就很细这一步可以跳过不影响结果。3.2 曲线提取分离坐标轴与网格线二值化之后图里有曲线、坐标轴、刻度线、网格线需要把曲线单独拎出来。这一步是整个项目最容易出问题的地方。function [curvePixels, axisInfo] extract_curve(bw) % 通过 Hough 变换检测直线识别坐标轴 [H, T, R] hough(bw); P houghpeaks(H, 10); lines houghlines(bw, T, R, P); % 找出最长的水平线和垂直线作为坐标轴 axisInfo find_axes(lines, size(bw)); % 从二值图中移除坐标轴区域 bw_noaxis remove_axes(bw, axisInfo); % 移除网格线细的周期性强直线 bw_nogrid remove_grid(bw_noaxis); % 连通区域标记每个区域是一条曲线 [L, num] bwlabel(bw_nogrid); curvePixels cell(num, 1); for i 1:num [rows, cols] find(L i); curvePixels{i} [cols, rows]; % 注意x 是列y 是行 end endHough 变换用来检测直线坐标轴通常是图中最长的水平线和垂直线。houghpeaks找峰值houghlines把峰值转成线段。find_axes是自定义函数逻辑是遍历所有检测到的直线找长度最长且接近水平/垂直的那两条。移除坐标轴和网格线之后剩下的连通区域就是曲线。bwlabel做连通区域标记每个标记对应一条曲线。这里有个坑如果两条曲线交叉它们会被标记为同一个连通区域。解决办法是在交叉点做分割但实现起来比较复杂。常见做法是假设曲线不交叉或者手动指定曲线数量后用其他方法分离。curvePixels里存的是像素坐标注意 x 是列号y 是行号这和 MATLAB 矩阵索引一致但和常规笛卡尔坐标系的 xy 相反。后面坐标转换时要留意。3.3 坐标轴校准像素坐标到数据坐标的映射提取到曲线像素后这些坐标还是像素值需要映射到实际数据坐标。映射关系是线性的数据坐标 (像素坐标 - 原点像素坐标) / 缩放比例。function calibration calibrate_axis(axisInfo) % axisInfo 包含坐标轴原点和刻度信息 % 假设已知 x 轴范围 [xmin, xmax] 和 y 轴范围 [ymin, ymax] % 原点像素坐标左下角 origin_px axisInfo.origin; % x 轴方向缩放每像素对应多少数据单位 x_range axisInfo.xmax - axisInfo.xmin; x_pixels axisInfo.x_axis_length; calibration.x_scale x_range / x_pixels; % y 轴方向缩放 y_range axisInfo.ymax - axisInfo.ymin; y_pixels axisInfo.y_axis_length; calibration.y_scale y_range / y_pixels; calibration.origin origin_px; calibration.xmin axisInfo.xmin; calibration.ymin axisInfo.ymin; end function [dx, dy] pixel2data(px, py, cal) % 像素坐标转数据坐标 dx cal.xmin (px - cal.origin(1)) * cal.x_scale; dy cal.ymin (cal.origin(2) - py) * cal.y_scale; % y 轴翻转 end这里的关键参数是axisInfo里的坐标轴范围。程序怎么知道 x 轴是从 0 到 10 还是从 0 到 100两种方式一是手动输入在运行前告诉程序二是自动识别刻度标签用 OCR 读取。这个项目默认用手动输入因为 OCR 识别刻度数字的准确率不稳定手动输入反而更可靠。pixel2data里 y 轴做了翻转因为图像坐标系原点在左上角y 向下增大而数据坐标系 y 向上增大。这个细节如果搞错出来的曲线是上下颠倒的而且不容易发现。提示坐标轴范围一定要在运行前确认清楚。如果图片里 x 轴标注的是 0 到 5你按 0 到 10 输入所有数据点都会差一倍。4. 避坑与常见问题跑不通时先查这几处4.1 二值化后曲线断裂现象imshow(bw)看到曲线中间断成几截连通区域数量比实际曲线多。原因阈值选得偏高曲线颜色较浅的部分被当成背景。或者图片压缩太厉害曲线边缘模糊。解决降低阈值或者改用自适应阈值imbinarize(gray, adaptive)。如果曲线断裂不严重可以用形态学闭运算连接% 闭运算连接断裂处 se strel(disk, 2); bw imclose(bw, se);4.2 坐标轴识别错误现象程序把网格线当成了坐标轴或者坐标轴没检测到。原因Hough 变换的参数不合适或者图片里坐标轴不是标准直线比如手绘图。解决调整houghpeaks的峰值数量或者手动指定坐标轴位置。在find_axes里加一个判断坐标轴应该在图像边缘附近不在中间的直线大概率是网格。4.3 多条曲线被合并成一条现象输出只有一条曲线但图里明明有好几条。原因曲线交叉导致连通区域合并或者曲线之间距离太近二值化后粘在一起。解决如果曲线交叉需要在交叉点分割。简单做法是按 x 坐标分段每段单独处理。如果曲线粘连先做腐蚀操作分离再提取。4.4 输出数据点顺序混乱现象csv 里数据点的 x 坐标不是递增的画出来是乱线。原因find函数返回的像素坐标按行扫描顺序排列不是按 x 排序。解决提取后按 x 坐标排序% 按 x 坐标排序 [~, idx] sort(curvePixels{i}(:, 1)); curvePixels{i} curvePixels{i}(idx, :);4.5 图片分辨率太低导致精度差现象识别出来的数据点很少曲线画出来是折线。原因低分辨率图片里曲线只占几个像素宽提取到的点自然少。解决换高分辨率图片或者在预处理时做上采样。但上采样不会增加信息量只是让曲线看起来平滑实际精度还是受原图限制。最好的办法是找到原始矢量图或者高分辨率版本。5. 二次开发与改造从能跑到好用5.1 批量处理与自动化原始代码一次只处理一张图实际用的时候往往有一批图要处理。改造思路是加一个批量入口function batch_process(folderPath) % 获取文件夹下所有图片 files dir(fullfile(folderPath, *.png)); for i 1:length(files) imagePath fullfile(folderPath, files(i).name); try main(imagePath); % 重命名输出文件避免覆盖 [~, name, ~] fileparts(files(i).name); movefile(result.csv, [name, _result.csv]); catch e fprintf(处理 %s 失败%s\n, files(i).name, e.message); end end end这个改造的关键是错误处理。批量处理时某张图失败不能影响后面的用 try-catch 包起来记录失败文件名事后单独排查。5.2 增加 GUI 交互命令行传参对不熟悉 MATLAB 的人不友好。可以用 App Designer 做一个简单界面选择图片、输入坐标轴范围、点击运行、显示结果预览。核心代码不用改只是包一层界面。MATLAB 的uigetfile和uieditfield组件够用了。5.3 提高曲线分离的鲁棒性前面提到曲线交叉会导致合并。一个可行的改进是用颜色信息分离曲线。如果原图是彩色的不同曲线颜色不同可以在预处理阶段按颜色通道分离而不是转成灰度图。这样即使曲线交叉也能按颜色区分开。% 按颜色通道分离曲线 r img(:, :, 1); g img(:, :, 2); b img(:, :, 3); % 红色曲线 red_curve (r 150) (g 100) (b 100);这个方法的局限是要求曲线颜色差异明显且背景干净。如果图片质量差还是得回到灰度处理加手动分割的老路。5.4 数据平滑与拟合提取到的数据点往往有噪声直接画图会有毛刺。可以在输出前加一步平滑% 移动平均平滑 windowSize 5; smoothed movmean(dataPoints{i}(:, 2), windowSize);但平滑会改变数据如果后续要做精确拟合建议保留原始数据平滑只用于可视化。我一般会输出两份一份原始数据一份平滑后的让用户自己选。5.5 验证识别精度的方法改完代码怎么知道识别准不准一个实用的办法是用 MATLAB 自己画一张已知数据的曲线图保存成图片再用识别程序跑一遍对比输出数据和原始数据的差异。如果误差在可接受范围内说明流程没问题。% 生成测试图片 x linspace(0, 10, 100); y sin(x); plot(x, y); saveas(gcf, test_curve.png); % 用识别程序处理对比结果 % 理想情况下识别出的数据应该和 x, y 高度吻合这个验证方法我每次改完核心算法都会跑一遍。有一次改了二值化阈值测试图识别正常但换了一张真实实验图就翻车了——因为测试图太干净没有噪声和网格线。从那以后我每次改完都强制走一遍真实图片的验证流程再也不敢只拿理想图测试了。希望这些改造思路帮到你拿到源码后先跑通示例再按自己的需求逐步调整。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑