把一堆主题杂乱、数量超过 9 张的照片,自动排成 9 张 1080×1080 的朋友圈九宫格。
设计前提是一句话:
朋友圈九宫格是「相册」,不是「海报」。 别人点开会想看完整的照片,所以每张照片完整显示、绝不裁切到只剩局部。
照片比例各异(竖图 0.46 ~ 横图 3.5),硬塞进正方形必然产生留白或裁切。 本项目把这件事当成一个**二维装箱问题(2D Bin Packing,NP-hard)**来解:
| 环节 | 做法 |
|---|---|
| 视觉理解 | 多模态模型逐张分析:主体描述、类别、文字行数、核心区 core_bbox、亮度 |
| 信息量评分 | 文字行数×10 + 字数×0.1 + 类别加成 + 人脸 +3 − 手握小物件特写 −8 |
| 温和分级 | 按信息量严格降序分配目标面积(3 张 45/32/20%+、4 张 38/27/20/15%) |
| 装箱 | Squarified Treemap 密铺画布;槽位不够贴合时用 cover 裁切(受 max_crop 限制) |
| 立绘当贴纸 | 白底动漫立绘抠出人物 + 灰色圆角底,原图不参与拼图 |
| 不丢图 | 三层保障:上限自动放宽 + 溢出回填 + 渲染后按几何审计补图 |
git clone <repo> && cd NineCollage
pip install -r requirements.txt视觉分析需要一个大模型 API(本项目默认用 DeepSeek,见下方「视觉配置」)。
python -m ninecollage.cli.main3 \
--src ./photos --out ./output \
--vision deepseek --k 9 --canvas 1080 \
--layout-engine tight --theme hermes \
--max-crop 0.40 --photo-budget 0.92产物:
output/
├── 1.jpg … 9.jpg # 九宫格(朋友圈原生,按序发即可)
├── preview.jpg # 九宫格总览
├── posters.json # 每页布局 + 几何(可复现)
└── vision.json # 每张图的视觉分析结果
| 参数 | 说明 |
|---|---|
--vision deepseek |
视觉模型:deepseek(= DeepSeek V4.1)/ kimi / qwen |
--layout-engine tight |
tight=信息量分级装箱(推荐);slot=旧槽位式 |
--theme hermes |
hermes=深色紫罗兰;paper=米白手账 |
--max-crop 0.40 |
允许的裁切上限。调低更保守(照片更完整、留白更多) |
--photo-budget 0.92 |
照片占画布面积上限 |
--k 9 |
出几张(朋友圈九宫格=9) |
通过环境变量提供密钥(不要写进代码或提交到仓库):
# DeepSeek(默认,性价比高)
export DEEPSEEK_API_KEY=sk-xxxxxxxx
# 可选:指定模型,默认 deepseek-flash(= DeepSeek V4.1)
export DEEPSEEK_VISION_MODEL=deepseek-flash
# 或 Moonshot / Kimi
export KIMI_API_KEY=sk-xxxxxxxx
# 或通义千问
export DASHSCOPE_API_KEY=sk-xxxxxxxx也可放在项目根的 .env(已被 .gitignore 忽略)。
「每张照片完整」与「完全没有留白」在数学上不可兼得。 矩形比例互不相同时无法密铺正方形,只能四选一:
| 方案 | 结果 | 代价 |
|---|---|---|
保完整(默认 max_crop 小) |
照片覆盖率 ~66% | 有留白,用装饰填充 |
允许裁切(max_crop 0.40) |
覆盖率 ~88% | 边缘被裁掉 |
| 改底色为内容 | 视觉上不留空 | 需要额外渲染 |
| 每页减少照片数 | 每张都大 | 页数不够装下所有照片 |
本项目默认偏向「保完整」:留白交给装饰(颜文字、手绘、色块)填补, 而不是把照片裁到只剩局部。
ninecollage/
├── pipeline3.py # 主流程 + 全局审计(三层不丢图)
├── layout/
│ ├── engine3.py # 信息量评分 / 分级 / 裁切比例守卫
│ ├── engine4.py # 按信息量装箱 + 裁切渲染
│ ├── pack3.py # Squarified Treemap 密铺 + cover 填满
│ ├── decor_hermes.py # 深色 UI 风装饰
│ └── theme.py # 配色(从截图量化提取)
├── vision/
│ ├── analyzer.py # 多模态分析(可插拔 provider)
│ └── review.py # 文案生成
└── cli/main3.py # 命令行入口
- NP-hard 问题,无最优解:装箱用启发式(Squarified Treemap)。 文献里的 quasi-human 启发式在本数据集上实测不如 treemap。
- 依赖视觉模型质量:模型偶尔会给出错误的核心区 / 裁切建议, 代码内已加比例合理性守卫(偏离超过 ~2 倍则丢弃该建议)。
- 需要网络调用视觉 API(逐张分析,37 张约 1~3 分钟)。
MIT,见 LICENSE。