Skip to content

Commit 79fc555

Browse files
committed
feat: 新增线描 / 色块 / 素描三种重绘风格
原来只有一套油画工序,现在把「风格」抽成可选项,每种风格有自己的工序、 笔触语言和底纹,不是同一套笔刷换配色。 - core.js 重构为风格注册表(STYLES),工序的权重与中文标签下沉到每个工序, 时间轴不再硬编码油画那十道 - 分析结果(分层 / 边缘 / 方向场 / 显著性)四种风格共用,只在笔触生成上分叉 - 线描:种子只撒在 Canny 脊线上,行走时沿法线吸附,maxTurn 限制转角防止打卷 - 色块:marching squares 抽闭合轮廓 + 偶数填充规则平涂;RDP 简化在闭合轮廓上 要先切断(首尾重合会让所有距离为 0,退化成两点),另修了 resample 在 m<2 时 cum[j+1] 越界导致崩溃 - 素描:按明暗分四遍排线,rot90 让交叉线正交,亮部用高亮笔擦回纸白 - 新增 render.js:网页与下载播放器共用同一套笔触渲染器,保证所见即所得 - 界面加风格选择卡片,按风格切换工序提示与底纹
1 parent f8e1669 commit 79fc555

7 files changed

Lines changed: 1330 additions & 444 deletions

File tree

‎.gitattributes‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# 静态站点:源码统一用 LF,避免 Windows 上自动转 CRLF 造成的无意义 diff
2+
*.js text eol=lf
3+
*.html text eol=lf
4+
*.md text eol=lf
5+
*.yml text eol=lf
6+
*.css text eol=lf
7+
*.json text eol=lf
8+
CNAME text eol=lf

‎README.md‎

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,87 @@
1-
# strokeoil · 油画工序逐笔重绘
1+
# strokeoil · 图片逐笔重绘
22

3-
把任意图片重绘成「按真实油画十道工序逐笔画出」的动画。**纯前端实现,图片不上传、无需后端**,可直接托管到 GitHub Pages。
3+
把任意图片重绘成「一笔一笔画出来」的过程动画,内置 **四种绘画风格**:油画、线描、色块、素描。
4+
**纯前端实现,图片不上传、无需后端**,可直接托管到 GitHub Pages。
45

56
仓库:<https://github.com/tyuecode/tyuecode.github.io>
67

78
在线体验:<https://tangyue.me/>
89

10+
## 四种风格
11+
12+
| 风格 | 工序 | 效果 | 适合 |
13+
|---|---|---|---|
14+
| **油画** | 刷底色 → 起稿 → 单色底层 → 铺大色 → 塑造 → 塑形 → 罩染 → 干扫 → 细部 → 提白 | 十道古典工序,笔触有起收锋、笔毛分叉、颜料渐枯、厚涂浮雕、罩染透叠 | 人像、风景,想要「真在画画」的质感 |
15+
| **线描** | 定形 → 勾主线 → 结构线 → 细描 → 点睛 | 近黑底上的细白线,只勾结构不铺色,像版画稿/工程图 | 线条为主的原图、想要高对比的图 |
16+
| **色块** | 铺底色 → 暗部色块 → 中间调 → 亮部 → 点缀 | k-means 分层后逐层平涂硬边色块,限量配色的海报感 | 扁平/插画风,做海报和封面 |
17+
| **素描** | 起形 → 铺调子 → 排线 → 交叉线 → 提亮 | 纸底石墨排线,顺结构走向,暗部交叉线压深 | 想要手绘草稿感、练习用的稿子 |
18+
19+
每种风格都有自己的一套工序、笔触语言和底纹,**不是同一套笔刷换配色**:
20+
线描的线是贴着 Canny 脊线吸附出来的,色块是把分层区域用 marching squares 抽成轮廓直接填充,
21+
素描的排线按局部明暗分四遍逐层压深。三种的笔触数据结构也各不相同(线 / 闭合填充 / 排线)。
22+
923
## 特点
1024

11-
- 🎨 **真实油画工序**:刷底色 → 起稿 → 单色底层 → 铺大色 → 塑造 → 塑形 → 罩染 → 干扫 → 细部 → 提白,十道工序顺序严格
25+
- 🎨 **四种风格**:油画 / 线描 / 色块 / 素描,各有一套工序和笔触语言
1226
- 🖌 **物理笔触**:起收锋、笔毛分叉、颜料渐枯、厚涂浮雕、罩染透叠
13-
- 📱 **响应式**:桌面双栏、移动端单栏,自动适配触屏
1427
- 🔒 **本地处理**:图片只在你的浏览器里,绝不联网上传
1528
- 📦 **可下载**:生成结果打包成单个 HTML 文件,双击离线播放、随意分享
16-
- ⚡ **快**:1500px 图约 1.5–3 秒,8 万条笔触
29+
- 📱 **响应式**:桌面双栏、移动端单栏,自动适配触屏
30+
- ⚡ **快**:1400px 图约 1.5–3 秒,6 万条笔触
1731

1832
## 使用
1933

2034
1. 打开网站(或本地 `python -m http.server` 后访问)
2135
2. 拖入 / 选择图片(PNG / JPG / WEBP)
22-
3. 调「细腻程度」「动画时长」「处理精度」
23-
4. 点「开始生成」
24-
5. 页面内实时预览,或下载单文件播放器
36+
3. **选一种风格**
37+
4. 调「细腻程度」「动画时长」「处理精度」
38+
5. 点「开始生成」
39+
6. 页面内实时预览,或下载单文件播放器
2540

2641
## 文件结构
2742

2843
| 文件 | 说明 |
2944
|---|---|
30-
| `index.html` | 主页面(上传、调参、实时预览、下载) |
31-
| `core.js` | 算法核心 |
45+
| `index.html` | 主页面(上传、选风格、调参、实时预览、下载) |
46+
| `core.js` | 分析 + 四种风格的笔触生成 + 时间轴 |
47+
| `render.js` | 共用的笔触渲染器(网页预览与播放器共用,保证所见即所得) |
3248
| `worker.js` | Web Worker,后台生成不卡界面 |
33-
| `player-template.html` | 下载用的单文件播放器模板 |
49+
| `player-template.html` | 下载用的单文件播放器模板(内联 `render.js`) |
3450
| `CNAME` | 自定义域名(tangyue.me) |
3551
| `.github/workflows/deploy.yml` | GitHub Pages 自动部署 |
3652

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×笔宽`(色块额外按面积开方)分配每笔时长,然后逐条校验零重叠零断点。
3871

39-
**分层定色、结构张量定走向、工序定笔触语言、串行时间轴定节奏。**
72+
**颜色取自原图**:沿笔触取 5 个采样点的中位色,只做轻微抖动,绝不用调色板。
73+
色块风格例外——它按设计就是要用量化后的限量配色。
4074

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+
所以页面里看到的效果和下载后播放的完全一致。
4677

4778
## 部署到 GitHub Pages
4879

4980
仓库本身就是 Pages 站点,`main` 分支 + GitHub Actions 自动部署。
5081

5182
换成你自己的域名:改 `CNAME` 文件内容即可。
5283

53-
其他静态托管(Cloudflare Pages / Netlify / Vercel)同样适用——四个静态文件,无构建步骤。
84+
其他静态托管(Cloudflare Pages / Netlify / Vercel)同样适用——几个静态文件,无构建步骤。
5485

5586
## 本地开发
5687

0 commit comments

Comments
 (0)