ハンドアイキャリブレーション入門 第3章 補足:OpenCV の5つの解法の注意点 ― Andreff の偏りと Daniilidis の 180° 問題

シリーズ「ハンドアイキャリブレーション入門」の第3章の補足です。第3章では、コーナー位置誤差(画像から検出したコーナーの位置のずれ)・姿勢の数・回転の大きさを変えて、ハンドアイキャリブレーションの精度を調べました。そのなかで、OpenCV の5つの解法のうち2つに、ほかの解法とは違う振る舞いが見つかりました。

  • Andreff:並進誤差だけが大きく、姿勢を増やしても減らない
  • Daniilidis:ほとんどの試行は問題ないが、まれに大きく外れる

この章では、それぞれの原因を突き止め、対策を示します。どちらも OpenCV でハンドアイキャリブレーションを使う人が、知らずに踏みうる落とし穴です。

目次

シリーズの構成

第3章の実験で見つかった内容を掘り下げるため、「第3章 補足」として追加した記事です。

章内容ロボットカメラ
第1章ハンドアイキャリブレーションの考え方――
第2章シミュレーションで AX = XB を解き、正しく解けることを確認シミュレーションシミュレーション
第3章精度は何で決まるか:計測誤差・姿勢の数・回転の大きさシミュレーションシミュレーション
第3章 補足(今回・追加)OpenCV の5つの解法の注意点:Andreff の偏りと Daniilidis の 180° 問題シミュレーションシミュレーション
第4章RealSense の内部パラメータは信用できるか―実測
第5章ボードの位置姿勢の計測はどれくらいばらつくか―実測
第6章実測したばらつきを使って、実機での精度を予測するシミュレーション実測した誤差
番外編(予定)市販の安価なロボットアームで実機検証実機実測

おさらい:5つの解法

OpenCV の calibrateHandEye には、AX = XB を解く方法が5つあり、引数 method で選びます。名前は、それぞれの方法を提案した論文の著者名です。

解法解き方
Tsai回転を先に解き、次に並進を解く
Park回転を先に解き、次に並進を解く
Horaud回転を先に解き、次に並進を解く
Andreff回転と並進を同時に解く
Daniilidis回転と並進を同時に解く

第3章で見つかった2つの異常

図1は、第3章の実験2(姿勢の数を変えた実験)の結果です。条件は、コーナー位置誤差 0.1px、傾き最大 35°、ロール ±90°で、各条件 200 回の中央値を示しています。

異常1:Andreff の並進誤差が下がらない ほかの解法は、姿勢を増やすと並進誤差が下がり、30姿勢で約 0.26〜0.29mm になります。Andreff だけは、15姿勢を超えても約 0.7mm のままでした。さらに第3章の実験1では、コーナー位置誤差を 0.1px から 0.3px に増やすと、Andreff の並進誤差は 0.66mm から 5.04mm へと約8倍に悪化しました(ほかの解法は約3倍)。

異常2:Daniilidis がまれに大きく外れる Daniilidis の中央値はほかの解法とほぼ同じですが、20姿勢以上のときに、200 回中2回だけ大きく外れました。外れたときの誤差は、並進 3.6〜19.8mm、回転 0.4〜2.3° で、同じデータを使った Park は 0.2〜0.3mm でした。

調べ方

原因を調べるために、次の2つを行いました。

  1. OpenCV のソースコードを読む:calibrateHandEye の中身(calibration_handeye.cpp)で、各解法がどう計算しているかを確認しました。
  2. OpenCV の計算を Python で再現する:同じ計算を自分で書き、途中の値を取り出せるようにしました。OpenCV の結果との差は 3×10<sup>−12</sup> 以下で、計算を正しく再現できています。

誤差は、次の2つに分けて調べています。

  • 偏り:試行を何度繰り返しても、毎回同じ方向に残るずれ。200 回分の誤差を、向きも含めて平均したものの大きさで測ります。姿勢を増やしても減りません。
  • ばらつき:試行ごとにランダムに変わるずれ。姿勢を増やすと減ります。

注意点1:OpenCV の Andreff は、並進に偏りが出る

原因:並進を解き直していない

OpenCV の Andreff は、回転(回転行列の9個の数)と並進(3個の数)をまとめて1つの連立一次方程式とし、最小二乗法で解きます。

最小二乗法で解いた9個の数は、正しい回転行列の形になっていません。そこで OpenCV は、後から最も近い回転行列に直します。ところが並進は、直す前の回転と組で求めたものをそのまま使っています。

なぜずれるのか:回転が縮み、並進が埋め合わせる

この連立方程式は、係数そのもの(カメラが測ったボードの回転や位置から作る値)に誤差を含んでいます。係数に誤差がある方程式を最小二乗法で解くと、解が小さめに偏る性質があります。

実際に、直す前の回転行列の大きさ(特異値)は、正しい回転なら 1 のところ、コーナー位置誤差 0.1px で 0.9987、0.3px で 0.988 に縮んでいました。回転と並進を同時に解いているので、回転が縮んだ分のつじつまを並進がずれて埋め合わせます。回転は後から直されますが、並進のずれは残ります。

図2(a) は、係数に誤差があると最小二乗法の答えが小さめに偏ることを、1次元の簡単な例で示したものです。図2(b) は、それによって回転が縮み、足りない分を並進がずれて埋め合わせる様子です(縮み方は分かりやすく誇張しています)。

このずれの大きさは、次の式でおおよそ見積もれます。

偏り ≈ (1 − 特異値) × カメラからボードまでの距離

0.1px のときは、0.0013 × 約 500mm ≈ 0.65mm です。シミュレーションで測った偏り(約 0.64mm)と一致しました。また、コーナー位置誤差を3倍(0.1→0.3px)にすると、偏りは約9倍(0.64→5.65mm)になり、偏りがコーナー位置誤差の2乗に比例することも確かめられました。第3章の実験1で、Andreff だけ曲線的に悪化していたのはこのためです。

条件解法並進誤差の中央値偏りばらつき
0.1px・15姿勢Park0.37 mm0.03 mm0.47 mm
0.1px・15姿勢Andreff0.66 mm0.64 mm0.72 mm
0.1px・30姿勢Park0.26 mm0.03 mm0.32 mm
0.1px・30姿勢Andreff0.71 mm0.68 mm0.49 mm
0.3px・15姿勢Park1.10 mm0.10 mm1.39 mm
0.3px・15姿勢Andreff5.04 mm5.65 mm3.47 mm

(各条件 200 回。ばらつきは、誤差が平均のまわりにどれだけ散らばっているかの大きさ)

Andreff の偏りは、15姿勢でも30姿勢でも約 0.65mm で変わりません。姿勢を増やしても誤差が下がらなかったのは、このためです。

対策:直した回転で、並進だけを解き直す

Andreff の回転の精度は、もともとほかの解法と同じです。そこで、OpenCV が返した回転を固定し、並進だけを最小二乗法で解き直します。

import numpy as np

def refit_translation(R_cam2gripper, gripper2base_list, target2cam_list):
    """回転を固定して、並進だけを最小二乗法で解き直す(4×4 の同次変換行列のリストを受け取る)"""
    M, y = [], []
    n = len(gripper2base_list)
    for i in range(n):
        for j in range(i + 1, n):
            Hg = np.linalg.inv(gripper2base_list[j]) @ gripper2base_list[i]
            Hc = target2cam_list[j] @ np.linalg.inv(target2cam_list[i])
            M.append(np.eye(3) - Hg[:3, :3])
            y.append(Hg[:3, 3] - R_cam2gripper @ Hc[:3, 3])
    return np.linalg.lstsq(np.vstack(M), np.concatenate(y), rcond=None)[0]

calibrateHandEye(method=cv2.CALIB_HAND_EYE_ANDREFF)が返した回転行列を R_cam2gripper に渡すと、解き直した並進が返ります。OpenCV と同じく、すべての姿勢の組 (i, j) を使っています。

条件ParkAndreffAndreff(並進を解き直し)
0.1px・15姿勢0.37 mm0.66 mm0.37 mm
0.1px・30姿勢0.26 mm0.71 mm0.26 mm
0.3px・15姿勢1.10 mm5.04 mm1.11 mm

(並進誤差の中央値。各条件 200 回)

解き直すだけで、Park と同じ精度になりました。第3章のグラフの緑の破線が、この解き直し版です。

注意点2:Daniilidis は、回転の差が 180° 近い姿勢の組があると、まれに大きく外れる

原因:クォータニオンの符号の取り違え

Daniilidis の方法は、姿勢と姿勢の間の回転をクォータニオンで表します。クォータニオンは回転を4つの数で表す方法で、1つ目の数(スカラー部)は cos(回転角/2)、残り3つは回転軸の向きから決まります。同じ回転を、4つの数すべての符号を反転した2通りで書けるのが特徴です。

Daniilidis の方法では、ロボット側とカメラ側のクォータニオンを、同じ符号どうしで組み合わせる必要があります。OpenCV は、どちらもスカラー部が正になるように符号をそろえています。

ところが回転角が 180° に近いと、スカラー部 cos(回転角/2) はほぼ 0 になります。すると、カメラ側だけがわずかな計測誤差で符号が反転し、ロボット側と逆の符号で組まれてしまうことがあります(以下、符号の食い違い)。逆の符号で組まれた式が1つでも混ざると、解が大きく外れます。

図3は、回転角とスカラー部 w の関係です。回転角が小さいうちは w が 1 に近く、符号ははっきり決まります。180° に近づくと w はほぼ 0 になり、わずかな誤差で符号が変わってしまいます。

確かめ方

正しく組めていれば、ロボット側のクォータニオンと、カメラ側のクォータニオンを正解の X で回したものが一致します。この2つの内積(4つの数どうしを掛けて足したもの)が負なら、符号が食い違っていると判定できます。シミュレーションなので正解の X が分かっており、この判定ができます。

結果

外れた試行と、符号の食い違いの関係(コーナー位置誤差 0.1px、ロール ±90°、各 200 回)

姿勢の数大きく外れた回数(並進 2mm 超)符号の食い違いがあった回数外れた試行のうち、食い違いがあったもの
1500―
20222 / 2
30222 / 2
  • 大きく外れた試行では、すべて、回転の差がほぼ 180° の姿勢の組で符号が食い違っていました。食い違いがなかった試行で外れたものはありません。
  • 20姿勢と30姿勢で外れたのは、どちらも同じ2つの試行でした。同じ試行番号では最初の20姿勢が共通なので、実質的には 200 回中2回(1%)です。
  • 15姿勢以下で起きなかったのは、姿勢が少ないと、回転の差が 180° に近い組ができにくいためと考えられます(30姿勢では、組の数は 435 通りあります)。

ロールの範囲を狭めたとき(30姿勢、0.1px、各 200 回)

ロールの範囲大きく外れた回数符号の食い違いがあった回数
±90°22
±60°00
±30°00

ロールが ±90° だと、2つの姿勢のロールの差は最大 180° になります。ロールを ±60° 以下にすると、回転の差が 180° に届かなくなり、外れはなくなりました。

対策

  • 2つの姿勢の回転の差がほぼ 180° になる組(例:光軸まわりにカメラを 180° 回した2つの姿勢)を作らない
  • そうした姿勢を避けられないときは、Park か Horaud を使う

まとめ:OpenCV で解法を選ぶときの指針

解法回転並進注意点
Park・Horaud良い最も良い特になし。迷ったらこれ
Tsai良い1〜2割悪い特になし
Andreff良い偏りが出る並進は解き直して使う
Daniilidis良い良い回転の差が 180° 近い姿勢の組を避ける
  • OpenCV の Andreff は、並進を解き直していないため、並進に偏りが出る。偏りはコーナー位置誤差の2乗に比例し、姿勢を増やしても減らない。並進を解き直せば Park と同じ精度になる
  • OpenCV の Daniilidis は、回転の差が 180° 近い姿勢の組があると、クォータニオンの符号を取り違えて、まれに大きく外れる
  • どちらも、OpenCV が返す値だけを見ていると気づきにくい。正解の分かっているシミュレーションで確かめることの大切さが、ここでも表れた

次の第4章からは、実際の RealSense を使います。まず、シミュレーションで「理想的」と仮定してきたカメラの内部パラメータ(レンズの焦点距離、画像の中心、ゆがみなど、カメラ固有の性質を表す値)が信用できるかを確かめます。

参考

  • N. Andreff, R. Horaud, and B. Espiau, “On-line hand-eye calibration,” Proc. 2nd International Conference on 3-D Digital Imaging and Modeling, 1999.
  • K. Daniilidis, “Hand-eye calibration using dual quaternions,” The International Journal of Robotics Research, 1999.
  • OpenCV のソースコード:modules/calib3d/src/calibration_handeye.cpp(4.x)
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次