2018.06.29

ARKitを使ってボックスの大きさを見積もる手法を考える

Pocket

こんにちは。F.S.です。
今回は久しぶりにAR機能を使った実験をしてみました。

※画像はAirMeasureを使ったものです

何の役に立つのかは言及しませんが、ARKitを使って目の前に置かれたボックス(立方体)の大きさを測る手法を考えてみたいと思います。
ARKitによる寸法の計測といえば、現在でも AirMeasure のようなアプリがいくつか存在し、iOS12からはApple公式のメジャーアプリも出てきます。それを使えばいいじゃないかという話もあると思いますが、今回は始点、終点を選択するような計測行為をせずに、箱の大きさを予測する手法を検討しました。

立方体なので幅、長さ、高さがわかれば大きさを求めることができますが、それをどれだけ簡単に計測するかというのが課題です。

実験環境

  • iPhone 7
  • iOS 11.3(ARKit 1.5)
本エントリで計測対象にしたボックスです。家に転がっていた子供の双眼鏡のハコです。

手法の検討

やり方をいくつか考えてみました。

①立方体の面を認識し、認識した面の見積もりサイズ (ARPlaneAnchor.extent) を使用する方法
⇒そこそこ精度よく認識できる場合がありますが、認識を継続しているとなぜかサイズが拡大していく傾向が見られ、制御が難しいので見送りました
※薄い青の面が立方体の上面を認識したARPlaneAnchor。角度がずれたりはみ出る場合があります。

②立方体の水平、垂直面を認識し、面同士の交線から立方体の辺の長さを求めるやり方
⇒面の認識精度がそこそこ良ければ綺麗に計算できそうですが、認識すべき面が多く操作が簡単ではないのでこちらも見送りました
※薄い赤の面は立方体の側面を認識したARPlaneAnchor。全方位認識させるのは結構大変です。

③立方体を上面から写して四角形のアウトラインを画像認識し、四隅の座標を求めるやり方(以前のブログ ARKitで野球のグラウンド作りは楽になるのか? のホームベース認識と近い手法)
⇒今回トライしたのがこちらです。

なお、計測するボックスはホームベースのように領域がはっきりわかるものとは限らないため、輪郭検出に使ったcv::findContours ではうまく欲しい領域を切り取ることができません。かわりに直線を検出して、四角形の辺であることを推定します。

以下に手順を解説します。

手順

1. 平面認識

ボックスをおいてある床面とボックスの上面の2つの水平面を認識させます。
垂直面の認識は行いません。

2. キャプチャ画像を取得

画面をタップして、ARセッションのフレームからキャプチャした画像を取得します。
四角形の辺を推定しやすくするために、下の画像のように立方体の真上から長方形が映るように撮影させます。

3 cv::Canny でエッジを検出する

エッジ検出器で画像を二値化します。この際、RGBチャンネルごとに分割検出してビット和をとると、よりはっきりしたエッジが検出できます。必要に応じてエッジ検出の前段で GaussianBlur を入れます。

4. cv::createLineSegmentDetector で直線を検出

直線の検出というとまずハフ変換が思い浮かびますが、ノイズの多い画像には不向きで、確率的ハフ変換を用いても意図しない直線が多数検出される場合がありました。そのため、今回はLSD(Line Segments Detector)を試してみることにしました。OpenCVではver.3から対応しています。

最終的に必要になる直線は四角形の辺なので、LSDで検出した線分において、長さ・傾きが許容範囲外のものは排除します。その中から水平線、垂直線で一番外側にある線分を選定します。

5. 交点を四隅の座標とする

選定された4本の線分の延長線から、交点座標を求めます。

6. ワールド座標に変換

キャプチャ画像から求めた四隅の座標をARフレームの座標に変換し、認識した平面とHitTestを行ってワールド座標を求めます。HitTestはボックス上面と床面の両方の面に対して行います。

斜めからみるとこんな感じです。
床面にヒットした座標が面に沿ってかなり広がってしまってますが、こちらは高さ(y軸の値)が必要なだけなので特に気にしません。

7. ワールド座標から距離を計算

下記のようにワールド座標が取得できました。

ボックス上面 [x, y, z]
[0.207665,-0.351492,-0.103989]
[0.0777198,-0.351492,-0.0780758]
[0.107713,-0.351492,0.0733802]
[0.238401,-0.351492,0.0478433]

床面 [x, y, z]
[0.233794,-0.43332,-0.136682]
[0.0565964,-0.43332,-0.101345]
[0.0974702,-0.43332,0.105211]
[0.275708,-0.43332,0.0703826]

ここまできたらあとはワールド座標間の距離を計算するだけです。

結果

統計データでなくて恐縮ですが。。上記手順の距離計算により下記の結果が出ました。
  • 長さ:15.4cm 〜 15.5cm
  • 幅 :13.3cm
  • 高さ:8.2cm
正解はこちらですので、
  • 長さ:16cm
  • 幅 :14cm
  • 高さ:8cm
下記の通りの誤差になります。
  • 長さ:-3.8% 〜 -3.1%
  • 幅 :-5.0%
  • 高さ:2.5%
ARKitによる距離計測は、経験則でだいたい5%程度の誤差があるとの認識でした。画像認識の誤差も含まれますが、トータルでもそこそこの誤差に収まる結果となりました。
2平面の認識で3〜5秒かかりますが、ワンタップでおおよその大きさを見積もることができました。まずまずの結果が得られたと思います。

それでは、また。

次世代システム研究室では、アプリケーション開発や設計を行うリードエンジニアを募集しています。アプリケーション開発者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ 募集職種一覧 からご応募をお願いします。