扫描电镜报告PDF解析:从pdfplumber到颗粒尺寸自动统计
2026/9/18 21:51:45 网站建设 项目流程

简介:这份资料是扫描电镜(SEM)实验报告的完整PDF版本,面向材料科学、生物、地质等专业需掌握电子显微分析技术的学生与实验人员,可作为课程实验报告撰写、考试复习或实验课前预习的参考。报告包含实验目的、要求、原理、步骤、数据总结及教师意见栏,系统梳理了真空系统、电子束系统、成像系统三大核心组成,并介绍形貌衬度与原子序数衬度的实际应用,帮助读者理解电子束与样品相互作用的次级电子、背散射电子、X射线等信号产生机制。文档中对纤维区、放射区、瞬断区等断口特征的观察记录,展示了如何借助SEM区分不同微观组织结构,对撰写实验报告或准备相关课程答辩具有直接参考价值。资源为单份PDF文件,共1个文件,包体约402KB,轻量易用。目前已有166人学习下载,可作为扫描电镜实验教学与自学的配套材料。

1. 扫描电镜实验报告.pdf:数据躺在 PDF 里,取不出来就是白做

实验室拿到一份扫描电镜实验报告 PDF,关心的是能不能交差、能不能发文章;IT 这边真正头疼的是后面的事:加速电压、工作距离、放大倍数散在页面表格里,显微图被封成压缩位图,颗粒尺寸只能对着标尺数像素。材料数据入库、批量质检、把图像喂给下游分析脚本时,这份 PDF 就是黑盒。下面这条路径能把扫描电镜实验报告.pdf 拆成结构化字段、原始显微图、标尺换算系数和颗粒统计结果,拆完还能交叉验证。适合批量处理 SEM 报告、被 PDF 解析反复折磨的工程师和数据工程师。

2. 解析扫描电镜报告 PDF:先拆文本参数表,再拆图像

2.1 先弄清 SEM 报告 PDF 的版式和参数落点

ZEISS、Thermo Fisher、Hitachi、JEOL 各家生成的扫描电镜报告版式差异不小,但信息落点有共性:第一页通常是样品信息加成像参数表,下面排一到四张显微图,后面是能谱或更大倍率的附图。成像参数表里高频出现的键是「加速电压 EHT/HV」「工作距离 WD」「放大倍数 Mag」「探测器 Detector(SE2/BSD/InLens)」「扫描速度」。键名和值之间可能有冒号、制表符,也可能被拆进表格的两个单元格,解析必须兼容这两种布局。

解析路径上建议直接在上游 PDF 上做,先别想着 pdf转word。转 Word 会把表格打散、图片二次压缩,标尺文字变成文本框还会错位;转曲再导出的路线损失更大。PDF 原生文本层只要不是扫描件,字段就是完整保真的,直接解析效率和准确率都高得多。

2.2 用 pdfplumber 优先抽参数表,无边框时退回文本行

解析参数表我习惯分三步:pdfplumber 抽表格、无边框时退回文本行、字段级正则收敛。第一步先直接看表格解析的实际效果:

import pdfplumber with pdfplumber.open("扫描电镜实验报告.pdf") as pdf: for pno, page in enumerate(pdf.pages, 1): for row in page.extract_tables(): print("第{}页:".format(pno), row)

extract_tables 默认策略对无边框表格不友好,返回空列表时先别急着换库,显式传 table_settings 往往能救回来,专门处理竖线存在、横线缺失的"半线框"表格:

settings = { "vertical_strategy": "lines", "horizontal_strategy": "text", "snap_tolerance": 3, "join_tolerance": 3, } rows = page.extract_tables(settings)

参数说明:vertical_strategy 指定竖线来源,lines 表示只认线条;horizontal_strategy 用 text 是让 pdfplumber 按文字行推断横线位置。snap_tolerance 和 join_tolerance 控制线段吸附与合并的像素容差,单位是 pt,报告缩放比例异常、线对不齐时,把 3 调到 5~8 一般能解决。pdfplumber 逐页解析几十页会明显偏慢,所以它只负责把表格结构看清,字段提取交给下一节。

2.3 用 PyMuPDF 按块取文本,正则收敛字段

我一般第二遍用 PyMuPDF(fitz)按块取文本,再用正则把字段收敛成字典,速度比 pdfplumber 快一个量级:

import fitz import re FIELD_PATTERNS = { "accelerating_voltage_kv": re.compile( r"(?:加速电压|EHT|HV)\s*[::]?\s*([\d.]+)\s*k?V", re.I), "working_distance_mm": re.compile( r"(?:工作距离|WD|Work\s*Dist\.?)\s*[::]?\s*([\d.]+)\s*mm", re.I), "magnification": re.compile( r"(?:放大倍数|Mag)\s*[::]?\s*([\d,]+)\s*[×xX]?", re.I), } doc = fitz.open("扫描电镜实验报告.pdf") page = doc[0] text = page.get_text("text") for field, pat in FIELD_PATTERNS.items(): m = pat.search(text) if m: print(field, "=", m.group(1).replace(",", ""))

逻辑说明:get_text("text") 返回整页纯文本,正则先匹配键名再取数值,避免正文里恰好出现相似单位;group(1) 里的千分位逗号统一去掉再转 float,后续 JSON 序列化才不会有字符串混入。常用字段对照表直接按这个建字典:

字段常见键名单位正则要点
加速电压加速电压 / EHT / HVkV键名后允许全半角冒号与空格
工作距离工作距离 / WD / Work Dist.mm必须先锁键名再取值
放大倍数放大倍数 / Mag×兼容 1,000× 千分位写法
探测器探测器 / Detector只取 2~6 位纯字母

提示:少数报告把参数表做成了图片,get_text 抽不到任何内容。这种情况只能对图像区域做 OCR,用 Tesseract 的中英文混合模型识别后,再过一遍同一张字段表。

3. 提取扫描电镜图像并做歪斜校正纠偏:先拿到干净位图

3.1 用 extract_image 取原始位图,先算有效 DPI

pdfplumber 也能取图,但要绕页面对象和裁剪矩阵,批量场景效率不如 PyMuPDF。取图首选 doc.extract_image:

import fitz doc = fitz.open("扫描电镜实验报告.pdf") page = doc[0] for i, info in enumerate(page.get_images(full=True)): xref, smask, w, h = info[0], info[1], info[2], info[3] base = doc.extract_image(xref) fname = "micrograph_{}.{}".format(i, base["ext"]) with open(fname, "wb") as fh: fh.write(base["image"]) eff_dpi = w / (page.rect.width / 72.0) print(fname, base["ext"], w, h, "有效DPI约", round(eff_dpi))

这里的关键是"有效 DPI"的计算思路。PDF 页面尺寸单位是 pt,1 pt 等于 1/72 英寸;一张 900×800 像素的图被排版成 4.5×4 英寸,有效 DPI 就是 200 上下。很多 SEM 报告的显微图嵌入时接近 300 DPI,但页面上显示宽度只有七八厘米,直接导出页面图片会把分辨率压到 150 DPI 以下,颗粒边界发糊,标尺像素长度也跟着失真。所以取图必须走 extract_image,拿嵌入的原始 JPEG/PNG 流,而不是页面截图。

参数说明:get_images(full=True) 返回的 info 里,xref 是图像对象编号,smask 是透明度遮蔽层的 xref,w、h 是像素宽高。extract_image(xref) 返回 dict,二进制内容在 ["image"],格式后缀在 ["ext"]。有效 DPI 低于 150 的报告图,后面测出来的尺寸只当参考,别进正式结论。

3.2 歪斜校正纠偏:旋转角小于 0.15 度就别动

PDF 歪斜校正纠偏这个操作,落到扫描电镜报告上通常有两个来源:纸质报告二次扫描时页面转了零点几度,以及 PDF 编辑器导出图片时带的旋转残差。角度虽小,但标尺像素长度会按 cos 缩水,颗粒直径同样带偏差。用 OpenCV 做整体纠偏:

import cv2 import numpy as np def deskew(gray): th = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] coords = np.column_stack(np.where(th > 0)) if coords.shape[0] < 3: return gray angle = cv2.minAreaRect(coords)[-1] if angle < -45: angle = 90 + angle if abs(angle) < 0.15: return gray h, w = gray.shape M = cv2.getRotationMatrix2D((w / 2, h / 2), angle, 1.0) return cv2.warpAffine(gray, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE)

逻辑说明:Otsu 二值化后把所有前景像素坐标收集起来,minAreaRect 算最小外接矩形的倾斜角;负角换算到 -45~45 度区间,小于 0.15 度直接跳过,避免重采样把本来就正的图搞糊。重采样用 INTER_CUBIC 比 INTER_NEAREST 平滑;borderMode 用 REPLICATE 复制边缘像素,防止旋转后四角变黑——黑边会被后面的标尺检测误判成干扰线。干扰项过滤维度按像素面积和宽高比来:

干扰对象典型尺寸过滤规则
仪器 logo100×100 以下宽或高低于 160 直接丢弃
页眉水印文字细长条宽高比大于 6 丢弃
能谱图与显微图接近按页面显示位置过滤
正常 SEM 显微图方形或 4:3保留,进入标尺校准

3.3 取图时记录显示矩形和旋转标志

取图顺手把 page.get_image_rects(xref) 的显示矩形也存下来。标尺文字通常紧贴图像下边缘,用矩形 Y 坐标加偏移去匹配文本块,比全局 OCR 定位省事得多。旋转标志同样落盘,第 5 章人工抽检要靠它定位问题报告。

4. 标尺校准与颗粒尺寸统计:像素怎么换算成微米

4.1 标尺识别的两种做法:OCR 读数值,Hough 找线段

标尺识别两条路:OCR 读出 "10 µm" 这类数值文字(Tesseract 单行模式 psm 7 命中率较好),图像底部区域用 Hough 直线检测找最长水平线段作为像素长度。两条路结合用,数值走 OCR,长度走直线检测:

h, w = gray.shape roi = gray[int(h * 0.9):, :] # 标尺常驻图底边,只看底部10% edges = cv2.Canny(roi, 50, 150) lines = cv2.HoughLinesP(edges, 1, np.pi / 180, threshold=80, minLineLength=int(w * 0.08), maxLineGap=2) longest = max(lines, key=lambda l: abs(l[0][2] - l[0][0])) x1, y1, x2, y2 = longest[0] scale_bar_pix = abs(x2 - x1) # 标尺像素长度

参数说明:ROI 只取底部 10% 是经验值,SEM 标尺几乎总在图下边缘或右下角,这样能避开颗粒纹理被误认为水平线。minLineLength 设为图像宽度的 8%,短于这个长度不可能是标尺。maxLineGap=2 允许标尺中间的细微断线拼回一条。若检出的最长线段明显短于标尺文字宽度,多半是标尺颜色偏灰、Canny 阈值太紧,把 50/150 改成 30/100 再看。

4.2 像素到微米的换算系数,以及闭环校验怎么做

换算关系只有一句:像素到微米的系数等于标尺物理长度除以像素长度。OCR 数值和 Hough 像素长度都拿到后,换算和合理性检查一次算完:

scale_text = ocr_scale_bar_text(roi) # 复用Tesseract封装,返回单行文本 physical_um = float(re.search(r"([\d.]+)\s*(?:µm|μm|um)", scale_text).group(1)) um_per_px = physical_um / scale_bar_pix # 像素到微米的换算系数 fov_width_um = w * um_per_px # 整幅图的物理视场宽度 print("换算系数:", round(um_per_px, 4), "µm/px, 视场宽度:", round(fov_width_um, 2), "µm")

参数说明:OCR 读出的标尺文字要事先做单位归一化,报告里 μm、µm 甚至全角符号都有,正则写宽容易误吃相邻字符,建议先替换再匹配。视场宽度是副产品,用来做快速合理性检查:放大倍数标 5000× 时视场宽度一般落在 20~100 µm,超出量级就要怀疑 OCR 把 "5.0" 读成了 "50"。

真正的闭环校验不靠公式反推,而是拿已知周期的标准样品报告做端到端对比:同一条处理链导出标准样品的统计结果,和厂商标称值比,误差 5% 以内说明"下载-纠偏-标尺-分割"整条链路是通的。

4.3 Otsu 分割加等效直径做颗粒尺寸统计

分割和统计的骨架代码:

def measure_particles(gray, um_per_px, min_area_px=80): blur = cv2.medianBlur(gray, 5) th = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] contours, _ = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) out = [] for c in contours: area_px = cv2.contourArea(c) if area_px < min_area_px: continue out.append({ "area_um2": round(area_px * um_per_px ** 2, 2), "eq_diameter_um": round(2 * (area_px / 3.14159) ** 0.5 * um_per_px, 3), }) return out

逻辑说明:二次电子像里颗粒相对背景是亮目标,用 BINARY_INV 反转;要统计孔洞时改成 BINARY 即可。Otsu 自动选阈值,同批次报告通常不用手调。min_area_px=80 用来滤噪点,300 DPI 下 80 像素约为 0.014 平方微米,正好压掉电荷噪声。粘连颗粒会被当成一个大目标导致直径偏大,纯粒径分布场景要加分水岭分割;先记面积分布反而是更稳的中间产物。测量常见误判与对策:

现象原因对策
直径整体偏大颗粒粘连成团改报面积分布,或加 watershed
直径整体偏小min_area 切掉小颗粒下调到 40~60 重跑
只有大块没细节JPEG 压缩太狠回 3.1 查有效 DPI
标尺像素和文字对不上底部 ROI 混入页码ROI 改右下 20% 区域重检

5. 批量解析扫描电镜报告 PDF 的收尾技巧:JSON 落地、抽检、旋转角留痕

5.1 一条命令从 PDF 目录到 JSON

把前面的逻辑收进 sem_report_parser.py,暴露 CLI,命令行用 --in 指定 PDF 目录、--out 指定输出目录:

import argparse, json, pathlib ap = argparse.ArgumentParser() ap.add_argument("--in", dest="in_dir", required=True) ap.add_argument("--out", dest="out_dir", default="./parsed") args = ap.parse_args() results = [] for pdf_path in sorted(pathlib.Path(args.in_dir).glob("*.pdf")): result = parse_one(str(pdf_path)) # 返回字段/图像/换算系数/统计 results.append(result) pathlib.Path(args.out_dir).mkdir(exist_ok=True) out_json = pathlib.Path(args.out_dir) / "reports.json" out_json.write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding="utf-8") print("已生成", out_json, "共", len(results), "份报告")
python sem_report_parser.py --in "E:/SEM/2025/pdf" --out "E:/SEM/2025/json"

reports.json 每条记录包含报告名、解析字段、图像文件名、标尺像素长度、um_per_px 换算系数和颗粒统计数组。字段与统计分层存放,Pandas 读的时候不用做二次清洗。

5.2 人工抽检和旋转角留痕

验证时把等效直径画成红圈叠加回原图,用任一 pdf 编辑器打开原报告对照,手工量三五个颗粒,误差 ±5% 以内通过。歪斜校正生效时,把 deskew 返回的 angle 写进 JSON;抽检对不上的报告先查 angle 是否非零,再看 OCR 读出的标尺数值有没有把 "5 µm" 读成 "50 µm"。

批量收尾最值得留的就是中间产物:有效 DPI、angle、标尺像素长度全部落盘,别只存最终统计。下次复跑或下游复核时直接从 JSON 看每一步的取值,不用重新解析一遍 PDF。angle 非零的报告单独列一个清单,作为人工复核队列的入口;这个清单配合报告名和图像序号命名,长期归档也不怕丢上下文。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询