基于ARKit与Vision的本地人脸图片身份认证实现问询
Great question! Implementing local image-based authentication on iOS using modern frameworks like Vision (ditching outdated methods and cloud services like Amazon Rekognition) is totally doable. Let's walk through the full implementation step by step:
1. Account Registration Flow
When users create an account, let them select an image from their photo library and securely store it for future authentication checks.
Step 1: Let Users Select an Image
Use UIImagePickerController with sourceType = .photoLibrary to let users pick their auth image:
func presentPhotoLibraryPicker() { let picker = UIImagePickerController() picker.sourceType = .photoLibrary picker.delegate = self present(picker, animated: true) } // Handle the selected image func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) guard let selectedImage = info[.originalImage] as? UIImage else { return } // Save the image securely saveAuthImage(selectedImage) }
Step 2: Securely Store the Image
Never store sensitive auth data in plain files—use Keychain for encryption and device-bound storage:
func saveAuthImage(_ image: UIImage) { guard let imageData = image.jpegData(compressionQuality: 0.8) else { print("Failed to convert image to data") return } let keychainQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "UserAuthImage", kSecValueData as String: imageData, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly // Prevents iCloud sync ] // Delete existing entry if it exists (for account updates) SecItemDelete(keychainQuery as CFDictionary) // Add the new image data to Keychain let status = SecItemAdd(keychainQuery as CFDictionary, nil) if status != errSecSuccess { print("Failed to save auth image to Keychain") } }
2. Login & Camera Capture Flow
On login, use the device camera to capture a new image and compare it against the stored one.
Step 1: Present Camera Picker
Configure UIImagePickerController with sourceType = .camera:
func presentCameraLoginPicker() { guard UIImagePickerController.isSourceTypeAvailable(.camera) else { print("Camera not available") return } let picker = UIImagePickerController() picker.sourceType = .camera picker.delegate = self present(picker, animated: true) } // Handle captured image func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true) guard let capturedImage = info[.originalImage] as? UIImage else { return } // Start image comparison authenticateWithCapturedImage(capturedImage) }
3. Core Image Matching with Vision
Apple's Vision framework provides robust, local image feature matching that's far more reliable than old pixel-comparison methods. Here's how to use it:
import Vision func authenticateWithCapturedImage(_ capturedImage: UIImage) { // Retrieve the stored auth image from Keychain guard let savedImageData = getSavedAuthImageData(), let savedImage = UIImage(data: savedImageData), let savedCGImage = savedImage.cgImage, let capturedCGImage = capturedImage.cgImage else { print("No saved auth image found or invalid image format") handleAuthFailure() return } // Use a background queue to avoid blocking the main thread DispatchQueue.global(qos: .userInitiated).async { do { // Generate feature prints for both images let savedFeaturePrint = try self.generateImageFeaturePrint(from: savedCGImage) let capturedFeaturePrint = try self.generateImageFeaturePrint(from: capturedCGImage) // Calculate similarity distance (lower = more similar) var distance = Float(0) try savedFeaturePrint.computeDistance(&distance, to: capturedFeaturePrint) DispatchQueue.main.async { // Adjust this threshold based on your testing (0.7-0.9 works for most cases) let authThreshold: Float = 0.8 if distance < authThreshold { self.handleAuthSuccess() } else { print("Authentication failed: distance = \(distance)") self.handleAuthFailure() } } } catch { DispatchQueue.main.async { print("Error during image comparison: \(error.localizedDescription)") self.handleAuthFailure() } } } } // Helper to generate Vision feature prints private func generateImageFeaturePrint(from cgImage: CGImage) throws -> VNImageFeaturePrintObservation { let request = VNGenerateImageFeaturePrintRequest() let handler = VNImageRequestHandler(cgImage: cgImage) try handler.perform([request]) guard let featurePrint = request.results?.first as? VNImageFeaturePrintObservation else { throw NSError(domain: "AuthError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to generate feature print"]) } return featurePrint } // Helper to retrieve saved image from Keychain private func getSavedAuthImageData() -> Data? { let keychainQuery: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "UserAuthImage", kSecReturnData as String: kCFBooleanTrue!, kSecMatchLimit as String: kSecMatchLimitOne ] var data: AnyObject? let status = SecItemCopyMatching(keychainQuery as CFDictionary, &data) return status == errSecSuccess ? data as? Data : nil } // Placeholder methods for auth result handling private func handleAuthSuccess() { print("Authentication successful!") // Navigate to main app flow } private func handleAuthFailure() { print("Authentication failed. Please try again.") // Show error message to user }
Key Considerations
- Security: Using Keychain ensures the auth image is encrypted and tied to the device (if you use
kSecAttrAccessibleWhenUnlockedThisDeviceOnly). Avoid storing images inDocumentsorUserDefaults—these are not secure. - Threshold Tuning: Test the
authThresholdvalue with real user scenarios. A lower value means stricter matching, while a higher value allows minor variations (like lighting changes). - Image Preprocessing: For better accuracy, you can preprocess images (crop to the same aspect ratio, normalize lighting) before generating feature prints.
- ARKit Integration (Optional): If your use case is face-based authentication, you can combine Vision with ARKit's
ARFaceTrackingConfigurationto capture 3D face data for even more precise matching. - Performance: Feature extraction is lightweight, but always run it on a background queue to keep the UI responsive.
内容的提问来源于stack exchange,提问作者Egghead




