414 lines
25 KiB
Markdown
414 lines
25 KiB
Markdown
---
|
||
title: Генерация датасетов
|
||
---
|
||
|
||
Одной из подзадач управления робототехнической системой является задача обнаружения и классификации объектов в сцене, реализуемая с помощью камеры (машинного зрения). Одним из методов решения данной задачи является использование нейросетевой модели, полученной в ходе обучения на предварительно подготовленных наборах данных. Разработанный модуль генерации наборов данных (датасетов) позволяет автоматизировать процесс их подготовки. Полигональные модели экспортируются из CAD-системы - в результате получается mesh-файл формата `obj`. В ходе генерации формируется сцена для симуляции окружения робота (файл сцены в формате blend). В модуле используется пакет создания синтетических изображений BlenderProc, с помощью которого подготавливается набора данных для обучения нейросети.
|
||
|
||
## Обнаружению объектов в формате COCO
|
||
|
||
В качестве выходного форма# Модуль восприятия окружения роботом rbs_perception
|
||
|
||
## Навык обнаружения объектов (Object Detection). Описание API.
|
||
|
||
Вначале попытаемся описать полную последовательность действий по подготовке и использованию навыка обнаружения объектов. Задача обнаружения объектов сенсорами робота (в частности, RGB камерой в нашем случае) ставится в случае, например, когда необходимо в заданном окружении (сцене) определить наличие или отсутствие необходимых деталей для сборки изделия. Такие детали представлены в информационной среде в виде ассетов, хранимых в базе данных с заданными характеристиками. Поэтому входным параметром навыка обнаружения объектов является список ассетов, экземпляры которых в текущей задаче необходимо обнаруживать. Результатом использования навыка в информационной системе будет являться получение данных о заданном ассете на конкретном изображении, полученном с помощью RGB камеры.
|
||
|
||
Начальным этапом навыка является создание датасета, состоящего из синтетических изображений, полученных с использованием пакета [BlenderProc](https://github.com/DLR-RM/BlenderProc). Этот датасет представляет из себя набор файлов изображений и файлов меток к ним, а также файл аннотации, описывающий весь датасет в целом. Он имеет определённую структуру папок и будет использован для обучения нейросетевой модели обнаружения объектов на реальных изображениях в работе (runtime-режим). После создания такой датасет должен быть помещён в базу данных, как единый объект, с заданными характеристиками. В дальнейшем датасет может быть пополнен другими изображениями (например, фото из реального окружения робота), позволяющими произвести дообучение нейросети и улучшить качество работы навыка.
|
||
|
||
На втором этапе происходит обучение нейросетевой модели [YOLOv8](https://github.com/ultralytics/ultralytics). На выходе получаем файл весов модели, который также помещается в базу данных, с указанием версии этого файла и параметров обучения.
|
||
|
||
Теперь мы имеем всё необходимое для использования навыка обнаружения объектов (Object Detection) в реальном сценарии при управлении роботом в режиме runtime.
|
||
|
||
Рассмотрим наиболее общий вариант использования этого навыка в среде ROS2.
|
||
|
||
Первым шагом будет являться первоначальный запуск lifecycle-узла ROS2, отвечающего за работу навыка. Чтобы начать процесс обнаружения конкретной детали на изображении нужно выполнить стартовые действия по шаблону в дереве поведения, задав необходимые параметры процесса (топики получения изображения и выдачи результатов обнаружения, режим работы и другие). После решения поставленной задачи обнаружения конкретного объекта выполняются действия по шаблону приостановки работы навыка. Данные шаблоны деревьев поведения выполняются с помощью исполнителя [BehaviorTree](https://github.com/BehaviorTree/BehaviorTree.ROS2). Затем можно начать обнаружение другого объекта, вновь выполнив стартовый шаблон действий и подготовив новые параметры процесса.
|
||
|
||
Теперь перейдём к полному описанию данного API.
|
||
|
||
### Создание датасета
|
||
|
||
Для создания датасета используется модуль на Python для BlenderProc. Внешними параметрами для модуля являются:
|
||
- файл, описывающий параметры рандомизиции, а также объекты сцены с подготовленными мешами (файл *.json)
|
||
- выходной каталог.
|
||
|
||
Формируется сцена для случайного размещения в ней объектов из описания. Затем производится рендеринг полученной сцены с рандомизацией параметров освещения, текстур и размещением камеры. Имена объектов должны совпадать с именами ассетов в нашей базе данных.
|
||
В результате будет получен датасет в формате [BOP](../technologies/cv-perception-methods#соревнование-bop-benchmark-of-pose-estimation)
|
||
|
||
Пример запуска модуля генерации датасета:
|
||
```bash
|
||
blenderproc run renderBOPdataset2.py --form description.json --path /home/user/path/to/dataset
|
||
```
|
||
Пример файла description.json:
|
||
```json
|
||
{"output":{
|
||
"datasetObjects":{
|
||
"details":[
|
||
{"name":"star",
|
||
"inertia":{
|
||
"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1
|
||
},
|
||
"mass":"0",
|
||
"visual":"/assets/libs/objects/star.dae",
|
||
"collision":"/assets/libs/objects/star.stl",
|
||
"type":"env",
|
||
"material_path":"",
|
||
"part_path":"/libs/objects/star.stl",
|
||
"fbx":"/home/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/assets/libs/objects/star.fbx",
|
||
"solidType":"active",
|
||
"isSelect":true
|
||
}
|
||
]
|
||
},
|
||
"typedataset":"ObjectDetection",
|
||
"models_randomization":{
|
||
"loc_range_low":[-1,-1,0],"loc_range_high":[1,1,2]
|
||
},
|
||
"scene":{
|
||
"objects":[
|
||
{"name":"floor","collision_shape":"BOX","loc_xyz":[0,0,0],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}},
|
||
{"name":"star","collision_shape":"BOX","loc_xyz":[0,0,0.2],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}
|
||
],
|
||
"lights":[
|
||
{"id":1,"type":"SUN","loc_xyz":[5,5,5],"rot_euler":[-0.06,0.61,-0.19],"color_range_low":[0.5,0.5,0.5],"color_range_high":[1,1,1],"energy_range":[2,9]}
|
||
]
|
||
},
|
||
"camera_position":{
|
||
"center_shell":[0,0,0],
|
||
"radius_range":[0.3,0.65],
|
||
"elevation_range":[10,90]
|
||
},
|
||
"generation":{
|
||
"n_cam_pose":3,
|
||
"n_sample_on_pose":3,
|
||
"n_series":222,
|
||
"image_format":"JPEG",
|
||
"image_size_wh":[640,480]
|
||
}
|
||
}
|
||
```
|
||
|
||
В результате работы модуля в папке '/home/user/path/to/dataset' будет создана файловая структура с датасетом.
|
||
|
||
### Обучение модели Yolov8.
|
||
|
||
Для обучения модели используется модуль на Python. Внешним параметром для модуля является:
|
||
- каталог с датасетом, сгенерированный на первом этапе.
|
||
|
||
Пример запуска модуля обучения:
|
||
```bash
|
||
python train_Yolo.py --path /home/user/path/to/dataset --epoch 11 --outpath /home/user/path/to/weights
|
||
```
|
||
- path: путь к каталогу с датасетом
|
||
- epoch 11: количество эпох обучения (пока рекомендуем 30-50)
|
||
В результате работы создается файл весов нейросети с лучшими характеристиками обнаружения best.pt
|
||
|
||
### Использование навыка в ROS2 для обнаружения объекта на изображении (runtime).
|
||
|
||
1. Подготовить папку с файлами BT v.4
|
||
* Папка /path/to/bt/
|
||
* bt.xml
|
||
```xml
|
||
<root BTCPP_format="4">
|
||
<BehaviorTree ID="Main">
|
||
<Sequence>
|
||
<Action ID="RbsAction" do="ObjectDetection" command="odConfigure" sid="a"></Action>
|
||
</Sequence>
|
||
</BehaviorTree>
|
||
</root>
|
||
```
|
||
* skills.json
|
||
```json
|
||
{"skills": [
|
||
{
|
||
"sid": "a",
|
||
"SkillPackage": {
|
||
"name": "Robossembler", "version": "1", "format": "1.0"
|
||
},
|
||
"Module": {
|
||
"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"
|
||
},
|
||
"BTAction": [
|
||
{
|
||
"name": "odConfigure",
|
||
"type": "run",
|
||
"param": [
|
||
{
|
||
"type": "weights",
|
||
"dependency": {"object_name": "board", "weights_file": "/home/shalenikol/0_rbs/w_od_board.pt"}
|
||
},
|
||
{
|
||
"type": "topic",
|
||
"dependency": {
|
||
"type": "topic",
|
||
"topicType": "sensor_msgs/msg/Image",
|
||
"sid": "7b832b17-3030-4758-aab5-96a5046797f7",
|
||
"topicOut": "/robot_camera/image"
|
||
},
|
||
"isFilled": true
|
||
}
|
||
],
|
||
"result": [],
|
||
"typeAction": "ACTION"
|
||
}
|
||
],
|
||
"topicsOut": [
|
||
{
|
||
"name": "lc_yolo/object_detection",
|
||
"type": "rbs_skill_interfaces/msg/BoundBox"
|
||
}
|
||
],
|
||
"Launch": {
|
||
"executable": "od_yolo_lc.py",
|
||
"package": "rbss_objectdetection"
|
||
}
|
||
}
|
||
]}
|
||
```
|
||
|
||
2. Запуск интерфейсной ноды с сервером навыка, реализующего алгоритм обнаружения объектов.
|
||
|
||
```bash
|
||
ros2 launch rbs_bt_executor interface.launch.py bt_path:=/path/to/bt
|
||
```
|
||
|
||
3. Запуск процесса обнаружения заданного объекта через дерево поведения.
|
||
Выполняется командой:
|
||
```bash
|
||
ros2 launch rbs_bt_executor rbs_executor.launch.py bt_path:=/path/to/bt
|
||
```
|
||
После этого узел начинает публиковать в выходной топик информацию об обнаружении объекта на каждом полученном с камеры изображении.
|
||
|
||
4. Прекращение процесса обнаружения объекта.
|
||
|
||
Для завершения навыка нужно выполнить дерево поведения:
|
||
```xml
|
||
<root BTCPP_format="4">
|
||
<BehaviorTree ID="Main">
|
||
<Sequence>
|
||
<Action ID="RbsAction" do="ObjectDetection" command="odStop" sid="b"></Action>
|
||
</Sequence>
|
||
</BehaviorTree>
|
||
</root>
|
||
```
|
||
Файл skills.json
|
||
```json
|
||
{"skills": [
|
||
{
|
||
"sid": "b",
|
||
"SkillPackage": { "name": "Robossembler", "version": "1", "format": "1.0" },
|
||
"Module": {"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"},
|
||
"BTAction": [
|
||
{
|
||
"name": "odStop",
|
||
"type": "stop",
|
||
"param": [],
|
||
"result": [],
|
||
"typeAction": "ACTION"
|
||
}
|
||
],
|
||
"topicsOut": [
|
||
{
|
||
"name": "lc_yolo/object_detection",
|
||
"type": "rbs_skill_interfaces/msg/BoundBox"
|
||
}
|
||
],
|
||
"Launch": {
|
||
"executable": "od_yolo_lc.py",
|
||
"package": "rbss_objectdetection"
|
||
}
|
||
}
|
||
]}
|
||
```
|
||
Команда запуска этого дерева та же, что и в пункте 3.
|
||
После выполнения этих действий lifecycle-узел навыка перейдёт в начальное состояние и можно, повторив пункт 1-3, вновь запустить процесс обнаружения уже с другим объектом.
|
||
ного модуля являются: модель объекта в формате `obj`, файл описания сцены в формате `blend` и параметры генерации. Интерфейс реализован через параметры командной строки (Command Line Interface — CLI):
|
||
- `scene` (путь к файлу описания сцены в формате blend);
|
||
- `obj_path`: путь к каталогу с файлами описания детектируемых объектов в формате `obj`;
|
||
- `output_dir`: выходной каталог;
|
||
- `vhacd_path`: каталог, в котором должен быть установлен или уже установлен vhacd;
|
||
- `-imgs`: количество серий рендеринга (по 15 изображений в каждой серии) на выходе
|
||
|
||
Пример вызова:
|
||
```bash
|
||
blenderproc run objs2Yolov4dataset.py [scene] [obj_path] [output_dir] [vhacd_path] [–imgs 1]
|
||
```
|
||
|
||
Пример полученных синтетических изображений из набора:
|
||
|
||

|
||
|
||
### Производительность
|
||
|
||
Процесс создания набора изображений для одной детали в количестве 3000 шт. занимает около 10 часов машинного времени (1 CPU Ryzen 3700X + 1 GPU Nvidia RTX 2060 Super), поэтому для снижения ресурсоёмкости работы алгоритма применяется оригинальный метод - на вход программы подаются вместе со сценой также набор 3D-моделей заданных объектов для их совместного включения в изображения, что соответствует реальным условиям работы, где необходимо обнаруживать и распознавать сразу множество различных объектов, представляющих детали сборки или оснастку. Помимо этого, данный подход позволяет сократить размер общего дискового пространства, занимаемого файлами с весами нейросетевых моделей всех деталей, что также полезно для прикладных применений.
|
||
|
||
## Обнаружение объектов в формате BOP Challenge
|
||
|
||
Внешними параметрами для модуля являются:
|
||
1. Файл, описывающий параметры рандомизиции, а также объекты сцены с подготовленными мешами (файл *.json)
|
||
2. Выходной каталог.
|
||
|
||
Формируется сцена для случайного размещения в ней объектов из описания. Затем производится рендеринг полученной сцены с рандомизацией параметров освещения, текстур и размещением камеры. Имена объектов должны совпадать с именами ассетов в нашей базе данных.
|
||
|
||
Пример запуска модуля генерации датасета:
|
||
```bash
|
||
blenderproc run renderBOPdataset2.py --form description.json --path /home/user/path/to/dataset
|
||
```
|
||
|
||
Пример файла description.json:
|
||
```json
|
||
{"output":{
|
||
"datasetObjects":{
|
||
"details":[
|
||
{"name":"star",
|
||
"inertia":{
|
||
"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1
|
||
},
|
||
"mass":"0",
|
||
"visual":"/assets/libs/objects/star.dae",
|
||
"collision":"/assets/libs/objects/star.stl",
|
||
"type":"env",
|
||
"material_path":"",
|
||
"part_path":"/libs/objects/star.stl",
|
||
"fbx":"/home/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/assets/libs/objects/star.fbx",
|
||
"solidType":"active",
|
||
"isSelect":true
|
||
}
|
||
]
|
||
},
|
||
"typedataset":"ObjectDetection",
|
||
"models_randomization":{
|
||
"loc_range_low":[-1,-1,0],"loc_range_high":[1,1,2]
|
||
},
|
||
"scene":{
|
||
"objects":[
|
||
{"name":"floor","collision_shape":"BOX","loc_xyz":[0,0,0],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}},
|
||
{"name":"star","collision_shape":"BOX","loc_xyz":[0,0,0.2],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}
|
||
],
|
||
"lights":[
|
||
{"id":1,"type":"SUN","loc_xyz":[5,5,5],"rot_euler":[-0.06,0.61,-0.19],"color_range_low":[0.5,0.5,0.5],"color_range_high":[1,1,1],"energy_range":[2,9]}
|
||
]
|
||
},
|
||
"camera_position":{
|
||
"center_shell":[0,0,0],
|
||
"radius_range":[0.3,0.65],
|
||
"elevation_range":[10,90]
|
||
},
|
||
"generation":{
|
||
"n_cam_pose":3,
|
||
"n_sample_on_pose":3,
|
||
"n_series":222,
|
||
"image_format":"JPEG",
|
||
"image_size_wh":[640,480]
|
||
}
|
||
}
|
||
```
|
||
|
||
В результате работы модуля в папке '/home/user/path/to/dataset' будет создана файловая структура с датасетом.
|
||
|
||
## Оценка 6D положения объекта (Pose Estimation)
|
||
|
||
### Создание датасета
|
||
|
||
Этот этап точно такой же, как и в случае с Object Detection. Так как синтетический датасет формата [BOP](https://github.com/thodan/bop_toolkit/blob/master/docs/bop_datasets_format.md) содержит в аннотации истинные позиции заданных объектов в сцене (ground true pose), поэтому его можно использовать также и при обучения модели [DOPE](https://github.com/NVlabs/Deep_Object_Pose) для оценки 6D положения объекта.
|
||
|
||
|
||
### Обучение модели [DOPE](https://github.com/NVlabs/Deep_Object_Pose/tree/master/train)
|
||
|
||
Для обучения модели используется скрипт на Python. Аргументом для скрипта является:
|
||
- каталог с датасетом, сгенерированный на первом этапе.
|
||
В ходе работы скрипта исходный датасет предварительно конвертируется в формат, который используется непосредственно при обучении модели DOPE.
|
||
|
||
Пример запуска модуля обучения:
|
||
```bash
|
||
python train_Dope.py --path /home/user/path/to/dataset --epoch 44 --outpath /home/user/path/to/weights --name weightsX
|
||
```
|
||
- path: путь к каталогу с датасетом
|
||
- epoch: количество эпох обучения
|
||
- name: наименование файла весов модели на выходе
|
||
- outpath: выходной каталог
|
||
В результате работы создается файл весов модели с лучшими характеристиками обнаружения weightsX.pth
|
||
|
||
### Использование навыка в ROS2 для оценки 6D-положения объекта на изображении (runtime)
|
||
|
||
Этот процесс аналогичен такому же при обнаружении объекта (YoloV8), здесь приведу лишь дерево (bt.xml) и файл описания скилов в дереве (skills.json).
|
||
* Папка /path/to/bt/
|
||
* bt.xml
|
||
```xml
|
||
<root BTCPP_format="4">
|
||
<BehaviorTree ID="Main">
|
||
<Sequence>
|
||
<Action ID="RbsAction" do="PoseEstimation" command="peConfigure" sid="a"></Action>
|
||
</Sequence>
|
||
</BehaviorTree>
|
||
</root>
|
||
```
|
||
* skills.json
|
||
```json
|
||
{"skills": [
|
||
{
|
||
"sid": "a",
|
||
"SkillPackage": {"name": "Robossembler","version": "1.0","format": "1"},
|
||
"Module": {"node_name": "lc_dope","name": "PoseEstimation","description": "Pose Estimation skill with DOPE"},
|
||
"BTAction": [
|
||
{
|
||
"name": "peConfigure",
|
||
"type": "run",
|
||
"param": [
|
||
{
|
||
"type": "weights",
|
||
"dependency": { "object_name": "knight", "weights_file": "/home/shalenikol/0_rbs/w_knight.pth", "dimensions": [0.03, 0.026, 0.065] }
|
||
},
|
||
{
|
||
"type": "topic",
|
||
"dependency": {
|
||
"type": "topic",
|
||
"topicType": "sensor_msgs/msg/Image",
|
||
"topicOut": "/rgbd_camera/image"
|
||
},
|
||
"isFilled": true
|
||
},
|
||
{
|
||
"type": "topic",
|
||
"dependency": {
|
||
"type": "topic",
|
||
"topicType": "sensor_msgs/msg/CameraInfo",
|
||
"topicOut": "/rgbd_camera/camera_info"
|
||
},
|
||
"isFilled": true
|
||
}
|
||
],
|
||
"result": [],
|
||
"typeAction": "ACTION"
|
||
}
|
||
],
|
||
"topicsOut": [
|
||
{
|
||
"name": "lc_dope/pose_estimation",
|
||
"type": "geometry_msgs/msg/Pose"
|
||
}
|
||
],
|
||
"Launch": {
|
||
"executable": "pe_dope_lc.py",
|
||
"package": "rbss_poseestimation"
|
||
},
|
||
"Settings": {
|
||
"output": {
|
||
"params": [
|
||
{
|
||
"name": "publishDelay",
|
||
"value": "0.5"
|
||
},
|
||
{
|
||
"name": "tf2_send_pose",
|
||
"value": "1"
|
||
},
|
||
{
|
||
"name": "mesh_scale",
|
||
"value": "0.001"
|
||
}
|
||
]
|
||
},
|
||
"type": "formBuilder"
|
||
}
|
||
}
|
||
]}
|
||
```
|