カメラとオブジェクトのトラッキングは、高度なバーチャルプロダクションワークフローの重要な構成要素です。 しかし、業界は大きな課題に直面しています。それは無数のトラッキングデバイスが異なる通信プロトコルを使用しており、 ハードウェアメーカー、ソフトウェア開発者、制作チームにとって複雑さを生み出しているということです。
統合トラッキングプロトコル(C-Tracking)がこの問題を解決します。 業界の専門家たちによって作成されたC-Trackingは、すべてのプラットフォームとデバイス間でトラッキングを合理化するように設計され、 かつ無料で、統一化された将来性のあるプロトコルです 。 正確で柔軟性があり、実装が簡単で、制限なく無料で使用できます。これにより、業界全体のスタンダートとして理想的と言えます。
ハードウェアの構築、バーチャルプロダクションプラットフォーム開発、または大規模制作を管理している場合などでも、 C-Trackingはライセンス料や使用制限なしにニーズを満たすように構築されています。
統合トラッキングプロトコルの仕様書をダウンロード
プロトコルの実装方法を学び、シームレスで標準化されたトラッキングを実現するムーブメントにぜひ加わってください。
登録不要。
リビジョン43
このプロトコルは、ネットワーク上でデバイスのトラッキングデータを送信するために使用されます。 C-Trackingは、実際の物理値を送信するように設計されています。詳細は付録Dを参照してください。 トラッキング情報に加えて、他の測定データも含めることができます。
このプロトコルのメッセージはUDP経由で送信されます。 IPおよびUDPヘッダーを除いたメッセージの最大長は1400バイトです。
メッセージはソース(「送信側」)によって生成され、事前に設定された宛先IPアドレス-UDPポートペア(「受信側」)に送信されます。 メッセージは定期的な間隔で、または送信側の裁量でデータが利用可能になり次第生成される場合があります。 宛先IPアドレスは、ユニキャスト、ブロードキャスト、またはマルチキャストである場合があります。 逆方向(受信側から送信側への)通信はありません。
UDPパケットは単一の論理デバイスに関する情報を含む必要があり、同じポートに送信されるすべてのUDPパケットは同じデバイスに関する情報を含む必要があります。 デバイスがカメラの場合、それに関するすべての情報(レンズ情報、位置など)は単一のパケットで送信されることが期待されます。 デバイスは、空間内の単一オブジェクトの位置および/または方向の測定のみを表すこともでき、その場合、パケットはおそらく位置/方向情報のみを含むでしょう。
任意の宛先ポート番号を使用できますが、1024未満のポート番号は、受信側システムがそのようなポートでリッスンするために特別な権限を必要とする場合に問題を引き起こす可能性があるため、 デフォルト値としては推奨されません。推奨されるデフォルト宛先ポートは、最初のデバイスに対して2001、追加のデバイスに対して後続のポート番号です。
パケット形式は柔軟で、送信されるすべてのデータ(短いヘッダーを除く)は要素に含まれ、それぞれがオプションです。 これにより、送信側は不明なデータ、または報告されるデバイスに適用されないデータ(例:トラッキングデバイスのレンズ歪み情報)を省略できます。 ただし、すべてのパケットは、前回のパケットから変更されていない場合でも、デバイスで利用可能なすべてのデータを含む必要があります。
複数バイトにまたがるパケット内のすべての数値フィールドは、ビッグエンディアンバイト順で格納されます。符号付き整数フィールドは、2の補数表記で格納されます。 浮動小数点値は、IEEE 754-2008のbinary32(「単精度」)形式に従ってエンコードされます。無限値とNaN値は、明示的に記載されている場合にのみ許可されます。 送信されるすべてのNaN値は、指定されたペイロードで、または言及されていない場合は0のペイロードで、静的(非シグナル)である必要があります。
以下の表で使用される型の説明:
ヘッダーはパケットのアドレス0から始まります。
受信側は、予期しないプロトコル識別子を持つパケットを破棄します。
受信側は、ヘッダー長が6未満のパケットを破棄します。ヘッダー長が6より大きい場合、受信側は最初の6 bytesを超えるヘッダーの内容を黙って無視します。
ProtocolIdentifier | 4 bytes | "CTrk"(ビッグエンディアンバイト順の値0x4354726B)。 |
HeaderLength | uint16 | 6 |
すべての要素はオプションです。ただし、送信側が送信するパケットにFrame rate要素を含めることが推奨されます。 この要素がない場合、受信側はパケットが送信側から不規則に到着する可能性があると仮定する必要があります。 各要素は、要素の説明で特に記載されていない限り、パケット内に1回のみ存在できます。
すべての要素は、前の要素の後(最初の要素の場合はヘッダーの後)の4の倍数に整列した最初のアドレスから開始されます。 パディングバイト(3個以下)は、この整列を強制するために、ヘッダーの後、要素間、およびオプションで最後の要素の後に送信側によって挿入されます。 送信側はパディングバイトを0に設定します。受信側はパディングバイトの内容を無視します。 パケットは、最後の要素の後にオプションで最大3個のパディングバイトを除いて、データを含まない場合があります。
受信側は、要素長が4未満の要素を含むパケットを破棄します。
受信側は、未知の要素タイプを持つ要素を黙って無視します。
受信側が期待する長さより短い要素に遭遇した場合、その要素を黙って無視します。
受信側が期待する長さより長い要素に遭遇した場合、期待する長さであるかのように要素を解析し、余分なデータを無視します。 次の要素のアドレスは、ElementLengthフィールドの値に基づいて計算されます。
ElementType | uint16 | 要素タイプ |
ElementLength | uint16 | ElementTypeとElementLengthフィールドを含む要素の長さ。パディングバイトは除く。 |
Payload | 要素タイプ固有のペイロード |
この要素には、パケットのタイムコードが含まれています。
HH:MM:SS:FFタイムコードの4つの部分は別々のフィールドで送信され、以下に説明するサブフレームインデックス用の追加のオプションフィールドがあります。
タイムコードベースは通常、送信システムのフレームレートと等しくなります。プロトコルは255までの任意の整数タイムコードベースを許可します。 ただし、SMPTE標準に準拠するのは30以下のタイムコードベースのみです。より高いフレームレートでSMPTE準拠のタイムコードを送信するには、フレームレートの30以下の最大の約数にBaseを設定します。 この場合、連続する複数のフレームが同じHH:MM:SS:FFタイムコードを持つことになります。 これらを区別するために、同じフレーム番号を持つ後続のフレームごとにSubframeを1増やし、フレーム番号が変わるときにSubframeを0にリセットします。
例えば、50フレーム/秒を表現するには、Baseを単純に50に設定できます。この場合、Frameは1秒内で0から49まで増加し、Subframeは常に0になります。 SMPTE準拠の場合、Baseを25に設定できます。この場合、Frameは1秒の終わりに0に戻る前に0から24まで増加するだけです。 各HH:MM:SS:FFタイムコードは連続する2つのフレームで繰り返されます。Subframeは最初のフレームで0、2番目のフレームで1に設定する必要があります。
NTSCベースのフレームレート(23.976、29.97、59.94、119.88、239.76)のタイムコードベースを指定するには、Baseをそれぞれ24、30、60、120、240に設定し、FlagsでNTSCビット(最下位ビット)を設定します。 SMPTE準拠の表現では、サブフレームなしで表現できる最大フレームレートは29.97です。 例えば、SMPTE準拠形式で239.76フレーム/秒を指定するには、Baseを30に設定し、NTSCビットを設定し、同じHH:MM:SS:FF値を区別するためにSubframe値を0から7まで周期的に使用します。
また、23.976を除くすべてのNTSCベースのフレームタイムコードはドロップフレームと見なされることに注意してください。
ElementType | uint16 | 0 |
ElementLength | uint16 | 11 |
時 | uint8 | タイムコードの時間部分 |
分 | uint8 | タイムコードの分部分 |
秒 | uint8 | タイムコードの秒部分 |
Frames | uint8 | タイムコードのフレーム部分 |
Subframe | uint8 | サブフレームインデックス |
Base | uint8 | タイムコードベース |
Flags | uint8 | 最下位ビットはNTSCフレームレートの場合は1に、そうでなければ0に設定されます。 他のビットは現在未割り当てで、送信時は0に設定する必要があります。 |
この要素には、カメラの視野角とフレームアスペクト比が含まれています。
ElementType | uint16 | 1 |
ElementLength | uint16 | 12 |
HorizontalFieldOfView | single | 度単位の水平視野角 |
FrameAspectRatio | single | フレームアスペクト比、幅/高さ |
この要素には、カメラのK1/K2ベースのレンズ歪みパラメータが含まれています。
この要素は、汎用レンズの放射歪みを記述するためのみに使用されます。特に、魚眼、 アナモルフィック、またはティルトシフトレンズの歪みを記述するのには適していません。
この要素を含むパケットには、「視野角」要素も含める必要があります。 視野角情報がなければ、この要素の内容は受信側にとって有用ではありません。
この要素のフィールドには、OpenCVで使用される歪みモデルに従った係数が含まれています。 歪みモデルの説明は付録Bに記載されており、K1とK2以外のすべての係数がゼロであることを前提としています。
不明な(測定/校正されていない)値を持つフィールドには、ゼロを含める必要があります。
基本パラメータセットと拡張パラメータセットの選択については、付録B.2を参照してください。
ElementType | uint16 | 2 |
ElementLength | uint16 | 20 |
CenterX | single | 画像中心に対する主点のX座標。画像の左端は-0.5、右端は0.5です。 |
CenterY | single | 画像中心に対する主点のY座標。画像の下端は-0.5、上端は0.5です。 |
K1 | single | 第1放射歪み係数 |
K2 | single | 第2放射歪み係数 |
この要素には、カメラの拡張レンズ歪みパラメータセットが含まれています。
この要素は、汎用レンズの歪みを記述するためにのみ使用されます。特に、魚眼、アナモルフィック、またはティルトシフトレンズの歪みを記述するのには適していません。
この要素を含むパケットには、「視野角」要素も含める必要があります。視野角情報がなければ、この要素の内容は受信側にとって有用ではありません。
この要素のフィールドには、OpenCVで使用される歪みモデルに従った係数が含まれています。歪みモデルの説明は付録Bに記載されています。
未知(測定/校正されていない)の値を持つフィールドは0を含む必要があります。
基本パラメータセットと拡張パラメータセットの選択については、付録B.2を参照すること。
ElementType | uint16 | 3 |
ElementLength | uint16 | 60 |
CenterX | single | 画像中心に対する主点のX座標。画像の左端は-0.5、右端は0.5。 |
CenterY | single | 画像中心に対する主点のY座標。画像の上端は-0.5、下端は0.5。 |
K1 | single | 第1放射歪み係数 |
K2 | single | 第2放射歪み係数 |
K3 | single | 第3放射歪み係数 |
K4 | single | 第4放射歪み係数 |
K5 | single | 第5放射歪み係数 |
K6 | single | 第6放射歪み係数 |
P1 | single | 第1接線歪み係数 |
P2 | single | 第2接線歪み係数 |
S1 | single | 第1薄プリズム歪み係数 |
S2 | single | 第2薄プリズム歪み係数 |
S3 | single | 第3薄プリズム歪み係数 |
S4 | single | 第4薄プリズム歪み係数 |
この要素には、カメラの焦点が合っているオブジェクトまでの距離が含まれています。 距離は付録Bで説明されているように入射瞳から測定されます。この距離は、カメラセンサーから計算された物理的距離とは異なる場合があります。 ただし、ほとんどの実用的なケースでは、これら2つの値の違いは無視できます。
ElementType | uint16 | 4 |
ElementLength | uint16 | 8 |
FocusDistance | single | Tメートル単位の焦点距離 |
この要素には、カメラのセンサーに関する情報が含まれています。
ElementType | uint16 | 5 |
ElementLength | uint16 | 16 |
ActiveSensorWidth | single | 出力画像の生成に使用されるカメラセンサー部分の幅(ミリメートル単位)。不明な場合はゼロになります。 |
ActiveSensorHeight | single | 出力画像の生成に使用されるカメラセンサー部分の高さ(ミリメートル単位)。不明な場合はゼロになります。 |
ActiveHorizontalResolution | unit16 | 出力画像の生成に使用されるカメラセンサー部分の水平解像度(ピクセル単位)。不明な場合はゼロになります。 |
ActiveVerticalResolution | unit16 | 出力画像の生成に使用されるカメラセンサー部分の垂直解像度(ピクセル単位)。不明な場合はゼロになります。 |
この要素には、カメラの絞りの幅がF値として含まれています。
ElementType | uint16 | 6 |
ElementLength | uint16 | 8 |
FNumber | single | F値。例えば、f/5.6の絞りは値5.6で表現されます。 |
この要素には、画像の周辺部に向かって明度が徐々に減少することに関する情報が含まれています。
この要素は、円形のビネット効果を持つ汎用レンズのビネットを記述するためのみに使用されます。 特に、魚眼、アナモルフィック、またはティルトシフトレンズの効果を記述するのには適さない場合があります。
この要素には、任意の数N(≥1)のデータフィールドが含まれます。これらの各フィールドには、 画像中心からの特定の距離で失われる明度の比率が含まれています。各フィールドには0.0から1.0の値が含まれている必要があり、 0.0は明度の損失なし、1.0は完全な明度の損失(常に黒いピクセル)を表します。
値は画像中心から角までの順序で、等間隔で配置されます。 最初の値は画像中心から角への1/Nの位置での明度損失、2番目の値は2/Nの位置、以下同様です。最後の値は角での明度損失です。 画像中心の値は送信されず、常に0(明度損失なし)と仮定されます。
ElementType | uint16 | 7 |
ElementLength | uint16 | 要素の長さ。8 + 4⋅RatioCountに等しい。 |
RatioCount | uint16 | パケット内の比率フィールドの数(N)。 |
Reserved | uint16 | ゼロ |
Ratio1 | single | 画像中心からコーナーまでの1/Nの位置での明度損失 |
Ratio2 | single | 画像中心からコーナーまでの2/Nの位置での明度損失 |
... | ||
RatioN | single | 画像角での明度損失 |
この要素には、カメラまたはスタンドアロン・トラッキングデバイスの位置に関する情報が含まれています。
デバイスがカメラの場合、報告される位置は付録Bで説明されている入射瞳の位置です。
位置は平行移動と回転の組み合わせで表現されます。 これらは通常の順序(回転が最初、次に平行移動)で適用され、位置を表す変換を得ます。
平行移動は、右手座標系でメートル単位で指定されます。座標系の軸は、トラッキングシステムの右(X)、上(Y)、後方(Z)方向を表します。 トラッキングシステムがそれを保証できる場合、Y = 0は床レベルに対応し、Y > 0は床より上のオブジェクトを表します。
回転は、(x、y、z、w)の形式の単位クォータニオン(基底要素の乗算にハミルトンの定義を使用) として表現され、x、y、zはそれぞれの座標に対応する成分、wは実成分です。
平行移動値の誤差はTranslationErrorフィールドで記述されます。このフィールドには、 報告された平行移動と実際の平行移動ベクトルの差の最大大きさが含まれ、99.73%(3σ、正規分布の測定誤差を仮定)の信頼度を持ちます。
平行移動が不明な場合、平行移動誤差フィールドは正の無限大に設定する必要があります。 平行移動の誤差が不明な場合、平行移動誤差フィールドにはゼロを含める必要があります。
回転値の誤差はRotationErrorフィールドで記述されます。 これには、報告された回転(RotationX、RotationY、RotationZ、RotationWフィールドで記述)と実際の回転の間の回転の最大角度が含まれ、99.73%の信頼度を持ちます。
回転が不明な場合、回転誤差フィールドは正の無限大に設定する必要があります。 回転の誤差が不明な場合、回転誤差フィールドにはゼロを含める必要があります。
ElementType | uint16 | 8 |
ElementLength | uint16 | 40 |
TranslationX | single | メートル単位の平行移動ベクトルのX成分 |
TranslationY | single | メートル単位の平行移動ベクトルのY成分 |
TranslationZ | single | メートル単位の平行移動ベクトルのZ成分 |
RotationX | single | 回転クォータニオンのX成分 |
RotationY | single | 回転クォータニオンのY成分 |
RotationZ | single | 回転クォータニオンのZ成分 |
RotationW | single | 回転クォータニオンの実成分 |
TranslationError | single | メートル単位の平行移動ベクトルの誤差。平行移動ベクトルが不明な場合は+∞、誤差が不明な場合は0.0。 |
RotationError | single | ラジアン単位の回転成分の誤差。回転が不明な場合は+∞、誤差が不明な場合は0.0。 |
この要素には、カメラまたはスタンドアロン・トラッキングデバイスの速度と角速度に関する情報が含まれています。 受信側がパケット間でデバイスの位置を近似するのに役立ちます。
速度は位置と同じ座標系でメートル毎秒で指定されます。角速度(毎秒)は回転と同様に単位クォータニオンで表現されます。
速度または角速度のいずれかが不明な場合、不明な量の成分フィールドにはNaNを含める必要があります。
ElementType | uint16 | 9 |
ElementLength | uint16 | 32 |
VelocityX | single | メートル毎秒の速度ベクトルのX成分。速度が不明な場合はNaN |
VelocityY | single | メートル毎秒の速度ベクトルのY成分。速度が不明な場合はNaN |
VelocityZ | single | メートル毎秒の速度ベクトルのZ成分。速度が不明な場合はNaN |
AngularVelocityX | single | 角速度クォータニオンのX成分(毎秒)。角速度が不明な場合はNaN |
AngularVelocityY | single | 角速度クォータニオンのY成分(毎秒)。角速度が不明な場合はNaN |
AngularVelocityZ | single | 角速度クォータニオンのZ成分(毎秒)。角速度が不明な場合はNaN |
AngularVelocityW | single | 角速度クォータニオンの実成分(毎秒)。角速度が不明な場合はNaN |
この要素には、トラッキングデバイスのフレームレートが含まれています。
この要素の存在は、送信側が1/フレームレート秒ごとに1つのパケットを生成する定期的な間隔でパケットを生成することを示します。 この要素が存在する場合、送信側はこのスケジュールに可能な限り近いタイミングでパケットを送信する必要があります。
フレームレートは有理数(2つの整数の商)の形式で表現されます。 これは、NTSCベースのフレームレートを正確に表現するために必要です。
フレームレートが整数である非NTSCの場合、分母として1を使用することを推奨します。 例えば、50 fpsは50 / 1として表現されます。分数フレームレートの場合は適切な分母を使用し、例えば12.5 fpsは25 / 2となります。
NTSCの場合、分母として1001を使用することが必須です。例えば、23.976 fpsは24000 / 1001として、59.94 fpsは60000 / 1001として表現する必要があります。
ElementType | uint16 | 10 |
ElementLength | uint16 | 12 |
FrameRateNumerator | uint32 | フレーム毎秒値の分子部分 |
FrameRateDenominator | uint32 | フレーム毎秒値の分母部分 |
この要素は、測定値を報告するために使用できます。測定値は、ズーム、フォーカス、絞りなどの通常のエンコーダー値、または温度などの任意のカスタム測定値の場合があります。 このタイプの複数の要素をパケットに含めることができますが、各インスタンスはMeasurementTypeフィールドに異なる値を含む必要があります。
生のズームとフォーカス値の送信は、デバッグデータなどの補助的な追加のみであることに注意が必要です。生のズームエンコーダー値が存在する場合は視野角要素を、 生のフォーカスエンコーダー値が存在する場合は焦点距離要素を、生の絞りエンコーダー値が存在する場合は絞り要素をパケットに含めることが必須です。
ElementType | uint16 | 11 |
ElementLength | uint16 | 20 |
MeasurementType | uint32 | 要素に含まれる値のタイプを記述する識別子。ズームエンコーダーは0、フォーカスエンコーダーは1、絞りエンコーダーは2。他の値はカスタム測定を指定します。 |
Value | single | 測定の値 |
MinValue | single | 測定の最小可能値、不明な場合はNaN。下限がない場合、値は負の無限大である場合があります。 |
MaxValue | single | 測定の最大可能値、不明な場合はNaN。上限がない場合、値は正の無限大である場合があります。 |
受信側は、レンズの焦点距離、フォーカス距離、絞り幅から被写界深度を計算できます。焦点距離自体は、 視野角と出力画像の生成に使用されるカメラセンサー部分のサイズから計算されます。
これは、受信側が被写界深度情報を計算できるように、パケットに次の要素を含める必要があることを意味します:
送信されるデータには「水平視野角」と「フレームアスペクト比」の値が含まれています。垂直視野角の値も必要な場合は、次のように計算できます:
\[ \textit{FOV}_y = 2 \cdot \textit{arctan}\left( \textit{tan}\left( \frac{\textit{FOV}_x}{2} \right) \cdot \frac{1}{\textit{AR}} \right) \]
カメラの投影と歪みを表現するために、 https://docs.opencv.org/4.x/d9/d0c/group__calib3d.html#detailsで説明されているOpenCVで使用されるものと類似した歪みモデルを追加したピンホールカメラモデルが使用されます。
このモデルは、ほとんどの汎用カメラレンズをよく記述しますが、魚眼、アナモルフィック、またはティルトシフトレンズの歪みを記述するのには適していません。
モデルは、カメラの入射瞳(透視の中心、時には節点と誤って呼ばれることもある)を中心としています。入射瞳は、レンズやカメラの物理的な点ではありません。 それは、実際のカメラの視野と完全に重なるように仮想ピンホールカメラを配置しなければならない点です。入射瞳は、カメラの光軸上、レンズの後方のどこかに位置しています。ズームレンズの場合、 その位置は固定されておらず、視野が変化するにつれて前後に移動します。
カメラの座標系は入射瞳を中心とし、X軸は右を指し、Y軸は上を指し、Z軸は後方を指します。
この座標系で座標(xc , y c , z c )にある点をカメラが表示するピクセルの座標(u, v)を見つけるために、以下の手順が使用されます:
座標はz = 1平面に投影されます:
$$x_1 = \frac{x_c}{z_c}$$
$$y_1 = \frac{y_c}{z_c}$$
光軸からの距離が計算されます:
$$r = \sqrt{x_1^2 + y_1^2}$$
レンズ歪みが適用されます:
$$ x_d = x_1 \cdot \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + 2p_1 x_1 y_1 + p_2 (r^2 + 2x_1^2) + s_1 r^2 + s_2 r^4 $$
$$ y_d = y_1 \cdot \frac{1 + k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + p_1 (r^2 + 2 y_1^2) + 2 p_2 x_1 y_1 + s_3 r^2 + s_4 r^4 $$
歪んだ点は画像センサーに投影されます:
$$u = f_x \cdot x_d + c_x$$
$$v = f_y \cdot y_d + c_y$$
係数 k1 から k6 は放射歪み(樽型歪み、糸巻き型歪み、またはその組み合わせ)を表します。 p1 と p2 は接線(脱中心)歪みを表します。s1 から s4 は薄プリズム歪みを表します。「レンズ歪み」要素には、これらの係数が含まれています。これらの係数のいずれかが測定されていない場合は、ゼロとして渡す必要があります。
汎用レンズで最も一般的な歪みタイプは放射歪みで、通常 k1 と k2のみを使用してかなり正確に記述できます。 レンズ歪みがこれら2つの係数のみを使用するモデルで計算される場合、「レンズ歪み」要素の残りのフィールドはゼロである必要があります。
最終ステップでは、fx と fy はピクセル単位で測定された焦点距離を含み、 (cx, cy)はピクセル単位の主点(光軸が画像センサーと交差する点)の座標です。 これらの値は、カメラによって送信される画像の解像度への依存を避けるために、パケットに直接含まれていません。代わりに次のデータが送信されます:
$$\textit{FOV}_x = 2 \cdot \textit{arctan}\left(\frac{r_x}{2 f_x}\right)$$
\[ \textit{AR} = \frac{r_x}{r_y} \cdot \frac{f_x}{f_y} \]
(FOVは度で測定されます)、そして
\[ C_x = \frac{c_x}{r_x} - 0.5 \]
\[ C_y = \frac{c_y}{r_y} - 0.5 \]
ここで、rxとryはそれぞれ画像の水平および垂直解像度です。
拡張モデルは基本モデルのスーパーセットですが、そのK1とK2係数は基本モデルのK1とK2値と異なる場合があります。 送信側は、レンズ校正が実行されるモデルを送信する必要があります。ただし、送信側が拡張モデルを使用する場合、基本パラメータセットも計算して送信するか、 少なくともUIでそれを行う選択可能なオプションを提供することを強く推奨します。
受信側は、その目的により適したものに応じて、モデルの1つのみをサポートすることが許可されています。
プロトコルは、1つの形式でのみレンズ歪みデータを受け入れます。レンズの歪みが異なるモデルを使用して計算される場合、 この表現に変換する必要があります。これを行う正確な方法は、使用される歪みモデルに依存します。いくつかの一般的な違いを以下に示します。
カメラモデルは通常、視野を記述するために焦点距離を使用します。このプロトコルは代わりに視野角を期待します。一般的に、
$$\textit{FOV}_x = 2 \cdot \textit{arctan}\left(\frac{s_x}{2 f_x}\right)$$
$$\textit{FOV}_y = 2 \cdot \textit{arctan}\left(\frac{s_y}{2 f_y}\right)$$
方程式は、焦点距離(fx, fy)とセンサーサイズ(sx, sy))から視野を計算するために使用できます。2つの量は同じ測定単位である必要があります。校正ツールは通常、fxとfyとfyをピクセル単位で出力します。この場合、 sxとsyはそれぞれ画像の水平と垂直です。ただし、一部のデバイスは両方をミリメートル単位で出力する場合があり、その場合も同じ式を使用できます。
他のモデルは、異なる単位または異なる方向を使用して主点を記述する場合があります。モデルの説明が主点が何であるかを明示的に言及していない場合、放射歪みの中心点として見つけるのが最も簡単なことが多いです。
一部のモデルは、歪みと投影を逆の順序で適用します。つまり、最初にオブジェクト座標をセンサーに投影し(fx、 fy、 cx、 cy)を使用)、 その後に歪みを適用します。そのようなモデルから歪み係数をこのプロトコルで使用されるものに変換するには、まず画像を単位距離の平面に再投影し、それに応じて係数を変換する必要があります。
さらに、係数の値は、座標の単位の選択に依存します。座標は、ピクセル、ミリメートル(カメラセンサー上)、または画像の幅、高さ、対角線の倍数で指定されることが多いです。例として、座標がミリメートルで測定される場合、 k1はmm-2で測定され、 k2はmm-4で測定されます。係数をこのプロトコルで使用される表現に変換する際には、測定単位を考慮する必要があります。
このプロトコルで使用されるモデルでは、歪みのない座標x1とy1は入射瞳から単位距離の平面で測定され、 これは自然な表現と見なすことができる結果となります。これは、歪み係数が焦点距離と xc、 yc、zcの測定に使用される単位の両方から独立していることを意味します。
また、技術的には、焦点距離(fxとfy)を使用した投影後に適用される歪みは、このプロトコルで使用されるモデルを使用して表現することはできない(およびその逆も同様)ことにも注意する必要があります:一方における円対称の放射歪みは、一般的に他方において非円形歪みをもたらします。ただし、 fxとfy がほぼ同一である限り(画像を一方向に意図的に圧縮しないレンズの場合と同様)、結果は視覚的に区別できないはずです。
上記に加えて、一部のモデルは逆方向の歪みを記述します。つまり、歪んだピクセルの座標の関数として歪みのないピクセルの座標を与えます。 そのようなモデルの逆形式を計算する正確な方法は一般的にありませんが、あまり大きくない歪みでうまく機能する方法があります。areaWidthは投影領域を指し、通常はカメラセンサー幅の使用部分です。その単位は、変換元のモデルに依存します。
bool InvertRadial(double K1, double K2, float areaWidth, double& invK1, double& invK2)
{
invK1 = invK2 = 0.0;
const int N = 5;
double pa = 0.5f * areaWidth;
double dx = 1.0 / N;
double x = dx;
double D[N][2];
double d[N];
for (int i = 0; i < N; i++, x += dx)
{
double undist = x;
double p = x * pa;
double p2 = p * p;
p *= (1.0f + p2 * (K1 + p2 * K2));
double dist = p / pa;
double r = dist * pa;
double q = undist * pa;
double r2 = r * r;
D[i][0] = r * r2;
D[i][1] = r * r2 * r2;
d[i] = q - r;
}
// D.transp() * D
double A[2][2];
memset(A, 0, sizeof(A));
for (int i = 0; i < N; i++)
{
A[0][0] += D[i][0] * D[i][0];
A[0][1] += D[i][0] * D[i][1];
A[1][1] += D[i][1] * D[i][1];
}
A[1][0] = A[0][1];
// (D.transp() * D).inv()
double B[2][2];
double det = (A[0][0] * A[1][1] - A[0][1] * A[1][0]);
if (fabs(det) < 1e-14) return false;
B[0][0] = A[1][1] / det;
B[1][1] = A[0][0] / det;
B[0][1] = B[1][0] = -A[0][1] / det;
// (D.transp() * D).inv() * D.transp()
double C[2][N];
for (int i = 0; i < N; i++)
{
C[0][i] = B[0][0] * D[i][0] + B[0][1] * D[i][1];
C[1][i] = B[1][0] * D[i][0] + B[1][1] * D[i][1];
}
// (D.transp() * D).inv() * D.transp() * d
for (int i = 0; i < N; i++)
{
invK1 += C[0][i] * d[i];
invK2 += C[1][i] * d[i];
}
return true;
}
C-Trackingは、実際の物理値を送信するように設計されています。例えば、ズームセンサーの生エンコーダー値を送信する代わりに、実際のFOVとレンズ歪みデータを送信することが推奨されます。 これには、レンズ校正がトラッキングデバイス側で行われる必要があります。もう少し関与が必要かもしれませんが、その代わりにトラッキングデバイスは真のプラグアンドプレイデバイスになります。PTZカメラなどの場合には、これは工場で行うことができます。同じ構築パラメータを持つカメラのバッチの場合、一度行うだけで十分であり、校正プロファイルはファームウェアに格納できます。