照片水印(水印相机 APP 风格)
输入一张现场照片 + 时间 + 地点,输出同比例的「水印相机」APP 风格水印成品。
字体、两个图标、间距、不透明度全部对齐真实 APP,参数化后可直接换照片复用。
原图若自带手机厂商水印(如 HUAWEI Mate 30 5G / SuperSensing Camera | LEICA),
默认先把那一小块抹掉再叠自己的水印——否则两套水印会在画面底部打架。
一、绝不要用 AI 生图
「在原始照片上加水印」要求原图内容一字不改。AI 生图 / 图生图会重绘画面细节
(设备、吊带、人员位置都会变),对现场留痕照片是硬伤,中文小字也容易糊。
一律用 PIL 合成图层:矢量精确、原图像素零改动、免费、可重复。
去厂商水印同理:那是「局部像素修复」,不是重画。拿 AI 修图,整张照片会被重绘一遍,
照片作为凭证的价值就没了。走本地算法修复,只动水印那几行像素。
只有用户明确要「把照片重画成某种风格」时才走 nano-banana-pro 那类技能。
二、标准作业流程
第 1 步 · 收齐三要素。 缺哪个问哪个,不要自己编。
| 要素 | 必填 | 说明 |
|---|---|---|
| 日期 | 是 | 决定星期几,自动推算,不照抄参考图 |
| 时间 | 是 | 通常是"拍照那一刻",如 18:14 |
| 地点 | 是 | 如 泰州市·长强钢铁 |
用户可能只给一张参考图说"要这个效果"——那是样式参考,
文字内容仍按用户明确给的填,交付时提一句可换。
第 2 步 · 跑生成脚本。 输出到项目 outputs/,
不要默认丢到桌面根目录(用户明确要求桌面保持干净)。
需要给用户一份到桌面时,用 --copy-to 显式指定。
python <技能目录>/scripts/make_watermark.py \
--src "原图绝对路径.jpg" \
--date 2026-09-17 --time 18:14 \
--location "泰州市·长强钢铁" \
--out-dir "项目目录/outputs" \
--keep-clean # 想核对去水印效果时加上
脚本会先检测原图自带的厂商水印,把握充分才动手;拿不准就原样留着不动。
日志里 去厂商水印: 那一行就是它的结论,三种情形:
命中 N 处—— 已去掉,后面跟着每处的坐标、字块数、改动像素数未检出,原图像素未动—— 原图本来就没有厂商水印去水印模块不可用—— 缺 opencv,已跳过,其余功能正常
这一行要原样转述给用户,不要自己概括成「已处理」——用户需要知道到底动没动、
动了哪块。--keep-clean 会给出一份叠水印之前的底图方便人工核对(未检出时它就是原图),
所以加了这个参数就一定会落盘,日志里给到的路径必然存在。
第 3 步 · 自检(必做)。 交付前跑一次,确认版式没跑偏、去水印没越界:
python <技能目录>/scripts/verify_layout.py \
--src "原图.jpg" --out "成品.jpg" --clean "去水印底图.jpg" \
--ref "参考APP截图.jpg"
四项检查:A 版式比例、B 相机图标与参考图的 IoU、C 水印区以外像素未被改动、
D 旧厂商水印已清干净且改动未越出掩膜。--ref / --clean 是可选的,给了才跑对应项。
有任何 FAIL 先排查再交付,不要带病交付。
第 4 步 · 需要肉眼验收时出比对图。
python <技能目录>/scripts/make_compare.py \
--mine "成品.jpg" --ref "参考APP截图.jpg" --out-dir "项目目录/outputs/compare"
产出 compare_版式.png(同尺度上下拼接)、compare_图标_相机.png、
compare_图标_定位.png(自动定位后放大并排)。
第 5 步 · 交付。 用 present_files 给出成品。说明时列出五项
(时间 / 日期星期 / 地点 / 右下角标识 / 是否去过原图自带的厂商水印)。
用户没要求归档就不要动桌面。
三、参数
| 参数 | 默认 | 说明 |
|---|---|---|
--src |
必填 | 原图路径 |
--date |
必填 | 2026-09-17 / 2026/9/17 / 2026.9.17 / 20260917 都认 |
--location |
必填 | 地点;·•・ 各种间隔号会自动统一 |
--time |
18:14 |
18:14 / 1814 / 18.14 都认 |
--weekday |
自动 | 按日期推算;显式传入可覆盖 |
--no-weekday |
— | 不显示星期 |
--app / --no-app |
水印相机 |
右下角标识文字 / 整块隐去 |
--scale |
1.0 |
水印整体大小倍率(以底部中心为基准等比缩放) |
--shadow |
0.50 |
阴影强度,0 关闭 |
--quality |
96 |
JPEG 质量 |
--strip-vendor |
auto |
去厂商水印:auto 把握充分才动手 / on 连可疑的一起 / off 完全不去 |
--strip-zone |
— | 手动指定去水印区域 x0,y0,x1,y1,自动漏检时用 |
--strip-k |
5 |
去水印填充轮数系数,一般不用动 |
--keep-clean |
— | 额外输出一份叠水印前的底图(..._去水印底图.jpg),便于核对。未检出 / off 时该图即原图 |
--out-dir / --out-name |
outputs / 自动 |
输出位置;文件名默认 水印_{地点}_{YYYYMMDD}_{HHMM}.jpg |
--copy-to |
— | 额外拷一份到指定目录 |
四、环境要求(踩过的坑)
- 必须用带 numpy / opencv 的解释器。
- 缺 numpy:导入即
ModuleNotFoundError: No module named 'numpy',整个脚本跑不起来。 - 缺 opencv:只影响去厂商水印,会自动降级跳过,其余功能照常。
- Windows 上优先用默认 venv(
~/.workbuddy/binaries/python/envs/default/Scripts/python.exe)
或系统 python;缺包装numpy pillow opencv-python。 - 托管版 python 常是精简环境,别默认它有这些包。
- 中文字体按候选列表查找(Noto Sans SC → 微软雅黑 → 等线 → 黑体 → PingFang → Noto CJK)。
全都没有时脚本会明确报错,不要静默降级。 - 不要把 python 脚本接进 shell 管道(
python ... | grep)。这台机器的 bash 不装外部命令,
管道右端(grep/tail/mkdir/dirname)经常command not found,
而左端的 python 仍然会照跑,于是出现「看起来失败、其实已经落盘」的假象。
要看输出就直接跑;shell 整体失灵时改走 PowerShell 或python -c。
五、换照片时的行为与限制
- 任意画幅都支持:横图、竖图、方图。缩放基准是长边,锚定在底部居中。
注意:实测样本只有两张横图,竖图规律是按「长边等比 + 底部居中」外推的。 - 手机照片的 EXIF 方向标签会自动应用(
ImageOps.exif_transpose),
输出时把方向标签归 1,避免被看图软件再转一次。EXIF 其余部分原样保留。 - 超大图自动降超采样(
8000 / 长边,上限 4×),防止内存爆掉。 - 水印是纯白的。如果照片底部本身就是白的(雪地、过曝水面),水印会看不清。
APP 本身也这样,属于忠实还原。可以调--shadow加强对比,或提示用户。 - 输出文件名里的非法字符(
<>:"/\|?*)会被自动去掉。
去厂商水印的边界(要主动告知用户)
- 只认「成行排列的纯白文字」这一种形态,判据三条同时成立:够白(字块亮度 ≥205)、
够密(行内间隙 ≤0.04 图宽)、够齐(行高变异 ≤0.35)。彩色厂商 logo、单颗图标、
艺术字排版的机型水印,auto认不出,会当成「未检出」放过。
照片里的白色物体(船体、栏杆)从来够不到纯白,会被这三条挡在外面。 - 照片本身有白色文字时(船名、船号、招牌、编号),
auto也可能放过——
这是「宁可漏检、不可误删」的取舍。要强行动手得显式指定--strip-zone。 - 修复质量取决于水印底下是什么。大面积同色(天空、水面、纯色船体、甲板)
补得几乎看不出;压在锐利结构上(栏杆、缆绳、货箱棱边)会留一段
「说不上哪不对」的模糊。做不到 100% 无痕,交付时要主动说明。 - 亮背景 + 白色水印:检测走的是「亮 + 低饱和」,两者会互相干扰,
可能漏检。此时输出「未检出」,不会硬改。
六、详细规格
改代码或调参前,先读 references/layout-spec.md——那里是全部比例、图标几何、
色值、不透明度的实测记录,以及每条经验(为什么中文要补字距、为什么「·」要手画、
为什么厂商水印的掩膜必须是笔画形状而不能用矩形框)的来源与数据。
改完必须重跑 verify_layout.py。
快速定位:
grep -n "R_TIME_W\|R_LOGO_S\|CAM_LENS_C\|PIN_D_EM" references/layout-spec.md
grep -n "^R_\|^GAP_\|^CAM_\|^CJK_TRACK" scripts/make_watermark.py
grep -n "^D_\|^S_\|^CONF_" scripts/vendor_watermark.py