From b29b1c73191c41d4873a48cc463c6dba9cca537e Mon Sep 17 00:00:00 2001 From: dedsec995 Date: Wed, 5 Feb 2025 15:23:21 -0500 Subject: [PATCH] Add Support for Kinect as Webcam on Linux --- CMakeLists.txt | 7 ++ README.md | 7 ++ examples/kinect_webcam/CMakeLists.txt | 79 +++++++++++++++ examples/kinect_webcam/Kinect_Webcam.cpp | 124 +++++++++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 examples/kinect_webcam/CMakeLists.txt create mode 100644 examples/kinect_webcam/Kinect_Webcam.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d8ef04736..7a7b14376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/README.md b/README.md index 3bde4ceb0..7d0b0aeac 100644 --- a/README.md +++ b/README.md @@ -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` diff --git a/examples/kinect_webcam/CMakeLists.txt b/examples/kinect_webcam/CMakeLists.txt new file mode 100644 index 000000000..cd3de9e5a --- /dev/null +++ b/examples/kinect_webcam/CMakeLists.txt @@ -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} $ + ) + ENDFOREACH(FILEI) +INSTALL(TARGETS Kinect_Webcam DESTINATION bin) + INSTALL(FILES ${Kinect_Webcam_DLLS} DESTINATION bin) +ENDIF() +INSTALL(TARGETS Kinect_Webcam DESTINATION bin) \ No newline at end of file diff --git a/examples/kinect_webcam/Kinect_Webcam.cpp b/examples/kinect_webcam/Kinect_Webcam.cpp new file mode 100644 index 000000000..d8634d1a4 --- /dev/null +++ b/examples/kinect_webcam/Kinect_Webcam.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +}