From 4f00c4c74d213a37a4b1a3313e50ce2b4dd51271 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 22 Mar 2013 21:48:15 +0100 Subject: finish rename --- faceapi/xxx_main.cpp | 543 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 543 insertions(+) create mode 100644 faceapi/xxx_main.cpp (limited to 'faceapi/xxx_main.cpp') diff --git a/faceapi/xxx_main.cpp b/faceapi/xxx_main.cpp new file mode 100644 index 00000000..46732cb3 --- /dev/null +++ b/faceapi/xxx_main.cpp @@ -0,0 +1,543 @@ +/******************************************************************************** +* FaceTrackNoIR This program is a private project of the some enthusiastic * +* gamers from Holland, who don't like to pay much for * +* head-tracking. * +* * +* Copyright (C) 2013 Wim Vriend (Developing) * +* Ron Hendriks (Researching and Testing) * +* * +* Homepage * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU General Public License as published by the * +* Free Software Foundation; either version 3 of the License, or (at your * +* option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but * +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * +* more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, see . * +*********************************************************************************/ +/* + Modifications (last one on top): + 20130105 - WVR: Set engine state to TERMINATED, when EXIT. + 20110501 - WVR: Added some command to be handled from FaceTrackNoIR (settings dialog). + 20110322 - WVR: Somehow the video-widget of faceAPI version 3.2.6. does not + work with FaceTrackNoIR (Qt issue?!). To be able to use + release 3.2.6 of faceAPI anyway, this console-app is used. + It exchanges data with FaceTrackNoIR via shared-memory... +*/ + +//Precompiled header +#include "stdafx.h" + +//FaceAPI headers +#include +#include "ftnoir_tracker_sm_types.h" +#include "utils.h" + +//local headers +#include "build_options.h" + +//namespaces +using namespace std; +using namespace sm::faceapi::samplecode; + +// +// global variables +// +HANDLE hSMMemMap = NULL; +SMMemMap *pMemData; +HANDLE hSMMutex; +smEngineHeadPoseData new_head_pose; +bool stopCommand = false; +bool ftnoirConnected = false; + +//enums +enum GROUP_ID +{ + GROUP0=0, +}; + +enum EVENT_ID +{ + EVENT_PING=0, + EVENT_INIT, +}; + +enum INPUT_ID +{ + INPUT0=0, +}; + +//function definitions +void updateHeadPose(smEngineHeadPoseData* temp_head_pose); +bool SMCreateMapping(); + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +//FaceAPI function implementations +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void STDCALL receiveLogMessage(void *, const char *buf, int /*buf_len*/) +{ + Lock lock(g_mutex); // serialize logging calls from different threads to avoid garbled output. + //cout << string(buf); +} + +// Callback function for face-data +void STDCALL receiveFaceData(void *, smEngineFaceData face_data, smCameraVideoFrame video_frame) +{ + Lock lock(g_mutex); + + // Get info including data pointer to original image from camera + smImageInfo video_frame_image_info; + THROW_ON_ERROR(smImageGetInfo(video_frame.image_handle, &video_frame_image_info)); // reentrant, so ok + + // video_frame_image_info.plane_addr[*] now point to the image memory planes. + // The memory is only valid until the end of this routine unless you call smImageAddRef(video_frame.image_handle). + // So you can deep copy the image data here, or use smImageAddRef() and just copy the pointer. + // If you use smImageAddRef() you are responsible for calling smImageDestroy() to avoid a memory leak later. + + // In this callback you will typically want to copy the smEngineFaceData data into your own data-structure. + // Since the smEngineFaceData contains multiple pod types copying it is not atomic and + // a mutex is required to avoid the race-condition with any thread simultaneously + // reading from your data-structure. + // Such a race condition will not crash your code but will create weird noise in the tracking data. + + if (g_do_face_data_printing) + { + //cout << video_frame << " " << face_data; + + // Save any face texture to a PNG file + if (face_data.texture) + { + // Create a unique filename + std::stringstream filename; + filename << "face_" << video_frame.frame_num << ".png"; + // Try saving to a file + if (saveToPNGFile(filename.str(), face_data.texture->image_info) == SM_API_OK) + { + cout << "Saved face-texture to " << filename.str() << std::endl; + } + else + { + cout << "Error saving face-texture to " << filename.str() << std::endl; + } + } + } +} + +// Callback function for head-pose +void STDCALL receiveHeadPose(void *,smEngineHeadPoseData head_pose, smCameraVideoFrame video_frame) +{ + Lock lock(g_mutex); + + // Get info including data pointer to original image from camera + smImageInfo video_frame_image_info; + THROW_ON_ERROR(smImageGetInfo(video_frame.image_handle, &video_frame_image_info)); // reentrant, so ok + + // video_frame_image_info.plane_addr[*] now point to the image memory planes. + // The memory is only valid until the end of this routine unless you call smImageAddRef(video_frame.image_handle). + // So you can deep copy the image data here, or use smImageAddRef() and just copy the pointer. + // If you use smImageAddRef() you are responsible for calling smImageDestroy() to avoid a memory leak later. + + // In this callback you will typically want to copy the smEngineFaceData data into your own data-structure. + // Since the smEngineFaceData contains multiple pod types copying it is not atomic and + // a mutex is required to avoid the race-condition with any thread simultaneously + // reading from your data-structure. + // Such a race condition will not crash your code but will create weird noise in the tracking data. + + if (g_do_head_pose_printing) + { + //cout << video_frame << " " << head_pose << std::endl; + } + + //make a copy of the new head pose data and send it to simconnect + //when we get a simmconnect frame event the new offset will be applied to the camera + updateHeadPose(&head_pose); +} + +// Create the first available camera detected on the system, and return its handle +smCameraHandle createFirstCamera() +{ + // Detect cameras + smCameraInfoList info_list; + THROW_ON_ERROR(smCameraCreateInfoList(&info_list)); + + if (info_list.num_cameras == 0) + { + throw runtime_error("No cameras were detected"); + } + else + { + cout << "The followings cameras were detected: " << endl; + for (int i=0; ihandle,TRUE)); + THROW_ON_ERROR(smHTV2SetHeadPoseFilterLevel(engine_handle, pMemData->initial_filter_level)); + pMemData->handshake = 0; + } + else { + THROW_ON_ERROR(smVideoDisplayCreate(engine_handle,&video_display_handle,0,TRUE)); + } + + // Setup the VideoDisplay + THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags)); + + // Get the handle to the window and change the title to "Hello World" + smWindowHandle win_handle = 0; + THROW_ON_ERROR(smVideoDisplayGetWindowHandle(video_display_handle,&win_handle)); + SetWindowText(win_handle, _T("faceAPI Video-widget")); + MoveWindow(win_handle, 0, 0, 250, 180, true); + + // Loop on the keyboard + while (processKeyPress(engine_handle, video_display_handle) && !stopCommand) + { + // Read and print the current head-pose (if not using the callback mechanism) + #if (USE_HEADPOSE_CALLBACK==0) + #pragma message("Polling Headpose Manually") + if (engine_licensed) + { + smEngineHeadPoseData head_pose; + Lock lock(g_mutex); + + THROW_ON_ERROR(smHTCurrentHeadPose(engine_handle,&head_pose)); + if (g_do_head_pose_printing) + { + std::cout << head_pose << std::endl; + } + + } + #endif + + // NOTE: If you have a windows event loop in your program you + // will not need to call smAPIProcessEvents(). This manually redraws the video window. + THROW_ON_ERROR(smAPIProcessEvents()); + + // Prevent CPU overload in our simple loop. + const int frame_period_ms = 10; + Sleep(frame_period_ms); + + // + // Process the command sent by FaceTrackNoIR. + // + if (ftnoirConnected && (pMemData != 0)) { + + sprintf_s(msg, "Command: %d, \n", pMemData->command, pMemData->par_val_int); + OutputDebugStringA(msg); + std::cout << msg; + + // + // + // Determine the trackers' state and send it to FaceTrackNoIR. + // + THROW_ON_ERROR(smEngineGetState(engine_handle, &state)); + pMemData->state = state; + pMemData->handshake += 1; + + // + // Check if FaceTrackNoIR is still 'in contact'. + // FaceTrackNoIR will reset the handshake, every time in writes data. + // If the value rises too high, this exe will stop itself... + // + if ( pMemData->handshake > 200) { + stopCommand = TRUE; + } + + // + // Check if a command was issued and do something with it! + // + switch (pMemData->command) { + case FT_SM_START: + + // + // Only execute Start, if the engine is not yet tracking. + // + if (state != SM_API_ENGINE_STATE_HT_TRACKING) { + THROW_ON_ERROR(smEngineStart(engine_handle)); // Start tracking + } + pMemData->command = 0; // Reset + break; + + case FT_SM_STOP: + THROW_ON_ERROR(smEngineStop(engine_handle)); // Stop tracking + pMemData->command = 0; // Reset + break; + + case FT_SM_EXIT: + THROW_ON_ERROR(smEngineStop(engine_handle)); // Stop tracking + stopCommand = TRUE; + pMemData->command = 0; // Reset + pMemData->state = SM_API_ENGINE_STATE_TERMINATED; // One last update, before quitting... + break; + + case FT_SM_SET_PAR_FILTER: + THROW_ON_ERROR(smHTV2SetHeadPoseFilterLevel(engine_handle, pMemData->par_val_int)); + pMemData->command = 0; // Reset + break; + + case FT_SM_SHOW_CAM: + THROW_ON_ERROR(smEngineShowCameraControlPanel(engine_handle)); + pMemData->command = 0; // Reset + break; + + default: + pMemData->command = 0; // Reset + // should never be reached + break; + } + } + } // While(1) + + // Destroy engine + THROW_ON_ERROR(smEngineDestroy(&engine_handle)); + // Destroy video display + THROW_ON_ERROR(smVideoDisplayDestroy(&video_display_handle)); + + if (ftnoirConnected) { + if ( pMemData != NULL ) { + UnmapViewOfFile ( pMemData ); + } + + if (hSMMutex != 0) { + CloseHandle( hSMMutex ); + } + hSMMutex = 0; + + if (hSMMemMap != 0) { + CloseHandle( hSMMemMap ); + } + hSMMemMap = 0; + } + +} // run() + +// Application entry point +int _tmain(int /*argc*/, _TCHAR** /*argv*/) +{ + OutputDebugString(_T("_tmain() says: Starting Function\n")); + + try + { + if (SMCreateMapping()) { + run(); + } + } + catch (exception &e) + { + cerr << e.what() << endl; + } + + return smAPIQuit(); +} + +// +// This is called exactly once for each FaceAPI callback and must be within an exclusive lock +// +void updateHeadPose(smEngineHeadPoseData* temp_head_pose) +{ + // + // Check if the pointer is OK and wait for the Mutex. + // + if ( (pMemData != NULL) && (WaitForSingleObject(hSMMutex, 100) == WAIT_OBJECT_0) ) { + + // + // Copy the Raw measurements directly to the client. + // + if (temp_head_pose->confidence > 0.0f) + { + memcpy(&pMemData->data.new_pose,temp_head_pose,sizeof(smEngineHeadPoseData)); + } + ReleaseMutex(hSMMutex); + } +}; + +// +// Create a memory-mapping to the faceAPI data. +// It contains the tracking data, a command-code from FaceTrackNoIR +// +// +bool SMCreateMapping() +{ + OutputDebugString(_T("FTCreateMapping says: Starting Function\n")); + + // + // A FileMapping is used to create 'shared memory' between the faceAPI and FaceTrackNoIR. + // FaceTrackNoIR creates the mapping, this program only opens it. + // If it's not there: the program was apparently started by the user instead of FaceTrackNoIR... + // + // Open an existing FileMapping, Read/Write access + // + hSMMemMap = OpenFileMappingA( FILE_MAP_ALL_ACCESS , false , (LPCSTR) SM_MM_DATA ); + if ( ( hSMMemMap != 0 ) ) { + ftnoirConnected = true; + OutputDebugString(_T("FTCreateMapping says: FileMapping opened successfully...\n")); + pMemData = (SMMemMap *) MapViewOfFile(hSMMemMap, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(TFaceData)); + if (pMemData != NULL) { + OutputDebugString(_T("FTCreateMapping says: MapViewOfFile OK.\n")); + pMemData->state = 0; + } + hSMMutex = CreateMutexA(NULL, false, SM_MUTEX); + } + else { + OutputDebugString(_T("FTCreateMapping says: FileMapping not opened...FaceTrackNoIR not connected!\n")); + ftnoirConnected = false; + pMemData = 0; + } + + return true; +} -- cgit v1.2.3