🕊️

【SwiftUI】Visionで色々と認識してみる

2023/03/21に公開

画像などからテキストやバーコード、顔、顔のランドマークを検出できるフレームワークに
Vision Framework があります。

https://developer.apple.com/documentation/vision

はじめに

Visionをインポートします。
ライブビデオなどからテキストなどを認識できるVisionKit もありますが、今回はVisionを使用します。

import Vision

VisionKitについてはこちらで取り上げています。
https://zenn.dev/tomo_devl/articles/bc54ee2066458d

実際に試してみる

1. テキスト(文字)認識

let request = VNRecognizeTextRequest { (request, error) in
    if let results = request.results as? [VNRecognizedTextObservation] {
        let recognizedStrings = results.compactMap { observation in
            observation.topCandidates(1).first?.string
        }
                    
        print(recognizedStrings)
    }
}

テキストの認識をするためには、VNRecognizeTextRequestを使用します。
画像からテキストを見つけると、認識をするようにリクエストをします。
VNRecognizedTextObservationは、VNRecognizeTextRequestの結果や認識したテキストの内容を持っています。
 

let image: UIImage = "画像" 
guard let cgImage = image.cgImage else {
    return
}

let handler = VNImageRequestHandler(cgImage: cgImage, options: [:])
DispatchQueue.global().async {
    do {
        try handler.perform([request])
                
    } catch {
        print(error)
    }
}

リクエストを実行しています。
VNImageRequestHandlerは、リクエストを処理するためのオブジェクトです。

認識できる言語は、supportedRecognitionLanguagesを使用することで確認できます。

try! request.supportedRecognitionLanguages()

また、recognitionLanguagesを使用することで、認識したい言語に優先順位をつけることができます。

request.recognitionLanguages = ["ja-JP"]

全体のコード

テキスト認識
func textRecognition(_ image: UIImage) { 
    let request = VNRecognizeTextRequest { (request, error) in         
        if let results = request.results as? [VNRecognizedTextObservation] {
	    let recognizedStrings = results.compactMap { observation in
		observation.topCandidates(1).first?.string
            }
                    
            print(recognizedString)
        }
    }
    
    request.recognitionLanguages = ["ja-JP"]
    
    guard let cgImage = image.cgImage else {
        return
    }

    DispatchQueue.global().async {
        do {
            try handler.perform([request])
                
        } catch {
            print(error)
        }
    }
}

2. バーコード認識

let request = VNDetectBarcodesRequest { (request, error) in
    if let results = request.results as? [VNBarcodeObservation] {
        let barcodes = results.compactMap { observation in
            observation.payloadStringValue
        }
                    
        print(barcodes)
    }
}

バーコード認識では、VNDetectBarcodesRequestを使用します。
役割は、VNRecognizeTextRequestと同様にバーコードやQRを見つけるとリクエストをします。
VNBarcodeObservationも同様で、結果や内容を持っています。

また、supportedSymbologiessymbologiesを使用することで、認識できるバーコードシンボルがわかります。

// サポートしているバーコードシンポル
try! request.supportedSymbologies()
// 画像から認識できるバーコードシンボル
request.symbologies

全体のコード

バーコード認識
func barkodeRecognition(_ image: UIImage) { 
    let request = VNDetectBarcodesRequest { (request, error) in
        if let results = request.results as? [VNBarcodeObservation] {
            let barcodes = results.compactMap { observation in
                observation.payloadStringValue
            }
                    
            print(barcodes)
        }
    }

    guard let cgImage = image.cgImage else {
        return
    }

    DispatchQueue.global().async {
        do {
            try handler.perform([request])
                
        } catch {
            print(error)
        }
    }
}

3. 顔認識

let request = VNDetectFaceRectanglesRequest { (request, error) in
    if let error {
        print(error)
        return
    }
                
    request.results?.forEach({ result in
        guard let observation = result as? VNFaceObservation else {
            return
        }
                    
        print(observation.boundingBox)
    })
}

顔認識では、顔を見つけてリクエストを行うVNDetectFaceRectanglesRequestか、
今回は使用していませんが、目や鼻、口などの特徴のリクエストを行う、VNDetectFaceLandmarksRequestを使用します。
他のと同様に、VNFaceObservationは 結果、内容を持っています。

全体のコード

顔認識
func faceRecognition(_ image: UIImage) {
    let request = VNDetectFaceRectanglesRequest { (request, error) in
        if let error {
            print(error)
            return
        }
                
        request.results?.forEach({ result in
             guard let observation = result as? VNFaceObservation else {
                 return
             }
                    
             print(observation.boundingBox)
        })
    }

    guard let cgImage = image.cgImage else {
        return
    }

    DispatchQueue.global().async {
        do {
            try handler.perform([request])
                
        } catch {
            print(error)
        }
    }
}

その他のリクエストをいくつか

VNRecognizeAnimalsRequest ... 動物を認識できます。(犬と猫しかできないみたいです。)
VNDetectHumanRectanglesRequest ... 顔だけでなく、全身を認識できます。
VNDetectRectanglesRequest ... 長方形のオブジェクトを認識できます。

最後に

テキスト認識はかなり精度がよく、日本語もひらがな、カタカナはほぼ完璧に認識してくれました。
漢字も精度はいいですが、画数が多いものは別の漢字として認識されてしまうことがありました。
また、普通のアルファベットも筆記体も少し癖が入ると正しく認識できていませんでした。
上の画像では、筆記体の「i」が「e」と認識されてしまっています。
英語を公用語にしている国では、もっと形を崩したものが多いので、手書きのものはほとんど認識できないと思います。 まぁ手書きのテキストを認識することはあまりないと思いますが。

GitHubでテキスト、バーコード、顔を認識できるアプリを公開しています。
参考にしてもらえると嬉しいです。

https://github.com/Tomo-devel/RecognisingObjectsFromImages

Discussion