#ifndef SM_API_TESTAPPCONSOLE_UTILS_H #define SM_API_TESTAPPCONSOLE_UTILS_H #include "lock.h" #include <exception> #include <iostream> #define THROW_ON_ERROR(x) \ { \ smReturnCode result = (x); \ if (result < 0) \ { \ std::stringstream s; \ s << "API error code: " << result; \ std::cerr << s; \ throw std::exception(); \ } \ } namespace sm { namespace faceapi { namespace samplecode { // Global variables Mutex g_mutex; bool g_ctrl_c_detected(false); bool g_do_head_pose_printing(false); bool g_do_face_data_printing(false); unsigned short g_overlay_flags(SM_API_VIDEO_DISPLAY_HEAD_MESH | SM_API_VIDEO_DISPLAY_PERFORMANCE); // CTRL-C handler function void __cdecl CtrlCHandler(int) { Lock lock(g_mutex); std::cout << "Ctrl-C detected, stopping..." << std::endl; g_ctrl_c_detected = true; } // Radians to degrees conversion float rad2deg(float rad) { return rad*57.2957795f; } void toggleFlag(unsigned short &val, unsigned short flag) { if (val & flag) { val = val & ~flag; } else { val = val | flag; } } // Save an image to PNG file smReturnCode saveToPNGFile(const std::string& filepath, smImageInfo image_info) { smBool ok; smReturnCode error; // Create an API string smStringHandle filepath_handle = 0; ok = (error = smStringCreate(&filepath_handle)) == SM_API_OK; ok = ok && (error = smStringReadBuffer(filepath_handle,filepath.c_str(),filepath.size())) == SM_API_OK; // Create an API image smImageHandle image_handle = 0; smImageMemoryCopyMode copy_mode = SM_API_IMAGE_MEMORYCOPYMODE_AUTO; ok = ok && (error = smImageCreateFromInfo(&image_info,©_mode,&image_handle)) == SM_API_OK; // Save the image as PNG ok = ok && (error = smImageSaveToPNG(image_handle,filepath_handle)) == SM_API_OK; // Destroy the image and string smStringDestroy(&filepath_handle); smImageDestroy(&image_handle); return error; } // Stream operators for printing std::ostream &operator<<(std::ostream & os, const smSize2i &s) { return os << "[" << s.h << "," << s.h << "]"; } std::ostream &operator<<(std::ostream & os, const smCoord3f &pos) { return os << "(" << pos.x << "," << pos.y << "," << pos.z << ")"; } std::ostream &operator<<(std::ostream & os, const smRotEuler &rot) { return os << "(" << rad2deg(rot.x_rads) << "," << rad2deg(rot.y_rads) << "," << rad2deg(rot.z_rads) << ")"; } std::ostream &operator<<(std::ostream & os, const smPixel &p) { return os << "[" << static_cast<int>(p.x) << "," << static_cast<int>(p.y) << "]"; } std::ostream &operator<<(std::ostream & os, const smFaceTexCoord &ftc) { return os << "{" << ftc.u << "," << ftc.v << "}"; } std::ostream &operator<<(std::ostream & os, const smFaceLandmark &lm) { return os << "id "<< lm.id << " fc" << lm.fc << " ftc" << lm.ftc << " pc" << lm.pc << " wc" << lm.wc; } std::ostream &operator<<(std::ostream & os, const smImageInfo &im) { os << "format "; switch (im.format) { case SM_API_IMAGECODE_GRAY_8U: os << "GRAY_8U"; break; case SM_API_IMAGECODE_GRAY_16U: os << "GRAY_16U"; break; case SM_API_IMAGECODE_YUY2: os << "YUY2"; break; case SM_API_IMAGECODE_I420: os << "I420"; break; case SM_API_IMAGECODE_BGRA_32U: os << "BGRA_32U"; break; case SM_API_IMAGECODE_ARGB_32U: os << "ARGB_32U"; break; case SM_API_IMAGECODE_BGR_24U: os << "BGR_24U"; break; case SM_API_IMAGECODE_RGB_24U: os << "RGB_24U"; break; default: os << "unknown"; break; } os << " res" << im.res; os << " plane_addr(" << static_cast<void *>(im.plane_addr[0]) << "," << static_cast<void *>(im.plane_addr[1]) << "," << static_cast<void *>(im.plane_addr[2]) << "," << static_cast<void *>(im.plane_addr[3]) << ")"; os << " step_bytes(" << im.step_bytes[0] << "," << im.step_bytes[1] << "," << im.step_bytes[2] << "," << im.step_bytes[3] << ")"; os << " user_data " << im.user_data; return os; } std::ostream &operator<<(std::ostream & os, const smFaceTexture &t) { os << "type "; switch (t.type) { case SM_ORTHOGRAPHIC_PROJECTION: os << "orthographic"; break; default: os << "unknown"; break; } os << " origin" << t.origin << " scale" << t.scale << std::endl; os << " image_info " << t.image_info << std::endl; os << " num_mask_landmarks " << t.num_mask_landmarks << std::endl; for (int i=0; i<t.num_mask_landmarks; i++) { os << " " << t.mask_landmarks[i] << std::endl; } return os; } // Stream operator for printing face landmarks std::ostream &operator<<(std::ostream &os, const smEngineFaceData &face_data) { fixed(os); showpos(os); os.precision(2); os << "Face Data: " << "origin_wc" << face_data.origin_wc << " " << "num_landmarks " << face_data.num_landmarks << std::endl; for (int i=0; i<face_data.num_landmarks; i++) { os << " " << face_data.landmarks[i] << std::endl; } // Print any face texture info if (face_data.texture) { os << "Face Texture: " << *face_data.texture; } return os; } // Stream operator for printing head-pose data std::ostream &operator<<(std::ostream & os, const smEngineHeadPoseData &head_pose) { fixed(os); showpos(os); os.precision(2); return os << "Head Pose: " << "head_pos" << head_pose.head_pos << " " << "head_rot" << head_pose.head_rot << " " << "left_eye_pos" << head_pose.left_eye_pos << " " << "right_eye_pos" << head_pose.right_eye_pos << " " << "confidence " << head_pose.confidence; } std::ostream &operator<<(std::ostream & os, const smCameraVideoFrame &vf) { fixed(os); showpos(os); os.precision(2); return os << "Framenum: " << vf.frame_num; } // Handles keyboard events: return false if quit. bool processKeyPress(smEngineHandle engine_handle, smVideoDisplayHandle video_display_handle) { Lock lock(g_mutex); if (g_ctrl_c_detected) { return false; } if (!_kbhit()) { return true; } int key = _getch(); switch (key) { case 'q': return false; case 'r': { // Manually restart the tracking THROW_ON_ERROR(smEngineStart(engine_handle)); std::cout << "Restarting tracking" << std::endl; } return true; case 'a': { // Toggle auto-restart mode int on; THROW_ON_ERROR(smHTGetAutoRestartMode(engine_handle,&on)); THROW_ON_ERROR(smHTSetAutoRestartMode(engine_handle,!on)); std::cout << "Autorestart-mode is " << (on?"on":"off") << std::endl; } return true; case '1': toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_REFERENCE_FRAME); THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags)); return true; case '2': toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_PERFORMANCE); THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags)); return true; case '3': toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_HEAD_MESH); THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags)); return true; case '4': toggleFlag(g_overlay_flags,SM_API_VIDEO_DISPLAY_LANDMARKS); THROW_ON_ERROR(smVideoDisplaySetFlags(video_display_handle,g_overlay_flags)); return true; case 'l': if (smAPINonCommercialLicense() == SM_API_TRUE) { return false; } else { int on; THROW_ON_ERROR(smHTGetLipTrackingEnabled(engine_handle,&on)); THROW_ON_ERROR(smHTSetLipTrackingEnabled(engine_handle,!on)); } return true; case 'e': if (smAPINonCommercialLicense() == SM_API_TRUE) { return false; } else { int on; THROW_ON_ERROR(smHTGetEyebrowTrackingEnabled(engine_handle,&on)); THROW_ON_ERROR(smHTSetEyebrowTrackingEnabled(engine_handle,!on)); } return true; case 'h': if (smEngineIsLicensed(engine_handle) != SM_API_OK) { return false; } else { g_do_head_pose_printing = !g_do_head_pose_printing; std::cout << "HeadPose printing is " << (g_do_head_pose_printing?"on":"off") << std::endl; } return true; case 'f': if (smEngineIsLicensed(engine_handle) != SM_API_OK) { return false; } else { g_do_face_data_printing = !g_do_face_data_printing; std::cout << "FaceData printing is " << (g_do_face_data_printing?"on":"off") << std::endl; } return true; default: return true; } } // Setup console window geometry / font etc void initConsole() { HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Buffer of 255 x 1024 COORD buffer_size; buffer_size.X = 255; buffer_size.Y = 1024; SetConsoleScreenBufferSize(console_handle, buffer_size); // Window size of 120 x 50 SMALL_RECT window_size; window_size.Left = 0; window_size.Right = 120; window_size.Top = 0; window_size.Bottom = 50; SetConsoleWindowInfo(console_handle,TRUE,&window_size); // Green text SetConsoleTextAttribute(console_handle, FOREGROUND_GREEN | FOREGROUND_INTENSITY); // ShowWindow(GetConsoleWindow(), SW_HIDE); } } } } #endif