Думаю, что многие наслышаны о такой интересной штуке, как Kinect. Сегодня я напишу простейшие рекомендации к использованию сего девайса при помощи OpenNI и Point Cloud Libray на C++.
Какие возможности это даст?
С помощью Kinect+OpenNI+PCL можно получать и обрабатывать облако точек с информацией о их цвете. Самое простое решение показано на видео.Что нужно установить?
Итак, для использования необходимо установить необходимые пакеты. Для пользователей Windows можно скачать с официального сайта PCL готовый установщик со всем необходимым под MS Visual Studio. Любителям MinGW и других компиляторов придётся собирать пакет вручную, хотя с CMake это не сложно.
Пользователи linux также могут скачать готовый пакет из репозитория своего дистрибутива. Для поддержки Kinect ставим пакеты openni-dev и ps-engine (в разных дистрах названия могут чуть-чуть отличаться).
Тем, кто решился собирать из исходников советую обратиться к этому руководству .
Установка драйверов
- Windows
Итак, для установки используйте драйвера из папки в которую установлен PrimeSense(в папке /SensorKinect/Driver/). После установки в диспетчере устройств должно появиться три устройства (*Audio, *Motion, *Camera).
- Linux
Если вы поставили всё верно, то введя lsusb будете наблюдать примерно это:
Bus 002 Device 008: ID 045e:02ad Microsoft Corp. Xbox NUI Audio
Bus 002 Device 007: ID 045e:02b0 Microsoft Corp. Xbox NUI Motor
Bus 002 Device 009: ID 045e:02ae Microsoft Corp. Xbox NUI Camera
Если этого не происходит, то надо проверить пакеты openni-dev и ps-engine и проверить снова.
Hello world from Kinect
На сайте с документацией по PCL есть пример работы с Kinect, но PCL не всегда стабильна и иногда сбоит. Например, те туториалы, что описаны на официальном сайте с документацией, у меня не завелись(тестил под PCL1.6 Windows, PCL1.7 Kubuntu 12.10).Для начала возьмём пример отсюда.
Иерархия директорий такая
Project_root_dir
| + CMakeLists.txt
|--src
| + main.cpp
|--build
// -----------------------------------------------------
// Original code can be found here // http://robotica.unileon.es/mediawiki/ // index.php/ Kinect_tutorial_1:_First_steps // Based on Geoffrey's Biggs, taken from the PCL tutorial in // http://pointclouds.org/documentation/tutorials/pcl_visualizer.php // Simple Kinect viewer that also allows to write the current scene to a .pcd // when pressing SPACE. #include <iostream> #include <pcl/io/openni_grabber.h> #include <pcl/io/pcd_io.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/console/parse.h> using namespace std; using namespace pcl; // В проекте используются умные указатели BOOST // Например, PointCloud<PointXYZRGBA>::Ptr означает, // что мы создаём умный указатель на объект // класса PointCloud<PointXYZRGBA> // т.е. boost::shared_ptr< PointCloud<PointXYZRGBA> > PointCloud<PointXYZRGBA>::Ptr cloudptr(new PointCloud<PointXYZRGBA>); // Облако с типом точек содержащих координаты и цвет PointCloud<PointXYZ>::Ptr fallbackCloud(new PointCloud<PointXYZ>); // Ооблако с типом точек содержащих только координаты boost::shared_ptr<visualization::CloudViewer> viewer; // Объект позволяющий просматривать облако Grabber* kinectGrabber; // Осуществляет захват данных с Kinect unsigned int filesSaved = 0; // For the numbering of the clouds saved to disk. bool saveCloud(false), noColour(false); // Program control. void printUsage(const char* programName) { cout << "Usage: " << programName << " [options]" << endl << endl << "Options:\n" << endl << "\t<none> start capturing from a Kinect device.\n" << "\t-v NAME visualize the given .pcd file.\n" << "\t-h shows this help.\n"; } // Callback-функция //(вызывается когда появляются новые данных с устройства) void grabberCallback(const PointCloud<PointXYZRGBA>::ConstPtr& cloud) { if (! viewer->wasStopped()) viewer->showCloud(cloud); if (saveCloud) { stringstream stream; stream << "inputCloud" << filesSaved << ".pcd"; string filename = stream.str(); if (io::savePCDFile(filename, *cloud, true) == 0) { filesSaved++; cout << "Saved " << filename << "." << endl; } else PCL_ERROR("Problem saving %s.\n", filename.c_str()); saveCloud = false; } } // For detecting when SPACE is pressed. void keyboardEventOccurred(const visualization::KeyboardEvent& event, void* nothing) { if (event.getKeySym() == "space" && event.keyDown()) saveCloud = true; } // Creates, initializes and returns a new viewer. boost::shared_ptr<visualization::CloudViewer> createViewer() { boost::shared_ptr<visualization::CloudViewer> v (new visualization::CloudViewer("3D Viewer")); v->registerKeyboardCallback(keyboardEventOccurred); return(v); } int main(int argc, char** argv) { if (console::find_argument(argc, argv, "-h") >= 0) { printUsage(argv[0]); return 0; } bool justVisualize(false); string filename; if (console::find_argument(argc, argv, "-v") >= 0) { if (argc != 3) { printUsage(argv[0]); return 0; } filename = argv[2]; justVisualize = true; } else if (argc != 1) { printUsage(argv[0]); return 0; } // First mode, open and show a cloud from disk. if (justVisualize) { // Try with colour information... try { io::loadPCDFile<PointXYZRGBA>(filename.c_str(), *cloudptr); } catch (PCLException e1) { try { // ...and if it fails, fall back to just depth. io::loadPCDFile<PointXYZ>(filename.c_str(), *fallbackCloud); } catch (PCLException e2) { return -1; } noColour = true; } cout << "Loaded " << filename << "." << endl; if (noColour) cout << "This file has no RGBA colour information present." << endl; } // Second mode, start fetching and displaying frames from Kinect. else { kinectGrabber = new OpenNIGrabber(); if (kinectGrabber == 0) return false; boost::function<void (const PointCloud<PointXYZRGBA>::ConstPtr&)> f = boost::bind(&grabberCallback, _1); kinectGrabber->registerCallback(f); } viewer = createViewer(); if (justVisualize) { if (noColour) viewer->showCloud(fallbackCloud); else viewer->showCloud(cloudptr); } else kinectGrabber->start(); // Main loop. while (! viewer->wasStopped()) boost::this_thread::sleep(boost::posix_time::seconds(1)); if (! justVisualize) kinectGrabber->stop(); }
// -----------------------------------------------------
Будем собирать проект CMake, для этого создадим в папке проекьта файл CMakeLists.txt, содержащий следующее:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR) project(kinect_PCL_viewer) find_package(PCL 1.6 REQUIRED) include_directories(${PCL_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) set(PCL_BUILD_TYPE Release) file(GLOB kinectpclviewer_SRC "src/*.h" "src/*.cpp" ) add_executable(kinectPCLviewer ${kinectpclviewer_SRC}) target_link_libraries (kinectPCLviewer ${PCL_LIBRARIES})
Собираем
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make
После сборки можете запустить программу. По нажатию пробела она будет сохранять полученное облако в файл в формате PCD
После можно будет посмотреть его с помощью этой же программы так:
./kinectPCLviewer -v inputCloud0.pcd
Каверзные вопросы
Итак, предположим, что Вы научились получать данные с Kinect и хотитеих обработать PCL, но все ваши попытки это сделать приводят к ошибкам сегментации и т.д. Самые распространённые по опыту причины:
- Nan в данных. Специфика Kinect такова, что при невозможности получить данные о глубине(положении), координаты точки выставляются в Nan(not a number). Многие алгоритмы PCL при встрече с такими точками работают некорректно или падают. Поэтому перед тем, как начать работу с облаком, удалите из него точки со значениями Nan.
- Ошибка при работе с указателями. Пусть это не отностися напрямую к Kinect, но следите за инициализацией, операциями с указателями. Да, Boost и так облегчает это, но не избавляет от невниматльности.
Таким образом, мы научились настраивать всё необходимое и рассмотрели простой пример использования Kinect с помощью PCL на C++.
Комментариев нет:
Отправить комментарий