|
1 | | -# strokeoil · 油画工序逐笔重绘 |
| 1 | +# strokeoil · 图片逐笔重绘 |
2 | 2 |
|
3 | | -把任意图片重绘成「按真实油画十道工序逐笔画出」的动画。**纯前端实现,图片不上传、无需后端**,可直接托管到 GitHub Pages。 |
| 3 | +把任意图片重绘成「一笔一笔画出来」的过程动画,内置 **四种绘画风格**:油画、线描、色块、素描。 |
| 4 | +**纯前端实现,图片不上传、无需后端**,可直接托管到 GitHub Pages。 |
4 | 5 |
|
5 | 6 | 仓库:<https://github.com/tyuecode/tyuecode.github.io> |
6 | 7 |
|
7 | 8 | 在线体验:<https://tangyue.me/> |
8 | 9 |
|
| 10 | +## 四种风格 |
| 11 | + |
| 12 | +| 风格 | 工序 | 效果 | 适合 | |
| 13 | +|---|---|---|---| |
| 14 | +| **油画** | 刷底色 → 起稿 → 单色底层 → 铺大色 → 塑造 → 塑形 → 罩染 → 干扫 → 细部 → 提白 | 十道古典工序,笔触有起收锋、笔毛分叉、颜料渐枯、厚涂浮雕、罩染透叠 | 人像、风景,想要「真在画画」的质感 | |
| 15 | +| **线描** | 定形 → 勾主线 → 结构线 → 细描 → 点睛 | 近黑底上的细白线,只勾结构不铺色,像版画稿/工程图 | 线条为主的原图、想要高对比的图 | |
| 16 | +| **色块** | 铺底色 → 暗部色块 → 中间调 → 亮部 → 点缀 | k-means 分层后逐层平涂硬边色块,限量配色的海报感 | 扁平/插画风,做海报和封面 | |
| 17 | +| **素描** | 起形 → 铺调子 → 排线 → 交叉线 → 提亮 | 纸底石墨排线,顺结构走向,暗部交叉线压深 | 想要手绘草稿感、练习用的稿子 | |
| 18 | + |
| 19 | +每种风格都有自己的一套工序、笔触语言和底纹,**不是同一套笔刷换配色**: |
| 20 | +线描的线是贴着 Canny 脊线吸附出来的,色块是把分层区域用 marching squares 抽成轮廓直接填充, |
| 21 | +素描的排线按局部明暗分四遍逐层压深。三种的笔触数据结构也各不相同(线 / 闭合填充 / 排线)。 |
| 22 | + |
9 | 23 | ## 特点 |
10 | 24 |
|
11 | | -- 🎨 **真实油画工序**:刷底色 → 起稿 → 单色底层 → 铺大色 → 塑造 → 塑形 → 罩染 → 干扫 → 细部 → 提白,十道工序顺序严格 |
| 25 | +- 🎨 **四种风格**:油画 / 线描 / 色块 / 素描,各有一套工序和笔触语言 |
12 | 26 | - 🖌 **物理笔触**:起收锋、笔毛分叉、颜料渐枯、厚涂浮雕、罩染透叠 |
13 | | -- 📱 **响应式**:桌面双栏、移动端单栏,自动适配触屏 |
14 | 27 | - 🔒 **本地处理**:图片只在你的浏览器里,绝不联网上传 |
15 | 28 | - 📦 **可下载**:生成结果打包成单个 HTML 文件,双击离线播放、随意分享 |
16 | | -- ⚡ **快**:1500px 图约 1.5–3 秒,8 万条笔触 |
| 29 | +- 📱 **响应式**:桌面双栏、移动端单栏,自动适配触屏 |
| 30 | +- ⚡ **快**:1400px 图约 1.5–3 秒,6 万条笔触 |
17 | 31 |
|
18 | 32 | ## 使用 |
19 | 33 |
|
20 | 34 | 1. 打开网站(或本地 `python -m http.server` 后访问) |
21 | 35 | 2. 拖入 / 选择图片(PNG / JPG / WEBP) |
22 | | -3. 调「细腻程度」「动画时长」「处理精度」 |
23 | | -4. 点「开始生成」 |
24 | | -5. 页面内实时预览,或下载单文件播放器 |
| 36 | +3. **选一种风格** |
| 37 | +4. 调「细腻程度」「动画时长」「处理精度」 |
| 38 | +5. 点「开始生成」 |
| 39 | +6. 页面内实时预览,或下载单文件播放器 |
25 | 40 |
|
26 | 41 | ## 文件结构 |
27 | 42 |
|
28 | 43 | | 文件 | 说明 | |
29 | 44 | |---|---| |
30 | | -| `index.html` | 主页面(上传、调参、实时预览、下载) | |
31 | | -| `core.js` | 算法核心 | |
| 45 | +| `index.html` | 主页面(上传、选风格、调参、实时预览、下载) | |
| 46 | +| `core.js` | 分析 + 四种风格的笔触生成 + 时间轴 | |
| 47 | +| `render.js` | 共用的笔触渲染器(网页预览与播放器共用,保证所见即所得) | |
32 | 48 | | `worker.js` | Web Worker,后台生成不卡界面 | |
33 | | -| `player-template.html` | 下载用的单文件播放器模板 | |
| 49 | +| `player-template.html` | 下载用的单文件播放器模板(内联 `render.js`) | |
34 | 50 | | `CNAME` | 自定义域名(tangyue.me) | |
35 | 51 | | `.github/workflows/deploy.yml` | GitHub Pages 自动部署 | |
36 | 52 |
|
37 | | -## 算法原理 |
| 53 | +## 技术实现 |
| 54 | + |
| 55 | +**分析一次,四种风格共用。** 先在降采样后的工作分辨率上算一张「结构图」: |
| 56 | + |
| 57 | +1. **分层**:在 L\*(亮度)× S(饱和度)平面上做 k-means(k-means++ 初始化),把画面按材质和明暗分开 |
| 58 | +2. **边缘**:两套 Canny(粗 σ=3.0 出主要轮廓,细 σ=1.2 出细节边缘),双阈值 + 滞后连接 |
| 59 | +3. **方向场**:结构张量(Sobel → 特征分解)求每个像素的主导走向;平坦区改用低频方向场,避免笔触乱指 |
| 60 | +4. **显著性**:梯度幅值 + 方向一致性 + 细边缘密度加权,告诉笔触「哪里值得多画几笔」 |
| 61 | + |
| 62 | +四种风格从同一张结构图出发,各取所需: |
| 63 | + |
| 64 | +- **油画**:网格播种 → 沿方向场行走 → 按显著性分配笔宽和密度,七道工序逐层加细 |
| 65 | +- **线描**:种子只撒在 Canny 脊线上,行走时向法线方向吸附(`requireEdge`),走偏即止;用 `maxTurn` 限制转角,防止笔画打卷成毛线团 |
| 66 | +- **色块**:对每个分层跑 marching squares 抽闭合轮廓,用 RDP 简化(闭合轮廓要在离起点最远处切成两条开链,否则首尾重合会让 RDP 退化),最后用 `evenodd` 填充规则一次平涂 |
| 67 | +- **素描**:按局部亮度分四遍排线,`rot90` 让交叉线垂直正交;石墨色按原图明暗映射,亮部再用高亮笔擦回纸白 |
| 68 | + |
| 69 | +**严格串行的时间轴**:`start[i] == start[i-1] + dur[i-1]`。每道工序按权重分配时长, |
| 70 | +工序内按 `0.0035 + 0.0010×弧长 + 0.0006×笔宽`(色块额外按面积开方)分配每笔时长,然后逐条校验零重叠零断点。 |
38 | 71 |
|
39 | | -**分层定色、结构张量定走向、工序定笔触语言、串行时间轴定节奏。** |
| 72 | +**颜色取自原图**:沿笔触取 5 个采样点的中位色,只做轻微抖动,绝不用调色板。 |
| 73 | +色块风格例外——它按设计就是要用量化后的限量配色。 |
40 | 74 |
|
41 | | -1. **五层明暗分层**:在 L\*(亮度)× S(饱和度)平面上做 k-means,把人像与背景按材质分开 |
42 | | -2. **轮廓与方向**:Canny 提取边缘,结构张量(Sobel → 特征分解)求每一笔的走向;平坦区改用低频方向场,避免笔触乱指 |
43 | | -3. **十道工序**:每道工序有自己的笔宽、密度、透明度与颜色处理,宽度逐档过渡(否则细笔硬盖巨笔会毛躁) |
44 | | -4. **严格串行**:`start[i] == start[i-1] + dur[i-1]`,逐条校验零重叠零断点 |
45 | | -5. **颜色取自原图**:沿笔触取中位色,只做轻微抖动,绝不用调色板 |
| 75 | +**网页与播放器共用渲染器**:`render.js` 被 `index.html` 和下载的单文件播放器共同引用, |
| 76 | +所以页面里看到的效果和下载后播放的完全一致。 |
46 | 77 |
|
47 | 78 | ## 部署到 GitHub Pages |
48 | 79 |
|
49 | 80 | 仓库本身就是 Pages 站点,`main` 分支 + GitHub Actions 自动部署。 |
50 | 81 |
|
51 | 82 | 换成你自己的域名:改 `CNAME` 文件内容即可。 |
52 | 83 |
|
53 | | -其他静态托管(Cloudflare Pages / Netlify / Vercel)同样适用——四个静态文件,无构建步骤。 |
| 84 | +其他静态托管(Cloudflare Pages / Netlify / Vercel)同样适用——几个静态文件,无构建步骤。 |
54 | 85 |
|
55 | 86 | ## 本地开发 |
56 | 87 |
|
|
0 commit comments