一些快递公司,曾经开始试点通过无人机或无人车递送快递;一些汽车品牌,正在研发能够自主行驶的车辆并获得了肯定的成绩;甚至一些生产级电子设备,也曾经开始配备相似 LiDAR 这样的激光定位雷达。传说中的将来生存仿佛曾经触手可及!
不过你就不好奇,这到底是怎么实现的?最重要的事,这些自主行驶的车辆,到底是如何判断周围环境呢?
这首先要从 3D 对象的跟踪说起。这是个很宏大的话题,本文将次要聚焦于如何借助 Amazon SageMaker Ground Truth 对 3D 点云数据进行标记的能力对 3D 点云数据执行数据转换,从而应用 SageMaker Ground Truth 来标记 3D 对象跟踪。对于其余性能的更多详细信息,请参阅 AWS News 博客。
基于 SageMaker Ground Truth 的 3D 对象跟踪
主动驾驶车辆(AV)厂商通常应用 LiDAR 传感器生成对车辆周边环境的 3D 成像后果。例如,他们会将 LiDAR 装置在车辆顶端,借此间断捕获周边 3D 环境的工夫点快照。LiDAR 传感器输入的是一系列 3D 点云图像帧(常见的捕获速率为每秒10帧)。为了建设起可能主动跟踪车辆周边重点对象(例如其余车辆及行人)的感知零碎,主动驾驶厂商往往首先在3D点云图像帧中手动标记对象,而后应用标记后的 3D 图像帧训练机器学习(ML)模型。
在构建感知零碎方面,目前最常见的做法是应用来自多个传感器的输出以补救繁多传感器的局限。例如,摄像机可能提供重要的上下文信息 —— 例如以后交通信号灯显示红色、黄色还是绿色。但其在光明条件下的感知能力却十分无限。在另一方面,LiDAR 传感器无奈提供特定的上下文背景(例如交通信号灯的色彩),但却能在360度范畴内实现纵深信息的收集,且无论内部光照条件如何。
SageMaker Ground Truth 可能轻松在一系列 3D 点云帧上标记对象以构建机器学习训练数据集,且反对将多达8台摄像机输出的 LiDAR 传感数据加以交融。SageMaker Ground Truth 做图像交融要求视频帧与 3D 点云帧进行事后同步。在启用传感器交融性能之后,标记人员能够配合同步视频帧查看 3D 点云帧。除了为标记工作提供更多视觉环境信息之外,传感器交融性能还会将 3D 点云中绘制的任何标签投射至视频帧,保障在某一帧内实现的标记调整将精确呈现在另一帧中。
在本文中,咱们将演示如何筹备 3D 点云数据与同步视频数据,以供 SageMaker Ground Truth 应用。咱们将从 KITTI Vision Benchmark Suite 开始,这是现有风行的主动驾驶数据集*。除了视频数据外,该数据集还蕴含由 Velodyne LiDAR 传感器生成的 3D 点云数据。具体操作步骤如下:
- 明确 SageMaker Ground Truth 3D 点云标记作业的输出数据格式与要求。
- 将 KITTI 数据集从部分坐标系转换为世界坐标系。
- 将视频数据与同步 LiDAR 数据相关联,以进行传感器交融。
- 筹备一个输出 SageMaker Ground Truth 的 Manifest 文件。
- 为 3D 点云对象检测创立一个标记作业,并逾越一系列帧进行跟踪。
- 在工作人员标记 UI 界面当中应用辅助标记工具。
要实现本轮演练,请应用 Ground Truth Labeling Jobs 下 Notebook 实例中 Amazon SageMaker Examples 选项卡下的 3D-point-cloud-input-data-processing.ipynb 这个 Notebook。咱们也能够在 GitHub 上获取此 Notebook。
3D 点云标记作业输出数据
在本节中,咱们将介绍 Ground Truth 输出数据的概念,以及对于 3D 点云标记作业的根本要求。
3D 点云帧与 3D 点云序列
所谓「点云帧」,是指某一时刻 3D 场景下所有 3D 点的汇合。每个点都应用三个坐标来形容,别离为 x、y 与 z。向点云中增加色彩及点强度变动,即可使点具备其余属性,例如强度 i 或者红色(r)、绿色(g)及蓝色(b)色调通道的值(8位)。所有地位坐标(x, y, z)皆以米为单位。在创立 Ground Truth 3D 点云标记作业时,大家能够应用 ASCII 或者二进制格局的点云数据。
而「序列」的定义,则是在 LiDAR 挪动时(例如位于车辆顶端的 LiDAR)所捕捉到的3D点云帧的工夫序列汇合。SageMaker Ground Truth 将序列文件格式定义为各帧的有序排列后果,其中每个帧都与工夫戳相关联。
在本文中,咱们将演示如何依据KITTI数据集创立SageMaker Ground Truth 序列文件,并以此为根底创立用于3D对象跟踪的标记作业。
世界坐标系
在对象跟踪中,大家能够在参考点(主动驾驶汽车)挪动时跟踪对象(例如人行道上的行人)的静止轨迹。咱们的参考点上装置有传感器以感应周边的环境,这也是目前「自主车辆」的常见设计思路。
在执行对象跟踪时,咱们须要应用世界坐标系(也称为全局参照系),这是因为自主车辆自身的确是在世界范畴内挪动。通常,SageMaker Ground Truth 要求咱们将点云数据转换为您所选定的参考坐标系。大家个别能够通过将 3D 帧中的各个点与 LiDAR 传感器的内部矩阵相乘来实现此类转换。传感器的内部矩阵是一种同构转换矩阵,用于将数据的透视图从传感器本身的坐标系转换为世界坐标系。平均变换是指对三个旋转轴(x轴、y轴与z轴)以及原点平移的序列转换,旋转矩阵则为定义三者旋转序列的3x3矩阵。
本文将向大家介绍如何应用内部矩阵将 KITTI 3D 帧从部分坐标系转换为世界坐标系。KITTI 数据集为每个 3D 点云帧提供一对应的内部矩阵。咱们能够应用来自自主车辆的 GPS 数据得出内部矩阵,并应用 NumPy 矩阵乘法函数将此矩阵与帧中的各个点相乘,将其转换为 KITTI 数据集应用的世界坐标系。
通过自定义设置,大家还能够应用 GPS/IMU 与自主车辆上 LiDAR 传感器的绝对地位与方向(纬度/经度/高度/侧倾角/俯角/仰角)计算内部变换矩阵。例如,咱们能够基于_pose = convertOxtsToPose(oxts)_从 KITTI原始数据计算车辆姿势,并将 oxts 数据转换为由4x4刚性变换矩阵指定的部分欧氏姿态。接下来,就能够应用世界坐标系中的参考帧转换矩阵将该姿势转换矩阵转换为全局参考帧。
传感器交融
LiDAR 传感器与每台摄像机都领有本人的内部矩阵,SageMaker Ground Truth 利用它们来实现传感器交融性能。要将标签从 3D 点云投射至摄像机立体图像,SageMaker Ground Truth 须要将 3D 点由 LiDAR 坐标系转换为摄像机坐标系。这一转换通常是应用 LiDAR 内部矩阵将 3D 点从 LiDAR 自有坐标转换为世界坐标系来实现的。接下来,咱们应用摄像机内部矩阵的逆(从世界到摄像机)将上一步中取得的世界坐标系3D点转换为摄像机立体图像。如果 3D 点云数据曾经转换为世界坐标系模式,则无需进行第一次转换,而且3D与2D之间的转换将仅须要应用摄像机内部矩阵。
如果在世界坐标系中存在一个旋转矩阵(由轴旋转组成)与平移矢量(或原点),而非繁多内部变换矩阵,则能够间接应用旋转与平移来计算车辆姿势。具体参见以下代码:
rotation = [[ 9.96714314e-01, -8.09890350e-02, 1.16333982e-03],[ 8.09967396e-02, 9.96661051e-01, -1.03090934e-02],[-3.24531964e-04, 1.03694477e-02, 9.99946183e-01]] origin= [1.71104606e+00 5.80000039e-01 9.43144935e-01]from scipy.spatial.transform import Rotation as R# position is the originposition = originr = R.from_matrix(np.asarray(rotation))# heading in WCS using scipyheading = r.as_quat()
如果领有一个4x4内部矩阵,且矩阵模式为[R T; 0 0 0 1],其中R为旋转矩阵,T为原点平移矢量,则意味着咱们能够从矩阵中提取旋转矩阵与平移矢量,具体如下所示:
import numpy as nptransformation= [[ 9.96714314e-01, -8.09890350e-02, 1.16333982e-03, 1.71104606e+00], [ 8.09967396e-02, 9.96661051e-01, -1.03090934e-02, 5.80000039e-01], [-3.24531964e-04, 1.03694477e-02, 9.99946183e-01, 9.43144935e-01], [ 0, 0, 0, 1]]transformation = np.array(transformation )rotation = transformation[0:3][0:3]translation= transformation[0:3][3]from scipy.spatial.transform import Rotation as R# position is the origin translationposition = translationr = R.from_matrix(np.asarray(rotation))# heading in WCS using scipyheading = r.as_quat()print(f"position:{position}nheading: {heading}")Python
在传感器交融当中,咱们能够通过原点地位(用于平移)以及四元数指向(用于批示xyz轴的旋转)以传感器姿势的模式提供内部矩阵。以下示例代码是在输出 Manifest 文件中应用的姿势 JSON 文件:
{ "position": { "y": -152.77584902657554, "x": 311.21505956090624, "z": -10.854137529636024 }, "heading": { "qy": -0.7046155108831117, "qx": 0.034278837280808494, "qz": 0.7070617895701465, "qw": -0.04904659893885366 }}
所有地位坐标(x, y, z)皆以米为单位,所有姿势朝向(qx, qy, qz, qw)均以四元数在空间方向上的朝向为指标。对于每台摄像机,别离提供自摄像机内部提取到的姿势数据。
摄像机校准、外部与失真
几何摄像机校准(也称为摄像机切除)用来标定摄像机的镜头和图像传感器参数。咱们能够应用这些参数校对镜头失真、测量对象的实在大小或确定场景中摄像机的地位。此外,如果相机图像失真,也能够提供额定的校准参数(如外部和失真)来校对图像。
相机参数包含本征矩阵参数、内部矩阵参数与失真系数,点击此处理解更多。详见以下代码:
# intrinsic paramatersfx (float) - focal length in x direction.fy (float) - focal length in y direction.cx (float) - x coordinate of principal point.cy (float) - y coordinate of principal point.# Radial distortion parametersk1 (float) - Radial distortion coefficient.k2 (float) - Radial distortion coefficient.k3 (float) - Radial distortion coefficient.k4 (float) - Radial distortion coefficient.# Tangential distortion parametersp1 (float) - Tangential distortion coefficient.p2 (float) - Tangential distortion coefficient.
摄像机的外部变换通过以下公式进行定义,其中 * 代表矩阵乘法。
|x| |f_x, 0, c_x| |X||y| = |0, f_y, c_y| * |Y||z| | 0, 0, 1 | |Z|
输出 Manifest 文件
Ground Truth 采纳输出 Manifest 文件,其中的每一行都形容了须要由正文人员(或者对某些内置工作类型进行主动标记)实现的工作单元。输出 Manifest 文件的格局由您的理论工作类型决定:
- 3D点云对象检测或者语义分段标记作业 —— 输出 Manifest 文件中的每一行,都蕴含与繁多3D点云帧及传感器交融数据相干的信息。此 Manifest 文件被称为3D点云帧输出 Manifest。
- 3D点云对象检测与标记作业跟踪 —— 输出 Manifest 文件中的每一行都蕴含指向某一序列文件的链接,该文件负责定义一系列与3D点云帧及传感器交融前怕狼;后怕虎数据。其中各序列被称为3D点云序列,而此 Manifest 被称为点云序列输出 Manifest。
在本次试验中,咱们将创立一个点云序列 Manifest 文件。大家也能够批改解决方案以创立本人的点云帧输出 Manifest。示例 Notebook 中提供了更多详细信息。
将 KITTI 数据集转换为世界坐标系
咱们能够应用 Notebook 运行本节中的各代码片段。
世界坐标系由具体数据集决定。某些数据集会应用第一帧中的LiDAR地位作为原点,数据集中所有其余3D帧皆以第一帧作为参考对象,包含车辆的行驶方向与地位也将以第一帧为原点。也有一部分数据集会选取不同于原点的设施地位作为终点。KITTI 数据集应用第一帧地位作为其世界坐标系的参考对象。
本文将展现如何绝对于第一帧中的 LiDAR 传感器原点,将 KITTI 数据集转换为全局参考帧,以便 SageMaker Ground Truth 可能理论应用。KITTI 原始数据集中蕴含各个帧的旋转矩阵与平移矢量,咱们能够应用此数据为各个帧计算内部矩阵。解决原始数据可能比拟艰难,因而倡议大家应用 pykitti Python 模块以升高 KITTI 数据集的解决门槛。
在数据集中,dataset.oxts[i].T_w_imu负责给出第i帧的LiDAR内部变换,咱们能够将其与该帧中的各点相乘,以应用NumPy矩阵乘法函数matmul: matmul(lidar_transform_matrix, points)将其转换为世界坐标系下的帧。通常,将LiDAR帧中的各点与 LiDAR 内部矩阵相乘,即可实现世界坐标系转换。其中T_w_imu 约定即代表从 IMU 到世界坐标系的转移(因而标记为 T_destinationFrame_originFrame)。
以下示例代码,阐明了如何将 KITTI 点云帧转换为世界坐标系:
import pykittiimport numpy as npbasedir = '/Users/nameofuser/kitti-data'date = '2011_09_26'drive = '0079'# The 'frames' argument is optional - default: None, which loads the whole dataset.# Calibration, timestamps, and IMU data are read automatically.# Camera and velodyne data are available via properties that create generators# when accessed, or through getter methods that provide random access.data = pykitti.raw(basedir, date, drive, frames=range(0, 50, 5))# i is frame numberi = 0# customer computes lidar extrinsicslidar_extrinsic_matrix = data.oxts[i].T_w_imu# velodyne raw point cloud in lidar scanners own coordinate systempoints = data.get_velo(i)# transform points from lidar to global frame using lidar_extrinsic_matrixdef generate_transformed_pcd_from_point_cloud(points, lidar_extrinsic_matrix): tps = [] for point in points: transformed_points = np.matmul(lidar_extrinsic_matrix, np.array([point[0], point[1], point[2], 1], dtype=np.float32).reshape(4,1)).tolist() if len(point) > 3 and point[3] is not None: tps.append([transformed_points[0][0], transformed_points[1][0], transformed_points[2][0], point[3]]) return tps# customer transforms points from lidar to global frame using lidar_extrinsic_matrixtransformed_pcl = generate_transformed_pcd_from_point_cloud(points, lidar_extrinsic_matrix)
将视频数据与 LiDAR 数据相关联,以实现传感器交融
KITTI 提供 LiDAR 内部与相机内部矩阵。咱们能够应用这些矩阵提取姿势数据,而后依据3D点云序列输出 Manifest 的需要将这部分数据转换为 JSON 格局。
对于 KITTI 数据集,能够应用 pykitti Python 模块加载 KITTI 数据。在数据集中,.oxts[i].T_w_imu 负责给出第i帧的 LiDAR 内部矩阵(lidar_extrinsic_transform)。咱们能够将其转换为平移与四元数指向模式,别离代表 JSON 格局的 LiDAR 朝向与地位。具体请参见以下代码:
from scipy.spatial.transform import Rotation as R# utility to convert extrinsic matrix to pose heading quaternion and positiondef convert_extrinsic_matrix_to_trans_quaternion_mat(lidar_extrinsic_transform): position = lidar_extrinsic_transform[0:3, 3] rot = np.linalg.inv(lidar_extrinsic_transform[0:3, 0:3]) quaternion= R.from_matrix(np.asarray(rot)).as_quat() trans_quaternions = { "translation": { "x": position[0], "y": position[1], "z": position[2] }, "rotation": { "qx": quaternion[0], "qy": quaternion[1], "qz": quaternion[2], "qw": quaternion[3] } } return trans_quaternions
同样,咱们也能够应用相机内部参数提取相机姿势数据。咱们能够通过inv(matmul(dataset.calib.T_cam0_velo, inv(dataset.oxts[i].T_w_imu)))在第i帧中计算cam0的Camera_extrinsic_transform,进而将其转换为cam0的朝向与地位。详见以下代码:
def convert_camera_inv_extrinsic_matrix_to_trans_quaternion_mat(camera_extrinsic_transform): position = camera_extrinsic_transform[0:3, 3] rot = np.linalg.inv(camera_extrinsic_transform[0:3, 0:3]) quaternion= R.from_matrix(np.asarray(rot)).as_quat() trans_quaternions = { "translation": { "x": position[0], "y": position[1], "z": position[2] }, "rotation": { "qx": quaternion[0], "qy": quaternion[1], "qz": quaternion[2], "qw": -quaternion[3] } } return trans_quaternions
相机校准:外部与失真
KITTI 数据集为每台摄像机提供一项校准参数。例如,data.calib.K_cam0 当中就蕴含以下相机外部矩阵:
fx 0 cx 0 fy cy 0 0 1
创立输出 Manifest 文件
将 KITTI 数据集中的一系列帧转换为世界坐标系,并从 LiDAR 及相机内部矩阵提取姿势信息之后,就能够创立一个蕴含传感器交融数据的3D点云序列 Manifest 文件了。咱们能够应用以下函数为序列输出 Manifest 文件主动创立序列文件:
def convert_to_gt(): # The 'frames' argument is optional - default: None, which loads the whole dataset. # Calibration, timestamps, and IMU data are read automatically. # Camera and velodyne data are available via properties that create generators # when accessed, or through getter methods that provide random access. data = pykitti.raw(basedir, date, drive, frames=range(0, 50, 5)) image_paths = [data.cam0_files, data.cam1_files, data.cam2_files, data.cam3_files] camera_extrinsic_calibrations = [data.calib.T_cam0_velo, data.calib.T_cam1_velo, data.calib.T_cam2_velo, data.calib.T_cam3_velo] camera_intrinsics = [data.calib.K_cam0, data.calib.K_cam1, data.calib.K_cam2, data.calib.K_cam3] seq_json = {} seq_json["seq-no"] = 1 seq_json["prefix"] = 's3://pdx-groundtruth-lidar-test-bucket/pdx-groundtruth-sequences/kittiseq2/frames/' seq_json["number-of-frames"] = len(data) seq_json["frames"] = [] default_position = {"x": 0, "y": 0, "z": 0} default_heading = {"qx": 0, "qy": 0, "qz": 0, "qw": 1} for i in range(len(data)): # customer computes lidar extrinsics lidar_extrinsic_matrix = data.oxts[i].T_w_imu # velodyne raw point cloud in lidar scanners own coordinate system points = data.get_velo(i) # customer transforms points from lidar to global frame using lidar_extrinsic_matrix transformed_pcl = generate_transformed_pcd_from_point_cloud(points, lidar_extrinsic_matrix) # Customer computes rotation quaternion and translation from LiDAR Extrinsic trans_quaternions = convert_extrinsic_matrix_to_trans_quaternion_mat(lidar_extrinsic_matrix) # Customer uses trans_quaternions to populates GT ego veicle pose ego_vehicle_pose = {} ego_vehicle_pose['heading'] = trans_quaternions['rotation'] ego_vehicle_pose['position'] = trans_quaternions['translation'] # open file to write the transformed pcl with open(output_base+"/"+str(i)+'.txt', "w") as out: writer = csv.writer(out, delimiter=' ', quotechar='"', quoting=csv.QUOTE_MINIMAL) for point in transformed_pcl: writer.writerow((point[0], point[1], point[2], point[3])) frame = {} frame["frame-no"] = i frame["frame"] = str(i)+'.txt' frame["unix-timestamp"] = data.timestamps[i].replace(tzinfo=timezone.utc).timestamp() frame["ego-vehicle-pose"] = ego_vehicle_pose images = [] image_dir_path = os.path.join(output_base, 'images') if not os.path.exists(image_dir_path): os.makedirs(image_dir_path) for j in range(len(image_paths)): # copy image image_path = image_paths[j][i] image_suffix_path = 'images/frame_'+str(i)+'_camera_'+str(j)+'.jpg' copyfile(image_path, os.path.join(output_base, image_suffix_path)) # If customer has the camera extrinsics then they use them to compute the camera transform camera_transform= np.linalg.inv(np.matmul(camera_extrinsic_calibrations[j], np.linalg.inv(data.oxts[i].T_w_imu))) # Customer computes rotation quaternion and translation from camera inverse Extrinsic cam_trans_quaternions = convert_camera_inv_extrinsic_matrix_to_trans_quaternion_mat(camera_transform) image_json = {} image_json["image-path"] = image_suffix_path image_json["unix-timestamp"] = frame["unix-timestamp"] image_json['heading'] = cam_trans_quaternions['rotation'] image_json['position'] = cam_trans_quaternions['translation'] image_json['fx'] = camera_intrinsics[j][0][0] image_json['fy'] = camera_intrinsics[j][1][1] image_json['cx'] = camera_intrinsics[j][0][2] image_json['cy'] = camera_intrinsics[j][1][2] image_json['k1'] = 0 image_json['k2'] = 0 image_json['k3'] = 0 image_json['k4'] = 0 image_json['p1'] = 0 image_json['p2'] = 0 image_json['skew'] = 0 images.append(image_json) frame["images"]=images seq_json["frames"].append(frame) with open(output_base+'/mykitti-seq2.json', 'w') as outfile: json.dump(seq_json, outfile)
创立标记作业
输出 Manifest 文件创建实现后,即能够用 Notebook 创立一个标记作业。在创立标记作业时(参照 Notebook 内的相干阐明),请应用外部工作团队,以保障可能在工作人员门户中随时查看各工作人员工作并与工作人员标记 UI 进行交互。
标记作业的预处理工夫,是工作开始时显示在工作人员门户中的所需工夫。具体时长取决于输出数据的大小、点云的分辨率以及用于传感器交融的数据(如果存在)。因而,在应用 Notebook 时,标记作业可能须要几分钟工夫才会显示在工作人员门户当中。在工作呈现后,将其选定并抉择 Start Working。
对于工作人员 UI 的更多详细信息,请参阅3D 点云对象跟踪。以下为工作人员标记UI中提供的局部辅助标记工具:
- 标签主动填充:当工作人员向帧中增加框体时,此性能会主动将框体请回至序列中的所有帧。当工作人员手动调整其余帧中同一对象的正文时,主动填充标签也将进行主动调整。
- 标签插值:工作人员在两个帧中标记繁多对象后,Ground Truth 会应用这些正文在两帧之间的挪动中对该对象进行插值。
- 捕获:工作人员能够在对象周边增加一个框体,并应用键盘快捷键或菜单选项让 Ground Truth 主动拟合工具紧紧贴合对象的边界。
- 适应高空:在工作人员向3D场景中增加框体后,工作人员能够主动使该框体与高空相适应。例如,工作人员能够应用此性能将框体贴合至场景中的路线或人行道。
- 多视图标记:工作人员将3D框体增加至3D场景之后,侧面板上会显示侧面与侧面两个透视图,以帮忙工作人员在对象周边严密调整该框体。工作人员能够在3D点云或侧面板上调整标签,相应调整也会实时显示在其余视图当中。
- 传感器交融:如果提供传感器交融数据,则工作人员能够在3D场景与2D图像当中调整正文,且该正文会被实时投射至其余视图当中。
以下视频演示了插值的过程。工作人员只须要将两个长方形框体增加至序列中的第一帧与最初一帧。这些手动增加的框体将在左下方的导航栏中以红色段示意,两头的所有标签(在导航栏中显示为蓝色)均由 Ground Truth 负责插入。
下图所示,为多视图标记与传感器交融。将长方形框体增加至3D点云可视化图后,咱们能够在三个侧视图与摄像机图像中对其进行调整。
除了标签之外,大家还能够增加标签属性以收集各个对象上的其余元数据。在以下视频中,能够看到带有「Car」标签的长方形框体。该标签还蕴含与之关联的两项标签属性:Occlusion 与 Color。工作人员能够为各个标签属性抉择对应的值。
Ground Truth 每15分钟主动保留一次正文。在作业实现之后,抉择 Submit。当工作实现后,输入数据将被保留于在 HumanTaskConfig 中指定的 Amazon Simple Storage Service (Amazon S3)存储桶当中。
要理解对于输入数据格式的更多详细信息,请参阅 Ground Truth 输入数据页面中的3D点云对象跟踪局部。
总结
在本次试验中,咱们理解了 Ground Truth 3D点云标记作业对于输出数据的要求与选项,同时尝试创立了对象跟踪标记作业。对于咱们可能在3D点云标记作业中实现的其余工作类型,请参阅3D点云工作类型。另外,咱们还要感激 KITTI 团队为咱们提供这套贵重的数据集,用于演示如何筹备3D点云数据并将其引入 SageMaker Ground Truth。
*KITTI 数据集领有本人的应用许可。请保障您对数据集的应用形式完全符合其中提出的条款与要求。