机器人视觉系统搭建指南:从硬件选型到闭环控制实战
1. 从零搭建机器人视觉系统为什么我选择“先跑通再优化”的路线很多人第一次接触机器人视觉脑子里蹦出来的第一个念头往往是“我要用深度学习”“我要上目标检测”“我要搞SLAM”。结果环境配了三天显卡驱动还没装明白最后热情耗尽项目文件夹再也没打开过。我自己带过不少刚入门的同学十个里有八个卡在同一个地方把视觉系统当成一个“模型问题”而实际上它首先是一个“工程问题”。所谓机器人视觉说白了就是让机器通过摄像头这类传感器“看懂”周围环境并据此做出决策。它涵盖的范围很广从最简单的颜色识别、循迹到复杂的物体抓取、三维重建、自主导航都属于这个范畴。而“JBR-001”这个编号本身并不重要重要的是它代表了一类典型的入门级机器人视觉项目有明确的硬件平台、有可复现的软件流程、有看得见摸得着的输出结果。这篇文章适合谁看如果你手里有一台带摄像头的机器人小车、一个机械臂或者哪怕只是一个普通USB摄像头加一块开发板想让它“睁开眼睛”那这篇内容就是为你准备的。我不会一上来就丢一堆公式和论文而是按照一个合格从业者真实的推进节奏来先让画面出来再让画面里的信息变得有用最后让这些信息驱动动作。整个过程我会解释每一步为什么这么做、参数怎么定、坑在哪里。我个人的经验是机器人视觉项目失败的原因九成不是算法不够先进而是基础环节没打牢——光照一变就废、标定没做导致坐标全错、图像传输延迟大到没法闭环控制。所以这篇指南的核心思路是“先跑通最小闭环再逐步替换更优方案”。下面我会从硬件选型、环境搭建、图像采集、预处理、特征提取、坐标映射到闭环控制一步步拆开讲。2. 硬件选型与连接别让第一个坑出现在物理层2.1 摄像头选型的三个硬指标机器人视觉的第一件事是选摄像头。市面上从几十块到几千块的摄像头都有但并不是越贵越好。你需要关注三个核心指标分辨率、帧率、接口类型。分辨率决定了你能看到多少细节。对于循迹、颜色识别这类任务640×480足够用如果要识别二维码或做简单的形状匹配1280×720会更稳妥。但分辨率不是越高越好因为图像越大处理耗时越长。我实测过在一块普通ARM开发板上处理1080p图像的单帧耗时可能是480p的四倍以上如果还要做滤波和特征提取帧率直接掉到个位数闭环控制根本没法做。帧率决定了系统的响应速度。机器人视觉通常要求至少15fps才能有基本的实时感30fps是比较舒服的水平。如果你要做高速抓取或避障60fps以上才够用。这里有个容易被忽略的点很多摄像头标称30fps是在特定分辨率下才成立的比如MJPG格式下能到30fps但YUV格式可能只有10fps。买之前一定要看数据手册里的格式-帧率对照表。接口类型主要分USB、CSI、GigE等。USB摄像头最方便即插即用但带宽和延迟受总线影响CSI接口直接连在嵌入式主板的MIPI总线上延迟低、CPU占用少适合对实时性要求高的场景GigE工业相机稳定但贵一般入门用不上。提示如果你用的是树莓派这类板子优先选CSI摄像头USB摄像头在同时跑其他外设时容易出现带宽争抢导致掉帧。2.2 安装位置与光照的隐形影响摄像头装在哪里比用什么摄像头更影响最终效果。我见过太多人把摄像头随便往车头一粘结果画面一半是地面一半是天空有效信息全挤在中间一小条。正确的做法是先想清楚你要看什么如果是循迹摄像头应该略微向下倾斜让画面下三分之二都是地面如果是识别前方物体摄像头应该水平安装保证目标在画面中央区域。光照是另一个隐形杀手。同一套颜色阈值在日光灯下和窗边自然光下可能完全失效。我的建议是如果项目允许加一个主动光源比如环形LED补光灯让光照条件可控。如果没法加光源那在算法上就要用对光照不敏感的特征比如边缘、梯度而不是单纯依赖颜色。2.3 连接与供电的实操细节连接摄像头之前先确认供电是否充足。USB摄像头在启动瞬间电流可能超过500mA如果开发板的USB口供电不足会出现画面闪烁甚至设备反复重连。我遇到过一块板子单独插摄像头没问题一插上电机驱动就掉线最后发现是电源功率不够。解决办法很简单给摄像头单独供电或者换一个功率更大的电源适配器。线缆长度也要注意。USB线超过3米信号就开始衰减CSI排线超过30厘米就可能出现花屏。如果摄像头必须装得离主板很远考虑用带屏蔽的延长线或者把图像采集和处理分开用网络传输图像。3. 软件环境搭建把“能出画面”作为第一个里程碑3.1 操作系统与驱动准备不管你用的是哪种开发板第一步都是让系统认出摄像头。Linux下用ls /dev/video*看设备节点是否存在用v4l2-ctl --list-devices看设备信息。如果设备节点都没有那说明驱动没加载先解决驱动问题别急着写代码。Python环境下OpenCV是最常用的视觉库。安装方式有两种pip install opencv-python和系统包管理器安装。我推荐用pip安装版本新、功能全。但要注意有些嵌入式平台pip安装的OpenCV不带硬件加速跑起来很慢这时候可能需要从源码编译并开启NEON或VFPV3优化。编译一次大概要一两个小时但性能提升可能是两三倍值得做。# 检查摄像头是否被识别 ls /dev/video* # 查看摄像头支持的格式和分辨率 v4l2-ctl --device/dev/video0 --list-formats-ext3.2 最小采集程序的编写与验证环境搭好后写一个最简单的采集程序目标只有一个把画面显示出来。不要小看这一步它能帮你确认摄像头工作正常、驱动没问题、OpenCV能读到数据。import cv2 cap cv2.VideoCapture(0) if not cap.isOpened(): print(摄像头打开失败) exit() while True: ret, frame cap.read() if not ret: print(读帧失败) break cv2.imshow(frame, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码跑通后你会看到一个实时画面窗口。如果画面卡顿先检查分辨率设置如果画面颜色不对可能是BGR和RGB顺序问题如果画面全黑检查镜头盖是否打开这个坑我踩过不止一次。3.3 分辨率与帧率的权衡配置默认情况下OpenCV会使用摄像头的最高分辨率但这往往不是最优选择。你可以手动设置cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_FPS, 30)设置完之后用cap.get()读回来确认是否生效。有些摄像头不支持任意分辨率会返回最接近的值。我一般会做一个分辨率-帧率测试表把几种常用组合都跑一遍记录CPU占用和实际帧率然后选一个平衡点。比如在树莓派4B上640×48030fps的CPU占用大约15%1280×72030fps就跳到40%以上如果还要跑其他算法前者明显更合适。4. 图像预处理让原始画面变成“可计算”的数据4.1 颜色空间转换的取舍摄像头输出的通常是BGR格式但很多视觉算法在HSV空间下工作得更好。原因很简单HSV把颜色H、饱和度S、明度V分开了光照变化主要影响V通道对H通道影响较小。这意味着你可以用H和S做颜色分割而对光照变化更鲁棒。hsv cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)但HSV也不是万能的。H通道在红色附近会环绕0和180都代表红色做阈值时需要处理两段区间。另外HSV转换本身有计算开销如果对帧率要求极高可以考虑在YUV空间直接处理跳过转换。4.2 滤波去噪高斯、中值还是双边原始图像里总有噪声噪声会让后续的边缘检测和轮廓提取产生大量误检。常见的滤波方式有三种滤波类型适用场景特点高斯滤波一般性平滑速度快会模糊边缘中值滤波椒盐噪声保边效果好速度中等双边滤波需要保边平滑效果最好速度最慢我的经验是如果只是做颜色块识别高斯滤波就够了如果要检测边缘和角点用中值滤波如果对边缘精度要求很高且算力充足再上双边滤波。核大小一般取3或5太大实时性会明显下降。4.3 阈值分割与形态学操作阈值分割是把图像变成二值图让目标区域凸显出来。对于颜色识别常用cv2.inRange()lower np.array([0, 100, 100]) upper np.array([10, 255, 255]) mask cv2.inRange(hsv, lower, upper)阈值怎么定不要靠猜。写一个小工具把鼠标点击位置的HSV值打印出来然后根据目标颜色的分布范围确定上下限。我通常会取目标区域采样点的H值±10、S和V取较宽的范围先保证不漏检再逐步收紧。形态学操作腐蚀、膨胀、开运算、闭运算用来清理二值图。开运算先腐蚀后膨胀去小噪点闭运算先膨胀后腐蚀填小孔洞。结构元素一般用3×3或5×5的矩形迭代次数1到2次。这里有个细节形态学操作对边缘形状有影响如果后续要做精确的轮廓分析迭代次数不宜过多。5. 特征提取与目标定位从“看到”到“看懂”5.1 轮廓查找与筛选策略二值图出来后用cv2.findContours()找轮廓。OpenCV 4.x里这个函数返回两个值轮廓列表和层级信息。拿到轮廓后不要直接用先做筛选。筛选条件通常包括面积太小的是噪声太大的是背景宽高比根据目标形状设定范围位置只关心画面特定区域的轮廓凸性有些目标要求是凸多边形contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: area cv2.contourArea(cnt) if area 500 or area 50000: continue x, y, w, h cv2.boundingRect(cnt) aspect_ratio w / float(h) if 0.8 aspect_ratio 1.2: cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2)这段代码会画出符合面积和宽高比条件的矩形框。实际项目中筛选条件需要根据测试结果反复调整。我一般会先把所有轮廓画出来观察哪些是目标、哪些是干扰然后针对干扰特征增加筛选条件。5.2 中心点计算与坐标映射找到目标轮廓后计算它的中心点。最简单的方法是用矩M cv2.moments(cnt) cx int(M[m10] / M[m00]) cy int(M[m01] / M[m00])这个(cx, cy)是图像坐标系下的像素坐标。但机器人要动需要的是物理世界坐标。这就涉及坐标映射。最简单的场景是摄像头固定、地面平坦可以用线性映射图像x方向对应机器人左右图像y方向对应前后距离。但线性映射只在特定条件下成立更通用的做法是相机标定。5.3 相机标定的必要性与简化方案相机标定是为了得到内参矩阵和畸变系数把像素坐标转换成归一化坐标再结合外参得到世界坐标。完整的标定需要棋盘格、多角度拍摄、角点检测、参数求解流程不复杂但比较繁琐。如果你的项目对精度要求不高可以跳过完整标定用一个简化的“查表法”在机器人工作范围内选几个已知位置记录对应的像素坐标拟合一个多项式映射。这种方法在平坦地面、固定高度的场景下精度够用而且省去了标定的麻烦。注意不管用哪种方法映射关系都会随摄像头角度、高度变化而失效。每次调整摄像头后必须重新标定或重新拟合。6. 闭环控制让视觉信息真正驱动机器人6.1 从像素偏差到控制量的转换视觉系统的最终目的是控制。假设机器人要追踪一个目标视觉给出目标中心与画面中心的偏差(dx, dy)控制器根据这个偏差计算左右轮速度或机械臂关节角度。最简单的控制是比例控制error_x cx - frame_width / 2 turn kp * error_x left_speed base_speed turn right_speed base_speed - turnkp是比例系数需要实验确定。太小了响应慢太大了会震荡。我一般从0.1开始试逐步增大到系统刚好不震荡为止。6.2 延迟补偿与滤波视觉处理有延迟从采集到输出控制量可能过了几十毫秒。如果机器人运动快这个延迟会导致控制滞后甚至震荡。解决办法有两个一是提高帧率降低延迟二是对控制量做预测或滤波。常用的滤波是低通滤波或卡尔曼滤波。低通滤波简单turn_filtered alpha * turn (1 - alpha) * turn_prevalpha取0.3到0.7之间根据延迟和噪声水平调整。卡尔曼滤波效果更好但需要建模入门项目用低通滤波通常就够了。6.3 实际调试中的经验参数调试闭环控制时我习惯先把摄像头固定手动移动目标观察控制量变化是否合理。然后再让机器人动起来从低速开始逐步提速。记录不同速度下的跟踪效果找到稳定工作的速度上限。还有一个容易被忽略的点电机死区。很多电机在PWM值很低时不转导致小偏差时机器人没反应偏差积累大了突然猛转。解决办法是在控制量上加一个最小启动值或者用带编码器的电机做闭环速度控制。7. 常见问题排查那些文档里不会写的坑7.1 画面卡顿与掉帧的排查链路画面卡顿是最常见的问题。排查顺序应该是先看CPU占用如果接近100%说明处理太重降低分辨率或简化算法再看摄像头格式MJPG通常比YUV帧率高然后看USB带宽如果同时接了多个USB设备试着拔掉其他设备最后看电源电压不稳会导致摄像头降速。我遇到过一次诡异的情况画面每隔几秒卡一下查了半天发现是后台有个定时任务在跑抢占了CPU。所以排查时也要看看系统里有没有其他进程在捣乱。7.2 颜色识别不稳定的根因分析颜色识别不稳定九成是光照问题。白平衡自动调整会导致颜色漂移曝光自动调整会导致明暗变化。解决办法是关闭摄像头的自动白平衡和自动曝光cap.set(cv2.CAP_PROP_AUTO_WB, 0) cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)然后手动设置合适的值。不同摄像头支持的属性不一样用v4l2-ctl --list-ctrls可以查看可调参数。如果关闭自动调整后还是不稳定那可能是光源本身在变化比如日光灯有频闪。这时候要么换光源要么在算法上做自适应阈值。7.3 坐标映射偏差过大的检查清单映射偏差大按这个清单逐项检查摄像头是否松动或角度变了标定或拟合时用的数据是否覆盖了工作范围镜头畸变是否严重广角镜头边缘畸变明显地面是否真的平坦计算映射时用的高度参数是否准确我见过一个案例映射怎么调都不对最后发现是摄像头装歪了画面本身就有旋转。所以在做映射之前先确保摄像头安装端正或者加一个旋转校正。8. 从Demo到可用系统我总结的几条实战原则第一先保证鲁棒性再追求精度。一个能在多种光照下稳定工作但精度一般的系统比一个精度很高但换个房间就废的系统有价值得多。第二日志和可视化比调试器好用。把每一帧的中间结果mask、轮廓、控制量保存下来或实时显示出问题时回看录像比单步调试快得多。第三参数不要硬编码。把阈值、系数、映射参数放到配置文件里改参数不用重新编译调试效率翻倍。第四留出降级方案。视觉失效时机器人应该能安全停止或切换到备用策略而不是失控乱跑。第五测试要覆盖边界条件。目标在画面边缘、光照突变、目标被部分遮挡这些情况在实验室里可能遇不到但在实际场景中一定会出现。我在实际项目里踩过最深的坑不是算法不会写而是忽略了机械安装的精度。摄像头支架稍微歪一点映射关系就全变了调算法调了半天才发现是物理问题。所以每次调试视觉之前先花五分钟检查硬件安装能省下后面几个小时的无用功。另外分享一个小技巧用手机慢动作拍摄机器人运动过程回放时能清楚看到视觉延迟和控制震荡的对应关系比盯着代码猜原因直观得多。这个办法帮我定位过好几次控制参数的问题。这个项目后续还可以往很多方向扩展比如加入深度相机做三维定位、用神经网络替换传统特征提取、多摄像头融合扩大视野。但不管怎么扩展上面这套从采集到控制的完整链路都是基础基础打牢了换什么高级算法都只是替换其中一个模块的事。

相关新闻

Jev替代品扎堆涌现,如何辨别真替代与伪替代

Jev替代品扎堆涌现,如何辨别真替代与伪替代

1. 一个工具爆火之后,为什么“替代品”总会扎堆出现Jev 这个名字最近在圈子里出现的频率确实有点高。不管你是刷技术社区、翻群聊记录,还是看各种工具推荐清单,总能撞见它。紧接着你会发现一个很有意思的现象:几乎在同一时间&…

2026/10/12 14:43:32 阅读更多 →
把“完美”翻译成动词:用Impeccable标准终结反复修改

把“完美”翻译成动词:用Impeccable标准终结反复修改

“impeccable”这个词,是我给自己一套交付标准起的代号。原因很直白:市面上聊“追求极致”的教程太多了,但真能把“极致”落到一个又一个可执行动作上的少之又少。我早些年也栽过跟头——方案改到第七版,对方一句“感觉还是差点意…

2026/10/12 14:43:36 阅读更多 →
吴江小规模代理记账怎么选?避开财税外包常见坑

吴江小规模代理记账怎么选?避开财税外包常见坑

在吴江开小店、做小生意的老板们注意了!很多人刚创业图省事,随便找个99元/月的代账就签了,最后要么账对不上,要么漏报逾期挨罚款,平白无故花冤枉钱。今天就用吴江本地老板们踩过的真实坑,给你唠明白怎么选小…

2026/10/12 14:42:38 阅读更多 →

最新新闻

数据结构期末试卷拆解:高频考点与手写算法提分策略

数据结构期末试卷拆解:高频考点与手写算法提分策略

简介:湖北大学《数据结构》2022—2023学年第一学期期末试卷(A卷),面向计算机相关专业本科生,适合期末复习、考研自测及教学参考。试卷为闭卷考试,覆盖判断分析题、简答题与应用分析题,重点涉及带…

2026/10/13 13:34:15 阅读更多 →
LiteLLM:统一LLM API网关的工程实践与生产落地

LiteLLM:统一LLM API网关的工程实践与生产落地

1. 项目概述:LiteLLM 是什么,它解决的到底是什么问题?LiteLLM 这个名字乍一听像是某个轻量级模型,但其实它压根不训练模型、不压缩参数、也不做推理加速——它是个“协议翻译器”,更准确地说,是一个统一 AP…

2026/10/13 13:34:15 阅读更多 →
Win7下部署PaddleOCR-json:离线OCR服务实战指南

Win7下部署PaddleOCR-json:离线OCR服务实战指南

简介:面向Windows 7 64位环境的PaddleOCR离线部署压缩包,适合需要在本地快速搭建文字识别能力的开发者和企业用户,可免去自行编译和下载模型的繁琐步骤。包内含PaddleOCR-json主程序、动态链接库运行环境、PP-OCRv3系列文本检测、方向分类与文…

2026/10/13 13:34:15 阅读更多 →
图数据库标签计数实战:从全表扫描到索引直读的避坑指南

图数据库标签计数实战:从全表扫描到索引直读的避坑指南

1. 从一次数据盘点需求说起:为什么“数标签”这件事没那么简单刚接触图数据库那会儿,我接到的第一个真实需求就是“把库里所有标签的数量统计出来”。当时心想,这不就是一句MATCH (n) RETURN labels(n), count(*)的事吗?结果跑出来…

2026/10/13 13:34:15 阅读更多 →
Elasticsearch 7.6.2 + IK分词器Docker部署全避坑指南

Elasticsearch 7.6.2 + IK分词器Docker部署全避坑指南

1. 为什么7.6.2版本的IK分词器在Docker里总“不认中文”?——从一次线上搜索失效说起 上周帮某高校实验室调试一个文献检索Demo,后端用的是Elasticsearch 7.6.2,前端输入“机器学习”“深度神经网络”这类词,返回结果全是空——不…

2026/10/13 13:34:15 阅读更多 →
DRF接口设计实战:十大接口标准化写法与视图家族选型指南

DRF接口设计实战:十大接口标准化写法与视图家族选型指南

1. 从“能跑通”到“敢上线”:DRF接口设计的真实分水岭刚接触Django REST Framework(后面统一叫DRF)的人,几乎都会经历同一个阶段:照着文档把序列化器、视图、路由拼起来,接口能返回JSON,就觉得…

2026/10/13 13:33:14 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →