diff options
-rw-r--r-- | CMakeLists.txt | 27 | ||||
-rw-r--r-- | facetracknoir/ui.cpp | 2 | ||||
-rw-r--r-- | ftnoir_protocol_sc/ftnoir_protocol_sc.h | 39 | ||||
-rw-r--r-- | ftnoir_tracker_ht/ftnoir_tracker_ht.cpp | 152 | ||||
-rw-r--r-- | ftnoir_tracker_ht/ftnoir_tracker_ht.h | 41 | ||||
-rw-r--r-- | ftnoir_tracker_ht/ht-api.h | 6 | ||||
-rw-r--r-- | ftnoir_tracker_ht/stdafx.h | 13 |
7 files changed, 163 insertions, 117 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c858587..b483000d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,8 +153,10 @@ SET(SDK_RIFT "" CACHE PATH "libOVR path for Oculus Rift") set(SDK_ARUCO_LIBPATH "" CACHE FILEPATH "Aruco paper marker tracker static library path") +set(SDK_HT "" CACHE FILEPATH "Path to headtracker library") +set(SDK_HT_FLANDMARK "" CACHE FILEPATH "Path to flandmark library for headtracker") + if(WIN32) - set(SDK_SIMCONNECT "" CACHE PATH "SimConnect SDK path for MS FSX") set(SDK_FSUIPC "" CACHE PATH "FSUIPC for older MS FSX path") endif() @@ -305,10 +307,8 @@ if(SDK_FSUIPC) #target_link_directories(${SDK_FSUIPC}) endif() -if(SDK_SIMCONNECT) +if(WIN32) opentrack_library(opentrack-proto-simconnect ftnoir_protocol_sc) - target_link_libraries(opentrack-proto-simconnect ${SDK_SIMCONNECT}/lib/SimConnect.lib) - include_directories(opentrack-proto-simconnect SYSTEM PUBLIC ${SDK_SIMCONNECT}/inc) endif() if(WIN32) @@ -371,11 +371,13 @@ if(OpenCV_FOUND) target_link_libraries(opentrack-filter-kalman ${OpenCV_LIBS}) target_include_directories(opentrack-filter-kalman SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) - opentrack_library(opentrack-tracker-ht ftnoir_tracker_ht) - target_link_libraries(opentrack-tracker-ht opentrack-compat) - link_with_dinput8(opentrack-tracker-ht) - target_link_libraries(opentrack-tracker-ht ${OpenCV_LIBS}) - target_include_directories(opentrack-tracker-ht SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) + if(SDK_HT AND SDK_HT_FLANDMARK) + opentrack_library(opentrack-tracker-ht ftnoir_tracker_ht) + target_link_libraries(opentrack-tracker-ht opentrack-compat ${SDK_HT} ${SDK_HT_FLANDMARK}) + link_with_dinput8(opentrack-tracker-ht) + target_link_libraries(opentrack-tracker-ht ${OpenCV_LIBS}) + target_include_directories(opentrack-tracker-ht SYSTEM PUBLIC ${OpenCV_INCLUDE_DIRS}) + endif() endif() link_with_dinput8(opentrack-tracker-joystick) @@ -491,8 +493,6 @@ if(NOT WIN32) endif() target_link_libraries(opentrack opentrack-api opentrack-version opentrack-pose-widget opentrack-spline-widget) - - if(APPLE) SET_TARGET_PROPERTIES(opentrack-qxt-mini PROPERTIES LINK_FLAGS "-framework Carbon -framework CoreFoundation") endif() @@ -520,11 +520,6 @@ if(SDK_XPLANE) install(TARGETS opentrack-xplane-plugin RUNTIME DESTINATION . LIBRARY DESTINATION . ) endif() -if(WIN32) - install(DIRECTORY ${CMAKE_SOURCE_DIR}/bin/tracker-ht DESTINATION .) - #install(TARGETS freetrackclient RUNTIME DESTINATION . LIBRARY DESTINATION . ) -endif() - install(DIRECTORY ${CMAKE_SOURCE_DIR}/3rdparty-notices DESTINATION .) install(FILES "${CMAKE_SOURCE_DIR}/bin/freetrackclient.dll" DESTINATION . ${opentrack-perms}) diff --git a/facetracknoir/ui.cpp b/facetracknoir/ui.cpp index 7a412bdb..6afb3475 100644 --- a/facetracknoir/ui.cpp +++ b/facetracknoir/ui.cpp @@ -84,6 +84,8 @@ MainWindow::MainWindow() : det_timer.start(1000); ensure_tray(); + + set_working_directory(); } MainWindow::~MainWindow() diff --git a/ftnoir_protocol_sc/ftnoir_protocol_sc.h b/ftnoir_protocol_sc/ftnoir_protocol_sc.h index cbdee7de..034a8e09 100644 --- a/ftnoir_protocol_sc/ftnoir_protocol_sc.h +++ b/ftnoir_protocol_sc/ftnoir_protocol_sc.h @@ -27,16 +27,7 @@ * must be treated as such... * ********************************************************************************/ #pragma once -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0502 #include "opentrack/plugin-api.hpp" -// -// Prevent the SimConnect manifest from being merged in the application-manifest -// This is necessary to run FaceTrackNoIR on a PC without FSX -// -#define SIMCONNECT_H_NOMANIFEST -#include <windows.h> -#include <SimConnect.h> #include "ui_ftnoir_sccontrols.h" #include <QThread> @@ -48,12 +39,7 @@ #include <QFile> #include "opentrack/options.hpp" using namespace options; - -typedef HRESULT (WINAPI *importSimConnect_Open)(HANDLE * phSimConnect, LPCSTR szName, HWND hWnd, DWORD UserEventWin32, HANDLE hEventHandle, DWORD ConfigIndex); -typedef HRESULT (WINAPI *importSimConnect_Close)(HANDLE hSimConnect); -typedef HRESULT (WINAPI *importSimConnect_CameraSetRelative6DOF)(HANDLE hSimConnect, float fDeltaX, float fDeltaY, float fDeltaZ, float fPitchDeg, float fBankDeg, float fHeadingDeg); -typedef HRESULT (WINAPI *importSimConnect_CallDispatch)(HANDLE hSimConnect, DispatchProc pfcnDispatch, void * pContext); -typedef HRESULT (WINAPI *importSimConnect_SubscribeToSystemEvent)(HANDLE hSimConnect, SIMCONNECT_CLIENT_EVENT_ID EventID, const char * SystemEventName); +#include <windows.h> struct settings : opts { value<int> sxs_manifest; @@ -75,6 +61,25 @@ public: return "FS2004/FSX"; } private: + enum { SIMCONNECT_RECV_ID_EVENT_FRAME = 7 }; + + #pragma pack(push, 1) + struct SIMCONNECT_RECV + { + DWORD dwSize; + DWORD dwVersion; + DWORD dwID; + }; + #pragma pack(pop) + + typedef void (CALLBACK *DispatchProc)(SIMCONNECT_RECV*, DWORD, void*); + + typedef HRESULT (WINAPI *importSimConnect_Open)(HANDLE * phSimConnect, LPCSTR szName, HWND hWnd, DWORD UserEventWin32, HANDLE hEventHandle, DWORD ConfigIndex); + typedef HRESULT (WINAPI *importSimConnect_Close)(HANDLE hSimConnect); + typedef HRESULT (WINAPI *importSimConnect_CameraSetRelative6DOF)(HANDLE hSimConnect, float fDeltaX, float fDeltaY, float fDeltaZ, float fPitchDeg, float fBankDeg, float fHeadingDeg); + typedef HRESULT (WINAPI *importSimConnect_CallDispatch)(HANDLE hSimConnect, DispatchProc pfcnDispatch, void * pContext); + typedef HRESULT (WINAPI *importSimConnect_SubscribeToSystemEvent)(HANDLE hSimConnect, DWORD EventID, const char * SystemEventName); + void run() override; volatile bool should_stop; @@ -85,13 +90,13 @@ private: volatile float virtSCRotY; volatile float virtSCRotZ; - importSimConnect_Open simconnect_open; // SimConnect function(s) in DLL + importSimConnect_Open simconnect_open; importSimConnect_Close simconnect_close; importSimConnect_CameraSetRelative6DOF simconnect_set6DOF; importSimConnect_CallDispatch simconnect_calldispatch; importSimConnect_SubscribeToSystemEvent simconnect_subscribetosystemevent; - HANDLE hSimConnect; // Handle to SimConnect + HANDLE hSimConnect; static void CALLBACK processNextSimconnectEvent(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext); settings s; QLibrary SCClientLib; diff --git a/ftnoir_tracker_ht/ftnoir_tracker_ht.cpp b/ftnoir_tracker_ht/ftnoir_tracker_ht.cpp index 3d142dcb..deb90ee5 100644 --- a/ftnoir_tracker_ht/ftnoir_tracker_ht.cpp +++ b/ftnoir_tracker_ht/ftnoir_tracker_ht.cpp @@ -44,49 +44,49 @@ void Tracker::load_settings(ht_config_t* config) config->classification_delay = 500; config->field_of_view = s.fov; - config->pyrlk_pyramids = 0; - config->pyrlk_win_size_w = config->pyrlk_win_size_h = 21; config->max_keypoints = 150; - config->keypoint_distance = 3.5; + config->keypoint_distance = 3.4; config->force_fps = nframes; config->camera_index = camera_name_to_index(s.camera_name); - config->ransac_num_iters = 100; - config->ransac_max_reprojection_error = 10; - config->ransac_max_inlier_error = 10; - config->ransac_abs_max_mean_error = 14; - config->ransac_max_mean_error = 8; + + config->ransac_max_reprojection_error = 8; + config->ransac_max_inlier_error = 8; + + config->pyrlk_pyramids = 0; + config->pyrlk_win_size_w = config->pyrlk_win_size_h = 21; + + config->ransac_max_mean_error = 999; + config->ransac_abs_max_mean_error = 999; + config->debug = 0; - config->ransac_min_features = 0.8; + config->ransac_min_features = 0.85; + config->ransac_num_iters = 300; + int res = s.resolution; if (res < 0 || res >= (int)(sizeof(resolution_choices) / sizeof(resolution_tuple))) res = 0; resolution_tuple r = resolution_choices[res]; config->force_width = r.width; config->force_height = r.height; - config->flandmark_delay = 500; + config->flandmark_delay = 50; for (int i = 0; i < 5; i++) config->dist_coeffs[i] = 0; } Tracker::Tracker() : - lck_shm(HT_SHM_NAME, HT_MUTEX_NAME, sizeof(ht_shm_t)), - shm(reinterpret_cast<ht_shm_t*>(lck_shm.ptr())), + ht(nullptr), + ypr {0,0,0, 0,0,0}, videoWidget(nullptr), - layout(nullptr) + layout(nullptr), + should_stop(false) { - shm->terminate = 0; - shm->result.filled = false; } Tracker::~Tracker() { - if (shm) { - shm->terminate = true; - subprocess.waitForFinished(5000); - } - subprocess.kill(); - if (shm) - shm->terminate = true; + should_stop = true; + wait(); + ht_free_context(ht); if (layout) delete layout; if (videoWidget) @@ -105,41 +105,81 @@ void Tracker::start_tracker(QFrame* videoframe) videoframe->setLayout(layout); videoWidget->show(); this->layout = layout; - load_settings(&shm->config); - shm->frame.channels = shm->frame.width = shm->frame.height = 0; - shm->pause = shm->terminate = shm->running = false; - shm->timer = 0; - shm->result.filled = false; - subprocess.setProcessChannelMode(QProcess::ForwardedChannels); - subprocess.setWorkingDirectory(QCoreApplication::applicationDirPath() + "/tracker-ht"); -#if defined(_WIN32) - subprocess.start("\"" + QCoreApplication::applicationDirPath() + "/tracker-ht/headtracker-ftnoir" + "\""); -#else - subprocess.start(QCoreApplication::applicationDirPath() + "/tracker-ht/headtracker-ftnoir"); -#endif + + load_settings(&conf); + ht = ht_make_context(&conf, nullptr); + start(); +} + +void Tracker::run() +{ + while (!should_stop) + { + ht_result_t euler; + euler.filled = false; + { + QMutexLocker l(&camera_mtx); + + if (!ht_cycle(ht, &euler)) + break; + } + if (euler.filled) + { + QMutexLocker l(&ypr_mtx); + ypr[TX] = euler.tx; + ypr[TY] = euler.ty; + ypr[TZ] = euler.tz; + ypr[Yaw] = euler.rotx; + ypr[Pitch] = euler.roty; + ypr[Roll] = euler.rotz; + } + { + const cv::Mat frame_ = ht_get_bgr_frame(ht); + if (frame_.cols <= HT_MAX_VIDEO_WIDTH && frame_.rows <= HT_MAX_VIDEO_HEIGHT && frame_.channels() <= HT_MAX_VIDEO_CHANNELS) + { + QMutexLocker l(&frame_mtx); + + const int cols = frame_.cols; + const int rows = frame_.rows; + const int pitch = cols * 3; + for (int y = 0; y < rows; y++) + { + for (int x = 0; x < cols; x++) + { + unsigned char* dest = &frame.frame[y * pitch + 3 * x]; + const cv::Vec3b& elt = frame_.at<cv::Vec3b>(y, x); + const cv::Scalar elt2 = static_cast<cv::Scalar>(elt); + dest[0] = elt2.val[0]; + dest[1] = elt2.val[1]; + dest[2] = elt2.val[2]; + } + } + frame.channels = frame_.channels(); + frame.width = frame_.cols; + frame.height = frame_.rows; + } + } + } } -void Tracker::data(double *data) +void Tracker::data(double* data) { - lck_shm.lock(); - shm->timer = 0; - if (shm->frame.width > 0) { - videoWidget->update_image(shm->frame.frame, shm->frame.width, shm->frame.height); - //memcpy(foo, shm->frame.frame, shm->frame.width * shm->frame.height * 3); - shm->frame.width = 0; + QMutexLocker l(&frame_mtx); + + if (frame.width > 0) + { + videoWidget->update_image(frame.frame, frame.width, frame.height); + frame.width = 0; + } } - if (shm->result.filled) { - data[Yaw] = shm->result.rotx; - data[Pitch] = shm->result.roty; - data[Roll] = shm->result.rotz; - data[TX] = shm->result.tx; - data[TY] = shm->result.ty; - data[TZ] = shm->result.tz; - } else { - shm->pause = false; + + { + QMutexLocker l(&ypr_mtx); + + for (int i = 0; i < 6; i++) + data[i] = ypr[i]; } - lck_shm.unlock(); } extern "C" OPENTRACK_EXPORT Metadata* GetMetadata() @@ -157,7 +197,7 @@ extern "C" OPENTRACK_EXPORT ITrackerDialog* GetDialog( ) return new TrackerControls; } -TrackerControls::TrackerControls() +TrackerControls::TrackerControls() : tracker(nullptr) { ui.setupUi(this); ui.cameraName->clear(); @@ -187,5 +227,11 @@ void TrackerControls::doCancel() void TrackerControls::camera_settings() { - open_camera_settings(nullptr, s.camera_name, nullptr); + if (tracker) + { + cv::VideoCapture* cap = ht_capture(tracker->ht); + open_camera_settings(cap, s.camera_name, &tracker->camera_mtx); + } + else + open_camera_settings(nullptr, s.camera_name, nullptr); } diff --git a/ftnoir_tracker_ht/ftnoir_tracker_ht.h b/ftnoir_tracker_ht/ftnoir_tracker_ht.h index 348fc246..b2fcb147 100644 --- a/ftnoir_tracker_ht/ftnoir_tracker_ht.h +++ b/ftnoir_tracker_ht/ftnoir_tracker_ht.h @@ -5,10 +5,8 @@ * copyright notice and this permission notice appear in all copies. */ -#ifndef FTNOIR_TRACKER_HT_H -#define FTNOIR_TRACKER_HT_H +#pragma once -#include "stdafx.h" #include "headtracker-ftnoir.h" #include "ui_ht-trackercontrols.h" #include "ht_video_widget.h" @@ -18,6 +16,12 @@ #include "opentrack/plugin-api.hpp" #include "opentrack/opencv-camera-dialog.hpp" +#include <QThread> +#include <QMutex> +#include <QMutexLocker> +#include <QHBoxLayout> +#include <QString> + using namespace options; struct settings : opts { @@ -33,42 +37,47 @@ struct settings : opts { {} }; -class Tracker : public QObject, public ITracker +class Tracker : public QThread, public ITracker { Q_OBJECT public: Tracker(); ~Tracker() override; + void run() override; void start_tracker(QFrame* frame); void data(double *data); void load_settings(ht_config_t* config); + headtracker_t* ht; + QMutex camera_mtx; private: + double ypr[6]; settings s; - PortableLockedShm lck_shm; - ht_shm_t* shm; - QProcess subprocess; + ht_config_t conf; HTVideoWidget* videoWidget; QHBoxLayout* layout; + QMutex ypr_mtx, frame_mtx; + ht_video_t frame; + volatile bool should_stop; }; -// Widget that has controls for FTNoIR protocol client-settings. class TrackerControls : public ITrackerDialog, protected camera_dialog<Tracker> { Q_OBJECT public: - explicit TrackerControls(); - void register_tracker(ITracker *) {} - void unregister_tracker() {} - + TrackerControls(); + void register_tracker(ITracker * t) + { + tracker = static_cast<Tracker*>(t); + } + void unregister_tracker() { + tracker = nullptr; + } private: Ui::Form ui; settings s; - + Tracker* tracker; private slots: void doOK(); void doCancel(); void camera_settings(); }; - -#endif - diff --git a/ftnoir_tracker_ht/ht-api.h b/ftnoir_tracker_ht/ht-api.h index 4f88a6a3..4629a00b 100644 --- a/ftnoir_tracker_ht/ht-api.h +++ b/ftnoir_tracker_ht/ht-api.h @@ -9,7 +9,8 @@ #if !defined(_WIN32) && !defined(_isnan) # define _isnan isnan #endif -//#include <opencv2/core.hpp> +#include <opencv2/core.hpp> +#include <opencv2/highgui.hpp> struct ht_context; typedef struct ht_context headtracker_t; @@ -44,6 +45,7 @@ typedef struct { HT_API(headtracker_t*) ht_make_context(const ht_config_t* config, const char* filename); HT_API(void) ht_free_context(headtracker_t* ctx); -//HT_API(const cv::Mat) ht_get_bgr_frame(headtracker_t* ctx); +HT_API(const cv::Mat) ht_get_bgr_frame(headtracker_t* ctx); HT_API(bool) ht_cycle(headtracker_t* ctx, ht_result_t* euler); HT_API(void) ht_reset(headtracker_t* ctx); +HT_API(cv::VideoCapture*) ht_capture(headtracker_t* ctx); diff --git a/ftnoir_tracker_ht/stdafx.h b/ftnoir_tracker_ht/stdafx.h index 6f1539b7..e69de29b 100644 --- a/ftnoir_tracker_ht/stdafx.h +++ b/ftnoir_tracker_ht/stdafx.h @@ -1,13 +0,0 @@ -#include <QWidget> -#include <QMessageBox> -#include <QProcess> -#include <QImage> -#include <QLabel> -#include <QCoreApplication> -#include <QIcon> -#include <QHBoxLayout> -#include <QTimer> -#include <QPainter> -#include <QPaintEvent> -#include <QList> -#include <QString> |