news 2026/10/8 1:05:52

用Python和dlib自建人脸识别系统:从录入到比对全流程解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python和dlib自建人脸识别系统:从录入到比对全流程解析

简介:这是一套基于Python与OpenCV的人脸录入与识别项目,核心借助dlib机器学习库完成人脸特征建模,并配套Tkinter图形界面,可录入人脸及中英文姓名信息。资源面向有一定Python基础、希望快速上手人脸识别实战的开发者,适合考勤打卡、实验教学、个人身份验证等场景;代码按采集、训练、识别模块拆分,便于阅读和二次改造。包内共25个文件,容量约96MB,主体为9个Python脚本与9张示例图片,另有2个dlib预训练数据文件、字体、说明文档、演示PPT等辅助内容;脚本覆盖摄像头采集人脸、特征提取、特征库导出CSV、实时识别、单张人脸识别等完整步骤,目录结构清晰。当前已有234人学习下载。通过该资源可获得可直接运行的交互式界面代码、模型文件与配套样例,沿示例逐步改造即可搭建一套可演示的人脸识别应用,并理解dlib人脸检测与特征比对的关键思路。

1. 为什么自己搭一套Python人脸识别:门禁机背后的黑匣子值得打开

人脸识别门禁机、考勤机到处都在用,但多数人只把它当成一个“黑匣子”,不知道它内部怎么录入、怎么比对、阈值设了多少、数据存到哪里。用Python、OpenCV和dlib自己搭一套人脸录入与识别系统,半小时就能跑通一个可用原型,而且整条链路——人脸检测、关键点对齐、128维特征提取、距离比对——每个环节都握在自己手里。dlib是老牌机器学习库,用它不需要自己训练模型,下载官方预训练模型就能干活;OpenCV负责摄像头读取和图像处理,各管一段。这套方案特别适合想做门禁/考勤原型的工程师、做课程设计的学生,以及想把“人脸识别”四个字真正落地成代码的入门者。

2. 环境搭建:Python、OpenCV、dlib的版本搭配与两个模型文件

2.1 选型理由:OpenCV管图像,dlib管人脸算法

先回答一个绕不开的问题:OpenCV自己就带人脸检测,为什么不直接用它?OpenCV内置的Haar Cascade和LBP检测器对正脸效果尚可,但角度稍偏、光线一变就漏检,而且它不提供人脸关键点,也不提供特征描述子。也就是说,OpenCV可以帮你“看到”画面,但很难帮你“认出”人。

dlib在这个方案里干两件大事:一是用HOG或CNN检测器做人脸检测——HOG版本在CPU上也能跑得动,实时性比OpenCV自带的级联检测器更稳;二是提供68点关键点模型和128维人脸特征模型。前者标记眼睛、鼻子、嘴巴的位置,后者把一张人脸压缩成128个浮点数,同一人的特征向量距离近,不同人的距离远。两者的分工很清楚:OpenCV处理图像输入输出和绘制结果,dlib负责“认脸”这一层。

2.2 最小安装组合:虚拟环境、pip命令与编译失败时的退路

dlib在Windows上经常需要源码编译,如果编译环境不齐会卡很长时间甚至报错。我的习惯是:先用Python 3.8或3.9创建独立虚拟环境,这两个版本对dlib预编译包的支持最稳。Python 3.10以上或最新版本,dlib的wheel往往还没跟上,就可能被迫走源码编译老路。

# 创建虚拟环境,Python 3.9 是我用下来最稳的组合 python -m venv face_env # Windows 激活虚拟环境 face_env\Scripts\activate # Linux / macOS 激活虚拟环境 source face_env/bin/activate # 安装两个核心库 pip install opencv-python pip install dlib

代码解释:python -m venv face_env创建独立环境,避免把依赖装进系统Python把环境搞乱。Windows和Linux的激活命令不同,激活成功后命令行提示符前面会出现(face_env)字样,看到这个再执行pip安装。opencv-python是OpenCV的官方Pypi包,包含cv2模块;dlib在多数平台会优先安装预编译wheel,安装过程几秒到几十秒不等。如果它开始“Building wheel for dlib”,说明正在源码编译,这时去吃个饭都未必编完。

如果编译失败,常见退路是找与你Python版本和操作系统匹配的dlib预编译whl文件,用pip直接安装:

# 文件名里的 cp39 对应 Python 3.9,请按自己的实际版本选择 pip install dlib-xxx.whl

参数说明:whl文件必须和Python版本、系统位数严格对应,装错版本会报“not supported on this platform”。装完后立刻验证环境,别急着跑业务代码。

2.3 验证环节:加载两个模型文件并跑通第一张人脸检测

dlib需要两个预训练模型文件,官方发布页可以找到,下载后建议统一放在models/目录。这两个文件是整套系统的“算法黑匣子”,它们决定检测和特征提取的精度:

模型文件用途核心输出
shape_predictor_68_face_landmarks.dat定位人脸68个关键点眼睛、鼻子、嘴巴坐标
dlib_face_recognition_resnet_model_v1.dat提取128维人脸特征同一人距离近,不同人距离远

环境验证脚本如下,能同时确认OpenCV、dlib、两个模型文件是否都正常:

import cv2 import dlib print("OpenCV version:", cv2.__version__) print("dlib version:", dlib.__version__) detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") face_rec = dlib.face_recognition_model_v1( "models/dlib_face_recognition_resnet_model_v1.dat") print("模型加载成功")

这段代码干了三件事:创建HOG人脸检测器、加载关键点模型、加载特征提取模型。如果某个模型文件路径不对或下载不完整,第三行就会抛异常。注意模型文件有几十MB,如果下载下来的文件只有几KB,加载时一定会报错,别怀疑自己的代码,先去重新下载模型文件。

3. 人脸录入:摄像头采集、68点对齐与128维特征入库

3.1 录入流程拆解:选帧、裁剪、质量控制三步

录入是整个识别系统的地基。识别阶段能不能认出人,很大程度上取决于录入阶段的样本质量。录入不是随便按几下快门,而是要从摄像头画面中挑出合格的人脸,提取成特征向量,再存进库里。整个过程分三步:选帧、裁剪、提取特征。选帧时评估人脸框大小和清晰度,人脸太小的直接丢弃;裁剪时只保留人脸区域,减少背景干扰;提取特征用dlib的128维模型,把图像变成一组数字。

这里有一个容易被忽视的点:重复样本问题。如果连续几帧拍到的是同一姿势,录进去的特征几乎一模一样,对提升识别鲁棒性没有帮助。我的做法是每帧最多保存一张,并且每录一张换一个姿势或角度,让人脸特征库尽量覆盖不同视角。还有一个“后悔药”技巧:录入时同时保存原始人脸图和对应的.npy特征文件,后续如果发现样本质量差,可以直接删掉对应文件重新录,不用动整个库。

3.2 关键点定位与对齐:68个点让系统知道眼睛在哪

dlib的关键点模型输出68个人脸坐标点,其中36和45分别是左眼外眼角和右眼外眼角,这两点计算人脸倾斜角度最可靠。关键点的价值不只是画图好看,而是让特征提取模型拿到一个“正”的人脸。先看一段可视化代码,确认模型工作正常:

def draw_landmarks(frame, shape): # 把68个关键点画在图像上,方便调试 for i in range(68): point = shape.part(i) cv2.circle(frame, (point.x, point.y), 1, (0, 255, 0), -1) # 标出左眼外眼角36和右眼外眼角45 cv2.circle(frame, (shape.part(36).x, shape.part(36).y), 3, (0, 0, 255), -1) cv2.circle(frame, (shape.part(45).x, shape.part(45).y), 3, (0, 0, 255), -1) return frame

这段代码把预测出来的人脸关键点逐一点在画面上,红色标记的是两只眼睛的外眼角,用来直观判断关键点定位准不准。

提示:dlib的compute_face_descriptor在提取特征时,会利用这些关键点对人脸做内部归一化对齐。所以录入和识别代码里不一定非要手动做仿射变换,直接把关键点传给特征提取函数即可,dlib会完成姿态纠正。

手动对齐不是必须的,但如果你想把采集到的人脸图片存档,或者后续要重新训练模型,建议在保存前先把人脸旋转到水平。用两眼连线的角度做旋转是最轻量可靠的做法,OpenCV的仿射变换函数就能完成。

3.3 特征提取与存储:把128维向量写进CSV

录入代码要一次性完成“采集样本+提取特征+保存结果”。下面的代码打开摄像头,连续采集20张合格人脸,每张都提取128维特征并保存:

import os import cv2 import dlib import numpy as np detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") face_rec = dlib.face_recognition_model_v1( "models/dlib_face_recognition_resnet_model_v1.dat") person_name = "zhangsan" save_dir = os.path.join("dataset", person_name) os.makedirs(save_dir, exist_ok=True) cap = cv2.VideoCapture(0) count = 0 while count < 20: ret, frame = cap.read() if not ret: break # dlib 内部按 RGB 顺序处理图像,OpenCV 默认读进来是 BGR rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) faces = detector(rgb, 1) # 每帧最多录入一张脸 if len(faces) == 0: continue face = faces[0] if face.width() < 80: continue shape = predictor(rgb, face) descriptor = face_rec.compute_face_descriptor(rgb, shape) feature = np.array(descriptor) crop = frame[face.top():face.bottom(), face.left():face.right()] cv2.imwrite(os.path.join(save_dir, f"{count}.jpg"), crop) np.save(os.path.join(save_dir, f"{count}.npy"), feature) count += 1 cv2.putText(frame, f"captured: {count}/20", (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow("capture", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

代码逻辑说明:每帧先转成RGB再送入检测器,因为OpenCV默认读入是BGR,而dlib按RGB顺序处理,不转换的话特征会跑偏。face.width() < 80过滤掉太远太小的人脸,这个值按你的摄像头分辨率调整。compute_face_descriptor返回的是dlib的向量对象,转成numpy数组方便后续计算距离。每张图的特征存成.npy,同时存一张裁剪图,方便你事后检查录入的样本长什么样。20张是起步数量,实际门禁入库我一般建议30到50张,覆盖正面、左右转头、抬头低头几个角度。

采集完成后,把散落的npy文件汇总成一个CSV,识别时加载这个文件就行:

import glob import csv import os import numpy as np def save_features_to_csv(csv_path="face_db.csv"): rows = [] # dataset/人名/xxx.npy 的结构 for npy_path in glob.glob(os.path.join("dataset", "*", "*.npy")): person = os.path.basename(os.path.dirname(npy_path)) feature = np.load(npy_path) row = ",".join([f"{v:.6f}" for v in feature]) rows.append(f"{person},{row}") with open(csv_path, "w", encoding="utf-8") as f: f.write("\n".join(rows)) print(f"已写入 {len(rows)} 条特征") def load_face_db(csv_path="face_db.csv"): db = {} with open(csv_path, encoding="utf-8") as f: for line in f: parts = line.strip().split(",") name = parts[0] feature = np.array([float(x) for x in parts[1:]]) db.setdefault(name, []).append(feature) return db

说明:CSV里每行是一个人脸特征,第一列是人名,后面128个浮点数用逗号分隔。加载时按人名聚合成列表,因为有人录了多张样本,识别时可以和这个人的所有样本都比一遍。选择CSV而不是SQLite,是因为人脸样本量通常只有几十到几百条,CSV简单直观,出错时用文本编辑器就能改。

4. 识别系统:特征距离比对、阈值设定与实时主循环

4.1 识别原理:欧氏距离和0.5阈值背后的权衡

人脸识别的本质不是“图像匹配”,而是“特征向量距离判断”。dlib的128维特征把一张人脸映射到高维空间,同一个人在不同表情、不同角度下特征距离小,不同人的特征距离明显大。判断标准是欧氏距离:

distance = np.linalg.norm(feature_a - feature_b)

距离小于阈值判为同一人,大于阈值判为陌生人。阈值怎么选,直接影响系统的实用体验:

阈值取值误识率(别人被认成你)拒识率(你没被认出来)适用场景
0.4低高保密门禁,宁可拒也不放错
0.5中等中等dlib官方示例常用值
0.6高低考勤机,优先保证识别通过

在正式使用前,不要迷信任何默认阈值。每台摄像头的安装角度、光线条件、人脸距离都不一样,阈值要拿到现场调。最简单的方法是录一批“本人”和“非本人”样本,分别算出距离,看两组数据的分布区间。如果本人距离普遍在0.35左右、非本人在0.7左右,0.5就是合适的中间点。如果两组数据有重叠,说明录入样本质量不够,先去补样本,而不是继续调阈值。

4.2 识别主循环代码:摄像头读帧、比对、画框、输出

识别部分是一个实时循环,持续从摄像头读帧,检测人脸、提取特征、和库里所有特征比对,然后把结果画在画面上:

import cv2 import dlib import numpy as np # 模型加载 detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") face_rec = dlib.face_recognition_model_v1( "models/dlib_face_recognition_resnet_model_v1.dat") # db 由上一章的 load_face_db("face_db.csv") 得到 db = load_face_db("face_db.csv") def find_match(feature, db, threshold=0.5): best_name = "unknown" best_dist = float("inf") for name, feats in db.items(): for feat in feats: dist = np.linalg.norm(feature - feat) if dist < best_dist: best_dist = dist best_name = name return best_name if best_dist < threshold else "unknown", best_dist cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() if not ret: break rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) faces = detector(rgb, 1) for face in faces: shape = predictor(rgb, face) descriptor = face_rec.compute_face_descriptor(rgb, shape) feature = np.array(descriptor) name, dist = find_match(feature, db, threshold=0.5) x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom() cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, f"{name} {dist:.2f}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.imshow("face recognition", frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()

逻辑说明:find_match函数遍历库里所有人的所有样本特征,取距离最小的那个作为候选结果,如果最小距离仍大于阈值,就判为unknown。dist输出的数值可以用来观察系统当前的判断余量:如果某个人每次识别距离都在0.3以下,说明样本充足;如果总是贴着0.48徘徊,识别就很危险,应该重新录入。

参数说明:detector(rgb, 1)的第二个参数表示上采样次数,1表示把图像放大一倍再检测,小脸检测率会提高,但速度也明显变慢。摄像头画面里人脸本来就大时,用0即可省下性能。threshold=0.5是默认值,实际要按4.1的方法现场调整。

4.3 工程化补丁:结果平滑、多人并列与FPS统计

实时识别跑起来后,你会发现三个工程问题:名字跳变、多人漏检、帧率没有感知。名字跳变是最常见的——同一个用户正对着摄像头,名字偶尔从“zhangsan”跳成“unknown”,过一帧又跳回来。原因是某一帧的角度或特征提取波动,让距离恰好越过了阈值。解决办法是加一个滑动窗口投票:

from collections import deque, Counter vote_queue = deque(maxlen=5) # 每帧得到 name 之后执行投票 vote_queue.append(name) if len(vote_queue) == 5: final_name, cnt = Counter(vote_queue).most_common(1)[0] # 连续5帧里至少3帧判定同一人,才输出最终结果 if cnt >= 3: print("识别结果:", final_name)

说明:窗口长度5、投票阈值3是经验值。这个机制能吸收单帧波动,代价是输出会延迟几帧,考勤场景完全够用。多人并列识别不需要改架构,第二层for face in faces已经遍历了画面里所有检测到的人脸,只需把每个人的结果分别显示即可。FPS统计用cv2.getTickCount()计算每帧耗时,当画面开始明显卡顿,优先把检测上采样次数从1改成0,再把图像分辨率调低,识别速度会立刻改善。

5. 避坑与排查:dlib编译失败、cv2导入报错等5个真实翻车记录

5.1 pip install dlib 卡在源码编译

现象:执行pip install dlib后命令行停在“Building wheel for dlib”,持续十几分钟不长进度,最后报CMake错误,错误路径里能看到pip-req-build这样的临时目录。

原因:你的Python版本没有对应预编译wheel,pip只好走源码编译。源码编译dlib需要完整的C++编译环境,Windows上缺Visual Studio Build Tools最典型。

解决:Windows安装Visual Studio Build Tools 2019,安装时勾选“使用C++的桌面开发”工作负载,然后重试。不想装编译环境的话,直接换Python 3.8或3.9再创建虚拟环境,这两个版本几乎总能找到现成的dlib wheel,安装秒级完成。

5.2 import cv2 报 No module named 'cv2'

现象:明明执行过pip install opencv-python,但运行脚本时提示ModuleNotFoundError: No module named 'cv2'。

原因:最常见的是机器上装了多个Python。pip命令用的是Python A的site-packages,运行脚本用的却是Python B;或者虚拟环境没激活就执行了安装。

解决:不要再用pip install,改成python -m pip install opencv-python,这样装包和运行脚本能锁定同一个Python解释器。装完立刻检查python -c "import cv2; print(cv2.__version__)",能打印版本就说明对上了。

5.3 识别时名字跳变,同一人一会儿A一会儿unknown

现象:识别结果不稳定,同一张脸几秒内名字反复变化,画面里能看到距离值在0.47和0.52之间来回跳,而阈值是0.5。

原因:阈值设在了距离波动区间中间,任何微小的光线或表情变化都会让结果越过阈值。另外一个隐藏因素是录入样本太少,只有1到2张,特征覆盖不够。

解决:先补录入样本到20张以上,再按4.3的方式加滑动窗口投票。投票比单纯调阈值更有效,因为它利用了时间连续性,单帧抖动不会直接改变最终输出。

5.4 侧脸一歪就识别失败

现象:正脸对准摄像头能识别,头稍微转一下就变成unknown,灵敏度很差。

原因:录入阶段只采了正脸样本,识别阶段一来角度大的侧脸,特征距离就偏离了原有特征空间。这不是dlib模型的问题,是训练集和识别条件不匹配。

解决:录入时让用户左右转头、抬头低头各拍几轮,保证样本覆盖角度。识别端确认传入了关键点,让dlib做姿态归一化。如果侧脸依然失效,最可靠的办法是装两个朝向不同的摄像头,识别时选择角度更正的画面。单摄像头硬件限制下,不要指望算法能逆天改命。

5.5 模型加载报错,提示dat文件无效

现象:加载shape_predictor_68_face_landmarks.dat时抛出异常,提示文件格式错误或者文件尾被截断。

原因:模型文件没有下载完整。这两个dat文件体积不小,下载中断会生成残缺文件,而dlib加载时对文件头有校验,残缺文件必然报错。

解决:先看文件大小。形状关键点模型约几十MB,特征模型约20MB左右,如果下载下来的文件只有几KB,基本就是下载不完整。删掉重新下载,下载后先运行2.3的验证脚本确认能加载,再进入录入流程。模型文件和.py代码放同一目录时要注意工作目录路径,用相对路径models/xxx.dat时,确保启动脚本的位置在models目录的上一级。

5.6 补充:BGR和RGB顺序颠倒导致特征异常

现象:识别能跑通,但同一个人的特征距离很大,不同人的距离反而很小,识别结果完全混乱。

原因:OpenCV的cv2.imread和cv2.VideoCapture读到的图像默认是BGR三通道顺序,而dlib的模型按RGB顺序训练和推理。不转换就直接送入compute_face_descriptor,特征会整体偏移。

解决:在调用dlib检测和特征提取前,统一执行rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)。注意绘制结果时仍用原来的BGR图像,因为OpenCV的画框和显示函数默认按BGR工作,混用会看到颜色诡异但不报错,这类问题排查起来比异常报错更费时间。

6. 把识别阈值调到最优:EER、活体检测与模型替换的下一步

最值得花时间调校的参数就是阈值0.5。它不是官方给出的真值,只是dlib在标准数据集上的推荐起点。换到你的摄像头和现场光线,最优阈值可能在0.45也可能在0.6。调阈值不能靠肉眼感觉,要按数据说话:录一组“本人”在不同角度、不同光线下的特征,再录一组“非本人”的特征,分别两两算出欧氏距离。本人距离构成一条分布曲线,非本人距离构成另一条,两条曲线交叉点对应的距离就是等错误率点(EER)。把阈值设在EER点,系统误识和拒识的概率最接近。这个调校过程看起来费时,实际半小时能完成,但比起拍脑袋调参,能明显减少实景翻车概率。

活体检测是当前方案的一大短板。这套系统只区分“这张脸是不是库里的这张脸”,分不出“这是真人还是手机屏幕上的照片”。课程设计或实验室内部场景,可以加一个“请眨眼”交互:检测到人脸后提示用户眨眼,用68个关键点里眼睛高宽比的变化判断是否有人眼闭合动作,连续几帧没有眨眼动作就不放行。商用门禁则建议走近红外双目或结构光方案,那已经超出dlib的能力范围,属于硬件选型范畴。

如果未来想继续提升识别精度,可以考虑把dlib的128维特征换成arcface框架产出的特征。arcface在难度更高的数据集上精度更好,但引入它意味着要换一套模型格式、预处理和推理代码,工程代价比想象中大。我的建议是:只有当dlib在你自己的数据分布上明显不够用时再换,不要在demo阶段折腾模型替换,先把数据流程跑顺。我自己写这套系统时,最深的教训是在录入阶段太省事,每个用户只录了五张,后来夜间光线一变识别率掉得惨不忍睹,补样本又花了一晚上。记住,录入阶段偷的懒,都会在识别阶段加倍还回来。希望这篇笔记能帮你少走一段弯路,也欢迎你带着自己的踩坑经验回来互相印证。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 1:05:51

TPS259483AYWPR与R7FA8D1BHECBD构建嵌入式电源韧性系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 1:05:05

工业级电源路径保护:TPS259483AYWPR与PIC32MZ协同设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 1:05:05

Hadoop+Spark信贷风控系统源码实战:架构、部署与调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 1:04:52

基于书评文本的Java个性化书籍推荐系统源码解析与调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/8 1:04:30

eFuse电子熔断器与MCU协同的嵌入式电源保护方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华