ObjecTips

Swift & Objective-C で iOS とか macOS とか

Vision Framework でテキスト検出 Text Detection

iOS 11 関連記事
iOS 11 UIKit の変更点 - ObjecTips
iOS 11 Foundation の変更点 - ObjecTips
iOS 11 Messages Framework の変更点 - ObjecTips
iOS 11 PDFKit - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
koze.hatenablog.jp

Vision Framework

iOS 11で Computer Vision の Framework が追加された。

Vision | Apple Developer Documentation

使えるのは以下

  • Face Detection and Recognition - 顔とパーツの認識
  • Machine Learning Image Analysis - 機械学習による画像分析
  • Barcode Detection - バーコードの検出
  • Image Alignment Analysis - 画像の並び解析
  • Text Detection - テキストの検出
  • Horizon Detection - 水平角の検出(傾き)
  • Object Detection and Tracking - 物体検出と追跡

特に機械学習による画像分析は MLModel -> VNCoreMLModel -> VNCoreMLRequest の流れで任意のモデルから分析を行える様になっているので、機能を限定されず自由に機械学習による画像分析が出来る模様。
これめちゃくちゃパワフルだと思う。

それはまた後で勉強するとして、まずは手始めに以前 Core Image でもやったテキスト検出を Vision framework で試してみる。
現時点でプログラミングガイドが見あたらないけど大体のクラスとメソッド名で理解できる様なシンプルな構成になっている。

実装

Text Detection with Vision framework

まず VNImageRequestHandler を作成。
NSURL の他に CVPixelBufferRef CGImageRef CIImage NSData を引数にするイニシャライザがあってどんな画像ソースも扱える様になっている。
UIImage なら一旦 CIImage を一旦経由すればいい。

次に VNDetectTextRectanglesRequest を作成して CompletionHandler を設定。
init してから設定するなら以下のメソッドでハンドラを設定

@property (readonly, nonatomic, copy, nullable) VNRequestCompletionHandler completionHandler;

init と同時に設定するなら以下のメソッドが使える。

- (instancetype) initWithCompletionHandler:(nullable VNRequestCompletionHandler)completionHandler NS_DESIGNATED_INITIALIZER;

次に reportCharacterBoxesYES に設定。
設定しないと文字領域のかたまりのみを検出する。YES だと1文字ずつの矩形を検出する。

最後に performRequests: でリクエストを実行する 。

実行結果

このコードを以下の画像に対して実行する。

f:id:Koze:20170607111252p:plain

結果は以下

{{0.19375000000000001, 0.546875}, {0.49687500000000007, 0.140625}}
 |-{{0.19375000000000001, 0.546875}, {0.09375, 0.10625}}
 |-{{0.29999999999999999, 0.546875}, {0.087499999999999994, 0.140625}}
 |-{{0.39687499999999998, 0.546875}, {0.087499999999999994, 0.10625}}
 |-{{0.49062499999999998, 0.546875}, {0.090624999999999997, 0.140625}}
 |-{{0.59999999999999998, 0.546875}, {0.090624999999999997, 0.10625}}
{{0.19062499999999999, 0.32187500000000002}, {0.63125000000000009, 0.14374999999999993}}
 |-{{0.19062499999999999, 0.32500000000000001}, {0.11874999999999999, 0.13750000000000001}}
 |-{{0.32500000000000001, 0.32500000000000001}, {0.10625, 0.13750000000000001}}
 |-{{0.44374999999999998, 0.32187499999999997}, {0.121875, 0.14374999999999999}}
 |-{{0.58750000000000002, 0.32500000000000001}, {0.1125, 0.13750000000000001}}
 |-{{0.72187500000000004, 0.32500000000000001}, {0.10000000000000001, 0.13750000000000001}}

検出できてるっぽい。
ちなみに NSStringFromCGRect を使わなくても直接オブジェクトをログ出力する事も出来る。こっちの方が分かりやすいかも。
VNTextObservation の uuid と精度(以下では全て1)も一緒に出力される。

2017-06-07 11:30:09.026853+0900 Test[10183:7799799] <VNTextObservation: 0x600000299f50> D1AA25AD-7749-40F5-A893-C6FCB75AEE94 1 [0.19375 0.546875 0.496875 0.140625]
2017-06-07 11:30:09.027137+0900 Test[10183:7799799] (
    "<_VNTextObservationCharacterBox: 0x6000008f8880> 91A22E36-C52E-436F-B4B0-DAE1B0CFAD8E 1 [0.19375 0.546875 0.09375 0.10625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8980> 20338509-1DA5-408F-BBC2-993AF9EB561B 1 [0.3 0.546875 0.0875 0.140625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8a80> EDD81518-D291-4DEC-932B-72F8FCC3C489 1 [0.396875 0.546875 0.0875 0.10625]",
    "<_VNTextObservationCharacterBox: 0x6000008f8b80> 86DA1678-ABC8-4833-B8A7-D2697A85D89F 1 [0.490625 0.546875 0.090625 0.140625]",
    "<_VNTextObservationCharacterBox: 0x6000008fcf00> 85447B91-87EA-4275-B837-5160FE01C2B3 1 [0.6 0.546875 0.090625 0.10625]"
)
2017-06-07 11:30:09.027244+0900 Test[10183:7799799] <VNTextObservation: 0x60000029ad60> F2E588DD-9AFE-4E2E-ADE6-10230EB22919 1 [0.190625 0.321875 0.63125 0.14375]
2017-06-07 11:30:09.027360+0900 Test[10183:7799799] (
    "<_VNTextObservationCharacterBox: 0x6000008fd480> C336A62D-F607-47F4-B0EB-E98D03E3A9F7 1 [0.190625 0.325 0.11875 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008fd580> 3917DF3A-13CF-4E63-B66F-4408EAEB5B0E 1 [0.325 0.325 0.10625 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008fd680> 06B97257-B8A5-417A-A0F6-64778AADE759 1 [0.44375 0.321875 0.121875 0.14375]",
    "<_VNTextObservationCharacterBox: 0x6000008f2900> 85A90B06-0F4C-4203-8427-59877D7DCAA2 1 [0.5875 0.325 0.1125 0.1375]",
    "<_VNTextObservationCharacterBox: 0x6000008f2800> 91530E7D-2891-4847-9031-603519071065 1 [0.721875 0.325 0.1 0.1375]"
)
結果のオーバーレイ

検出結果は0-1の範囲の様なのでこれを元にオーバーレイ画像を作成してみる。

Overlay Image from VNTextObservation

Core Image の時と同様、上下逆の座標で結果が返ってくるので途中に CGAffineTransform を使って座標を変換している。
結果は以下

f:id:Koze:20170607115927p:plain

バッチリ

日本語に対しても実行してみる。

f:id:Koze:20170607121311p:plain

平仮名がパーツで分割して認識されていたり漢字が認識されていなかったりするけど、以前は平仮名の行自体が検出されていなかったので検出精度は上がっている。


Core Image バージョンは以下
やってる事はそんなに変わらない。検出結果の座標系が違うのでオーバーレイ画像の作成処理は変わってくる。

koze.hatenablog.jp

ちなみに Core Image バージョンでも iOS 11 であれば Vision と同じで平仮名の検出が出来る様になっていた。
おそらく中身の処理は同じで、結果の違いはOSのバージョンの差異によるものだと思う。 *1

Core Image と Vision では文字の矩形のみの検出だけど、その先の文字内容の認識(OCR)を行う部分は iOS 11 で追加された機械学習の Core ML framework や Vision framework の VNCoreMLRequest で独自のモデルを使って各自どうぞって事なんだと思う。

*1:追記:Session 506 - Vision Framework: Building on Core ML によれば、顔認識については Vision では機械学習を使っていて Core Image の顔認識と比べて精度、処理速度、バッテリー処理の面で Vision の方が優位との事