「名刺撮影用カメラ」の文字をOCRで読んでみた(Computer Vision API)

ios

1 はじめに

前回作成した、「名刺撮影用カメラ」で写した名刺から、OCRで文字をテキスト化してみました。

AVFoundation+OpenCVで矩形検出(「名刺撮影用カメラ」みたいなやつ作ってみました)

動作しているようすは、下記のとおりです。

2 Computer Vision API

OCRとしては、MicrosoftのComputer Vision API(Preview)Read text in images を使用しました。


Computer Vision API

001

実は、iOSで利用可能なOSSのOCRを複数試してみたのですが、ちょっと日本語の読み取りは、きつい感じだったので、諦めました。 (すいません、使い方が未熟なだけかも知れません、精度を上げる方法をご存じの方がおられましたら、是非、教えてください。)

Computer Vision API(Preview)Read text in images は、名刺のような活字であれば、ある程度以上の解像度で、ほぼ100%変換できる感じがしました。

Microsoft Cognitive Servicesは、“Developer Code of Conduct for Microsoft Cognitive Services”に従うことで利用可能です。
http://go.microsoft.com/fwlink/?LinkId=698895

月間、5,000トランザクション、分間、20トランザクションまでなら、無料で利用が可能ですので、色々試してみることができると思います。

002

3 swiftによる実装

キーの取得方法や、APIの使用方法については、各所で紹介されていますので、ここでは、Swiftでアクセスしたコードのみ紹介させて頂きます。

下記は、RestAPIへアクセスするためのクラスです。

class Ocr {

    let url = "https://api.projectoxford.ai/vision/v1.0/ocr"
    let key = "API Key xxxxxxxxxxxxxxxxxxxxxxxxxx"

    func recognizeCharacters(imageData: Data, language: String, detectOrientation: Bool,completion: @escaping (_ response: [String]? ) -> Void) throws {

        let requestUrlString = url + "?language=" + language + "&detectOrientation%20=\(detectOrientation)"
        var request = URLRequest(url: URL(string: requestUrlString)!)
        request.setValue(key, forHTTPHeaderField: "Ocp-Apim-Subscription-Key")
        request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
        request.httpBody = imageData
        request.httpMethod = "POST"

        let task = URLSession.shared.dataTask(with: request){ data, response, error in
            if error != nil {
                completion(nil)
                return
            } else {
                let results = try! JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
                DispatchQueue.main.async {
                    completion(self.extractStringsFromDictionary(results!))
                }
            }
        }
        task.resume()
    }

    // レスポンスのJSONから、文字列を行単位で抽出する
    fileprivate func extractStringsFromDictionary(_ dictionary: [String:AnyObject]) -> [String] {
        var result: [String] = []
        let regions = dictionary["regions"] as? [[String:AnyObject]]
        for region in regions! {
            let lines = region["lines"] as! NSArray
            let inLine = lines.map {($0 as? NSDictionary)?["words"] as! [[String:AnyObject]] }
            inLine.map { $0.map { $0["text"] as! String }.reduce("", +) }.forEach { result.append($0) }
            result.append("")
        }
        return result
    }
}

上のクラスを使用して、名刺の画像を送ると、文字列を取得できます。

try! ocr.recognizeCharacters(imageData: UIImagePNGRepresentation(image)!, language: "unk", detectOrientation: true, completion: { (response) in
    card.lines = response!
})

Langageの指定を”unk”にしておくと、言語は向こうで判断してくれます。また、2値化や縦横も傾きの修正も何もかも全部丸投げで大丈夫です。

4 最後に

OCRによる文字の読み取りは、精度が重要だと思います。今回使用したComputer Vision API(Preview) は、非常に精度が高くてビックリしました。 ネットワーク経由での利用なので若干のレイテンシーはありますが、それほど気になるものでもなく、これから、このような分野は、クラウドでの作業が本命になる予感がしました。

5 参考リンク

Computer Vision curl Quick Starts
Computer Vision API - v1.0 OCR
[C#] Cognitive Servicesで光学文字認識(Computer Vision API OCR)