Skip to content

Add Support for Kinect as Webcam on Linux #1197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ SET(DEPENDS_DIR "${MY_DIR}/depends" CACHE STRING "dependency directory must be s

OPTION(BUILD_SHARED_LIBS "Build shared (ON) or static (OFF) libraries" ON)
OPTION(BUILD_EXAMPLES "Build examples" ON)
OPTION(BUILD_WEBCAM "Build Webcam" ON)
OPTION(BUILD_OPENNI2_DRIVER "Build OpenNI2 driver" ON)
OPTION(ENABLE_CXX11 "Enable C++11 support" OFF)
OPTION(ENABLE_OPENCL "Enable OpenCL support" ON)
@@ -457,6 +458,12 @@ IF(BUILD_EXAMPLES)
ADD_SUBDIRECTORY(${MY_DIR}/examples)
ENDIF()

IF(BUILD_WEBCAM)
SET(HAVE_WEBCAM yes)
MESSAGE(STATUS "Configuration of Kinect as Webcam")
ADD_SUBDIRECTORY(${MY_DIR}/examples/kinect_webcam)
ENDIF()

SET(HAVE_OpenNI2 disabled)
IF(BUILD_OPENNI2_DRIVER)
FIND_PACKAGE(OpenNI2)
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -243,6 +243,12 @@ Note: Ubuntu 12.04 is too old to support. Debian jessie may also be too old, and
* Install OpenNI2 (optional)
1. (Ubuntu 14.04 only) `sudo apt-add-repository ppa:deb-rob/ros-trusty && sudo apt-get update` (You don't need this if you have ROS repos), then `sudo apt-get install libopenni2-dev`
2. (Other) `sudo apt-get install libopenni2-dev`
* Install v4l2loopback-dksm (optional)
1. (Ubuntu) `sudo apt-get update && sudo apt-get install v4l2loopback-dkms`
2. (Arch) `sudo pacman -S v4l2loopback-dksm`
* Install OpenCV (optional)
1. (Ubuntu) `sudo apt-get update && sudo apt-get install libopencv-dev`
2. (Arch) `sudo pacman -S opencv`
* Build (if you have run `cd depends` previously, `cd ..` back to the libfreenect2 root directory first.)
```
mkdir build && cd build
@@ -254,3 +260,4 @@ Note: Ubuntu 12.04 is too old to support. Debian jessie may also be too old, and
* Set up udev rules for device access: `sudo cp ../platform/linux/udev/90-kinect2.rules /etc/udev/rules.d/`, then replug the Kinect.
* Run the test program: `./bin/Protonect`
* Run OpenNI2 test (optional): `sudo apt-get install openni2-utils && sudo make install-openni2 && NiViewer2`. Environment variable `LIBFREENECT2_PIPELINE` can be set to `cl`, `cuda`, etc to specify the pipeline.
* To use kinect as webcam, you need to run `sudo modprobe v4l2loopback devices=1 video_nr=10 card_label="Kinect Webcam"` and then simply run `Kinect_Webcam`
79 changes: 79 additions & 0 deletions examples/kinect_webcam/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12.1)

if(WIN32 AND NOT MINGW)
if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
set(CMAKE_DEBUG_POSTFIX "d")
endif()
endif()

IF(NOT DEFINED CMAKE_BUILD_TYPE)
# No effect for multi-configuration generators (e.g. for Visual Studio)
SET(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose: RelWithDebInfo Release Debug MinSizeRel None")
ENDIF()

PROJECT(kinect_webcam)

SET(MY_DIR ${libfreenect2_examples_SOURCE_DIR})
SET(DEPENDS_DIR "${MY_DIR}/../depends" CACHE STRING "Dependency directory")

OPTION(ENABLE_OPENGL "Enable OpenGL support" ON)

# The example build system is standalone and will work out-of-tree with these files copied
SET(freenect2_ROOT_DIR ${MY_DIR}/../..)
SET(flextGL_SOURCES ${freenect2_ROOT_DIR}/src/flextGL.cpp)
SET(flextGL_INCLUDE_DIRS ${freenect2_ROOT_DIR}/src) # for flextGL.h

FIND_PACKAGE(PkgConfig) # try find PKGConfig as it will be used if found
LIST(APPEND CMAKE_MODULE_PATH ${freenect2_ROOT_DIR}/cmake_modules) # FindGLFW3.cmake

FIND_PACKAGE(OpenCV REQUIRED)
SET(RESOURCES_INC_FILE "${PROJECT_BINARY_DIR}/resources.inc.h")
IF(TARGET freenect2)
MESSAGE(STATUS "Using in-tree freenect2 target")
SET(freenect2_LIBRARIES freenect2)
SET(freenect2_DLLS ${LIBFREENECT2_DLLS})
ELSE()
FIND_PACKAGE(freenect2 REQUIRED)
# Out-of-tree build will have to have DLLs manually copied.
ENDIF()

INCLUDE_DIRECTORIES(
"/usr/include/opencv4"
${freenect2_INCLUDE_DIR}
)
add_compile_options(-fexceptions)
SET(Kinect_Webcam_src
Kinect_Webcam.cpp
)

SET(Kinect_Webcam_LIBRARIES
${freenect2_LIBRARIES}
)

SET(Kinect_Webcam_DLLS
${freenect2_DLLS}
)

ADD_EXECUTABLE(Kinect_Webcam
${Kinect_Webcam_src}
)

TARGET_LINK_LIBRARIES(Kinect_Webcam
${Kinect_Webcam_LIBRARIES}
opencv_core
opencv_highgui
${OpenCV_LIBS}
)

IF(WIN32)
INSTALL(TARGETS Kinect_Webcam DESTINATION bin)
LIST(REMOVE_DUPLICATES Kinect_Webcam_DLLS)
FOREACH(FILEI ${Kinect_Webcam_DLLS})
ADD_CUSTOM_COMMAND(TARGET Kinect_Webcam POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FILEI} $<TARGET_FILE_DIR:Kinect_Webcam>
)
ENDFOREACH(FILEI)
INSTALL(TARGETS Kinect_Webcam DESTINATION bin)
INSTALL(FILES ${Kinect_Webcam_DLLS} DESTINATION bin)
ENDIF()
INSTALL(TARGETS Kinect_Webcam DESTINATION bin)
124 changes: 124 additions & 0 deletions examples/kinect_webcam/Kinect_Webcam.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <errno.h>
#include <string.h>
#include <opencv2/opencv.hpp>
#include <libfreenect2/libfreenect2.hpp>
#include <libfreenect2/frame_listener_impl.h>
#include <libfreenect2/registration.h>
#include <libfreenect2/packet_pipeline.h>
#include <libfreenect2/logger.h>

bool protonect_shutdown = false;
int v4l2_fd = -1;

void sigint_handler(int s)
{
protonect_shutdown = true;
}

bool init_v4l2_device(const char *device, int width, int height)
{
v4l2_fd = open(device, O_WRONLY);
if (v4l2_fd < 0)
{
std::cerr << "Error opening v4l2loopback device: " << strerror(errno) << std::endl;
return false;
}

struct v4l2_format v4l2_fmt;
memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
v4l2_fmt.fmt.pix.width = width;
v4l2_fmt.fmt.pix.height = height;
v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
v4l2_fmt.fmt.pix.sizeimage = width * height * 3;
v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;

if (ioctl(v4l2_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0)
{
std::cerr << "Error setting v4l2 format: " << strerror(errno) << std::endl;
close(v4l2_fd);
v4l2_fd = -1;
return false;
}

return true;
}

void write_frame_to_v4l2(unsigned char *rgb_data, int width, int height)
{
if (v4l2_fd < 0)
return;

cv::Mat frame(height, width, CV_8UC4, rgb_data);
cv::Mat bgr_frame;
cv::cvtColor(frame, bgr_frame, cv::COLOR_BGRA2BGR);

write(v4l2_fd, bgr_frame.data, width * height * 3);
}

int main(int argc, char *argv[])
{
libfreenect2::Freenect2 freenect2;
libfreenect2::Freenect2Device *dev = nullptr;
libfreenect2::PacketPipeline *pipeline = nullptr;

if (!init_v4l2_device("/dev/video10", 1920, 1080))
{
std::cerr << "Failed to initialize v4l2loopback device" << std::endl;
return -1;
}

if (freenect2.enumerateDevices() == 0)
{
std::cout << "No device connected!" << std::endl;
return -1;
}

std::string serial = freenect2.getDefaultDeviceSerialNumber();

dev = freenect2.openDevice(serial);

if (dev == nullptr)
{
std::cout << "Failure opening device!" << std::endl;
return -1;
}

signal(SIGINT, sigint_handler);

libfreenect2::SyncMultiFrameListener listener(libfreenect2::Frame::Color);
libfreenect2::FrameMap frames;

dev->setColorFrameListener(&listener);

if (!dev->start())
return -1;

std::cout << "Device serial: " << dev->getSerialNumber() << std::endl;
std::cout << "Device firmware: " << dev->getFirmwareVersion() << std::endl;

while (!protonect_shutdown)
{
if (!listener.waitForNewFrame(frames, 10 * 1000)) // 10 seconds
{
std::cout << "Timeout!" << std::endl;
return -1;
}
libfreenect2::Frame *rgb = frames[libfreenect2::Frame::Color];

write_frame_to_v4l2(rgb->data, rgb->width, rgb->height);

listener.release(frames);
}

dev->stop();
dev->close();
close(v4l2_fd);
return 0;
}