Not a Single Photo Uploaded: Flick's On-Device Similar Photo Detection
Analyzing the photo library entirely on device with Vision feature prints, Laplacian variance, and a SQLite cache.
Flick is a swipe-to-clean photo app. Its two core capabilities – finding similar photos and finding blurry photos – both run entirely on device, with no server dependency and no third-party SDKs. This post covers how it works.
Similarity detection: Vision feature prints
Apple’s Vision framework provides VNGenerateImageFeaturePrintRequest: feed it an image, get back a feature vector (feature print). The closer the distance between two images’ vectors, the more similar their content:
let request = VNGenerateImageFeaturePrintRequest()
try VNImageRequestHandler(cgImage: image).perform([request])
let print = request.results?.first as? VNFeaturePrintObservation
// print.computeDistance(_:to:) gives the distance between two images
Once I have vectors for the whole library, I cluster them by a distance threshold, and scenarios like burst shots, duplicate screenshots, and pick-one-of-nine all land in the same group. What’s left is presenting each group to the user and letting them swipe to keep one.
Blur detection: Laplacian variance
The classic way to tell whether a photo is blurry is to run a Laplacian convolution over the image and compute the variance: sharp images have rich edges and high variance, blurry ones have low variance. Using vImage for the convolution and vDSP for the variance, it’s a few milliseconds per image – fast enough on pure CPU. The algorithm is decades old and needs no machine learning model.
Engineering details
- Feature caching: with tens of thousands of photos, recomputing on every launch is out of the question. Feature vectors go into SQLite – straight C API, no ORM; at this scale that’s plenty.
- Analysis pipeline: a background coordinator processes in batches and is cancelable at any point, so the first full analysis doesn’t cook the device.
- iCloud placeholder files: on devices with iCloud Photos storage optimization enabled, many “photos” only exist locally as thumbnails. For these, read the metadata only and skip analysis – never trigger a download, or the user’s cellular data and iCloud storage both take the hit.
Why fully on-device, no exceptions
Privacy isn’t a slogan here; it’s decided by the architecture: with no server, “photos being uploaded” isn’t even a possible problem, and the privacy policy only needs one sentence. There’s a side benefit for an indie developer too – zero server cost. Every copy of the app sold is pure margin, with no monthly bill.