完成品
コード
VisionManager.swift
struct VisionManager {
/// 画像スキャン
static func read(image: UIImage?, completionHandler: @escaping (String) -> Void) {
guard let cgImage = image?.cgImage else { return }
// 分析する画像のリクエストを作成する
let requestHandler = VNImageRequestHandler(cgImage: cgImage)
// 認識するテキストの設定
let request = VNRecognizeTextRequest { request, error in
VisionManager.recognizeTextHandler(request: request, error: error, completionHandler: completionHandler)
}
// 認識を優先したい言語のISO言語コードを指定する
request.recognitionLanguages = ["ja"]
// テキスト認識の速度を優先するか精度を優先するかのプロパティらしい
// fast: 高速テキスト認識, accurate: 正確なテキスト認識
request.recognitionLevel = .accurate
do {
// 画像のスキャン開始
try requestHandler.perform([request])
} catch {
print(error)
}
}
/// 文字認識結果の処理
private static func recognizeTextHandler(request: VNRequest, error: Error?, completionHandler: (String) -> Void) {
// テキスト認識の結果配列
guard let observations = request.results as? [VNRecognizedTextObservation] else { return }
let recognizedStrings = observations.compactMap { observation in
// topCandidates(1)・・・読み取った文字の解釈で1番信頼度の高い文字列だけ取得する
// topCandidates(1)で1を指定しているため1つの結果のみ取得できるが配列で帰ってくるためfirstで絞っている
return observation.topCandidates(1).first?.string
}
// 読み取った文字列の配列を改行文字で繋いで1つの文字列にする
let text = recognizedStrings.joined(separator: "\n")
completionHandler(text)
}
}
まとめ
画像からテキストを読み取る機能というのはすごく難しそうな印象を持っていましたが、最低限の機能を実装するだけならすごく簡単に実装できることが分かりました。
Apple公式ドキュメントに実装方法は載っていたのでそれに従えばできる感じです。
精度もなかなかじゃないでしょうか?
スキャン結果のテキストに「三つ50」とあって何のことかな?と思って画像を見ていたのですが、
Wi-fiのマークを「三」と認識して充電の残量表示の50のことのようです。
素晴らしいですね!
画像を加工してからスキャンすることで必要な部分のみ読み取ったり、どの文字を読み取ったのかわかるように枠線で囲ったりなどもやってみようかなと思います。