EchoReel: 裝置端相片回憶系統
在不依賴雲端伺服器的前提下,使用 Apple Vision 與 SwiftUI 製作本機照片回憶影片的 iOS 應用程式。
目前進度與實測現況
- PhotoKit 本機讀取相片,不申請亦無任何網路權限
- Apple Vision 於裝置端偵測人臉位置與特徵
- 審查佇列(Review Queue)分群機制,必須手動點擊才確認身分
- SQLite 本機圖譜儲存已確認的關聯資料
- AVFoundation 前景運算輸出照片動態回顧影片
- 候選人臉特徵向量模型召回率未達門檻(實測 0.585 vs 目標 0.850),已淘汰捨棄
- 受限於 iOS 記憶體上限,無法於背景執行高負載影片渲染,需維持前景輸出
- 尚未上架 App Store 亦無外部用戶,僅在個人測試圖庫(1,420 張照片)驗證
01 · 想要解決的問題
主流的雲端相片服務通常會把個人的完整相片庫上傳到遠端伺服器,進行人臉辨識並自動生成回憶合輯。這會衍生隱私上的疑慮:生物特徵資料存放在遠端,且演算法一旦誤判,容易自動把不同人永久合併進同一個相簿紀錄。
EchoReel 是一套從一開始就以「本機優先」為原則打造的 iOS 應用程式。目標是在手機上完成人臉偵測、分群與照片動態回顧輸出,在維持極低記憶體增長(每張照片 ≤0.25 MiB)的同時,確保沒有任何照片或人臉特徵資料離開手機。
02 · 實作前提與限制
App 沙盒完全不宣告網路存取權限。沒有任何遠端呼叫、追蹤碼或第三方分析工具。
批次處理 4800 萬像素照片時,不能觸發 iOS Jetsam 記憶體強制終止機制。平均每張照片記憶體增長控制在 0.250 MiB 以下。
演算法只能產出候選分群建議,在使用者於介面上親自點擊確認前,絕不自動寫入關聯。
03 · 架構劃分與權限隔離
透過 Swift Actor 將照片讀取、Apple Vision 人臉運算、候選名單與使用者審查介面完全隔離。
裝置端相片處理流程
01. 本機讀取:透過 PhotoKit 讀取相片,App 本身完全不申請網路權限。
02. 裝置端偵測:由 Apple Vision 找出人臉位置與特徵點,全程在 iPhone 上運算。
03. 整理候選:把特徵相近的照片挑成候選組,不直接判定屬於同一個人。
04. 手動確認:在 SwiftUI 審查介面由使用者確認人物,避免系統誤認。
05. 本機儲存:確認後的關聯寫入本機 SQLite,平均每張照片記憶體增加 0.215 MiB。
06. 影片合成:使用 AVFoundation 直接在裝置上輸出回憶影片。
04 · 三項主要技術取捨
1. 採用 Apple 原生 Vision,不額外打包自製模型
減少依賴評估考量:評估過打包自製的 CoreML 人臉特徵模型,與直接調用 iOS 內建的 Apple Vision 框架。
採用的做法:決定使用 iOS 內建的 Vision 框架。系統會跨應用共用 Neural Engine 權重,讓 App 安裝檔大小從 85MB 縮減至 14MB,同時確保硬體加速。
結果與取捨:不同 iOS 小版本間的 API 行為需個別處理相容性,已透過單元測試與適配層封裝解決。
2. 降採樣縮圖管線與記憶體主動釋放
記憶體控制評估考量:批次讀取 4800 萬像素的 ProRAW 原始檔時,讀到第 30 張就容易吃光手機記憶體導致閃退。
採用的做法:在解碼前使用 CGImageSourceCreateThumbnailAtIndex 先將尺寸限制在 512px,並以 autoreleasepool 明確釋放暫存物件。
結果與取捨:在超過 1,000 張照片的批次測試中,平均每張照片記憶體增長維持在 0.215 MiB,安全低於 0.250 MiB 的上限。
3. 拒絕模糊門檻的自動合併
資料準確性評估考量:市面上許多相簿軟體會自行設定相似度門檻(如餘弦距離 < 0.6)直接將照片歸為同一人。
採用的做法:對於相似度落在中間模糊區間的照片,一律歸入審查佇列(Review Queue),絕不自動綁定身分。
結果與取捨:在測試圖庫中維持零錯誤合併;使用者對自己的人臉相簿擁有 100% 的決定權。
05 · 遇過最棘手的問題
AVFoundation 影片輸出時的記憶體累積
問題原因:製作動態平移縮放(Ken Burns)效果時,使用 AVVideoCompositionCoreAnimationTool 會快速累積 CALayer 與 CVPixelBuffer 暫存,釋放速度趕不上產生速度。
解決方式:重寫輸出流程,透過自訂的 VideoExportSessionCoordinator 控制預先讀取幀數並重複利用緩衝區;改用 AVVideoCompositing 搭配 Metal 著色器直接處理畫面變換。
測試結果:透過 Xcode Instruments 檢查,連續跑 20 次 60 秒 1080p 影片輸出均無記憶體洩漏,常駐記憶體維持在 68 MB 以下。
06 · 失敗的實驗:自製人臉特徵模型
把未達標準的實驗老實記錄下來,是工程開發重要的一環。當候選方案未達測試門檻時,及早淘汰比勉強上線更重要。
07 · 測試覆蓋與實機驗證
包含相片庫掃描、人臉邊界正規化與 SQLite 關聯查詢的單元與整合測試。
以 XCUITest 跑完首次引導、相簿掃描分類與影片匯出流程。
符合嚴格的 SwiftLint 規則與 Swift 5.9/6.0 並行安全性檢查。
目前版本與本機封存代碼的一致性比對完全相符。
08 · 專案回顧
專案心得:在手機上做這類應用,本質上是系統資源與記憶體管理的功課,而不只是挑選模型。如果一跑背景掃描就讓手機發燙閃退,或是匯出影片時畫面卡死,模型再先進也沒有意義。明確的並行權限隔離與記憶體控制,遠比追求複雜的模型結構更關鍵。
如果重做會做的調整:如果重來一次,我會在前期先準備好更多元角度與光線的人臉測試資料集,提早在電腦上把 Apple Vision 的極限測清楚,而不是等到裝上手機才逐一驗證邊界情況。