Community图像github.com

onemanylov/phone-screen

将手机照片转换为可复用的模板,并通过代码将任意图像放置到屏幕上,无需图像生成器。适用于制作新手机照片、新模板或验证模板。

phone-screen 是什么?

此技能通过代码实现将一张手机照片的整个正面区域(包括屏幕、黑色边框和刘海/灵动岛)替换为任意图像,而玻璃以外的部分保持原样。它支持两种主要场景:一是直接使用已有模板快速替换屏幕图像(`python3 swap.py <image>`),二是从真实手机照片创建新模板。创建新模板时,用户需要提供一张iPhone正面照片(排除倾斜超过25°或宽高比差异过大的照片),并遵循一系列步骤:裁剪、边缘检测、轮廓提取(考虑透视和镜头畸变)、验证、测量刘海/灵动岛位置、构建模板,最后通过严格的边框一致性检查(四边黑色框架宽度偏差不超过4像素)。模板创建完成后,可用于任意图像的屏幕替换。该技能基于Python脚本实现,不依赖任何图像生成模型,完全通过计算视觉和几何变换完成操作。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/onemanylov/phone-screen-swap/tree/HEAD/.claude/skills/phone-screen

Installed? Explore more 图像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

手机屏幕替换

照片:$ARGUMENTS。如果没有,则要求提供一张,或使用 find_photos.py 查找。 整个手机正面通过代码被替换:屏幕、黑色边框以及刘海或灵动岛。玻璃以外的照片部分保持不变。

对于已经存在的模板,此技能无需使用:python3 swap.py <image>。

新模板

获取:一张真实的iPhone照片,屏幕正对相机。跳过:Android、倾斜超过25°、一边长度超过另一边1.2倍(裁剪会拒绝它们)。跳过手指或袖子遮挡屏幕的照片: 如果没有灰色边框,会覆盖在屏幕上。整个玻璃区域(包括上面的眩光)都属于我们。只有从外部进入的皮肤部分保留在照片中。

P=<name, 8 characters, unique>; D=templates/corners
mkdir -p out
# 1. 查看照片并读取屏幕的大致角点:TL,TR,BR,BL
python3 tools/slide_crop.py --q '<corners>' <photo.jpg> templates/crop/$P.jpg       # 在裁剪图上打印角点
# 2. 精确的直边。如果 `live` 较低:R=34
python3 tools/slide_lines.py $P '<corners on the crop>' out/l.jpg                    # 输出末尾的精确角点
# 3. 轮廓:透视、镜头弯曲、半径、玻璃轮廓
python3 tools/slide_trace.py $P '<corners>' out/t.jpg $D/$P.json
# 4. 验证拟合未覆盖的部分。务必查看图片
python3 tools/slide_proof.py $P $D/$P.json out/$P-proof.jpg
# 5. 姿态,仅用于反射
python3 tools/slide_sheet.py $P $D/$P.pose.json init
# 6. 测量刘海或灵动岛、状态图标、黑色区域
python3 tools/slide_check.py $P measure
# 配方 $D/$P.recipe.json:复制 a841f108(刘海)或 f5dad639(灵动岛),然后设置 frame=$P、pose、corners 以及测得的选项
# 7. 将时间和图标调整到该手机的位置
python3 tools/slide_status.py $P init <line from measure>; python3 tools/slide_status.py $P build
# 8. 构建并进行红色测试
python3 tools/slide_check.py $P build
# 9. 泄漏热图
python3 tools/slide_check.py $P leak
# 10. 边框宽度
python3 tools/slide_check.py $P frame

完成之后,它就是一个模板:python3 swap.py <image> -t $P。

相信之前先检查

  1. out/$P-split.jpg: 照片、红色、结果。红色拟合到位,边框完整覆盖手机壳边缘,从主体向内的一切都属于我们。
  2. out/$P-leak.jpg: 黑色屏幕上的边框,亮度采用对数标度。任何发光部分都来自照片:切割边缘的线条、斑点、眩光。只有扬声器和真正突出物才会显示。
  3. out/$P-top.jpg: 照片上切割部分的绿色轮廓,图标到位。
  4. out/$P-zoom.jpg: 角落和边框放大图,旁边是照片。
  5. 通过 swap.py 使用白色图像的模板:深色页面会暴露不良的角落和边缘。
  6. out/$P-frame.jpg: 白色屏幕上的四个角点。在通过以下边框检查之前,模板不算完成。

边框检查

黑色边框是硬件,四周宽度一致。slide_check.py $P frame 在白色屏幕上构建,将其拉直并测量每侧中部的黑色宽度,单位为截图像素(591 宽)。它会分别打印 ours 和 photo 各侧的值、差异以及判定:最多 4 像素为 OK,超过则为 FIX。 4 像素的限值是根据这些手机确定的:7.5 像素的差异明显可见,而 4 像素则看不出来。 如果新模板显示 FIX:

  1. 重新运行 slide_trace.py:它会读取可见的黑色区域,并为每侧取中位数(frame: 行)。
  2. 重新构建,然后再次运行 frame。
  3. 仍然显示 FIX:比较 ours 和 photo。如果它们匹配,说明照片中该侧的边框被眩光、手机壳或手遮挡住了。如果不匹配,则轮廓有误:查看 -frame.jpg 和 -split.jpg。
  4. 如果无法收敛,则不要将模板标记为完成。说明是哪一侧偏差以及偏差的像素数。 也请目视检查 -frame.jpg:顶部和侧面应该匹配。 已发布的模板:f38fe44a 2.2、79186658 3.2 和 895d3ee8 3.8 通过。f5dad639 5.8、a841f108 6.2 和 14278a0b 8.5 未通过:它们的边框保持首次构建时的状态。

设置

  • 黑色: floor,使边框和切割部分与照片匹配。从 .003 开始,如果照片更暗则降低。build 会打印两者。
  • 刘海: 来自 measure 的值。根据绿色轮廓调整 cr,measure 读取的值偏低。
  • 刘海上的扬声器: grille=45。如果旧页面的一条细线出现在刘海周围:gband=1。
  • 灵动岛: 其中心是硬件,位于 591 中的 295.5。如果 measure 显示偏差超过 1 像素,说明某个亮部吞噬了边缘:取干净的边缘并通过中心镜像。在锁定屏幕上,从带有灵动岛的手机(时间 111,图标 479)获取 x,从 measure 获取 y。
  • 灵动岛上方的扬声器: 如果位于玻璃轮廓内部,grille=45 只恢复其浮雕。
  • 玻璃上的袖子: sleeve=1,仅当 templates/grey/(f38fe44a)中存在真实的灰色边框时使用。
  • 暗对暗: 当 720 个点中少于 400 个上升时,slide_trace.py 会自动切换。请额外仔细检查 -split。

工作原理

手机是刚性的,因此屏幕是一个带有 iOS 连续圆角的矩形,通过透视和一个径向镜头弯曲观察。边缘在对数亮度中查找,因此暗对暗也能工作,并在线性光线的中点处放置。图像绘制在拉直的照片上,然后通过玻璃反向弯曲。

已知陷阱

  • 仅通过深色页面判断。
  • 用一种方式拟合却用另一种方式检查:检查就是拟合本身,而验证才是检查被排除的内容。
  • 直接在照片上画直线:照片是弯曲的。直线只存在于拉直后的图像上。
  • 在亮屏上从外向内搜索手机壳边缘:布料的褶皱看起来像手机壳。应从屏幕向外搜索。

相关技能