IDPhotoMaker

一款在 iPhone 本地完成人像抠图、证件照裁剪、换底与基础调整的 iOS 工具。


IDPhotoMaker App 图标
IDPhotoMaker App 图标

IDPhotoMaker 是我做的第一个 iOS 应用,也是我真正开始接触 SwiftUI 和客户端开发的地方。

项目起点是开源项目 HivisionIDPhotos。它的原始实现以 Python 为主,我想试着把其中的核心处理流程放进 iPhone,在本地完成一张证件照。过程并不轻松,最终做出来的东西也还有不少粗糙之处,这里只是把实际采用的方案简单记下来。

它做了什么

应用从相册、相机或内置样例读取照片,识别人脸位置并分离人物,再按照证件照规格进行裁剪。之后可以保留透明背景,也可以换成纯色、上下渐变或中心渐变,最后做一些亮度、对比度、饱和度、锐化和美白调整,再保存到系统相册。

代码里整理了 18 组常用照片规格,包括一寸、二寸和部分考试、签证尺寸。它更像一个轻量的本地工具,没有把自己做成完整的影像工作台。

技术和框架

界面主要使用 SwiftUI。相册选择使用 PhotosUI;相机调用、图片绘制和保存等系统能力仍通过 UIKit 补齐。刚开始写这个项目时,我对 SwiftUI 与 UIKit 之间的边界并不熟,很多实现是在反复试验中慢慢稳定下来的。

模型推理由 ONNX Runtime 执行,图像矩阵、缩放、颜色空间、轮廓和像素调整交给 OpenCV。项目使用 Swift 5,最低支持 iOS 17。仓库当前锁定的 ONNX Runtime 版本是 1.19.2;OpenCV 以本地 xcframework 接入,仓库没有记录可核对的具体版本,因此这里不写一个猜测值。

两个模型怎样配合

应用当前使用两个 ONNX 模型,它们承担的工作不同:

  • hivision_modnet.onnx 用于人像抠图。照片会先缩放到 512 × 512,完成归一化和 HWC 到 CHW 的排列,再送入模型。输出的灰度遮罩会恢复到原图尺寸,并作为透明通道合回人物图像。后面还会做阈值、腐蚀、最大轮廓和孔洞填充,尽量减少边缘碎片。
  • retinaface-resnet50.onnx 用于人脸检测,不是身份识别。它输出人脸框、置信度和五个关键点,裁剪逻辑再根据人脸大小、头部高度、目标比例和人物轮廓估算证件照的位置。当前实现要求画面中只检测到一张脸。

美白、亮度、对比度、饱和度和锐化不是第三个 AI 模型,而是 OpenCV 的像素运算。这些调整比较基础,我没有把它描述成智能美颜。

一张照片的处理过程

  1. 从相册、相机或内置样例取得 UIImage,较大的原图先把最长边压到 2000 像素以内。
  2. MODNet 生成人物遮罩,应用把遮罩整理为透明通道。
  3. RetinaFace 找到单张人脸,提供裁剪所需的位置和关键点。
  4. 根据目标证件照比例计算裁剪区域,并结合人物轮廓修正上下边界。
  5. 生成透明、纯色或渐变背景,再叠加人物。
  6. 应用基础像素调整,按选定尺寸输出并保存到相册。

两个模型随应用一起放在本地,核心处理链路没有调用远端接口。这样做的直接好处是没有网络时也能处理,照片不必为了这一步上传到服务端;代价则是安装包会更大,模型初始化和推理也要占用手机资源。

从原型到上架

我从 2024 年 9 月开始搭工程,先调通抠图,再补上保存、人脸检测、照片裁剪和背景处理。11 月进入完整产品界面的整理,之后第一次处理开发者账号、证书、打包、TestFlight 和审核。IDPhotoMaker 最终在 2024 年 12 月 11 日上线 App Store,前后大约两个半月。

这段时间里,真正花时间的并不只是模型。Xcode 的构建、CocoaPods 依赖、Objective-C 桥接、签名和上架流程,对当时的我都很陌生。AI 帮我补了不少知识空白,但具体到模型输入输出、图像坐标和边缘处理,仍然需要回到代码和实际图片中逐项核对。

IDPhotoMaker 早期原型
IDPhotoMaker 早期原型

早期原型只把原图、抠图、调整和渲染结果并排展示,和现在的界面已经不同。

产品配图

下面三张图使用应用内置的样例照片,依次记录规格选择、透明背景与换底、基础人像调整。它们对应的是当前产品界面。

选择证件照规格
选择证件照规格

从样例照片进入制作页,选择一寸、二寸等输出规格。

透明背景与换底
透明背景与换底
基础人像调整
基础人像调整

抠图完成后,可以保留透明背景,也可以选择纯色或渐变背景。

基础调整包括美白、亮度、对比度、饱和度和锐化,最后保存到系统相册。