artcraft:基于Canvas的参数驱动视觉创作工具集
1. 从“artcraft”这个名字说起它到底想解决什么问题第一次看到“artcraft”这个项目标题我的直觉是这大概率是一个把“艺术创作”和“工程实现”缝合在一起的东西。art 是艺术craft 是手艺、工艺合在一起就是“艺术手艺”或者“艺术创作工具链”。在实际动手之前我先把这个标题拆成三个层面来理解因为只有把需求想透了后面选型和写代码才不会跑偏。第一个层面是内容生成。artcraft 最直接的理解就是让程序去“做艺术”。这里的艺术不一定是高深的绘画可能是生成一张渐变海报、一段动态图形、一组配色方案甚至是一个可以交互的视觉小玩具。它的核心诉求是把原本需要设计师手动拖拽、反复调整的工作变成可参数化、可批量、可复现的代码流程。第二个层面是创作辅助。很多做前端或者做数据可视化的人都有体会调一个好看的配色、找一个舒服的字体组合、生成一组风格统一的图标这些事情单看都不难但重复做就很烦。artcraft 这类项目的潜在需求就是把这些“审美决策”沉淀成可调用的模块让开发者不用每次都从零开始。第三个层面是学习与实验。我见过不少做创意编程的朋友他们需要一个轻量的沙盒环境能快速验证一个视觉想法比如“如果让粒子沿着正弦曲线运动颜色随速度变化会是什么效果”。artcraft 如果定位成这样的实验场那它的价值就不只是产出成品而是降低试错成本。所以我在规划这个项目时给自己定的目标很明确做一个基于 Web 的、参数驱动的视觉创作工具集既能当库用也能当独立的小应用跑起来。它要解决的核心问题是——让没有设计背景的开发者也能通过代码快速产出风格统一、可复用的视觉内容同时让有设计经验的人能把重复劳动交给程序。适合谁来参考这篇总结我认为有三类人一是前端开发者想给自己的项目加一点“设计感”但不想依赖重型设计软件二是创意编程爱好者需要一套轻量的生成艺术工具三是做数据可视化或运营活动页的工程师经常要批量产出视觉素材。这三类人的共同点是懂一点代码但不想在审美上死磕太久。2. 整体架构设计为什么我选择“参数驱动 分层渲染”2.1 核心思路把“审美”拆成可调参数artcraft 最核心的设计决策就是不把视觉结果写死而是把影响视觉的每个维度都暴露成参数。这个思路听起来简单但落地时要想清楚哪些东西该参数化哪些该固定。我试过两种极端。第一种是全部写死比如直接画一个红色圆形代码三行搞定但想换个颜色就得改代码复用性为零。第二种是全部参数化连圆形的贝塞尔控制点都暴露出来结果参数多到没人愿意调学习成本爆炸。最后我采用的是一种分层参数的策略第一层语义参数。比如theme主题、mood情绪、density密度。这些是给人看的用户不需要知道背后怎么实现只需要说“我想要一个冷静的、稀疏的构图”。第二层结构参数。比如palette配色方案、shapeType形状类型、layout布局模式。这些是给稍微懂一点的人调的决定了画面的基本骨架。第三层微调参数。比如noiseScale噪声缩放、rotationJitter旋转抖动、opacityRange透明度范围。这些是给想精细控制的人准备的决定了画面的“手感”。这样分层的好处是新手只用第一层就能出效果老手可以逐层往下钻。我在实际项目里发现大部分用户只会用到前两层第三层是给那些真正想调出独特风格的人留的口子。2.2 技术选型为什么是 Canvas 而不是 SVG 或 WebGL渲染层我纠结了很久。SVG 的优点是矢量、清晰、DOM 可操作但一旦图形数量上去比如几千个粒子性能就崩了。WebGL 性能最好但学习曲线陡而且对于“生成静态海报”这种场景有点杀鸡用牛刀。Canvas 2D 处在中间性能足够应付几千个图元API 简单而且可以直接导出成图片。我最后的方案是以 Canvas 2D 为主渲染层SVG 作为辅助导出格式。具体来说实时预览和交互用 Canvas因为要跑动画和粒子效果。最终导出时如果是简单图形走 SVG 路径保证无限放大不糊如果是复杂纹理走 Canvas 的toDataURL导出 PNG。这个混合策略的好处是兼顾了性能和输出质量。实测下来在普通笔记本上Canvas 渲染 3000 个粒子能稳定在 50fps 以上而同样数量的 SVG 元素浏览器直接卡死。注意Canvas 导出高分辨率图片时记得用devicePixelRatio做缩放否则在 Retina 屏上导出的图会模糊。我踩过这个坑导出的海报在手机上看着还行放到大屏上全是锯齿。2.3 模块划分五个核心模块的职责边界整个项目我拆成了五个模块每个模块只干一件事模块名职责对外暴露的接口调色板引擎根据主题和情绪生成配色generatePalette(theme, mood)形状生成器根据参数生成基础图形createShape(type, params)布局引擎决定图形在画布上的分布layout(shapes, mode)渲染器把图形画到 Canvas 上render(ctx, scene)导出器把场景导出为图片或代码export(scene, format)这样拆的好处是每个模块都可以单独测试和替换。比如我后来想换一种配色算法只需要改调色板引擎其他模块完全不用动。这种高内聚低耦合的设计在后期迭代时省了我大量时间。3. 核心细节解析调色板、形状与布局的实操要点3.1 调色板引擎怎么让程序“懂”配色配色是视觉创作里最玄学的部分。我一开始想用机器学习但后来发现对于 artcraft 这种工具基于色彩理论的规则引擎反而更可控。我的做法是先定义一组基础色相比如红、橙、黄、绿、青、蓝、紫。根据mood参数决定色相的偏移和饱和度范围。比如“冷静”对应低饱和度、偏蓝绿“活力”对应高饱和度、偏红黄。用 HSL 而不是 RGB 来生成颜色因为 HSL 更符合人对颜色的直觉。调亮度就是调 L调鲜艳度就是调 S不用去算 RGB 的混合。具体实现时我用了一个小技巧先随机生成一个主色然后根据色彩和谐规则互补、三角、类似生成辅助色。这样出来的配色不会太离谱但又有一点随机性不会每次都一样。function generatePalette(theme, mood) { const baseHue theme.baseHue mood.hueShift; const saturation mood.saturation; const lightness mood.lightness; // 互补色 const complement (baseHue 180) % 360; // 类似色 const analogous1 (baseHue 30) % 360; const analogous2 (baseHue - 30 360) % 360; return [ hsl(${baseHue}, ${saturation}%, ${lightness}%), hsl(${complement}, ${saturation * 0.8}%, ${lightness * 1.1}%), hsl(${analogous1}, ${saturation * 0.9}%, ${lightness * 0.9}%), hsl(${analogous2}, ${saturation * 0.7}%, ${lightness * 1.2}%) ]; }实操心得HSL 的 L 值不要设成 0 或 100否则颜色会变成纯黑或纯白失去色相信息。我一般把 L 控制在 20% 到 80% 之间这样颜色既有辨识度又不刺眼。3.2 形状生成器从“圆”到“有机形态”artcraft 里的形状不是简单的圆和方而是带噪声的有机形态。为什么因为纯几何图形看起来太“工程”加一点噪声就有了手绘的感觉。我的做法是先用基础图形圆、多边形、贝塞尔曲线生成轮廓然后在轮廓的每个顶点上叠加 Perlin 噪声。噪声的幅度由roughness参数控制0 就是完美几何1 就是完全随机。这里有个关键点噪声的频率要跟图形的尺寸匹配。如果图形很小噪声频率太高看起来就像毛刺如果图形很大噪声频率太低看起来就像变形。我一般用noiseScale 1 / Math.max(width, height)来动态计算。function createOrganicShape(baseShape, roughness, noiseScale) { const points baseShape.getPoints(); const noisyPoints points.map((p, i) { const noiseX noise(p.x * noiseScale, p.y * noiseScale) * roughness; const noiseY noise(p.x * noiseScale 100, p.y * noiseScale 100) * roughness; return { x: p.x noiseX, y: p.y noiseY }; }); return new Path(noisyPoints); }实测下来roughness在 0.1 到 0.3 之间时图形既有手绘感又不会太乱。超过 0.5 就基本认不出原形了。3.3 布局引擎让图形“散落”得好看布局是最容易被忽视但最影响观感的部分。我试过纯随机布局结果图形要么挤成一团要么散得太开画面很空。后来我改用基于网格的抖动布局先把画布划分成 N×N 的网格。每个网格单元里放一个图形位置在单元中心加上随机抖动。抖动幅度由jitter参数控制0 就是整齐排列1 就是完全随机。这样出来的布局既有秩序感又不会太死板。jitter我一般设在 0.3 到 0.6 之间具体看图形大小和数量。注意网格数量要根据图形数量动态调整。如果图形少网格多画面会显得很空如果图形多网格少图形会重叠。我的经验公式是gridSize Math.ceil(Math.sqrt(shapeCount * 1.5))这样每个网格平均有 1.5 个图形密度比较舒服。4. 完整实操流程从零跑起一个 artcraft 场景4.1 环境准备与项目初始化artcraft 本身不依赖重型框架我用的是原生 JavaScript Vite 做开发服务器。为什么不用 React 或 Vue因为 artcraft 的核心是 Canvas 渲染DOM 操作很少引入框架反而增加复杂度。Vite 的好处是启动快、热更新快改一行代码立刻能看到效果。初始化步骤npm create vitelatest artcraft -- --template vanilla cd artcraft npm install npm run dev然后建一个src/artcraft目录把五个模块分别放进去。入口文件main.js只做三件事创建 Canvas、初始化场景、启动渲染循环。import { createScene } from ./artcraft/scene; import { render } from ./artcraft/renderer; const canvas document.getElementById(canvas); const ctx canvas.getContext(2d); const scene createScene({ theme: ocean, mood: calm, shapeCount: 200, roughness: 0.2, jitter: 0.4 }); function loop() { render(ctx, scene); requestAnimationFrame(loop); } loop();4.2 参数配置与调参过程调参是 artcraft 最花时间的部分。我一般按这个顺序来先定主题和情绪。这决定了配色的大方向。比如theme: ocean配mood: calm出来的就是蓝绿色系、低饱和度的画面。再定图形数量和大小。数量太少画面空太多画面乱。我一般从 100 开始试根据画布尺寸调整。然后调粗糙度和抖动。这两个参数决定了画面的“手感”。粗糙度影响单个图形的形态抖动影响整体布局。最后微调透明度和混合模式。这一步是点睛之笔用globalCompositeOperation可以让图形叠加出意想不到的效果。我整理了一份常用参数对照表方便快速定位参数作用推荐范围调参方向shapeCount图形数量50-500越多越密roughness图形粗糙度0.1-0.3越大越手绘jitter布局抖动0.3-0.6越大越随机opacity透明度0.3-0.8越小越通透blendMode混合模式multiply/screen影响叠加效果4.3 渲染循环与性能优化渲染循环看起来简单但有几个坑不要在每一帧重新生成场景。场景生成是计算密集型的每帧都做会卡死。我的做法是场景只生成一次渲染循环只负责画。用离屏 Canvas 做缓存。如果场景是静态的可以先把场景画到一个离屏 Canvas 上然后每帧只做drawImage。这样性能提升非常明显。限制帧率。如果不是做动画没必要跑 60fps。我用setTimeout把帧率控制在 30fpsCPU 占用直接减半。let lastTime 0; const fps 30; const interval 1000 / fps; function loop(currentTime) { requestAnimationFrame(loop); const delta currentTime - lastTime; if (delta interval) return; lastTime currentTime - (delta % interval); render(ctx, scene); }实操心得如果你的场景里有大量半透明图形叠加globalCompositeOperation multiply比默认的source-over性能更好因为浏览器对混合模式有硬件加速优化。我实测下来同样 500 个图形multiply 模式比 source-over 快 20% 左右。4.4 导出与分享导出我做了两种格式PNG用canvas.toDataURL(image/png)适合分享到社交平台。SVG把场景里的图形转成 SVG 路径适合需要矢量编辑的场景。导出 PNG 时要注意分辨率。默认的 Canvas 尺寸是 CSS 像素导出时如果直接toDataURL得到的是 1x 图。想要 2x 或 3x 图需要临时把 Canvas 放大画完再导出。function exportPNG(scene, scale 2) { const canvas document.createElement(canvas); canvas.width scene.width * scale; canvas.height scene.height * scale; const ctx canvas.getContext(2d); ctx.scale(scale, scale); render(ctx, scene); return canvas.toDataURL(image/png); }5. 常见问题与排查技巧实录5.1 画面卡顿先查图形数量再查混合模式卡顿是最常见的问题。我的排查顺序是看图形数量。超过 1000 个图形Canvas 2D 就开始吃力了。解决办法是减少数量或者用离屏 Canvas 缓存。看混合模式。multiply和screen虽然好看但比source-over慢。如果卡顿先切回默认模式试试。看是否有每帧重绘。如果场景是静态的没必要每帧重画。用离屏 Canvas 缓存每帧只做drawImage。我遇到过一次诡异卡顿排查了半天发现是shadowBlur惹的祸。阴影模糊非常耗性能尤其是大尺寸图形。后来我把阴影改成用半透明图形模拟性能立刻恢复。5.2 导出图片模糊检查 devicePixelRatio导出图片模糊的原因通常是 Canvas 尺寸和实际像素不匹配。在 Retina 屏上canvas.width是 CSS 像素但实际渲染需要乘以devicePixelRatio。解决办法是在初始化 Canvas 时const dpr window.devicePixelRatio || 1; canvas.width cssWidth * dpr; canvas.height cssHeight * dpr; canvas.style.width cssWidth px; canvas.style.height cssHeight px; ctx.scale(dpr, dpr);这样渲染出来的图就是清晰的。导出时再按需要的倍数放大就能得到高分辨率图片。5.3 配色难看从 HSL 入手别碰 RGB配色难看是新手最常见的问题。我的建议是永远用 HSL 调色不要用 RGB。RGB 的三个通道是耦合的调一个通道会影响另外两个很难控制。HSL 的色相、饱和度、亮度是独立的调起来直观得多。另外不要用纯色。纯红、纯蓝、纯绿看起来都很刺眼。我一般把饱和度控制在 40% 到 70% 之间亮度控制在 30% 到 70% 之间。这样出来的颜色柔和但不失辨识度。5.4 图形重叠太乱调整布局参数图形重叠太乱通常是jitter太大或者网格太小。解决办法有两个减小 jitter。从 0.6 降到 0.3图形会整齐很多。增大网格。让每个网格单元更大图形之间的间距就更大。如果还是乱可以给图形加一点透明度让重叠的部分自然融合。opacity设在 0.5 左右重叠区域会形成更深的颜色反而有一种层次感。5.5 常见问题速查表问题可能原因解决办法画面卡顿图形太多 / 混合模式太重减少数量 / 换 source-over导出模糊没处理 devicePixelRatio初始化时乘以 dpr配色难看用了 RGB / 纯色改用 HSL控制饱和度亮度图形重叠jitter 太大 / 网格太小减小 jitter / 增大网格动画不流畅每帧重绘场景用离屏 Canvas 缓存颜色太刺眼饱和度太高降到 40%-70%6. 后续扩展方向与个人体会artcraft 目前还是一个比较基础的版本但它的架构留了很多扩展口。我后续想做的几个方向第一个是接入外部数据。比如把天气数据、股票数据、音乐频谱映射成视觉参数让画面随数据变化。这个方向很适合做数据可视化艺术。第二个是增加交互。现在只能通过代码调参如果加上鼠标拖拽、键盘快捷键就能变成一个实时创作工具。我试过用鼠标位置控制jitter和roughness效果很有意思画面会随着鼠标移动“活”起来。第三个是预设库。把常用的主题、情绪、布局组合保存成预设用户一键切换。这个功能对新手特别友好不用理解参数就能出效果。我个人在实际操作中的体会是生成艺术最难的不是技术而是审美决策。代码谁都能写但知道什么参数组合好看需要大量试错。我建议新手先从模仿开始找一些喜欢的海报或插画试着用参数去逼近那个效果。调着调着你就会对色彩、布局、形态有感觉了。最后再分享一个小技巧把随机种子固定下来。artcraft 里所有随机数都用同一个种子生成这样每次运行结果都一样。如果你想复现某个满意的画面只要记住种子就行。这个功能在调试和分享时特别有用不然每次刷新都是新画面根本没法对比。

相关新闻

k邻近算法实战指南:从数据清洗到在线更新的七道关卡

k邻近算法实战指南:从数据清洗到在线更新的七道关卡

1. 这不是“调个包”那么简单:k邻近算法在真实项目里到底怎么用你打开sklearn文档,看到from sklearn.neighbors import KNeighborsClassifier,敲下几行代码跑通了鸢尾花数据集——恭喜,你完成了k邻近算法的“Hello World”。但如果…

2026/10/13 12:05:53 阅读更多 →
环形链表 II:快慢指针找入环点的数学推导与代码实现

环形链表 II:快慢指针找入环点的数学推导与代码实现

要搞懂这道“环形链表Ⅱ”,光会判断有没有环远远不够。很多人在 LeetCode-141 里用快慢指针跑得飞起,一遇到 142 要找入环点就直接懵住。LeetCode-142 真正考的不是“会不会用双指针”,而是“能不能讲清楚快指针和慢指针相遇之后,…

2026/10/13 12:04:52 阅读更多 →
Excel多源数据清洗与高级筛选:从零搭建可复用动态看板

Excel多源数据清洗与高级筛选:从零搭建可复用动态看板

半年前我在处理一份四十万行销售流水时,连续加了三个夜班。表面问题是Excel卡顿,深层问题是数据源太杂:系统导出的订单表、手工维护的客户表、供应商提供的分类表,字段名五花八门,同一含义写成“商品名称”“产品名”“…

2026/10/13 12:04:52 阅读更多 →

最新新闻

AutoGen接入MCP工具全指南:原理、API与避坑实践

AutoGen接入MCP工具全指南:原理、API与避坑实践

这两天我在调AutoGen智能体的时候,发现一个很容易被忽略但非常关键的扩展包:autogen_ext.tools.mcp。如果你已经在用AutoGen做智能体,大概率接触过原生工具注册,也就是把函数直接塞给Agent。但实际项目里工具一多,函数…

2026/10/13 12:48:56 阅读更多 →
图书销售管理系统数据库设计:从需求到建表的完整落地路径

图书销售管理系统数据库设计:从需求到建表的完整落地路径

简介:这份资源是面向高校数据库课程大作业场景的图书销售管理系统数据库设计文档,适合正在完成数据库课程设计、需要参考完整设计流程的学生,以及希望巩固SQL Server建模与查询实践的初学者。压缩包内仅含1个docx文件,整体约1.66M…

2026/10/13 12:48:56 阅读更多 →
COMSOL混凝土压缩损伤模拟技术与工程应用

COMSOL混凝土压缩损伤模拟技术与工程应用

1. 混凝土压缩损伤模拟的核心价值在土木工程和建筑材料研究中,混凝土的压缩损伤行为一直是结构安全评估的关键课题。传统实验室测试虽然直观,但存在试件制备周期长、破坏性测试成本高、内部损伤演化难以观测等固有局限。COMSOL Multiphysics这类多物理场…

2026/10/13 12:48:56 阅读更多 →
从原理到落地:游程编码RLE压缩算法的完整实现与工程实践

从原理到落地:游程编码RLE压缩算法的完整实现与工程实践

1. 从一个“看起来很简单”的需求说起RLE,全称 Run-Length Encoding,中文一般叫游程编码。这大概是所有压缩算法里最容易理解的一个了——把连续重复的数据用“数量值”的方式记下来。比如AAAAABBB变成5A3B,就这么简单。很多人第一次接触数据…

2026/10/13 12:48:56 阅读更多 →
t3code轻量级代码工具集:从规则引擎到批量生成API客户端代码的实操指南

t3code轻量级代码工具集:从规则引擎到批量生成API客户端代码的实操指南

1. 从“t3code”这个标题说起:它到底是什么,能解决什么问题第一次看到“t3code”这个标题,很多人会愣一下——它不像“XX管理系统”那样直白,也不像“XX工具库”那样一看就知道用途。我当初接触这个项目时也是一头雾水&#xff0c…

2026/10/13 12:48:56 阅读更多 →
Python二维码条形码自动识别实战:原理、代码与排坑

Python二维码条形码自动识别实战:原理、代码与排坑

1. 项目背景与识别原理先说一个我自己的经历。有一次我需要批量处理一批图书的ISBN条形码,手动扫了几十本之后,手指头都快抽筋了,于是萌生了用Python写一个自动解析工具的想法。当时调研了一圈,发现这个需求远比想象中普遍——电商…

2026/10/13 12:47:52 阅读更多 →

日新闻

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

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

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

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 阅读更多 →