Fast Cleaner 如何在 iPhone 上尋找重複相片而毋須上載
Finding duplicate photos on iPhone without uploading a single one
Fast Cleaner 在 iPhone 上本機搜尋重複相片,毋須上載相片。它使用 Apple Vision 為相片建立嵌入向量,並以拍攝月份分組比較;160×160 縮圖載入速度快約 30%。掃描、報告、滑動清理及每日最多 300 MB 清理免費,Pro 月費為 $1.99。
Most photo cleaners send your library somewhere or lock the useful part behind a weekly subscription. We wanted the opposite for our app, Fast Cleaner: everything runs on the iPhone, and the free tier covers a normal daily cleanup. Here is how the duplicate finder works and what we learned shipping it to 50 languages.
1. One embedding per photo with Apple Vision
VNGenerateImageFeaturePrintRequest returns a feature vector for an image. Two photos of the same scene end up close to each other, even with small changes in framing or exposure.
let request = VNGenerateImageFeaturePrintRequest()
let handler = VNImageRequestHandler(cgImage: thumb, options: [:])
try handler.perform([request])
let print = request.results?.first as? VNFeaturePrintObservation
We request a 160×160 thumbnail from PhotoKit instead of the full image. Vision resamples to its own input size anyway, and the smaller request loads about 30% faster. Embeddings are cached on the device, so the second scan only processes new photos.
2. Compare only what can be similar
Comparing every photo with every other one is O(n²). On a 50,000-photo library that is far too slow. We bucket photos by the month they were taken and compare pairs inside a bucket. Duplicates and burst-like series are almost always taken close in time.
var d: Float = 0
try a.computeDistance(&d, to: b)
if d <= 0.3 { unionFind.union(i, j) }
A distance threshold of 0.3 gave the best balance between "same moment" and "similar but different". Union-find turns the pairs into groups.
3. Pick the best shot, offer the rest
Inside each group a simple weighted score picks the photo to keep:
- face capture quality (
VNDetectFaceCaptureQualityRequest): 0.35 - sharpness, Laplacian variance on luminance: 0.30
- resolution, log-scaled: 0.15
- open eyes and smile from face landmarks: 0.15
- newer date as a tiebreak: 0.05
Photos without faces get a neutral face score, so landscapes are not penalised.
4. Things that bit us
-
Memory. Batches of 50 images inside
autoreleasepool, otherwise large libraries run out of memory. - The simulator lies. In the iOS simulator Vision returned the same vector for every image, so all distances were 0 and every photo landed in one group. We now detect "collapsed" embeddings (different sizes, distance exactly 0) and skip such buckets.
- Main thread. Reading the photo library during view rendering caused watchdog kills on big libraries. All PhotoKit reads moved off the main thread.
- Deletion safety. Deletions go through PhotoKit, so everything lands in Recently Deleted for 30 days.
Pricing without a weekly plan
Scanning, the report, swipe-to-clean and up to 300 MB of cleanup a day are free. Pro removes the limit and adds video compression: $1.99/month (first month $0.99), $9.99/year or $19.99 once.
Fast Cleaner is on the App Store: https://apps.apple.com/app/id6772155675 — more at https://zoomapps.kz/fastcleaner/
來源:DEV Community · dev.to