Skip to content
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

Add example with C++ and OpenCV 2 #646

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -151,6 +151,7 @@ ENDIF()

IF(BUILD_CV)
add_subdirectory (wrappers/opencv)
add_subdirectory (wrappers/cppopencv)
ENDIF()

IF(BUILD_AS3_SERVER)
Expand Down
11 changes: 11 additions & 0 deletions wrappers/cppopencv/CMakeLists.txt
@@ -0,0 +1,11 @@
cmake_minimum_required(VERSION 3.8.2)

set(THREADS_USE_PTHREADS_WIN32 true)
find_package(Threads)
find_package( OpenCV REQUIRED )

include_directories(. ${THREADS_PTHREADS_INCLUDE_DIR})
Copy link
Author

@remmel remmel Nov 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

include_directories(. ${THREADS_PTHREADS_INCLUDE_DIR}) doesn't seems to be needed, maybe other OS? (tested on Ubuntu 20.04 LTS)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be necessary - I think THREADS_PTHREADS_INCLUDE_DIR does not even exist in CMake anymore. But since you already require cxx_std_11, you could use std::thread and std::mutex instead of pthread in the code. Then there would be no need to find Threads package at all.


add_executable( freenect-cppopencv cppopencv.cpp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion - make this conditional on if (BUILD_EXAMPLES).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that CMakeLists.txt is included only if BUILD_CV is enabled. Are you sure you want a 2nd condition?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally yes because this is an example. But I see the existing cvdemo does not depend on BUILD_EXAMPLES so it's just a suggestion.

target_compile_features(freenect-cppopencv PUBLIC cxx_std_11)
target_link_libraries( freenect-cppopencv freenect ${CMAKE_THREAD_LIBS_INIT} ${OpenCV_LIBS} )
143 changes: 143 additions & 0 deletions wrappers/cppopencv/cppopencv.cpp
@@ -0,0 +1,143 @@
// Based on https://openkinect.org/wiki/C%2B%2BOpenCvExample
// Use Cpp and OpenCV 2+ API
// Display RGB + D (640x480) frames and save it when pressing 's'

#include "libfreenect.hpp"
#include <iostream>
#include <pthread.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;


class myMutex {
public:
myMutex() {
pthread_mutex_init( &m_mutex, NULL );
}
void lock() {
pthread_mutex_lock( &m_mutex );
}
void unlock() {
pthread_mutex_unlock( &m_mutex );
}
private:
pthread_mutex_t m_mutex;
};

class MyFreenectDevice : public Freenect::FreenectDevice {
public:
MyFreenectDevice(freenect_context *_ctx, int _index) :
Freenect::FreenectDevice(_ctx, _index),
m_new_rgb_frame(false), m_new_depth_frame(false),
depthMat(Size(640,480),CV_16UC1),
rgbMat(Size(640,480), CV_8UC3, Scalar(0)) {
setDepthFormat(FREENECT_DEPTH_REGISTERED);
}

// Do not call directly even in child
void VideoCallback(void* _rgb, uint32_t timestamp) {
std::cout << "RGB callback " << timestamp << std::endl;
m_rgb_mutex.lock();
uint8_t* rgb = static_cast<uint8_t*>(_rgb);
rgbMat.data = rgb;
m_new_rgb_frame = true;
m_rgb_mutex.unlock();
};

// Do not call directly even in child
void DepthCallback(void* _depth, uint32_t timestamp) {
std::cout << "Depth callback " << timestamp << std::endl;
m_depth_mutex.lock();
uint16_t* depth = static_cast<uint16_t*>(_depth);
depthMat.data = (uchar*) depth;
m_new_depth_frame = true;
m_depth_mutex.unlock();
}

bool getVideo(Mat& output) {
m_rgb_mutex.lock();
if(m_new_rgb_frame) {
cv::cvtColor(rgbMat, output, COLOR_RGB2BGR);
m_new_rgb_frame = false;
m_rgb_mutex.unlock();
return true;
} else {
m_rgb_mutex.unlock();
return false;
}
}

bool getDepth(Mat& output) {
m_depth_mutex.lock();
if(m_new_depth_frame) {
depthMat.copyTo(output);
m_new_depth_frame = false;
m_depth_mutex.unlock();
return true;
} else {
m_depth_mutex.unlock();
return false;
}
}
private:
Mat depthMat;
Mat rgbMat;
myMutex m_rgb_mutex;
myMutex m_depth_mutex;
bool m_new_rgb_frame;
bool m_new_depth_frame;
};


int main(int argc, char **argv) {
bool die(false);
int i_snap(0),iter(0);

Mat depthMat(Size(640,480),CV_16UC1);
Mat depthMatNice (Size(640, 480), CV_8UC1);
Mat rgbMat(Size(640,480),CV_8UC3,Scalar(0));

Freenect::Freenect freenect;

cout << "Number of devices found: " << freenect.deviceCount() << endl;

MyFreenectDevice& device = freenect.createDevice<MyFreenectDevice>(0);

namedWindow("rgb", WINDOW_AUTOSIZE);
namedWindow("depth" ,WINDOW_AUTOSIZE);
device.startVideo();
device.startDepth();

while (!die) {
device.getVideo(rgbMat);
device.getDepth(depthMat);
cv::imshow("rgb", rgbMat);
depthMat.convertTo(depthMatNice, CV_8UC1, 255.0 / 5000); //display only range [0m-5m] in grayscale
cv::imshow("depth", depthMatNice);

char k = waitKey(5);
if( k == 27 ){ //ESC
destroyWindow("rgb");
destroyWindow("depth");
break;
}
if( k == 's' ) {
std::ostringstream file_rgb;
file_rgb << "snapshot_" << i_snap << "_rgb.png";
cv::imwrite(file_rgb.str(), rgbMat);
cout << "file_rgb rgb saved: " << file_rgb.str() << endl;
std::ostringstream file_d;
file_d << "snapshot_" << i_snap << "_depth.png";
cv::imwrite(file_d.str(), depthMat);
cout << "file_rgb depth saved: " << file_d.str() << endl;
i_snap++;
}
iter++;
}

device.stopVideo();
device.stopDepth();
return 0;
}