Home Utilizando Kinect v2 no Linux através da OpenCV
Post
Cancel

Utilizando Kinect v2 no Linux através da OpenCV

O que é o Kinect?

O Kinect é um sensor de movimentos desenvolvido para o Xbox 360 e Xbox One pela Microsoft em conjunto com a empresa Prime Sense. O Dispositivo possúi microfones, cameras RGB, projetores infravermelhos e um sensor CMOS monocromático. Utilizando os projectos e o sensor CMOS é possível estimar mapas de profundidade o que permite recriar a profundidade da cena.

O dispositivo foi criado com o intuito permitir uma interface natural para que os usuários interagissem com jogos sem a necessidade de controles. Ele é capaz de detectar a pose de até 4 pessoas simultâneamente.

Neste artigo demonstrarei os passos necessários para utilizar o Kinect v2 no linux e como acessá-lo utilizando a opencv.

Materiais

Dependências

Durante a escrita deste tutorial, dois sistemas operacionais foram utilizados: Ubuntu 20.04 e Ubuntu 22.04, portanto aqui nesta sessão serão apresentados alguns comandos do gerenciador de pacotes APT que permitirão instalar os pacotes précompilados disponíveis. Para os usuários de outras distribuições estará disponível o link do repositório do github que pode ser usado para compilar as bibliotecas necessárias.

OpenNI

A OpenNI (Open Natural Interaction) é um projeto Open Source com o objetivo de aprimorar a interoperabilidade de interfaces naturais de usuário, fornecendo um middleware que facilita acesso a dispositivos de interação natural para diferentes aplicações.

A PrimeSense encerrou o projeto original OpenNI quando foi comprada pela Apple em novembro de 2013, porém seus antigos parceiros matém um fork da OpenNI 2 como um projeto open source.

OpenCV

A OpenCV (Open Computer Vision) é uma biblioteca Open Source que reúne diversos algoritmos de visão computacional. A OpenCV foi construída para prover uma infraestrutura comum para aplicações de visão computacional possuindo suporte para diversas linguagens como: C++, python, java e MATLAB.

Para realizar a instalação é recomendado os seguintes passos para garantia que se tenha uma versão da OpenCV com suporte a OpenNI2:

1
2
3
4
5
6
7
8
9
10
11
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
cd opencv_contrib
git checkout 4.6.0
cd ../opencv
git checkout 4.6.0
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DBUILD_PERF_TESTS=OFF -DOPENCV_ENABLE_NONFREE=OFF -DOPENCV_EXTRA_MODULES=../opencv_contrib/modules -DWITH_OPENNI2=ON ..
make -j 4
sudo make install

PCL

A PCL (Point Clout Library) é uma biblioteca escrita em C++ especializada no processamento de núvens de pontos. Esta biblioteca possuí algoritmos para filtro, seleção de pontos chave, reconstrução de superfícies, comunicação com sensores, visualização de núvens de pontos e outros tópicos.

Fazendo funcionar

As bibliotecas descritas na sessão anterior serão nossas interfaces de programação em um nível mais elevado, para que possamos extrair os dados do sensor primeiro é necessário um driver que gerenciará a comunicação entre o sistema operacional e kinect. Como os drivers oficiais do kinect são proprietários e apenas disponíveis na Kinect SDK para o windows, a comunidade inicio a criação de um drive para o linux: o freenect, desenvolvido para a primeira versão do kinect, e freenect2, desenvolvido para a segunda versão do kinect.

Neste artigo concentraremos no freenect2 pois estamos trabalhando com o Kinect v2. Nas seguintes sessões compilaremos o projeto LibFreenect2 e configuraremos seu uso.

Compilando a libfreenect2

1
2
3
4
5
6
7
8
9
git clone https://github.com/OpenKinect/libfreenect2.git
cd libfreenect2
git checkout v0.2.1
mkdir build
cd build
cmake -DBUILD_OPENNI2_DRIVER=ON -DCMAKE_BUILD_TYPE=Release ..
make -j 4
sudo make install
sudo make install-openni2

Liberando acesso ao dispositivo para o usuário

Após compilar o projeto e instalar os artefatos, é necessário liberar o acesso ao dispositivo para os usuários, do contrário os programas que tentarem se comunicar com o kinect precisarão ser executados em modo root.

1
2
cd libfreenect2
sudo cp ./platform/linux/udev/90-kinect2.rules /etc/udev/rules.d/

Após a execução dos comandos acima é necessário desconectar o kinect da porta USB e conectar novamente.

Testando com NiViewer2

Como primeiro teste rápido é possivel utilizar agora o NiViewer2 para obter dados do kinect.

1
2
sudo apt install openni2-utils # caso não tenha sido instalado ainda
NiViewer2

Após a execução dos comandos acima são esperados uma tela conforme a image e a seguinte saída no terminal:

Tela NiViewer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Info] [Freenect2Impl] enumerating devices...
[Info] [Freenect2Impl] 10 usb devices connected
[Info] [Freenect2Impl] found valid Kinect v2 @2:2 with serial 067886733447
[Info] [Freenect2Impl] found 1 devices
[Info] [Freenect2DeviceImpl] opening...
[Info] [Freenect2DeviceImpl] transfer pool sizes rgb: 20*16384 ir: 60*8*33792
[Info] [Freenect2DeviceImpl] opened
[Info] [Freenect2DeviceImpl] starting...
[Info] [Freenect2DeviceImpl] submitting rgb transfers...
[Info] [Freenect2DeviceImpl] submitting depth transfers...
[Info] [Freenect2DeviceImpl] started
[Info] [DepthPacketStreamParser] 32 packets were lost
[Info] [DepthPacketStreamParser] 13 packets were lost
[Info] [TurboJpegRgbPacketProcessor] avg. time: 9.53263ms -> ~104.903Hz

Programa de Teste

Feito o teste com o NiView2, a seguir está um programa em C++ utilizando a PCL e OpenCV para obter informação do sensor e exibir a núvem de pontos em uma tela interativa. Ao final está contido o vídeo com o resultado esperado ao se compilar o programa abaixo.

Código Fonte

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
find_package(OpenCV 4 COMPONENTS core highgui videoio imgcodecs)

if(${OpenCV_FOUND})
else()
        find_package(OpenCV 2 COMPONENTS core highgui REQUIRED)
endif()


find_package(PCL COMPONENTS visualization REQUIRED)

set(OPENNI_CAPTURE_INCLUDE_DIRS 
	${OpenCV_INCLUDE_DIRS}
  ${PCL_INCLUDE_DIRS}
)

file(GLOB OPENNI_CAPTURE_SOURCES main.cpp)
include_directories(${OPENNI_CAPTURE_INCLUDE_DIRS})

add_executable(openni-capture ${OPENNI_CAPTURE_SOURCES})
target_link_libraries(openni-capture ${OpenCV_LIBS} ${PCL_LIBRARIES})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <pcl/visualization/cloud_viewer.h>

#include <fstream>

cv::VideoCapture cap(1, cv::CAP_OPENNI2); // Configura o cv::VideoCapture para abrir o dispositivo 1 utilizando a OpenNI2

void getPointCloud(pcl::visualization::PCLVisualizer& viewer)
{
    viewer.removeAllPointClouds(); // Remove as núvens de pontos anteriores

    cv::Mat pointCloudFrame, frame;

    cap.grab(); // Obtém-se uma leitura do sensor
    cap.retrieve(pointCloudFrame, cv::CAP_OPENNI_POINT_CLOUD_MAP); // Obtendo núvem de pontos em formato matricial
    cap.retrieve(frame, cv::CAP_OPENNI_BGR_IMAGE); // Obtendo informação de cor alinhada com a núvem de pontos

    pcl::visualization::CloudViewer::ColorCloud* cloud = new pcl::visualization::CloudViewer::ColorCloud();

    for(int i = 0; i<pointCloudFrame.rows; i++) // Para cada ponto contido na matriz
    {
        for(int j = 0; j<pointCloudFrame.cols; j++) // Para cada ponto contido na matriz
        {
            cv::Vec3b color = frame.at<cv::Vec3b>(i,j); // Obtém a informação de cor
            pcl::PointXYZRGB point(color[2], color[1], color[0]); // Cria um ponto no formato da PCL passando a informação da cor contida nesse ponto

            cv::Vec3f coords = pointCloudFrame.at<cv::Vec3f>(i,j); // Obtém as coordenadas deste ponto
            point.x = coords[0]; // Adiciona a coordenada ao ponto
            point.y = coords[1]; // Adiciona a coordenada ao ponto
            point.z = coords[2]; // Adiciona a coordenada ao ponto

            cloud->push_back(point); // Adiciona o ponto na núvem
        }
    }

    viewer.addPointCloud(pcl::visualization::CloudViewer::ColorCloud::ConstPtr(cloud)); // Envia a núvem de pontos para ser renderizada pelo visualizador
}


int main(int argc, char** argv)
{

    if(!cap.isOpened())
       return -1;

    cap.set(cv::CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION, 1); // Configurando OpenNI para gerar núvem de pontos com informações de cores


    pcl::visualization::CloudViewer viewer("point cloud"); // Inicializa um visualizador de núvens de pontos
    viewer.runOnVisualizationThread(getPointCloud); // Define a função utilizada para renderizar a cena

    while(!viewer.wasStopped()); // Aguarda a conclusão do visualizador de núvens de pontos

    cap.release(); // Encerra a captura do dispositivo
    
    return 0;

}

Resultado

Caso tenha dúvidas me envie um email,

Matheus Barcelos de Oliveira
Engenheiro de Visão Computacional

This post is licensed under CC BY 4.0 by the author.