Skip to content
All essays
iOSMarch 27, 202512 min

Swift Vision Framework: Computer Vision

Perform computer vision tasks with Vision framework. Face detection, text recognition, and image analysis.

Ü
Ümit Uz
Mobile & Full Stack Developer

Vision framework provides powerful computer vision capabilities. Learn to detect faces, recognize text, and analyze images.

Vision Setup

Import Vision

swift
import Vision
import UIKit
import CoreGraphics

class VisionProcessor {
    func processImage(_ image: UIImage) {
        guard let cgImage = image.cgImage else {
            return
        }

        let orientation = CGImagePropertyOrientation(image.imageOrientation)
        let requestHandler = VNImageRequestHandler(cgImage: cgImage, orientation: orientation) { request, error in
            // Handle results
        }

        let requests = [VNRecognizeAnimalsRequest(), VNRecognizeTextRequest()]

        for request in requests {
            requestHandler(request)
        }
    }
}

Face Detection

Detect Faces

swift
class FaceDetector: ObservableObject {
    @Published var faceCount: Int = 0
    @Published var faceBounds: [CGRect] = []

    func detectFaces(in image: UIImage) {
        guard let cgImage = image.cgImage else {
            return
        }

        let faceDetectionRequest = VNDetectFaceRectanglesRequest { request, error in
            guard let results = request.results as? [VNFaceObservation], error == nil else {
                return
            }

            DispatchQueue.main.async {
                self.faceCount = results.count
                self.faceBounds = results.map { $0.boundingBox }
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: .up, completionHandler: faceDetectionRequest)

        try? VNImageRequestHandler(cgImage: cgImage, orientation: .up).perform([faceDetectionRequest])
    }

    func detectFaceLandmarks(in image: UIImage) {
        let landmarkDetectionRequest = VNDetectFaceLandmarksRequest { request, error in
            guard let results = request.results as? [VNFaceObservation], error == nil else {
                return
            }

            for face in results {
                if let landmarks = face.landmarks {
                    print("Face detected at: \(landmarks.leftEye?.location)")
                }
            }
        }

        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up)

        try? handler.perform([landmarkDetectionRequest])
    }

    func captureQuality(in image: UIImage) {
        let qualityRequest = VNDetectFaceCaptureQualityRequest { request, error in
            guard let results = request.results as? [VNFaceObservation], error == nil else {
                return
            }

            for face in results {
                if let quality = face.faceCaptureQuality {
                    print("Quality: \(quality)")
                }
            }
        }

        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up)

        try? handler.perform([qualityRequest])
    }
}

Text Recognition

OCR

swift
class TextRecognizer: ObservableObject {
    @Published var recognizedText: String = ""

    func recognizeText(in image: UIImage) {
        guard let cgImage = image.cgImage else {
            return
        }

        let request = VNRecognizeTextRequest { request, error in
            guard let results = request.results as? [VNRecognizedTextObservation], error == nil else {
                return
            }

            let text = results.compactMap { $0.topCandidates(1).first?.string }
            let combinedText = text.joined(separator: "\n")

            DispatchQueue.main.async {
                self.recognizedText = combinedText
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: .up)

        try? handler.perform([request])
    }

    func recognizeTextRectangles(in image: UIImage) {
        let request = VNRecognizeTextRequest { request, error in
            guard let results = request.results as? [VNRecognizedTextObservation], error == nil else {
                return
            }

            for result in results {
                if let textBox = result.boundingBox {
                    print("Text box: \(textBox)")
                }
            }
        }

        let handler = VNImageRequestHandler(cgImage: image.cgImage!, orientation: .up)

        try? handler.perform([request])
    }
}

Object Detection

Detect Objects

swift
class ObjectDetector: ObservableObject {
    @Published var detectedObjects: [(label: String, confidence: VNConfidence, location: CGRect)] = []

    func detectObjects(in image: UIImage) {
        guard let cgImage = image.cgImage else {
            return
        }

        let request = VNRecognizeAnimalsRequest { request, error in
            guard let results = request.results as? [VNRecognizedObservation], error == nil else {
                return
            }

            let objects = results.map { observation in
                (
                    label: observation.labels.first?.identifier ?? "Unknown",
                    confidence: observation.confidence,
                    location: observation.boundingBox
                )
            }

            DispatchQueue.main.async {
                self.detectedObjects = objects
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: up)

        try? handler.perform([request])
    }

    func detectRectangles(in image: UIImage) {
        let request = VNDetectRectanglesRequest { request, error in
            guard let results = request.results as? [VNRectangleObservation], error == nil else {
                return
            }

            for rectangle in results {
                print("Rectangle: \(rectangle.boundingBox)")
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage!, orientation: .up)

        try? handler.perform([request])
    }

    func detectBarcodes(in image: UIImage) {
        let request = VNDetectBarcodesRequest { request, error in
            guard let results = request.results as? [VNBarcodeObservation], error == nil else {
                return
            }

            for barcode in results {
                print("Barcode: \(barcode.payloadStringValue ?? "")")
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage!, orientation: .up)

        try? handler.perform([request])
    }
}

Image Classification

Classify Images

swift
class ImageClassifier {
    func classify(image: UIImage) async throws -> [String] {
        guard let cgImage = image.cgImage else {
            throw ClassifyError.invalidImage
        }

        let model = try VNCoreMLModel(for: MLModel(contentsOf: Bundle.main.url(forResource: "ImageClassifier", withExtension: "mlmodelc")!)

        let classificationRequest = VNCoreMLRequest(model: model) { request, error in
            guard let results = request.results as? [VNClassificationObservation], error == nil else {
                return
            }

            let classifications = results.prefix(5).map {
                $0.identifier
            }

            print("Classifications: \(classifications)")
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: up)

        try await handler.perform([classificationRequest])
    }

    enum ClassifyError: Error {
        case invalidImage
    }
}

Core ML Integration

ML Models

swift
class MLImageProcessor {
    func processImageWithModel(image: UIImage) async throws -> String {
        guard let cgImage = image.cgImage else {
            throw ProcessingError.invalidImage
        }

        let configuration = MLModelConfiguration()
        let model = try VNCoreMLModel(for: MLModel(contentsOf: Bundle.main.url(forResource: "CustomModel", withExtension: "mlmodelc")!)

        let request = VNCoreMLRequest(model: model) { request, error in
            guard let results = request.results as? [VNClassificationObservation] else {
                return
            }

            if let topResult = results.first {
                DispatchQueue.main.async {
                    print("Classification: \(topResult.identifier), Confidence: \(topResult.confidence)")
                }
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: up)

        try await handler.perform([request])
    }

    enum ProcessingError: Error {
        case invalidImage
    }
}
swift
class VisualSearchManager {
    func generateFeatureVector(for image: UIImage) async throws -> [Float] {
        guard let cgImage = image.cgImage else {
            throw SearchError.invalidImage
        }

        let request = VNGenerateImageFeaturePrintRequest { request, error in
            if let featurePrint = request.results?.first as? VNFeaturePrintObservation {
                let data = featurePrint.data
                let featureVector = data.withUnsafeBytes { pointer in
                    Array(UnsafeBufferPointer(start: pointer, count: 128).compactMap { $0 as? Float })
                }

                DispatchQueue.main.async {
                    print("Feature vector: \(featureVector.count) dimensions")
                }

                return featureVector
            }
        }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: up)

        try await handler.perform([request])
    }

    func compareImages(_ image1: UIImage, _ image2: UIImage) async throws -> Float {
        let vector1 = try await generateFeatureVector(for: image1)
        let vector2 = try await generateFeatureVector(for: image2)

        let similarity = cosineSimilarity(vector1, vector2)
        return similarity
    }

    private func cosineSimilarity(_ a: [Float], _ b: [Float]) -> Float {
        guard a.count == b.count else { return 0 }

        let dotProduct = zip(a, b).map(*).reduce(0, +)
        let magnitudeA = sqrt(a.map { $0 * $0 }.reduce(0, +))
        let magnitudeB = sqrt(b.map { $0 * $0 }.reduce(0, +))

        return dotProduct / (magnitudeA * magnitudeB)
    }

    enum SearchError: Error {
        case invalidImage
    }
}

Text Tracking

Video Text Recognition

swift
class VideoTextProcessor {
    func processVideoFrame(_ image: UIImage) {
        let request = VNRecognizeTextRequest { request, error in
            guard let results = request.results as? [VNRecognizedTextObservation], error == nil else {
                return
            }

            for observation in results {
                print("Text: \(observation.topCandidates(1).first?.string ?? "")")
                print("Box: \(observation.boundingBox)")
            }
        }

        guard let cgImage = image.cgImage else { return }

        let handler = VNImageRequestHandler(cgImage: cgImage, orientation: .up)

        try? handler.perform([request])
    }
}

Best Practices

  1. 1Performance: Process images efficiently
  2. 2Memory: Manage memory for large images
  3. 3Accuracy: Choose appropriate models
  4. 4Thread: Use appropriate threading
  5. 5Error Handling: Handle errors gracefully
  6. 6Testing: Test with various images
  7. 7Models: Use optimized models
  8. 8UX: Provide feedback to users

Vision Framework enables powerful computer vision capabilities!

Related essays

Next essay
Swift UI: Modern Declarative UI Programming