kitti データセットの前処理
0 まえがき
注:velodyne_reduced为图像在三维空间内的视椎体的数据(训练使用)
└── KITTI_DATASET_ROOT
├── training <-- 7481 train data
| ├── image_2 <-- for visualization
| ├── calib <-- camera inner and outter parameters
| ├── label_2 <--label for trainning and evaluate
| ├── velodyne<--lidar data
| └── velodyne_reduced <-- empty directory,reduced by image size frustum
└── testing <-- 7518test data
├── image_2 <-- for visualization
├── calib
├── velodyne
└── velodyne_reduced <-- empty directory
传感器:
1惯性导航系统(GPS / IMU):OXTS RT 3003
1台激光雷达:Velodyne HDL-64E
2台灰度相机,1.4百万像素:Point Grey Flea 2(FL2-14S3M-C)
2个彩色摄像头,1.4百万像素:Point Grey Flea 2(FL2-14S3C-C)
4个变焦镜头,4-8毫米:Edmund Optics NT59-917
0.1.キャリブレーション
キャリブファイルは、カメラ、レーダー、慣性航法、その他のセンサーの補正データです。
P0: 7.215377000000e+02 0.000000000000e+00 6.095593000000e+02 0.000000000000e+00 0.000000000000e+00 7.215377000000e+02 1.728540000000e+02 0.000000000000e+00 0.000000000000e+00 0.000000000000e+00 1.000000000000e+00 0.000000000000e+00
P1: 7.215377000000e+02 0.000000000000e+00 6.095593000000e+02 -3.875744000000e+02 0.000000000000e+00 7.215377000000e+02 1.728540000000e+02 0.000000000000e+00 0.000000000000e+00 0.000000000000e+00 1.000000000000e+00 0.000000000000e+00
P2: 7.215377000000e+02 0.000000000000e+00 6.095593000000e+02 4.485728000000e+01 0.000000000000e+00 7.215377000000e+02 1.728540000000e+02 2.163791000000e-01 0.000000000000e+00 0.000000000000e+00 1.000000000000e+00 2.745884000000e-03
P3: 7.215377000000e+02 0.000000000000e+00 6.095593000000e+02 -3.395242000000e+02 0.000000000000e+00 7.215377000000e+02 1.728540000000e+02 2.199936000000e+00 0.000000000000e+00 0.000000000000e+00 1.000000000000e+00 2.729905000000e-03
R_rect 9.999239000000e-01 9.837760000000e-03 -7.445048000000e-03 -9.869795000000e-03 9.999421000000e-01 -4.278459000000e-03 7.402527000000e-03 4.351614000000e-03 9.999631000000e-01
Tr_velo_cam 7.533745000000e-03 -9.999714000000e-01 -6.166020000000e-04 -4.069766000000e-03 1.480249000000e-02 7.280733000000e-04 -9.998902000000e-01 -7.631618000000e-02 9.998621000000e-01 7.523790000000e-03 1.480755000000e-02 -2.717806000000e-01
Tr_imu_velo 9.999976000000e-01 7.553071000000e-04 -2.035826000000e-03 -8.086759000000e-01 -7.854027000000e-04 9.998898000000e-01 -1.482298000000e-02 3.195559000000e-01 2.024406000000e-03 1.482454000000e-02 9.998881000000e-01 -7.997231000000e-01
P0、1、2、3 はそれぞれ、左グレースケール カメラ、右グレースケール カメラ、左カラー カメラ、右カラー カメラの射影行列を表します。
P = K [ R , t ] = [ fx 0 cx 0 0 fycy 0 0 0 1 0 ] [ r 11 r 12 r 13 txr 21 r 22 r 23 tyr 31 r 32 r 33 tz 0 0 0 1 ] P=K [R ,t] =\begin{bmatrix} f_x & 0 & c_x & 0 \\ 0 & f_y & c_y & 0 \\ 0 & 0 & 1 & 0 \end{bmatrix} \begin{bmatrix} r_{11} & r_{12} & r_{13} & t_x \\ r_{21} & r_{22} & r_{23} & t_y \\ r_{31} & r_{32} & r_{33} & t_z \\ 0 & 0 & 0 & 1 \end{bmatrix}P=K [ R 、t ]= f×000fはい0c×cはい1000 r11r21r310r12r22r320r13r23r330t×tはいtz1
ワールド座標点をカメラ座標に変換し、カメラ座標をピクセル座標に変換するために使用されます。
-
R_rect: カメラ番号 0 の補正行列で、サイズは 3x3 です。目的は、4 台のカメラの共面結像を実現し、4 台のカメラの光学中心が同じ xoy 平面上にあることを保証することです。外部パラメータ行列を変更した後、カメラ座標系の座標を取得するために R0_rect を乗算する必要があります。
-
Tr_velo_cam: LIDAR とカメラの間の外部パラメータ マトリックス。LIDAR 座標系の点をカメラ座標系の点に変換するために使用されます。
T velo 2 cam = [ R velocamtvelocam 0 T 1 ] T_{velo2cam} = \begin{bmatrix} R^{cam}_{velo} & t^{cam}_{velo} \\ \mathbf{0}^T & 1 \end{b行列}Tv e l o 2カム_=[Rヴェロ_ _ _さあ_0Ttヴェロ_ _ _さあ_1】
-
要約すると、カメラ座標系の点群座標の座標は次と等しくなります。
内参矩阵 * 外参矩阵 * R0校准矩阵 * 点云坐标
つまり、次のようになります。P * R0_rect *Tr_velo_to_cam * x
-
Tr_imu_velo: IMU と LIDAR の間の外部パラメータ マトリックス。IMU 測定値を LIDAR 座標系の値に変換するために使用されます。
1、将 Velodyne 坐标中的点 x 投影到左侧的彩色图像中 y,使用公式 y = P2 * R0_rect * Tr_velo_to_cam * x
2、将 Velodyne 坐标中的点 x 投影到右侧的彩色图像中 y,使用公式 y = P3 * R0_rect * Tr_velo_to_cam * x
3、将 Velodyne 坐标中的点 x 投影到编号为 0 的相机(参考相机)坐标系中,使用公式 R0_rect * Tr_velo_to_cam * x
4、将 Velodyne 坐标中的点 x 投影到编号为 0 的相机(参考相机)坐标系中,再投影到编号为 2 的相机(左彩色相机)的照片上,使用公式 P2 * R0_rect * Tr_velo_to_cam * x
0.2.oxts(gps/imu)
OXTS (GPS/IMU) 各フレームについて、高度、全地球方位、速度、加速度、角速度、精度、衛星情報を含む地理座標などの 30 の異なる GPS/IMU 値をテキスト ファイルに保存します。加速度と角速度は両方とも 2 つの座標系を使用して指定され、1 つは物体 (x、y、z) に関連付けられ、もう 1 つはその位置の地表の接平面 (f、l、u) にマッピングされます。 OXTS デバイスの短時間 (約 1 秒) の通信障害の問題。この問題については、すべての値を線形補間し、不足している情報を示すために最後の 3 つのエントリを「-1」に設定します。詳細については、dataformat.txt を参照してください。変換ユーティリティは開発キットに含まれています。
49.015003823272 8.4342971002335 116.43032836914 0.035752 0.00903 -2.6087069803847 -6.811441479104 -11.275641809511 13.172716663769 -0.12475264293164 -0.032919903047354 -0.44519814607457 0.042957369847256 10.209865300506 -0.34030092211055 -0.31686915378551 10.209117821189 0.0090951755733632 -0.023140741253985 -0.017909034508194 0.0089018002187228 -0.022495299354602 -0.018809330937153 0.027658633371879 0.012727922061358 4 11 6 6 6
其中,每个字段的含义如下:
lat:纬度,单位为度
lon:经度,单位为度
alt:海拔高度,单位为米
Roll:横滚角,单位为弧度
Pitch:俯仰角,单位为弧度
Yaw:偏航角,单位为弧度
vn:北向速度,单位为米/秒
ve:东向速度,单位为米/秒
vf:车体前向速度,单位为米/秒
vl:车体横向速度,单位为米/秒
vu:车体垂直速度,单位为米/秒
ax:X轴方向加速度,单位为米/秒^2
ay:Y轴方向加速度,单位为米/秒^2
az:Z轴方向加速度,单位为米/秒^2
af:前向加速度,单位为米/秒^2
al:横向加速度,单位为米/秒^2
au:垂直加速度,单位为米/秒^2
wx:X轴方向角速度,单位为弧度/秒
wy:Y轴方向角速度,单位为弧度/秒
wz:Z轴方向角速度,单位为弧度/秒
wf:前向角速度,单位为弧度/秒
wl:横向角速度,单位为弧度/秒
wu:垂直角速度,单位为弧度/秒
pos_accuracy:GPS位置精度,单位为米
vel_accuracy:GPS速度精度,单位为米/秒
navstat:GPS状态,0代表无效,1代表GPS解算成功
numsats:使用的GPS卫星数
posmode:GPS定位模式,如下所示:
0:没有GPS定位
1:单点定位(SPS)
2:差分GPS定位(DGPS)
3:精密GPS定位(PPS)
4:实时动态差分GPS定位(Real Time Kinematic,RTK)
5:浮点解(Float RTK)
6:估算定位
7:手动输入定位
8:模拟定位
velmode:GPS速度模式,如下所示:
0:没有GPS速度
1:仅使用GPS速度测量
2:仅使用IMU速度测量
3:GPS和IMU速度融合
orimode:GPS姿态模式,如下所示:
0:没有GPS姿态
1:仅使用GPS姿态测量
2:仅使用IMU姿态测量
3:GPS和IMU姿态融合
0.3.ベロダイン
Velodyne 効率を向上させるため、Velodyne スキャンは浮動小数点バイナリ ファイルとして保存されます。点群データは浮動小数点バイナリ ファイル形式で保存されます。各行には 8 つのデータが含まれます。各データは 4 桁の 16 進数 (浮動小数点数) で表されます。 ). 各データはスペースで区切られます。点群データは 4 つの浮動小数点データで構成され、それぞれ点群の x、y、z、r (強度または反射値) を表します。スキャンごとのポイント数は一定ではありませんが、各ファイル/フレームの平均サイズは約 1.9 MB で、120,000 の 3D ポイントと反射率値に対応します。Velodyne レーザー スキャナは垂直軸の周り (反時計回り) に連続的に回転することに注意してください。これはタイムスタンプ ファイルを使用して考慮できます。
各 velodyne ファイルには、完全な LIDAR スキャン サイクル中に収集されたすべてのポイントの座標と反射強度の値が含まれており、データの保存形式は次のとおりです。
float x; // 点的x坐标,单位为米
float y; // 点的y坐标,单位为米
float z; // 点的z坐标,单位为米
float intensity;// 反射强度值,无单位
各ポイントは 16 バイトを占め、それぞれポイントの x、y、z 座標と反射強度値を表します。データ型はすべて浮動小数点数の形式です。
- x、y、z はそれぞれ 3 次元空間上の点の座標を表し、単位はメートルです。データ型は float で、通常は IEEE 754 浮動小数点形式で表現されます。
- 強度はポイントの反射強度値を表し、符号なしの整数です。値の範囲は通常 0 ~ 255 で、値が大きいほど反射強度が強くなります。反射強度値はベロダインライダーで測定した実際の物理量ではなく、レーザー光とターゲットとの反射関係を近似的に反映した量です。
0.4.画像_2/3
画像ファイルは 8 ビット PNG 形式で保存されます。
0.5.キティステップ/パノプティクス
STEP は The Segmenting and Tracking Every Pixel ベンチマークの略で、21 のトレーニング シーケンスと 29 のテスト シーケンスが含まれます。このデータセットは、KITTI Tracking Evaluation および Multi-Object Tracking and Segmentation (MOTS) ベンチマークに基づいています。
このデータセットは、各ピクセルに高密度ピクセル セグメンテーション ラベルを追加します。このベンチマークでは、各ピクセルにはセマンティック ラベルがあり、最も顕著なオブジェクト カテゴリ (車と歩行者) に属するすべてのピクセルには一意の追跡 ID があります。
0.6.ラベル
参照カメラの視野内の動的オブジェクトごとに、Velodyne 座標で表現された 3D 境界ボックス軌跡の形式で注釈を提供します。「自動車」、「バン」、「トラック」、「歩行者」、「人(座っている)」、「自転車」、「路面電車」、「その他」(トレーラー、セグウェイなど)のタイプを定義します。トラックレットは date_drive_tracklets.xml に保存されます。各オブジェクトにはクラスとその 3D サイズ (高さ、幅、長さ) が割り当てられます。図に示すように、フレームごとにオブジェクトの 3D 移動と回転を提供します。ヨー角のみを提供し、他の 2 つの角度はゼロに近いと想定されることに注意してください。さらに、オクルージョンとトランケーションのレベルが指定されます。
オブジェクトの座標。オブジェクトの座標。この図は、3D Velodyne レーザー スキャナ座標系に対する注釈付き 3D 境界ボックスの座標系を示しています。z 方向では、オブジェクト座標系はオブジェクトの基部 (支持面との接触点) に位置します。
ラベル ファイルを例に挙げます。
Truck 0.00 0 -1.57 599.41 156.40 629.75 189.25 2.85 2.63 12.34 0.47 1.49 69.44 -1.56
Car 0.00 0 1.85 387.63 181.54 423.81 203.12 1.67 1.87 3.69 -16.53 2.39 58.49 1.57
Cyclist 0.00 3 -1.65 676.60 163.95 688.98 193.93 1.86 0.60 2.02 4.59 1.32 45.84 -1.55
DontCare -1 -1 -10 503.89 169.71 590.61 190.13 -1 -1 -1 -1000 -1000 -1000 -10
DontCare -1 -1 -10 511.35 174.96 527.81 187.45 -1 -1 -1 -1000 -1000 -1000 -10
DontCare -1 -1 -10 532.37 176.35 542.68 185.27 -1 -1 -1 -1000 -1000 -1000 -10
DontCare -1 -1 -10 559.62 175.83 575.40 183.15 -1 -1 -1 -1000 -1000 -1000 -10
車を例に挙げます。
ラベル.txt | 車 | 0.00 | 0 | 1.85 | 387.63 181.54 | 423.81 203.12 | 1.67 1.87 3.69 | -16.53 2.39 58.49 | 1.57 |
---|---|---|---|---|---|---|---|---|---|
説明する | カテゴリー | truncated (切り捨て度)、0.00 は切り捨てなしを意味します | オクルージョン (オクルージョン率)、0 はオクルージョンがないことを意味します | alpha([-pi, pi]) 観察角 | 左上隅の 2D バウンディング ボックス (BB) 座標 | 右下隅の 2D BB 座標 | 3D BBの高さ、幅、長さ | カメラ座標における 3D BB 位置 | P/R 曲線を描くために使用される信頼度は、高いほど優れています。 |
DontCare
興味のない領域は分割され、その領域内のオブジェクトにはラベルが付けられません。
每一行代表一个object,每一行都有16列分别表示不同的含义,具体如下:
- 第1列(字符串):代表物体类别(type)
总共有9类,分别是:Car、Van、Truck、Pedestrian、Person_sitting、Cyclist、Tram、Misc、DontCare。
其中DontCare标签表示该区域没有被标注,比如由于目标物体距离激光雷达太远。为了防止在评估过程中(主要是计算precision),将本来是目标物体但是因为某些原因而没有标注的区域统计为假阳性(false positives),评估脚本会自动忽略DontCare区域的预测结果。
- 第2列(浮点数):代表物体是否被截断(truncated)
数值在0(非截断)到1(截断)之间浮动,数字表示指离开图像边界对象的程度。
- 第3列(整数):代表物体是否被遮挡(occluded)
整数0、1、2、3分别表示被遮挡的程度。
- 第4列(弧度数):物体的观察角度(alpha)
取值范围为:-pi ~ pi(单位:rad),它表示在相机坐标系下,以相机原点为中心,相机原点到物体中心的连线为半径,将物体绕相机y轴旋转至相机z轴,此时物体方向与相机x轴的夹角(如下图所示,y轴垂直与屏幕)
- 第5~8列(浮点数):物体的2D边界框大小(bbox)
四个数分别是xmin、ymin、xmax、ymax(单位:pixel),表示2维边界框的左上角和右下角的坐标。
- 第9~11列(浮点数):3D物体的尺寸(dimensions)
分别是高、宽、长(单位:米)
- 第12-14列(浮点数):3D物体的位置(location)
分别是x、y、z(单位:米),特别注意的是,这里的xyz是在相机坐标系下3D物体的中心点位置。
- 第15列(弧度数):3D物体的空间方向(rotation_y)
取值范围为:-pi ~ pi(单位:rad),它表示,在照相机坐标系下,物体的全局方向角(物体前进方向与相机坐标系x轴的夹角),如下图所示。
- 第16列(浮点数):检测的置信度(score)
在这里插入图片描述
1.create_kitti_ Depth_maps
画像と LIDAR データを使用して深度情報を取得します。KITTI データセットから Velodyne 点群を画像に投影し、深度マップを生成します。具体的な実装プロセスは次のとおりです。
-
1. KITTI データセットのP 行列、
R_rect
行列、Tr_velo_cam
行列を読み取ります。ここで、P
行列はカメラの投影行列、R_rect
行列はカメラの歪み補正行列、Tr_velo_cam
行列は Velodyne からの変換行列です。点群をカメラ座標系に変換します。 -
2. KITTI データセット内の oxts ファイルを読み取ります。このファイルには、GPS の位置、速度、姿勢、および各瞬間のその他の情報が含まれています。
-
3. 画像の各フレームに対して、対応する Velodyne 点群を読み取り、Velodyne 点群を Velodyne 座標系からカメラ座標系に変換します。
-
4. P マトリックスに従って点群を画像上に投影し、投影結果に基づいて深度マップを生成します。
-
5. 深度マップを Parquet ファイルに書き込みます。
Velodyne 点群からカメラ座標系への変換行列式:
T velo 2 cam = [ Rect 0 3 × 1 0 1 × 3 1 ] ⋅ [ R velo 2 cam T velo 2 cam 0 1 × 3 1 ] T_{velo2cam} =\begin{bmatrix}R_{rect} & 0_{3\times 1} \\ 0_{1\times 3} & 1 \end{bmatrix}\cdot\begin{bmatrix}R_{velo2cam} & T_{velo2cam} \\ 0_{1\times 3} & 1 \end{bmatrix}Tv e l o 2カム_=[R記録してください01 × 303 × 11】⋅[Rv e l o 2カム_01 × 3Tv e l o 2カム_1】
点群を画像に投影するための公式:
[ uv 1 ] = [ P 1 , 1 P 1 , 2 P 1 , 3 P 1 , 4 P 2 , 1 P 2 , 2 P 2 , 3 P 2 , 4 P 3 , 1 P 3 , 2 P 3 , 3 P 3 , 4 ] ⋅ [ XYZ 1 ] \begin{bmatrix}u\\v\\1\end{bmatrix}=\begin{bmatrix}P_{1,1}&P_ {1,2}&P_{1,3}&P_{1,4}\\P_{2,1}&P_{2,2}&P_{2,3}&P_{2,4}\\P_{3,1 }&P_{3,2}&P_{3,3}&P_{3,4}\end{bmatrix}\cdot \begin{bmatrix}X\\Y\\Z\\1\end{bmatrix}
あなたv1
=
P1、1 _ _P2、1 _ _P3、1 _ _P1、2 _ _P2、2 _ _P3、2 _ _P1、3 _ _P2、3 _ _P3、3 _ _P1、4 _ _P2、4 _ _P3、4 _ _
⋅
バツYZ1
深度マップを生成するとき、scatter_min 関数を使用して点群の深度値を集計します。scatter_min 関数の式は次のとおりです:
yi = min j ∈ { j ∣ Indexj = i } ( xj ) y_i= \text{min}_{j\ in\{j|index_j=i\}}(x_j)y私は=分j ∈ {
j ∣ in d e xj=私}( ×j)
その中で××xは入力テンソル、yyyは出力テンソル、インデックスインデックスin dex は集計に使用されるインデックスです。
- パラメータ:
- カメラキャリブレーションファイル:
- 画像、LIDAR、その他のデータを読み取ります。
- ライダー点群を使用してピクセルの深さを見つけます。
2.create_kitti_masks
静的オブジェクトのマスクを生成します。KITTI データセット内の oxts ファイルを読み取り、画像の各フレームを反復処理し、すべての動かないオブジェクト (建物、道路標識など) を静的オブジェクトとしてマークし、対応するマスク イメージを生成します。
-
1. KITTI データセット内の oxts ファイルを読み取り、車両の動作ステータスと位置情報を取得します。
-
2. 画像の各フレームを走査し、画像内のカテゴリ情報を読み取ります。
a.categoryi , j category_{i,j}カテゴリー_ _ _ _ _ _私、 j:第 i i フレームiのjjthjピクセルのカテゴリ情報。
-
3. すべての動いていないオブジェクト (建物、道路標識など) を静的オブジェクトとしてマークします。つまり、各ピクセルの値が True で、そのピクセルに対応するオブジェクトが存在することを示すブール マスク イメージを生成します。静的です。
a.moveri , j = { 1 、 categoryi の場合、 j は静的オブジェクト 0 、そうでない場合は mover_{i,j} = \begin{cases} 1, & \text{if } category_{i,j} \text{ は静的オブジェクトobject} \\ 0, & \text{otherwise} \end{cases}引っ越し_ _ _ _私、 j={ 1 、0、カテゴリーまたはyの場合 _ _ _私、 j 静的オブジェクトですそれ以外の場合
-
4. 生成されたマスク イメージを拡大して、マスク イメージ内の静的オブジェクト領域をより明確にします。
a.kerneli , j = { 1 、 i , j が半径拡張 0 の円内にある場合、そうでない場合 kernel_{i,j} = \begin{cases} 1, & \text{if } i,j \text{ は範囲内にあります半径の円 } 膨張 \\ 0, & \text{otherwise} \end{cases}カーネル_ _ _ _私、 j={ 1 、0、私なら 、j は半径di l a t i o nの 円内にあります それ以外の場合
b. ムーバー ' = ムーバー ⊗ カーネル ムーバー' = ムーバー \otimes カーネル引っ越し_ _ _ _』=移動_ _ _⊗カーネル_ _ _ _ -
5. 生成されたマスク イメージを KITTI データセット内の指定された場所に保存します。
a. static_mask = ムーバー' <= 0
b. sky_mask = category == SKY_CLASS
で、
- iii は画像フレームの数を表し、
- 一言もないj はピクセルインデックスを表し、上式では、
- ⊗ \時々⊗はコンボリューション演算、mover は移動体マスク画像、mover' は拡大演算後の移動体マスク画像、kernel は拡大演算のコンボリューションカーネル、dilation は拡大演算の半径を表し、
- static_mask は静的オブジェクトのマスク画像を表します。
- sky_mask は空のマスク画像を表します。
- categoryi , j category_{i,j}カテゴリー_ _ _ _ _ _私、 jii代目を代表するフレームiのjjthjピクセルのカテゴリー情報、
- SKY_CLASSは空カテゴリのカテゴリコードを表します。⊗ \時々⊗ は畳み込み演算を表し、
静的マスク:
- 0 (黒)、動的オブジェクト
- 1 (白)、静的オブジェクト
空のマスク:
- 0(黒)、その他
- 1(白)、空
このスクリプトは主に でkitti_step
与えられたデータに基づいて動的オブジェクトと静的オブジェクトを分割し、kitti_step
データセットによって直接与えられるため、実際にはここにはアルゴリズムの適用はありません。
- パラメータの読み取り:
static_02
ここでとsky_02
フォルダーが作成されます。
3.create_kitti_metadata
- パラメータ:
- センサー キャリブレーション ファイルを読み取ります。
(0) 校正パラメータの読み取り
(1) c2wを計算する
-
1. Kitti データセット内のキャリブレーションファイルを読み取ります。このファイルには、 などの複数の変換行列が含まれています
Tr_imu_velo、Tr_velo_cam、R_rect、P2和P3
。 -
2.
imu2velo、velo2cam_base、cam_base2rect
変換行列を計算します。-
imu2velo: IMU 座標系から Velodyne 座標系への変換行列。
imu2velo = [ Tr_imu_velo 0 0 1 ] \text{imu2velo} = \begin{bmatrix} \text{Tr\_imu\_velo} & 0 \\ 0 & 1 \end{bmatrix}イム2ベロ=[Tr_imu_velo001】 -
velo2cam_base: Velodyne 座標系からカメラ参照座標系への変換行列。
velo2cam_base = [ Tr_velo_cam 0 0 1 ] \text{velo2cam\_base} = \begin{bmatrix} \text{Tr\_velo\_cam} & 0 \\ 0 & 1 \end{bmatrix}velo2cam_base=[Tr_velo_cam001】 -
cam_base2rect: カメラベース座標系から直交カメラ座標系への変換行列。
cam_base2rect = [ R_rect 0 0 1 ] \text{cam\_base2rect} = \begin{bmatrix} \text{R\_rect} & 0 \\ 0 & 1 \end{bmatrix}cam_base2rect=[R_rect001】
-
-
3. 計算 :
P22imu和P32imu
2 番目のカメラと 3 番目のカメラの射影行列から IMU 座標系への変換を表します。
imu_pose: IMU ポーズ行列。
imu_pose = [ Rz ∗ Ry ∗ Rx T 0 1 ] \text{imu\_pose} = \begin{bmatrix} \text{Rz} * \text{Ry} * \text{Rx} & \text{T} \\ 0 & 1 \end{b行列}イムポーズ=[Rz∗ライ∗処方箋0T1】 -
4.
OXTS
データを読み取り、GPS 座標 (緯度、経度、高度) とオイラー角 (ロール、ピッチ、ヘディング) を取得します。GPS 座標をMercator
座標に変換し、IMU の並進ベクトルを計算します。オイラー角を使用して計算されたIMU
回転行列。IMU の並進ベクトルと回転行列に基づいて IMU の姿勢行列を計算します。oxts = [float(x) for x in line.strip().split()] if scale is None: scale = _lat_to_scale(oxts[0]) imu_pose = torch.eye(4, dtype=torch.float64) imu_pose[0, 3], imu_pose[1, 3] = _lat_lon_to_mercator(oxts[0], oxts[1], scale) imu_pose[2, 3] = oxts[2] # From https://github.com/autonomousvision/kitti360Scripts/blob/master/kitti360scripts/devkits/convertOxtsPose/python/convertOxtsToPose.py rx = oxts[3] # roll ry = oxts[4] # pitch rz = oxts[5] # heading Rx = torch.DoubleTensor([[1, 0, 0], [0, np.cos(rx), -np.sin(rx)], [0, np.sin(rx), np.cos(rx)]]) # base => nav (level oxts => rotated oxts) Ry = torch.DoubleTensor([[np.cos(ry), 0, np.sin(ry)], [0, 1, 0], [-np.sin(ry), 0, np.cos(ry)]]) # base => nav (level oxts => rotated oxts) Rz = torch.DoubleTensor([[np.cos(rz), -np.sin(rz), 0], [np.sin(rz), np.cos(rz), 0], [0, 0, 1]]) # base => nav (level oxts => rotated oxts) imu_pose[:3, :3] = torch.matmul(torch.matmul(Rz, Ry), Rx)
メルカトル座標の計算
_lat_lon_to_mercator
:mx = scale * lon * π * er / 180 my = scale * er * log(tan((90 + lat) * π / 360))
このうち、mx と my はそれぞれメルカトル座標の x 座標と y 座標を表し、lon と lat は経度と緯度、scale は経度と緯度からメルカトル座標への倍率、er は地球の平均半径を表します。
メルカトル図法は、地表上の点を 2 次元平面上にマッピングする地図投影法です。ここで示す数式は、球体地球モデルのメルカトル図法に基づいています。
まず、次のように地理座標 (経度と緯度) をラジアンに変換する必要があります。
经度弧度 = 经度 × (π / 180) ; 纬度弧度 = 纬度 × (π / 180)
次に、次の式を使用してメルカトル平面の座標を計算できます。
x = R × 经度弧度; y = R × ln[tan(π/4 + 纬度弧度/2)]
ここで、 R は地球の半径で、一般的には 6378137 メートルとみなされます。 x と y はメルカトル平面の座標です。
この投影では、極域付近で大きな歪みが生じることに注意してください。したがって、これらの領域でメルカトル図法を使用する場合は、細心の注意を払う必要があります。
-
8.c2w: 画像座標系から世界座標系への変換行列。
c2w = imu_pose ∗ P22imu または imu_pose ∗ P32imu \text{c2w} = \text{imu\_pose} * \text{P22imu} \quad \text{or} \quad \text{imu\_pose} * \text{P32imu}c2w=イムポーズ∗P22imuまたはイムポーズ∗P32imu
(2)构造image_path, c2w, image.size[0], image.size[1], image_index, Frame, Depth_map,sky_mask_path,dino_0,backward_flow_path,forward_flow_path,backward_neighbor,forward_neighbor等のデータ
(3) 画像のビーム境界を計算するget_bounds_from_depth()
Cameras クラス。nerfstudio ライブラリの実装を使用します。
戻り光線ビーム:
カメラ ビームの方向 (サイズは (N, 3)) と各方向の深さの値 (サイズは (N,)) を指定すると、ワールド座標系の点セット ポイントを計算できます (寸法は (N, 3)) です。
具体的な計算方法は以下の通りです。
points = item.c2w[:, 3].unsqueeze(0) + filtered_directions * filtered_depth * filtered_z_scale
bounds = [item.c2w[:, 3].unsqueeze(0), points]
if cur_min_bounds is not None:
bounds.append(cur_min_bounds.unsqueeze(0))
bounds.append(cur_max_bounds.unsqueeze(0))
bounds = torch.cat(bounds)
return bounds.min(dim=0)[0], bounds.max(dim=0)[0]
(4) タイムスタンプの正規化normalize_timestamp
各画像のタイムスタンプ item.time だけでなく、最小フレーム min_frame と最大フレーム max_frame もわかっています。タイムスタンプを [-1, 1] の範囲に正規化します。
具体的な計算方法は、
item . time = item . time − min_frame 0.5 × ( max _frame − min_frame ) − 1 item.time = \frac{item.time - min\_frame}{0.5 \times (最大 \_frame - 最小\_frame)} - 1それは私です。時間_ _=0.5×(マックス_フレーム_ _ _ _−分_フレーム) _ _ _それは私です。時間_ _−min_frame _ _ _ _ _−1
divisor = 0.5 * (max_frame - min_frame)
item.time = (item.time - min_frame) / divisor - 1
このうち、divisor はタイムスタンプのスケーリング係数、item.time は画像のタイムスタンプ、min_frame と max_frame はそれぞれフレーム範囲の最小値と最大値です。
(5) カメラ位置正規化scale_bounds
すべてのイメージの最小境界min_bounds
と最大境界がわかったらmax_bounds
、シーンの原点origin
とポーズのスケーリング係数を計算しますpose_scale_factor
。
具体的な計算方法は以下の通りです。
原点 = 最大境界 + 最小境界 2 原点 = \frac{最大\_境界 + 最小\_境界}{2}または私は入ります=2最大境界_ _ _ _ _ _ _+最小境界_ _ _ _ _ _ポーズ _ スケール _ ファクター = ∣ ∣ 最大境界 − 最小境界 2 ∣ ∣ ポーズ\_スケール\_ファクター = ||\frac{最大\_境界 - 最小\_境界}{2}||ポーズ_スケール_ファクトまたは_ _ _ _ _ _ _=∣∣2最大境界_ _ _ _ _ _ _−最小境界_ _ _ _ _ _∣∣
origin = (max_bounds + min_bounds) * 0.5
pose_scale_factor = ||(max_bounds - min_bounds) * 0.5||
item.c2w[:, 3] = (item.c2w[:, 3] - origin) / pose_scale_factor
このうち、pose_scale_factor はポーズのスケーリング係数、item.c2w はカメラの外部パラメータ、origin は計算の原点、min_bounds と max_bounds はそれぞれシーンの最小境界と最大境界です。
(5)write_metadata:
dataset/
├── origin
├── scene_bounds
├── pose_scale_factor
└── frames
├── frame_0
│ ├── image_index
│ ├── rgb_path
│ ├── depth_path
│ ├── feature_path
│ ├── backward_flow_path
│ ├── forward_flow_path
│ ├── backward_neighbor_index
│ ├── forward_neighbor_index
│ ├── c2w
│ ├── W
│ ├── H
│ ├── intrinsics
│ ├── time
│ ├── video_id
│ ├── is_val
│ ├── static_mask_path (optional)
│ ├── mask_path (optional)
│ └── sky_mask_path (optional)
├── frame_1
│ ├── ...
└── ...
- origin: シーンの原点座標。
- scene_bounds: シーンの最小境界と最大境界。
- pass_scale_factor: ポーズのスケーリング係数。
- フレーム: データセット内のすべてのフレーム。
- image_index: 画像のインデックス。
- rgb_path: RGB 画像へのパス。
- Depth_path: 深度画像のパス。
- feature_path: フィーチャー画像のパス。
- backward_flow_path: 逆方向オプティカル フローのパス。—> この時点では空になっているはずです
- forward_flow_path: 順方向オプティカル フローのパス。—> この時点では空になっているはずです
- backward_neighbor_index: 次の隣接フレームのインデックス。
- forward_neighbor_index: 前の隣接フレームのインデックス。
- c2w: 画像座標系から世界座標系への変換行列。
- W: 画像の幅。
- H: 画像の高さ。
- intrinsics: カメラの固有パラメータ行列。
- time: 画像がキャプチャされた時間。
- video_id: ビデオ シーケンスの ID。
- is_val: 検証フレームかどうか。
- static_mask_path (オプション): 静的マスクへのパス。
- Mask_path (オプション): マスク イメージへのパス。
- sky_mask_path (オプション): 空マスク画像へのパス。
各フレーム ディレクトリ内のファイルは、フレームの関連情報とデータを表します。一部のオプション フィールドは、存在しない場合、JSON に含まれません。
画像メタデータ
このクラスは、KITTI データセット内の画像、深度マップ、マスク、スカイ マスク、フィーチャ、オプティカル フロー、およびその他のデータを処理します。クラスには一連のロード関数があり、データのキャッシュ、読み取り、サイズ変更、その他の操作を実装できます。以下は、このコードの理解と数式の表現です。
まず、クラス コンストラクター __init__ があり、これは次のパラメーターを受け取ります。
image_path: 图像路径
c2w: 从相机坐标系到世界坐标系的转换矩阵
W, H: 图像的宽度和高度
intrinsics: 相机内参矩阵
image_index, time, video_id: 图像索引、时间戳和视频ID
depth_path: 深度图路径
mask_path, sky_mask_path: mask路径和天空mask路径
feature_path: 特征路径
backward_flow_path, forward_flow_path: 后向光流和前向光流路径
backward_neighbor_index, forward_neighbor_index: 后向和前向邻居索引
is_val: 布尔值,表示是否为验证集
pose_scale_factor: 位姿尺度因子
local_cache: 本地缓存路径
次に、次のような一連の読み込み関数があります。
load_image(): 加载图像并调整尺寸(如果需要)。
load_mask(), load_sky_mask(): 加载mask和天空mask,并调整尺寸(如果需要)。
load_features(): 加载特征并调整尺寸(如果需要)。
load_depth(): 加载深度图,将深度值转换为米,并调整尺寸(如果需要)。
load_backward_flow(), load_forward_flow(): 加载后向光流和前向光流,以及对应的有效性mask。
- 画像をロードするには、画像を W×H のサイズにリサイズします。
I' = resize(I, (W, H))
- ローディングマスクとスカイマスクの場合は、W×H: のサイズにリサイズします
M' = resize(M, (W, H))
。S' = resize(S, (W, H))
- フィーチャをロードするには、フィーチャを W×H のサイズにサイズ変更します。
F' = resize(F, (W, H))
- 深度マップをロードするには、深度値をメートルに変換し、幅×高さにサイズ変更します。
D' = resize(D, (W, H)) / pose_scale_factor
- オプティカル フローを読み込むには、オプティカル フローのサイズを W×H に変更し、X 値と Y 値を調整します。
flow_x' = flow_x * (W / orig_W) flow_y' = flow_y * (H / orig_H) flow' = resize((flow_x', flow_y'), (W, H))
_load_flow
この関数は主にオプティカル フロー データの読み込みを担当します。まず flow_path が None であるかどうかを確認し、そうである場合はオールゼロのオプティカル フローとオプティカル フロー有効性テンソルを返します。次に、データ形式とソースに従ってオプティカル フロー データを読み込みます。ここには主に 2 つの方法があります。Parquet ファイルからロードする方法と、VKITTI2 形式ファイルからロードする方法です。
-
(1) Parquet ファイルからの読み込み:
オプティカル フロー データが Parquet 形式で保存されている場合、関数は対応する Parquet ファイルを読み取り、その内容に従ってオプティカル フロー データを解析します。ここには主に 2 つの状況があります。- テーブルに
flow
名前付きの列が含まれている場合、その列はテンソルに直接変換され、メタデータで指定された形状に従って再形成されます。 - テーブルに名前付きの列が含まれていない場合は
flow
、テーブルからポイント ペアが抽出され(point1_x, point1_y)和(point2_x, point2_y)
、そのポイント ペアに基づいてオプティカル フローが計算されます。ここで、オプティカルフローの計算方法は、is_forward
Trueの場合は計算point2 - point1
、Falseの場合は計算というパラメータに基づいて決定されますpoint1 - point2
。
- テーブルに
-
(2) VKITTI2 形式のファイルからのロード:
オプティカル フロー データが VKITTI2 形式で保存されている場合、関数は OpenCV (cv2) ライブラリを使用してファイルをロードし、ファイルの内容に従ってオプティカル フロー データを解析します。具体的な手順は次のとおりです。- quantized_flow を読み取り、浮動小数点数に変換します。
- quantized_flow から無効オプティカル フロー フラグ (チャネル 0) を抽出し、有効なオプティカル フロー (チャネル 2、1) を計算します。ここで、オプティカル フローは、[-1, 1] の範囲に正規化し、画像の幅と高さを乗算することによって計算されます。
- 無効なオプティカル フロー フラグに基づいてフロー テンソルを更新します。
オプティカル フロー データがロードされて解析された後、関数は必要に応じてオプティカル フロー データのサイズを変更し、他のデータと同じサイズになるようにします。最後に、この関数はロードおよび処理されたオプティカル フロー データと有効性情報を返します。
_load_flow 関数自体には、オプティカル フローを計算する数学理論が含まれていないことに注意してください。主に、計算されたオプティカル フロー データを処理し、メモリにロードし、必要な形式変換とサイズ調整を実行します。オプティカル フローの計算方法自体には、Lucas-Kanade 法、Horn-Schunck 法などの一連の複雑な数学理論とアルゴリズムが含まれています。
4.extract_dino_features
Vision Transformer (ViT) モデルから特徴、記述子、顕著性マップを抽出します。ViTExtractor クラスには、モデルの作成、モデル解像度の変更、画像の前処理など、多くのメソッドがあります。このクラスの主な機能は、他のタスクで使用するために事前トレーニングされた ViT モデルから特徴と記述子を抽出することです。
-
1. 入力画像の場合、それを複数の小さな画像ブロックに分解できます。各画像ブロックのサイズは p × p です。ここで、p は ViT のパッチ サイズ (8 や 16 など) です。高さ H、幅 W の入力画像の場合、t = HW / p² + 1 トークンを取得できます。ここで、t はトークンの数です。
-
2. 特定のレイヤーで、ViT モデルから特徴を抽出します。特定のトークンについて、その d 次元の特徴表現を取得できます。ここで、d は ViT の埋め込み次元です。
-
3. 特定のトークンについて、ログビン化された記述子を計算できます。記述子を計算するには、まず抽出された特徴を空間次元に沿って平均プールし、次にこれらの特徴を連結します。計算プロセス中、さまざまなレベルで複数のプーリング カーネルを使用して、さまざまなスケールで情報を取得します。このプロセスは次の数式を使用して表現できます。
B をバッチ サイズ、h をヘッドの数、t をトークンの数、d を埋め込み次元、y と x はそれぞれグリッド内のトークンの行と列のインデックスを表し、階層は階層。各レベル k について、プーリング カーネル サイズ3 k ∗ 3 k 3^k * 3^kを計算します。3k∗3kの平均プーリング次に、結果としてプールされた特徴を連結して、最終的な記述子を取得します。
bin_x ∈ R^(B x (sub_desc_dim * num_bins) x (t-1))
このうち、sub_desc_dim はサブディスクリプタの次元、num_bins はビンの数、bin_x は最終的なディスクリプタ行列です。
-
4. 特定のレイヤーと入力画像について、特徴と記述子を計算できます。この情報は、画像の取得、ローカリゼーションなどの他のタスクに使用できます。
-
入力画像のサイズが
-
特徴抽出段階では、モデルから特定のレイヤーのアスペクト固有の特徴 F を、寸法 Bxhxtxd (バッチ サイズ x ヘッド数 x トークン数 x 埋め込み次元) で抽出します。
-
次に、機能 F を _log_bin メソッドに入力し、ログ ビン記述子 D を作成します。ディスクリプタ D のサイズは Bx1x(t-1)x(dxh) です。
-
コンストラクター __init__ は、ViT モデルを初期化し、評価モードに設定し、必要なモデル タイプとストライド パラメーターに基づいて適切なパラメーターを設定します。
-
create_model メソッドは、指定されたモデル タイプに従って、事前トレーニングされた ViT モデルを facebookresearch/dino ライブラリからロードします。
-
_fix_pos_enc メソッドは、位置エンコードされた補間を作成するために使用されます。
-
patch_vit_resolution メソッドは、パッチ抽出のストライドを変更することでモデル出力の解像度を変更するために使用されます。
-
前処理メソッドは、スケーリング、標準化などを含む入力画像を前処理します。
-
_get_hook、_register_hooks、および _unregister_hooks メソッドは、モデルの指定された層で特定のタイプの特徴を抽出するために使用される PyTorch のフォワード フック関数を実装するために使用されます。
-
_extract_features メソッドは、指定されたモデルを使用して入力イメージ テンソルから特定のタイプの特徴を抽出します。
-
_log_bin メソッドは、ログビン記述子を作成するために使用されます。
-
extract_descriptors メソッドは、入力画像から記述子を抽出します。
-
extract_saliency_map メソッドは、入力画像から顕著性マップを抽出します。
- パラメータのロード:
VIT モデルパラメータ:
最終的な記述子 (bin_x) のデータ形式は、次の形状の4 次元テンソルです。B x 1 x (t-1) x (d x h)
で:
- B: バッチサイズ、つまり一度に処理される画像の数
- t: トークンの数、つまり画像を分割するブロックの数 + 1
- d: ViT の埋め込み次元
- h: ヘッドの数。通常、PyTorch の規則ではチャネルの寸法 BxCxHxW に置き換えられます。
このテンソルは、バッチ内の各画像のローカル記述子を表し、異なる空間的位置に分散されます。
5.run_pca
- パラメータのロード:
- sklearn ライブラリに実装された PCA クラス:
PCA を使用してフィーチャの次元を削減します。
-
1. メタデータと特徴抽出機能の出力記述子をロードします。
-
2. 各記述子に対して次の操作を実行します。
- 機能を CPU にロードします: torch.load(buffer_from_stream('{}.pt'.format(frame['feature_path'])), map_location='cpu')
- 各記述子の形状を計算して保存します: num_patches_list.append([descriptor.shape[0], descriptor.shape[1]])
- 記述子に対して L2 ノルム正規化を実行します: descriptor /= descriptor.norm(dim=-1, keepdim=True)
- 記述子を NumPy 配列として保存します: descriptors_list.append(descriptor.view(-1, descriptor.shape[2]).numpy())
-
3. すべての記述子を NumPy 配列に連結します: descriptors = np.concatenate(descriptors_list, axis=0)
-
4. PCA を適用して次元を削減します。
- PCA 次元削減記述子を使用します: pca_descriptors = PCA(n_components=hparams.n_components, random_state=42).fit_transform(descriptors)
- 次元削減後の数式は次のとおりです。PCA ( X ) = X ⋅ V n PCA(X) = X \cdot V_{n}PC A ( X )=バツ⋅Vん、ここでXXXは元の記述子、V n V_{n}Vんは、PCA 変換行列の最初の n 個の主成分です。
-
5. PCA 記述子を画像ごとに分割します。
- 各画像の累積合計インデックスを計算します:split_idxs = np.cumsum(split_idxs)
- 累積合計インデックスに従って PCA 記述子を分割します: pca_per_image = np.split(pca_descriptors, split_idxs[:-1], axis=0)
-
6. PCA 記述子を元の形状に再形成し、結果を保存します。
- PCA 記述子を再形成して保存します: img_pca.reshape((num_patches[0], num_patches[1], hparams.n_components))
- 結果をファイルに書き込みます: pq.write_table(…)
-
7. 一時ファイルを削除します (必要な場合): fs.rm(tmp_path)