preprocesamiento del conjunto de datos de Kitti

0 Prefacio

注: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

Insertar descripción de la imagen aquí

传感器:
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

calibre 0.1

El archivo calib son los datos de corrección de cámaras, radares, navegación inercial y otros sensores.

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 y 3 representan respectivamente las matrices de proyección de la cámara en escala de grises izquierda, la cámara en escala de grises derecha, la cámara en color izquierda y la cámara en color derecha.

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 y 0 y 0 y 1 \end{bmatrix}PAG=k [ r ,t ]= Fx000Fy0CxCy1000 r11r21r310r12r22r320r13r23r330txtytz1

Se utiliza para convertir puntos de coordenadas mundiales en coordenadas de cámara y coordenadas de cámara en coordenadas de píxeles.

  • R_rect: es la matriz de corrección de la cámara No. 0, con un tamaño de 3x3, el propósito es lograr imágenes coplanares de las cuatro cámaras y asegurar que los centros ópticos de las cuatro cámaras estén en el mismo plano xoy. Después de cambiar la matriz de parámetros externos, es necesario multiplicarla por R0_rect para obtener las coordenadas en el sistema de coordenadas de la cámara.

  • Tr_velo_cam: la matriz de parámetros externos entre el lidar y la cámara, que se utiliza para convertir puntos en el sistema de coordenadas lidar en puntos en el sistema de coordenadas de la cámara.

T velo 2 cam = [ R velocamtvelocam 0 T 1 ] T_{velo2cam} = \begin{bmatrix} R^{cam}_{velo} ​​& t^{cam}_{velo} ​​\\ \mathbf{0}^T & 1 \end{bmatriz}tv e l o 2 c am=[Rvelo _ _ _estoy _0ttvelo _ _ _estoy _1]

  • En resumen, las coordenadas de la nube de puntos en el sistema de coordenadas de la cámara son iguales a: 内参矩阵 * 外参矩阵 * R0校准矩阵 * 点云坐标, es decir:P * R0_rect *Tr_velo_to_cam * x

  • Tr_imu_velo: la matriz de parámetros externos entre IMU y lidar, que se utiliza para convertir los valores de medición de IMU en valores en el sistema de coordenadas 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) Para cada cuadro, almacenamos 30 valores GPS/IMU diferentes en un archivo de texto: coordenadas geográficas, incluida la altitud, orientación global, velocidad, aceleración, tasa angular, precisión e información satelital. Tanto la aceleración como la velocidad angular se especifican utilizando dos sistemas de coordenadas, uno adjunto al cuerpo (x, y, z) y otro asignado al plano tangente (f, l, u) a la superficie de la Tierra en ese lugar. Problema con una breve interrupción de la comunicación (~1 segundo) del dispositivo OXTS, para lo cual interpolamos linealmente todos los valores y configuramos las últimas 3 entradas en "-1" para indicar la información que falta. Se proporcionan más detalles en dataformat.txt. Las utilidades de conversión se proporcionan en el kit de desarrollo.

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.velodino

Velodyne Para mejorar la eficiencia, los escaneos de Velodyne se almacenan como archivos binarios de punto flotante. Los datos de la nube de puntos se almacenan en formato de archivo binario de punto flotante. Cada fila contiene 8 datos. Cada dato está representado por un número hexadecimal de cuatro dígitos (número de punto flotante ).Cada dato separado por espacios. Los datos de una nube de puntos consta de cuatro datos de punto flotante, que representan respectivamente x, y, z, r (intensidad o valor de reflexión) de la nube de puntos. Aunque el número de puntos por escaneo no es constante, el tamaño promedio de cada archivo/cuadro es de aproximadamente 1,9 MB, lo que corresponde a 120.000 puntos 3D y valores de reflectancia. Tenga en cuenta que el escáner láser Velodyne gira continuamente alrededor de su eje vertical (en sentido antihorario), lo que se puede tener en cuenta mediante un archivo de marca de tiempo.

Cada archivo Velodyne contiene las coordenadas y los valores de intensidad de reflexión de todos los puntos recopilados durante un ciclo completo de escaneo LIDAR. El formato de almacenamiento de datos es el siguiente:

float x;        // 点的x坐标,单位为米
float y;        // 点的y坐标,单位为米
float z;        // 点的z坐标,单位为米
float intensity;// 反射强度值,无单位

Cada punto ocupa 16 bytes, que representan las coordenadas x, y, z y el valor de intensidad de reflexión del punto respectivamente. Los tipos de datos están todos en forma de números de punto flotante, donde:

  • x, y y z representan respectivamente las coordenadas del punto en el espacio tridimensional y la unidad es metros. Su tipo de datos es flotante, generalmente expresado en formato de punto flotante IEEE 754.
  • La intensidad representa el valor de intensidad de reflexión del punto, que es un número entero sin signo. Su rango de valores suele ser de 0 a 255. Cuanto mayor sea el valor, más fuerte será la intensidad de la reflexión. El valor de intensidad de reflexión no es una cantidad física real medida por Velodyne lidar, sino una cantidad que refleja aproximadamente la relación de reflexión entre el rayo láser y el objetivo.

0.4.imagen_2/3

Los archivos de imagen se almacenan en formato PNG de 8 bits.

0.5.kitti-step/panópticos

STEP significa The Segmenting and Tracking Every Pixel benchmark, que incluye 21 secuencias de entrenamiento y 29 secuencias de prueba. Este conjunto de datos se basa en los puntos de referencia de Evaluación de seguimiento de KITTI y Segmentación y seguimiento de objetos múltiples (MOTS).

Este conjunto de datos agrega etiquetas densas de segmentación de píxeles a cada píxel. En este punto de referencia, cada píxel tiene una etiqueta semántica y todos los píxeles que pertenecen a las categorías de objetos más destacados (automóviles y peatones) tienen una identificación de seguimiento única.

Insertar descripción de la imagen aquí

0.6.etiqueta

Para cada objeto dinámico dentro del campo de visión de la cámara de referencia, proporcionamos anotaciones en forma de trayectorias de cuadros delimitadores 3D, expresadas en coordenadas Velodyne. Definimos el tipo "coche", "furgoneta", "camión", "peatón", "persona (sentada)", "ciclista", "tranvía" y "varios" (por ejemplo, remolque, Segway). Los tracklets se almacenan en date_drive_tracklets.xml. A cada objeto se le asigna una clase y su tamaño 3D (alto, ancho, largo). Para cada cuadro, proporcionamos la traslación y rotación 3D del objeto como se muestra en la figura. Tenga en cuenta que solo proporcionamos el ángulo de guiñada, mientras que se supone que los otros dos ángulos son cercanos a cero. Además, se especifican los niveles de oclusión y truncamiento.

Insertar descripción de la imagen aquí
Coordenadas del objeto.Coordenadas del objeto. Esta figura ilustra el sistema de coordenadas de un cuadro delimitador 3D anotado en relación con el sistema de coordenadas del escáner láser 3D Velodyne. En la dirección z, el sistema de coordenadas del objeto se encuentra en la base del objeto (punto de contacto con la superficie de apoyo).

Tome un archivo de etiqueta como ejemplo:

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  

Tomemos como ejemplo el coche:

etiqueta.txt Auto 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
ilustrar categoría truncado (grado de truncamiento), 0,00 significa que no hay truncamiento ocluido (tasa de oclusión), 0 significa sin oclusión ángulo de observación alfa ([-pi, pi]) Coordenadas del cuadro delimitador 2D (BB) de la esquina superior izquierda Coordenadas 2D BB de la esquina inferior derecha BB 3D alto, ancho, largo Posición 3D BB en coordenadas de cámara. Confianza, utilizada para dibujar curvas p/r, cuanto más alta, mejor

DontCareEl área que no es interesante se divide y los objetos del área no se etiquetarán.

​每一行代表一个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)
整数0123分别表示被遮挡的程度。

-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_profundidad_maps

Utilice imágenes y datos LIDAR para obtener información de profundidad. Proyecte la nube de puntos Velodyne del conjunto de datos KITTI sobre la imagen y genere un mapa de profundidad. El proceso de implementación específico es el siguiente:

  • R_rect1. Lea la matriz P, la matriz y Tr_velo_camla matriz en el conjunto de datos KITTI , donde Pla matriz es la matriz de proyección de la cámara, R_rectla matriz es la matriz de corrección de distorsión de la cámara y Tr_velo_camla matriz es la matriz de transformación de Velodyne. nube de puntos al sistema de coordenadas de la cámara.

  • 2. Leer el archivo oxts en el conjunto de datos KITTI, que contiene posición GPS, velocidad, actitud y otra información en cada momento.

  • 3. Para cada cuadro de imagen, lea la nube de puntos Velodyne correspondiente y convierta la nube de puntos Velodyne del sistema de coordenadas Velodyne al sistema de coordenadas de la cámara.

  • 4. Proyecte la nube de puntos sobre la imagen de acuerdo con la matriz P y genere un mapa de profundidad según los resultados de la proyección.

  • 5. Escriba el mapa de profundidad en el archivo Parquet.


Fórmula matricial de transformación de la nube de puntos Velodyne al sistema de coordenadas de la cámara:
T velo 2 cam = [ R 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{bmatriz}tv e l o 2 c am=[Rrec t01 × 303 × 11][Rv e l o 2 c am01 × 3tv e l o 2 c am1]

Fórmula para proyectar una nube de puntos sobre una imagen:
[ 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} tuv1 = PAG1 , 1PAG2 , 1PAG3 , 1PAG1 , 2PAG2 , 2PAG3 , 2PAG1 , 3PAG2 , 3PAG3 , 3PAG1 , 4PAG2 , 4PAG3 , 4 XYz1

Al generar el mapa de profundidad, la función scatter_min se utiliza para agregar los valores de profundidad de la nube de puntos. La fórmula de la función scatter_min es la siguiente:
yi = min j ∈ { j ∣ indexj = i } ( xj ) y_i= \text{min}_{j\ in\{j|index_j=i\}}(x_j)yyo=mín.j { j en re mi xj= yo }( xj)

Entre ellos, xx.x es el tensor de entrada,yyy es el tensor de salida,índice índiceen dex es el índice utilizado para la agregación .


  • parámetro:

Insertar descripción de la imagen aquí

  • Archivo de calibración de la cámara:

Insertar descripción de la imagen aquí

  • Leer imagen, lidar y otros datos:

Insertar descripción de la imagen aquí

  • Utilice la nube de puntos del líder para encontrar la profundidad de los píxeles.

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

2.create_kitti_masks

Generar máscaras para objetos estáticos. Lea el archivo oxts en el conjunto de datos KITTI, luego recorra cada cuadro de la imagen, marque todos los objetos que no se mueven (como edificios, señales de tráfico, etc.) como objetos estáticos y genere la imagen de máscara correspondiente.

  • 1. Lea el archivo oxts en el conjunto de datos KITTI para obtener el estado de movimiento del vehículo y la información de ubicación.

  • 2. Recorra cada cuadro de la imagen y lea la información de la categoría en la imagen.

    a. categoríai, j categoría_{i,j}categoría _ _ _ _ _ _yo , j: No iijjthen el cuadro iInformación de categoría de j píxeles.

  • 3. Marque todos los objetos que no se mueven (como edificios, señales de tráfico, etc.) como objetos estáticos, es decir, genere una imagen de máscara booleana, en la que el valor de cada píxel es Verdadero, lo que indica que el objeto correspondiente al píxel es estático.

    a. moveri , j = { 1 , si categoríai , j es un objeto estático 0 , de lo contrario mover_{i,j} = \begin{cases} 1, & \text{if } categoría_{i,j} \text{ es estático objeto} \\ 0, & \text{de lo contrario} \end{casos}motor _ _ _ _yo , j={ 1 ,0 ,si  categoría g o y _ _ _yo , j es un objeto estáticode lo contrario

  • 4. Expanda la imagen de máscara generada para hacer más obvias las áreas de objetos estáticos en la imagen de máscara.

    a. kerneli , j = { 1 , si i , j están dentro de un círculo de dilatación de radio 0 , de lo contrario kernel_{i,j} = \begin{cases} 1, & \text{if } i,j \text{ están dentro de un círculo de radio } dilatación \\ 0, & \text{de lo contrario} \end{cases}kernel _ _ _ _yo , j={ 1 ,0 ,si  yo ,j  están dentro de un círculo de radio  d i l a t i o nde lo contrario
    b. motor ′ = motor ⊗ núcleo motor' = motor \otimes núcleomotor _ _ _ _=motor _ _ _kernel _ _ _ _

  • 5. Guarde la imagen de máscara generada en la ubicación especificada en el conjunto de datos KITTI.
    a. static_mask = mover' <= 0
    b. sky_mask = categoría == SKY_CLASS

en,

  • iii representa el número de fotogramas de la imagen,
  • ni una palabraj representa el índice de píxeles. En la fórmula anterior,
  • ⊗ \oveces representa la operación de convolución, mover representa la imagen de máscara del objeto en movimiento, mover' representa la imagen de máscara del objeto en movimiento después de la operación de expansión, kernel representa el núcleo de convolución de la operación de expansión, dilatación representa el radio de la operación de expansión,
  • static_mask representa una imagen de máscara de objeto estático,
  • sky_mask representa la imagen de la máscara del cielo,
  • categoríai, j categoría_{i,j}categoría _ _ _ _ _ _yo , jRepresenta la iithjjthen el cuadro iInformación de categoría de j píxeles,
  • SKY_CLASS representa el código de categoría de la categoría de cielo. ⊗ \oveces representa la operación de convolución,

máscara_estática:
Insertar descripción de la imagen aquí

  • 0 (negro), objeto dinámico
  • 1 (blanco), objeto estático

máscara_cielo:

Insertar descripción de la imagen aquí

  • 0 (negro), otro
  • 1 (blanco), cielo

Este script divide principalmente kitti_stepobjetos dinámicos y objetos estáticos según los datos proporcionados en y kitti_stepestá directamente proporcionado por el conjunto de datos, por lo que, de hecho, no hay ninguna aplicación algorítmica aquí.

  • Lectura de parámetros:

Insertar descripción de la imagen aquí

  • Aquí se crean las carpetas static_02y :sky_02

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

3.create_kitti_metadatos

  • parámetro:

Insertar descripción de la imagen aquí

  • Leer el archivo de calibración del sensor:

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

(0) Leer parámetros de calibración


(1) Calcular c2w

  • 1. Lea el archivo de calibración en el conjunto de datos de Kitti, que contiene múltiples matrices de transformación, como Tr_imu_velo、Tr_velo_cam、R_rect、P2和P3.

  • 2. Calcule imu2velo、velo2cam_base、cam_base2rectla matriz de transformación:

    • imu2velo: Matriz de transformación del sistema de coordenadas IMU al sistema de coordenadas Velodyne.
      imu2velo = [ Tr_imu_velo 0 0 1 ] \text{imu2velo} ​​​​= \begin{bmatrix} \text{Tr\_imu\_velo} ​​​​& 0 \\ 0 & 1 \end{bmatrix}imu2velo=[Tr_imu_velo001]

    • velo2cam_base: matriz de transformación del sistema de coordenadas Velodyne al sistema de coordenadas de referencia de la cámara.
      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: matriz de transformación del sistema de coordenadas base de la cámara al sistema de coordenadas de la cámara rectangular.
      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. Cálculo P22imu和P32imu, que representa la transformación de la matriz de proyección de la segunda cámara y la tercera cámara al sistema de coordenadas IMU.
    imu_pose: matriz de pose IMU.
    imu_pose = [ Rz ∗ Ry ∗ Rx T 0 1 ] \text{imu\_pose} = \begin{bmatrix} \text{Rz} * \text{Ry} * \text{Rx} & \text{T} \\ 0 y 1 \end{bmatriz}imu_pose=[rzryreceta0t1]

  • 4. Lea OXTSlos datos y obtenga coordenadas GPS (latitud, longitud, altitud) y ángulos de Euler (Roll, Pitch, Heading). Convierta coordenadas GPS en Mercatorcoordenadas y calcule el vector de traducción de la IMU. IMUMatriz de rotación calculada utilizando ángulos de Euler . Calcule la matriz de pose de la IMU en función del vector de traducción y la matriz de rotación de la 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)
    

    Cálculo de coordenadas de Mercator _lat_lon_to_mercator:

    mx = scale * lon * π * er / 180
    my = scale * er * log(tan((90 + lat) * π / 360))
    

    Entre ellos, mx y my representan las coordenadas xey de las coordenadas de Mercator respectivamente, lon y lat son la longitud y latitud, la escala es el factor de escala de longitud y latitud a las coordenadas de Mercator y er es el radio promedio de la Tierra.

    La proyección de Mercator es un método de proyección cartográfica que mapea puntos de la superficie terrestre en un plano bidimensional. La fórmula matemática dada aquí se basa en la proyección de Mercator del modelo esférico de la Tierra.
    Primero, necesita convertir las coordenadas geográficas (longitud y latitud) a radianes, de la siguiente manera: A
    经度弧度 = 经度 × (π / 180) ; 纬度弧度 = 纬度 × (π / 180)
    continuación, puede usar la siguiente fórmula para calcular las coordenadas del plano de Mercator:
    x = R × 经度弧度; y = R × ln[tan(π/4 + 纬度弧度/2)]
    donde R es el radio de la Tierra, generalmente tomado como 6378137 metros, x e y son las coordenadas del plano de Mercator.
    Cabe señalar que esta proyección produce una mayor distorsión cerca de las regiones polares. Por lo tanto, se debe extremar la precaución al utilizar la proyección Mercator en estas áreas.

    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí

  • 8.c2w: Matriz de transformación del sistema de coordenadas de la imagen al sistema de coordenadas mundial.
    c2w = imu_pose ∗ P22imu o imu_pose ∗ P32imu \text{c2w} = \text{imu\_pose} * \text{P22imu} \quad \text{o} \quad \text{imu\_pose} * \text{P32imu}c2w=imu_poseP22imuoimu_poseP32imu


(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等数据

Insertar descripción de la imagen aquí

(3) Calcule el límite del haz de la imagen.get_bounds_from_depth()

Insertar descripción de la imagen aquí
Clase de cámaras, usando la implementación en la biblioteca nerfstudio:

Insertar descripción de la imagen aquí

Haz de rayo de retorno:
Insertar descripción de la imagen aquí
dadas las direcciones del haz de la cámara (el tamaño es (N, 3)) y el valor de profundidad en cada dirección (el tamaño es (N,)), se pueden calcular los puntos establecidos en el sistema de coordenadas mundial (Dimensiones son (norte, 3)).
El método de cálculo específico es:

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]

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí

(4) Normalización de marca de tiempo normalize_timestamp

Se conoce la marca de tiempo item.time de cada imagen, así como el fotograma mínimo min_frame y el fotograma máximo max_frame. Normalice las marcas de tiempo al rango [-1, 1].
El método de cálculo específico es:
item.time = item.time − min _ frame 0.5 × ( max_frame − min_frame ) − 1 item.time = \frac{item.time - min\_frame}{0.5 \times ( máx \_frame - min\_frame)} - 1yo t e m . tiempo _ _=0,5×( ma x _ f r a m emin_f r am e ) _ _yo t e m . tiempo _ _min_f r am e _ _1

divisor = 0.5 * (max_frame - min_frame)
item.time = (item.time - min_frame) / divisor - 1

Entre ellos, divisor es el factor de escala de la marca de tiempo, item.time es la marca de tiempo de la imagen, min_frame y max_frame son los valores mínimo y máximo del rango de cuadros respectivamente.

(5) Normalización de la posición de la cámara scale_bounds

Conociendo los min_boundslímites mínimos y máximos de todas las imágenes max_bounds, calcule el origen de la escena originy el factor de escala de pose pose_scale_factor.
El método de cálculo específico es:

origen = max _ límites + min _ límites 2 origen = \frac{max\_bounds + min\_bounds}{2}o entro _ _=2max_b o u n d s _ _ _+min_b o u n d s _ _pose _ escala _ factor = ∣ ∣ max _ límites − min _ límites 2 ∣ ∣ pose\_scale\_factor = ||\frac{max\_bounds - min\_bounds}{2}||p ose _ escala _ f a c t o _ _ _=∣∣2max_b o u n d s _ _ _min_b o u n d s _ _∣∣

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

Entre ellos, pose_scale_factor es el factor de escala de pose, item.c2w es el parámetro externo de la cámara, origin es el origen del cálculo, min_bounds y max_bounds son los límites mínimo y máximo de la escena, respectivamente.

Insertar descripción de la imagen aquí

(5) escribir_metadatos:

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
    │   ├── ...
    └── ...
  • origen: Las coordenadas de origen de la escena.
  • scene_bounds: los límites mínimo y máximo de la escena.
  • pose_scale_factor: factor de escala de pose.
  • fotogramas: todos los fotogramas del conjunto de datos.
    • image_index: índice de imágenes.
    • rgb_path: la ruta a la imagen RGB.
    • Depth_path: la ruta de la imagen de profundidad.
    • feature_path: la ruta de la imagen característica.
    • backback_flow_path: el camino del flujo óptico hacia atrás. —> Debería estar vacío en este momento
    • forward_flow_path: la ruta del flujo óptico directo. —> Debería estar vacío en este momento
    • backward_neighbor_index: índice del siguiente cuadro vecino.
    • forward_neighbor_index: índice del marco vecino anterior.
    • c2w: Matriz de transformación del sistema de coordenadas de la imagen al sistema de coordenadas mundial.
    • W: El ancho de la imagen.
    • H: La altura de la imagen.
    • intrínsecos: matriz de parámetros intrínsecos de la cámara.
    • hora: hora en la que se capturó la imagen.
    • video_id: ID de la secuencia de vídeo.
    • is_val: si es un marco de verificación.
    • static_mask_path (opcional): la ruta a la máscara estática.
    • mask_path (opcional): ruta a la imagen de la máscara.
    • sky_mask_path (opcional): ruta a la imagen de la máscara del cielo.

Los archivos en cada directorio de cuadros representan la información y los datos relevantes del cuadro. Algunos campos opcionales no se incluirán en el JSON si no están presentes.
Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí


ImagenMetadatos

Esta clase procesa imágenes, mapas de profundidad, máscaras, máscaras de cielo, características, flujo óptico y otros datos en el conjunto de datos KITTI. Hay una serie de funciones de carga en la clase, que pueden implementar operaciones de almacenamiento en caché, lectura, cambio de tamaño y otras operaciones. Lo siguiente es una comprensión de este código y una representación de la fórmula matemática.

Primero, tenemos el constructor de clase __init__, que recibe los siguientes parámetros:

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: 本地缓存路径

A continuación se muestran una serie de funciones de carga, que incluyen:

load_image(): 加载图像并调整尺寸(如果需要)。
load_mask(), load_sky_mask(): 加载mask和天空mask,并调整尺寸(如果需要)。
load_features(): 加载特征并调整尺寸(如果需要)。
load_depth(): 加载深度图,将深度值转换为米,并调整尺寸(如果需要)。
load_backward_flow(), load_forward_flow(): 加载后向光流和前向光流,以及对应的有效性mask。
  • Para cargar imágenes, cambie el tamaño de la imagen al tamaño W×H:I' = resize(I, (W, H))
  • Para la máscara de carga y la máscara del cielo, cambie su tamaño al tamaño W×H: M' = resize(M, (W, H)),S' = resize(S, (W, H))
  • Para cargar funciones, cambie el tamaño de las funciones al tamaño W×H:F' = resize(F, (W, H))
  • Para cargar un mapa de profundidad, convierta el valor de profundidad a metros y cambie el tamaño a W×H:D' = resize(D, (W, H)) / pose_scale_factor
  • Para cargar el flujo óptico, cambie el tamaño del flujo óptico al tamaño W×H y ajuste sus valores X e Y:
    flow_x' = flow_x * (W / orig_W)
    flow_y' = flow_y * (H / orig_H)
    flow' = resize((flow_x', flow_y'), (W, H))
    

_load_flowLa función es principalmente responsable de cargar datos de flujo óptico. Primero verifique si flow_path es Ninguno; de ser así, devuelva los tensores de flujo óptico y de validez del flujo óptico completamente cero. A continuación, cargue los datos del flujo óptico según el formato y la fuente de los datos. Aquí hay dos formas principales: cargar desde archivos Parquet y cargar desde archivos en formato VKITTI2.

  • (1) Carga desde un archivo Parquet:
    si los datos de flujo óptico se almacenan en formato Parquet, la función leerá el archivo Parquet correspondiente y analizará los datos de flujo óptico según su contenido. Aquí hay dos situaciones principales:

    • Si la tabla contiene flowuna columna denominada, se convierte directamente en un tensor y se le reforma según la forma dada en los metadatos.
    • Si la tabla no contiene flowuna columna denominada, los pares de puntos se extraen de la tabla (point1_x, point1_y)和(point2_x, point2_y)y el flujo óptico se calcula en función de los pares de puntos. Aquí, el método de cálculo del flujo óptico se is_forwarddetermina en función de parámetros: si es Verdadero, se calcula point2 - point1; si es Falso, se calcula point1 - point2.
  • (2) Carga desde archivos en formato VKITTI2:
    si los datos de flujo óptico se almacenan en formato VKITTI2, la función utilizará la biblioteca OpenCV (cv2) para cargar el archivo y analizar los datos de flujo óptico de acuerdo con el contenido del archivo. Los pasos específicos son los siguientes:

    • Lea quantized_flow y conviértalo a un número de punto flotante.
    • Extraiga el indicador de flujo óptico no válido (canal 0) de quantized_flow y calcule el flujo óptico efectivo (canales 2 y 1). Aquí, el flujo óptico se calcula normalizándolo al rango [-1, 1] y multiplicándolo por el ancho y alto de la imagen.
    • Actualice el tensor de flujo según el indicador de flujo óptico no válido.

Una vez cargados y analizados los datos de flujo óptico, la función cambiará el tamaño de los datos de flujo óptico según sea necesario para garantizar que tengan las mismas dimensiones que los demás datos. Finalmente, la función devuelve los datos de flujo óptico cargados y procesados ​​y la información de validez.

Cabe señalar que la función _load_flow en sí no implica la teoría matemática para calcular el flujo óptico. Procesa principalmente los datos de flujo óptico calculados, los carga en la memoria y realiza la conversión de formato y el ajuste de tamaño necesarios. El método de cálculo del flujo óptico en sí incluye una serie de teorías y algoritmos matemáticos complejos, como el método de Lucas-Kanade, el método de Horn-Schunck, etc.

4.extract_dino_features

Extraiga características, descriptores y mapas de prominencia de los modelos Vision Transformer (ViT). La clase ViTExtractor tiene muchos métodos, como crear modelos, modificar la resolución del modelo, preprocesar imágenes, etc. La función principal de esta clase es extraer características y descriptores de modelos ViT previamente entrenados para usarlos en otras tareas.

  • 1. Para una imagen de entrada, podemos descomponerla en varios bloques de imagen pequeños, y el tamaño de cada bloque de imagen es p × p, donde p es el tamaño del parche de ViT, como 8 o 16. Para una imagen de entrada con alto H y ancho W, podemos obtener t = HW / p² + 1 tokens, donde t es el número de tokens.

  • 2. En una capa determinada, extraemos características del modelo ViT. Para un token determinado, podemos obtener su representación de características d-dimensional, donde d es la dimensión de incrustación de ViT.

  • 3. Para un token determinado, podemos calcular su descriptor log-binned. Para calcular los descriptores, primero agrupamos en promedio las características extraídas a lo largo de la dimensión espacial y luego concatenamos estas características. Durante el proceso de cálculo, utilizamos múltiples núcleos de agrupación en diferentes niveles para capturar información en diferentes escalas. Podemos expresar este proceso usando la siguiente fórmula matemática:

    Sea B el tamaño del lote, h el número de cabezas, t el número de tokens, d la dimensión de incrustación, y y x representan el índice de fila y columna del token en la cuadrícula respectivamente, y la jerarquía es el número de jerarquías. Para cada nivel k, calculamos un tamaño de núcleo de agrupación de 3 k ∗ 3 k 3^k * 3^k3k3Agrupación promedio de k . Luego concatenamos las características agrupadas resultantes para obtener el descriptor final.

    bin_x ∈ R^(B x (sub_desc_dim * num_bins) x (t-1))

    Entre ellos, sub_desc_dim es la dimensión del subdescriptor, num_bins es el número de contenedores y bin_x es la matriz del descriptor final.

  • 4. Para una capa y una imagen de entrada determinadas, podemos calcular características y descriptores. Esta información se puede utilizar para otras tareas como recuperación de imágenes, localización, etc.


  • Supongamos que las dimensiones de la imagen de entrada

  • En la etapa de extracción de características, extraemos características específicas de aspecto F de una capa específica del modelo, con dimensiones Bxhxtxd (tamaño de lote x número de cabezas x número de tokens x dimensión de incrustación).

  • A continuación, introducimos la característica F en el método _log_bin, creando un descriptor de contenedor de registro D. El tamaño del descriptor D es Bx1x(t-1)x(dxh).

  • El constructor __init__ inicializa un modelo ViT, lo configura en modo de evaluación y establece los parámetros apropiados según el tipo de modelo requerido y los parámetros de zancada.

  • El método create_model carga el modelo ViT previamente entrenado desde la biblioteca facebookresearch/dino según el tipo de modelo dado.

  • El método _fix_pos_enc se utiliza para crear interpolaciones codificadas en posición.

  • El método patch_vit_solving se utiliza para cambiar la resolución de la salida del modelo cambiando el ritmo de extracción del parche.

  • El método de preprocesamiento preprocesa la imagen de entrada, incluido el escalado, la estandarización, etc.

  • Los métodos _get_hook, _register_hooks y _unregister_hooks se utilizan para implementar la función de enlace directo de PyTorch, que se utiliza para extraer tipos específicos de características en capas específicas del modelo.

  • El método _extract_features extrae tipos específicos de características del tensor de la imagen de entrada utilizando el modelo dado.

  • El método _log_bin se utiliza para crear un descriptor agrupado en registros.

  • El método extract_descriptors extrae descriptores de la imagen de entrada.

  • El método extract_saliency_map extrae un mapa de prominencia de la imagen de entrada.


  • Carga de parámetros:

Insertar descripción de la imagen aquí

Parámetros del modelo VIT:

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

El formato de datos del descriptor final (bin_x) es un tensor de cuatro dimensiones con la siguiente forma:B x 1 x (t-1) x (d x h)

en:

  • B: tamaño del lote, es decir, la cantidad de imágenes procesadas a la vez
  • t: Número de tokens, es decir, el número de bloques en los que se divide la imagen + 1
  • d: dimensión de incrustación en el ViT
  • h: número de cabezales, generalmente reemplazado por la dimensión del canal BxCxHxW en la convención de PyTorch

Este tensor representa los descriptores locales de cada imagen del lote, que se distribuyen en diferentes ubicaciones espaciales.

5.run_pca

  • Carga de parámetros:

Insertar descripción de la imagen aquí

  • Clase PCA, implementada en la biblioteca sklearn:

Insertar descripción de la imagen aquí

Utilice PCA para reducir la dimensionalidad de las funciones:

  • 1. Cargue metadatos y el descriptor de salida del extractor de funciones.

  • 2. Realice las siguientes operaciones en cada descriptor:

    • Cargue funciones en la CPU: torch.load(buffer_from_stream('{}.pt'.format(frame['feature_path'])), map_location='cpu')
    • Calcule y almacene la forma de cada descriptor: num_patches_list.append([descriptor.shape[0], descriptor.shape[1]])
    • Realice la normalización de la norma L2 en el descriptor: descriptor /= descriptor.norm(dim=-1, keepdim=True)
    • Almacene descriptores como matrices NumPy: descriptors_list.append(descriptor.view(-1, descriptor.shape[2]).numpy())
  • 3. Concatene todos los descriptores en una matriz NumPy: descriptores = np.concatenate(descriptors_list, axis=0)

  • 4. Aplicar PCA para reducir la dimensionalidad:

    • Utilice descriptores de reducción de dimensionalidad de PCA: pca_descriptors = PCA(n_components=hparams.n_components, random_state=42).fit_transform(descriptors)
    • La expresión matemática después de la reducción de dimensionalidad es: PCA ( X ) = X ⋅ V n PCA(X) = X \cdot V_{n}PC A ( X )=XVnorte, donde XXX es el descriptor original,V n V_{n}Vnorteson los primeros n componentes principales de la matriz de transformación PCA.
  • 5. Divida los descriptores de PCA por imagen:

    • Calcule el índice de suma acumulativa de cada imagen: split_idxs = np.cumsum(split_idxs)
    • Divida los descriptores de PCA según el índice de suma acumulativa: pca_per_image = np.split(pca_descriptors, split_idxs[:-1], axis=0)
  • 6. Cambie la forma del descriptor PCA a su forma original y almacene el resultado:

    • Cambie la forma y almacene el descriptor PCA: img_pca.reshape((num_patches[0], num_patches[1], hparams.n_components))
    • Escriba los resultados en un archivo: pq.write_table(…)
  • 7. Elimine archivos temporales (si es necesario): fs.rm(tmp_path)

Supongo que te gusta

Origin blog.csdn.net/fb_941219/article/details/130365116
Recomendado
Clasificación