Identifying attention areas in images with Vision Framework

Identifying attention areas in images with Vision Framework

Learn how to use the Vision framework to pinpoint areas in an image that draw more attention.

Among the many features of the Vision framework, one of them is called Saliency Analysis. This feature analyzes an image and generates a heat map that highlights the areas in the image that are more likely to capture attention.

There are two types of saliency analysis ready to use in the Vision framework:

To perform an attention-based analysis use the GenerateAttentionBasedSaliencyImageRequest object to generate an image request that can be then performed using one of the variations of the perform(on:orientation:) method over an image.

@State var saliencyObservation: SaliencyImageObservation?

private func detectSaliency(on image: UIImage) async throws {
    guard let image = image.cgImage else {
        print("--- Could not load the image")
        return
    }
    
    let request = GenerateAttentionBasedSaliencyImageRequest()
    saliencyObservation = try await request.perform(on: image)
}

The result of the request is an object of the type SaliencyImageObservation. It contains a grayscale heat map of the important areas across the image analyzed. The highlights are the heatMap and the salientObjects properties.

With the heat map information, you can create an image overlay to represent the relevant areas visually.

struct HeatMapView: View {
    
    var observation: SaliencyImageObservation
    @State private var heatMapImage: CGImage? = nil
    
    var body: some View {
        Group {
            if let heatMapImage {
                Image(uiImage: UIImage(cgImage: heatMapImage))
                    .resizable()
            } else {
                Color.clear
            }
        }
        .task {
            self.processHeatMap(from: observation)
        }
    }
    
    private func processHeatMap(from observation: SaliencyImageObservation) {
        do {
            heatMapImage = try observation.heatMap.cgImage
        } catch let error {
            print("---- Could not generate heat map image: \\(error.localizedDescription)")
        }
    }
}
This feature can only be tested on a device. It will not work on the Xcode Preview canvas and simulator.

The following is an example of a SwiftUI view presenting the results of a saliency analysis. It presents an image and a button to trigger the analysis. Once it is finished the saliency observation is used to overlay the resulting heat map over the image with a multiply blend mode.

import SwiftUI
import Vision

struct ContentView: View {
    
    @State var image: UIImage = UIImage(named: "sweet")!
    @State var saliencyObservation: SaliencyImageObservation?
    
    var body: some View {
        
        Image(uiImage: image)
            .resizable()
            .scaledToFit()
        
            // Overlaying the heatmap over the image analyzed
            .overlay {
                if let saliencyObservation {
                    HeatMapView(observation: saliencyObservation)
                        .scaledToFill()
                        .blendMode(.multiply)
                }
            }
            
            // Aesthetic modifiers
            .clipShape(.rect(cornerRadius: 20))
            .padding()
            
            // Button to trigger the analysis
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Button("Analyze image", systemImage: "sparkle.magnifyingglass", action: performAnalysis)
                        .buttonStyle(.borderedProminent)
                }
            }
    }
    
    private func performAnalysis() {
        Task {
            try await detectSaliency(on: self.image)
        }
    }
    
    private func detectSaliency(on image: UIImage) async throws {
        // Image to be analyzed
        guard let image = image.cgImage else {
            print("--- Could not load the image")
            return
        }
        
        // Performing image analysis
        let request = GenerateAttentionBasedSaliencyImageRequest()
        saliencyObservation = try await request.perform(on: image)
    }
    
}