资讯动态

MATLAB曲线图片识别:从截图到坐标数据的完整实现

发布时间:2026/10/21 13:02:04 来源:尧图企业网站定制
简介这是一份面向科研人员与图像处理学习者的MATLAB曲线识别工具包用于从论文截图或实验图像中自动提取曲线坐标省去手工描点或重写绘图代码的麻烦。压缩包共14个文件约459KB包含12个png示例图片、1个mat数据文件和1个m脚本文件图片用于测试识别效果脚本承载核心算法mat文件保存中间或结果数据。程序覆盖图像预处理、边缘检测、轮廓追踪、曲线拟合、数据绘图、文件读写及GUI交互等环节并涉及算法优化思路适合具备MATLAB基础、希望快速上手图像曲线数字化的读者。已有2019人学习下载可借助示例图片与脚本对照理解从灰度化、二值化到坐标提取、拟合绘图的完整流程并在此基础上修改参数适配自己的图像数据提升科研数据处理效率。1. 曲线图片识别程序把一张截图还原成可计算的坐标数据手里拿到一张论文截图或者实验仪器导出的曲线图想把上面的曲线还原成数值手动描点能累到怀疑人生。这个基于 MATLAB 的曲线图片识别程序就是干这件事的读入一张带坐标轴的曲线图自动提取曲线上的像素点再按坐标轴刻度换算成实际物理量最后输出可以直接拿去拟合、画图、做误差分析的数据。它适合做实验数据处理的学生、需要复现文献曲线的工程师以及任何手里只有图片、没有原始数据的人。整个项目就是一套 MATLAB 脚本加函数不需要额外工具箱也不需要配置环境打开就能跑。下面我按“能干什么、怎么跑、怎么改”的顺序把这份源码拆开讲一遍。2. 项目结构与运行链路从图片到数据的完整流程2.1 目录里都有什么拿到源码包先别急着点运行花两分钟把目录扫一遍后面改代码会顺很多。这个项目的结构很典型属于“一个主入口 若干功能函数 示例图片”的轻量级组织方式curve_recognition/ ├── main.m % 主入口脚本跑这个 ├── load_image.m % 图片读取与预处理 ├── calibrate_axis.m % 坐标轴标定核心 ├── extract_curve.m % 曲线像素提取核心 ├── pixel2data.m % 像素坐标转物理坐标 ├── plot_result.m % 结果可视化与对比 ├── samples/ % 示例图片 │ ├── sample1.png │ └── sample2.jpg └── README.mdmain.m是唯一需要手动运行的脚本其余都是被它调用的函数。这种拆法的好处是每个环节可以单独调试——比如曲线提取效果不好你可以只改extract_curve.m不用动主流程。常见做法是把每个函数都写成接受图像矩阵、返回处理结果的纯函数避免用全局变量传数据这样二次开发时替换某个环节不会牵连其他部分。2.2 主流程代码逐段拆解先看main.m的主干它把整个链路串起来% main.m - 曲线图片识别主入口 clc; clear; close all; % 1. 读取图片统一转成灰度图 imgPath samples/sample1.png; [imgGray, imgRGB] load_image(imgPath); % 2. 坐标轴标定手动或自动确定坐标轴范围 % 返回 x/y 方向的像素-物理量映射关系 axisInfo calibrate_axis(imgRGB); % 3. 提取曲线像素点返回像素坐标 N×2 矩阵 curvePixels extract_curve(imgGray, axisInfo); % 4. 像素坐标转物理坐标 data pixel2data(curvePixels, axisInfo); % 5. 可视化原图叠加识别结果 数据曲线 plot_result(imgRGB, curvePixels, data); % 6. 导出数据 writematrix(data, output_data.csv); fprintf(识别完成共 %d 个数据点已导出 output_data.csv\n, size(data,1));这段代码的逻辑很直白读图 → 标定 → 提曲线 → 转坐标 → 画图 → 导出。关键参数在axisInfo这个结构体里它至少包含四个字段x 轴起点像素、x 轴终点像素、x 轴对应的物理量范围、y 轴同理。extract_curve拿到灰度图和标定信息后只在坐标轴围成的矩形区域内搜索曲线像素避免把坐标轴本身、刻度线、图例误当成曲线。提示第一次跑建议用samples/sample1.png它的坐标轴清晰、曲线颜色单一最容易出正确结果。换成自己的图之前先把示例跑通确认 MATLAB 版本和路径没问题。2.3 坐标轴标定整个项目最容易被低估的一步calibrate_axis.m是精度天花板所在。它的任务是把“像素位置”和“物理数值”对应起来。常见做法有两种自动检测坐标轴边界或者手动点选。这个项目两种都支持默认走手动交互因为自动检测在坐标轴颜色浅、有网格线干扰时容易翻车。function axisInfo calibrate_axis(imgRGB) % 显示图片让用户依次点击 x 轴起点、x 轴终点、y 轴起点、y 轴终点 figure; imshow(imgRGB); title(请依次点击x轴左端 → x轴右端 → y轴下端 → y轴上端); [px, py] ginput(4); % 获取 4 个点击点的像素坐标 % 弹出输入框让用户填写对应的物理量数值 prompt {x轴起点值:,x轴终点值:,y轴起点值:,y轴终点值:}; dlgtitle 输入坐标轴物理量范围; answer inputdlg(prompt, dlgtitle, 1, {0,10,0,100}); axisInfo.xPixel [px(1), px(2)]; % x 方向两个标定点的像素列坐标 axisInfo.xValue str2double(answer(1:2)); % 对应的物理值 axisInfo.yPixel [py(3), py(4)]; % y 方向两个标定点的像素行坐标 axisInfo.yValue str2double(answer(3:4)); % 计算线性映射系数物理值 k * 像素 b axisInfo.kx diff(axisInfo.xValue) / diff(axisInfo.xPixel); axisInfo.bx axisInfo.xValue(1) - axisInfo.kx * axisInfo.xPixel(1); axisInfo.ky diff(axisInfo.yValue) / diff(axisInfo.yPixel); axisInfo.by axisInfo.yValue(1) - axisInfo.ky * axisInfo.yPixel(1); end这里有几个参数要留意。ginput(4)的顺序不能乱先点 x 轴的两个端点再点 y 轴的两个端点点错顺序会导致映射系数完全错误。inputdlg里填的数值要和点击位置严格对应——你点的是 x 轴左端就填那个位置代表的物理值。映射关系假设坐标轴是线性的对数坐标轴需要额外处理这个后面在避坑章节会讲。2.4 曲线提取颜色阈值与连通域筛选extract_curve.m负责从灰度图里把曲线像素抠出来。核心思路是曲线通常有颜色比如红色、蓝色而坐标轴和文字是黑色或灰色所以用颜色通道差异做阈值分割再按连通域大小筛掉噪点。function curvePixels extract_curve(imgGray, axisInfo) % 限定搜索区域坐标轴围成的矩形内部 xRange round(sort(axisInfo.xPixel)); yRange round(sort(axisInfo.yPixel)); roi imgGray(yRange(1):yRange(2), xRange(1):xRange(2)); % 自适应阈值二值化提取暗色曲线 level graythresh(roi); bw imbinarize(roi, level); % 去除小面积噪点文字、刻度残留 bw bwareaopen(bw, 30); % 按列扫描每一列取曲线像素的行均值作为该 x 位置的 y [rows, cols] find(bw); curvePixels zeros(numel(unique(cols)), 2); idx 1; for c unique(cols) r rows(cols c); curvePixels(idx, :) [c xRange(1) - 1, mean(r) yRange(1) - 1]; idx idx 1; end endbwareaopen(bw, 30)里的 30 是面积阈值单位是像素。如果你的曲线很细、断点多这个值要调小如果噪点多就调大。按列取行均值是一种简化处理适合单值函数曲线每个 x 只有一个 y。如果曲线有回折、一个 x 对应多个 y这种按列扫描就会丢信息需要改成按连通域骨架提取。这个取舍在二次开发时要根据实际图片决定。3. 跑起来环境准备、参数调整与结果验证3.1 环境要求和启动步骤这个项目对 MATLAB 版本要求不高R2016b 以上都能跑因为用到的imbinarize、bwareaopen、writematrix都是图像处理工具箱和基础 MATLAB 里的函数。如果你没有图像处理工具箱graythresh和imbinarize会报错替代方案是用im2bw加手动阈值代码改动量很小。启动步骤就三步把curve_recognition文件夹放到 MATLAB 当前工作目录或者用addpath把路径加进去。在命令行窗口输入main回车。弹出的图片窗口里按提示点击坐标轴四个端点然后在输入框填物理量范围。跑完之后工作区会多出data变量当前目录会生成output_data.csv。plot_result会弹两个图一个是原图上叠加红色识别点用来肉眼检查提取是否准确另一个是转换后的数据曲线用来确认坐标换算没跑偏。3.2 关键参数怎么调项目里能调的参数不多但每一个都直接影响结果我按重要性排一下参数位置参数名默认值作用调整建议extract_curve.m面积阈值30过滤小噪点曲线断点多调小噪点多调大extract_curve.m二值化方法graythresh自动阈值背景不均时改手动阈值calibrate_axis.m标定点数4坐标轴端点对数轴需改映射公式main.m输出文件名output_data.csv导出路径按需改面积阈值是最常动的。示例图里曲线连续、噪点少30 够用。换成手机拍的实验图光照不均会产生大量小噪点这时候要么把阈值提到 100 以上要么在二值化之前加一步中值滤波。我一般会在extract_curve开头加一行roi medfilt2(roi, [3 3]);对椒盐噪声效果很明显。3.3 怎么判断识别结果靠不靠谱跑完不要只看数据导出了就完事至少做两个验证。第一看plot_result叠加图红色识别点应该严丝合缝盖在原始曲线上如果偏上或偏下说明坐标轴标定点击位置不准重新跑一次calibrate_axis。第二拿几个已知点核对比如曲线明显经过 (2, 50)看导出的 CSV 里 x2 附近对应的 y 是不是接近 50。偏差超过 2% 就要查标定环节。还有一个隐藏验证点数据点数量。如果导出的点数远少于曲线实际跨度说明二值化把部分曲线当噪点滤掉了回去调面积阈值。如果点数异常多、密密麻麻可能是把网格线也提取进来了需要在 ROI 里排除网格线颜色。4. 避坑与常见问题那些让我重跑好几遍的细节4.1 点击标定点时手抖结果整体偏移现象识别出的曲线整体平移形状对但数值全错。原因ginput点击时没有放大图片端点位置偏了几个像素而映射系数对像素位置很敏感。解决在calibrate_axis里imshow之后加zoom on;点击前先滚轮放大到能看清刻度再点。或者改用ginput之前先axis image保证像素纵横比一致。4.2 彩色曲线被当成背景滤掉现象二值化后曲线消失只剩坐标轴。原因imgGray是灰度图如果曲线颜色和背景灰度接近比如浅蓝色曲线在白底上graythresh算出的阈值会把曲线归到背景。解决不要用灰度图做分割改用 RGB 通道差异。比如红色曲线用imgRGB(:,:,1) - imgRGB(:,:,2)突出红色分量再二值化。这个改动在extract_curve开头几行把输入从imgGray换成imgRGB即可。4.3 对数坐标轴直接套线性公式数据全废现象x 轴是对数刻度识别出的数据在低值区严重压缩。原因calibrate_axis里用的是线性映射y kx b对数轴不成立。解决在axisInfo里加一个xScale字段标记linear或logpixel2data里根据标记选择映射公式。对数轴映射是物理值 10^(k * 像素 b)标定时取两个点的对数值来算 k 和 b。4.4 曲线有回折按列扫描丢了一半数据现象闭合曲线或 S 形曲线识别后只剩上半段。原因extract_curve按列取行均值一列里多个曲线像素被平均成一个点。解决改成按连通域提取骨架用bwmorph(bw, skel, Inf)细化后对每个连通域单独按路径顺序输出点。这个改动稍大但对付复杂曲线是必须的。4.5 导出的 CSV 用 Excel 打开乱码现象writematrix写的文件在 Excel 里中文列名乱码。原因MATLAB 默认写 UTF-8Excel 在部分区域设置下按 GBK 解析。解决要么导出时不写表头要么用writetable配合Encoding,GBK参数。最省事的办法是导出纯数值矩阵列名在 MATLAB 里自己记着。5. 二次开发把这套脚本改成能批量处理的工具跑通单张图片之后最自然的想法就是批量处理。我一开始也是一张一张跑后来发现实验有几十张图手动点坐标轴点到崩溃。下面说几个改造方向按投入产出比排序。第一个改造是把交互式标定改成半自动。思路是先用边缘检测找坐标轴的大致位置把候选端点画出来让用户确认而不是从零点击。具体做法是在calibrate_axis里加一段edge(imgGray, Canny)加hough找直线取最长的水平线和垂直线作为坐标轴候选然后用ginput(2)只让用户点两个对角确认。这样每张图的交互从四次点击降到两次批量时效率翻倍。第二个改造是参数配置化。把面积阈值、二值化方法、是否滤波这些参数抽到一个config.m里主脚本开头run(config.m)加载。这样换一批图片时只改配置文件不动函数代码。我一般会把配置写成结构体cfg.threshold 30; cfg.filter true;然后在各函数里通过参数传入避免全局变量。第三个改造是加一个批量入口batch_main.m用dir(samples/*.png)遍历文件夹对每张图跑一遍流程结果分别存成同名 CSV。这里有个坑批量时不能用交互式ginput所以要么提前把每张图的标定参数存成一个 mat 文件要么改成全自动标定。我的做法是第一次跑批量时仍然交互但把axisInfo存下来第二次跑就直接加载省去重复点击。% batch_main.m - 批量处理入口 files dir(samples/*.png); for i 1:numel(files) imgPath fullfile(files(i).folder, files(i).name); [imgGray, imgRGB] load_image(imgPath); % 标定参数缓存存在则加载不存在则交互并保存 cacheFile [files(i).name, _axis.mat]; if exist(cacheFile, file) load(cacheFile, axisInfo); else axisInfo calibrate_axis(imgRGB); save(cacheFile, axisInfo); end curvePixels extract_curve(imgGray, axisInfo); data pixel2data(curvePixels, axisInfo); [~, name, ~] fileparts(files(i).name); writematrix(data, [name, _data.csv]); fprintf(已处理 %s%d 个点\n, files(i).name, size(data,1)); end这段代码的关键是标定缓存机制。第一次跑批量时每张图还是要手动点但axisInfo存下来之后后续调参重跑就不用再点了。对于同一台仪器导出的图片坐标轴位置往往完全一致这时候甚至可以只标定第一张后面全部复用同一个axisInfo效率提升非常明显。最后一个改造方向是精度验证自动化。手动核对几个点毕竟靠眼睛我后来加了一个validate.m思路是把识别出的数据用polyfit拟合一条平滑曲线再计算原始曲线像素到拟合曲线的平均距离超过阈值就报警。这样批量处理时能自动筛出识别失败的图片不用一张张看。阈值我一般设在 2 到 3 个像素具体看图片分辨率。从那以后我每次拿到新的曲线图片都强制先跑一遍示例图确认环境再拿一张已知数据的图验证精度最后才上批量。这个习惯帮我省了很多“数据导出了但全是错的”的后悔药。希望这套拆解能帮到你源码包里的示例图跑通之后剩下的就是按自己的图片特点调参数了。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑