#include "app.h" #include "util.h" #include #include #define _USE_MATH_DEFINES #include #include // Constructor Kinect::Kinect() { // Initialize initialize(); } // Destructor Kinect::~Kinect() { // Finalize finalize(); } // Processing void Kinect::run() { // Main Loop while( true ){ // Update Data update(); // Draw Data draw(); // Show Data show(); // Key Check const int key = cv::waitKey( 10 ); if( key == VK_ESCAPE ){ break; } } } // Initialize void Kinect::initialize() { cv::setUseOptimized( true ); // Initialize Sensor initializeSensor(); // Initialize Color initializeColor(); // Initialize Body initializeBody(); // Initialize Face initializeFace(); // Wait a Few Seconds until begins to Retrieve Data from Sensor ( about 2000-[ms] ) std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); } // Initialize Sensor inline void Kinect::initializeSensor() { // Open Sensor ERROR_CHECK( GetDefaultKinectSensor( &kinect ) ); ERROR_CHECK( kinect->Open() ); // Check Open BOOLEAN isOpen = FALSE; ERROR_CHECK( kinect->get_IsOpen( &isOpen ) ); if( !isOpen ){ throw std::runtime_error( "failed IKinectSensor::get_IsOpen( &isOpen )" ); } // Retrieve Coordinate Mapper ERROR_CHECK( kinect->get_CoordinateMapper( &coordinateMapper ) ); } // Initialize Color inline void Kinect::initializeColor() { // Open Color Reader ComPtr colorFrameSource; ERROR_CHECK( kinect->get_ColorFrameSource( &colorFrameSource ) ); ERROR_CHECK( colorFrameSource->OpenReader( &colorFrameReader ) ); // Retrieve Color Description ComPtr colorFrameDescription; ERROR_CHECK( colorFrameSource->CreateFrameDescription( ColorImageFormat::ColorImageFormat_Bgra, &colorFrameDescription ) ); ERROR_CHECK( colorFrameDescription->get_Width( &colorWidth ) ); // 1920 ERROR_CHECK( colorFrameDescription->get_Height( &colorHeight ) ); // 1080 ERROR_CHECK( colorFrameDescription->get_BytesPerPixel( &colorBytesPerPixel ) ); // 4 // Allocation Color Buffer colorBuffer.resize( colorWidth * colorHeight * colorBytesPerPixel ); } // Initialize Body inline void Kinect::initializeBody() { // Open Body Reader ComPtr bodyFrameSource; ERROR_CHECK( kinect->get_BodyFrameSource( &bodyFrameSource ) ); ERROR_CHECK( bodyFrameSource->OpenReader( &bodyFrameReader ) ); // Initialize Body Buffer Concurrency::parallel_for_each( bodies.begin(), bodies.end(), []( IBody*& body ){ SafeRelease( body ); } ); } // Initialize Face inline void Kinect::initializeFace() { // Set Face Features to Enable const DWORD features = FaceFrameFeatures::FaceFrameFeatures_BoundingBoxInColorSpace | FaceFrameFeatures::FaceFrameFeatures_PointsInColorSpace | FaceFrameFeatures::FaceFrameFeatures_RotationOrientation | FaceFrameFeatures::FaceFrameFeatures_Happy | FaceFrameFeatures::FaceFrameFeatures_RightEyeClosed | FaceFrameFeatures::FaceFrameFeatures_LeftEyeClosed | FaceFrameFeatures::FaceFrameFeatures_MouthOpen | FaceFrameFeatures::FaceFrameFeatures_MouthMoved | FaceFrameFeatures::FaceFrameFeatures_LookingAway | FaceFrameFeatures::FaceFrameFeatures_Glasses | FaceFrameFeatures::FaceFrameFeatures_FaceEngagement; Concurrency::parallel_for( 0, BODY_COUNT, [&]( const int count ){ // Create Face Sources ComPtr faceFrameSource; ERROR_CHECK( CreateFaceFrameSource( kinect.Get(), 0, features, &faceFrameSource ) ); // Open Face Readers ERROR_CHECK( faceFrameSource->OpenReader( &faceFrameReader[count] ) ); } ); // Color Table for Visualization colors[0] = cv::Vec3b( 255, 0, 0 ); // Blue colors[1] = cv::Vec3b( 0, 255, 0 ); // Green colors[2] = cv::Vec3b( 0, 0, 255 ); // Red colors[3] = cv::Vec3b( 255, 255, 0 ); // Cyan colors[4] = cv::Vec3b( 255, 0, 255 ); // Magenta colors[5] = cv::Vec3b( 0, 255, 255 ); // Yellow // Face Property Label Text Table for Display labels[0] = "Happy"; labels[1] = "Engaged"; labels[2] = "WearingGlasses"; labels[3] = "LeftEyeClosed"; labels[4] = "RightEyeClosed"; labels[5] = "MouthOpen"; labels[6] = "MouthMoved"; labels[7] = "LookingAway"; } // Finalize void Kinect::finalize() { cv::destroyAllWindows(); // Release Body Buffer Concurrency::parallel_for_each( bodies.begin(), bodies.end(), []( IBody*& body ){ SafeRelease( body ); } ); // Close Sensor if( kinect != nullptr ){ kinect->Close(); } } // Update Data void Kinect::update() { // Update Color updateColor(); // Update Body updateBody(); // Update Face updateFace(); } // Update Color inline void Kinect::updateColor() { // Retrieve Color Frame ComPtr colorFrame; const HRESULT ret = colorFrameReader->AcquireLatestFrame( &colorFrame ); if( FAILED( ret ) ){ return; } // Convert Format ( YUY2 -> BGRA ) ERROR_CHECK( colorFrame->CopyConvertedFrameDataToArray( static_cast( colorBuffer.size() ), &colorBuffer[0], ColorImageFormat::ColorImageFormat_Bgra ) ); } // Update Body inline void Kinect::updateBody() { // Retrieve Body Frame ComPtr bodyFrame; const HRESULT ret = bodyFrameReader->AcquireLatestFrame( &bodyFrame ); if( FAILED( ret ) ){ return; } // Release Previous Bodies Concurrency::parallel_for_each( bodies.begin(), bodies.end(), []( IBody*& body ){ SafeRelease( body ); } ); // Retrieve Body Data ERROR_CHECK( bodyFrame->GetAndRefreshBodyData( static_cast( bodies.size() ), &bodies[0] ) ); Concurrency::parallel_for( 0, BODY_COUNT, [&]( const int count ){ const ComPtr body = bodies[count]; BOOLEAN tracked; ERROR_CHECK( body->get_IsTracked( &tracked ) ); if( !tracked ){ return; } // Retrieve Tracking ID UINT64 trackingId; ERROR_CHECK( body->get_TrackingId( &trackingId ) ); // Registration Tracking ID ComPtr faceFrameSource; ERROR_CHECK( faceFrameReader[count]->get_FaceFrameSource( &faceFrameSource ) ); ERROR_CHECK( faceFrameSource->put_TrackingId( trackingId ) ); } ); } // Update Face inline void Kinect::updateFace() { // ReSet Results results.fill( nullptr ); Concurrency::parallel_for( 0, BODY_COUNT, [&]( const int count ){ // Retrieve Face Frame ComPtr faceFrame; const HRESULT ret = faceFrameReader[count]->AcquireLatestFrame( &faceFrame ); if( FAILED( ret ) ){ return; } // Check Tracking ID is Valid BOOLEAN tracked; ERROR_CHECK( faceFrame->get_IsTrackingIdValid( &tracked ) ); if( !tracked ){ return; } // Release Previous Face Result and Retrieve Face Result ERROR_CHECK( faceFrame->get_FaceFrameResult( &results[count] ) ); } ); } // Draw Data void Kinect::draw() { // Draw Color drawColor(); // Draw Face drawFace(); } // Draw Color inline void Kinect::drawColor() { // Create cv::Mat from Color Buffer colorMat = cv::Mat( colorHeight, colorWidth, CV_8UC4, &colorBuffer[0] ); } // Draw Face inline void Kinect::drawFace() { if( colorMat.empty() ){ return; } Concurrency::parallel_for( 0, BODY_COUNT, [&]( const int count ){ const ComPtr result = results[count]; if( result == nullptr ){ return; } // Retrieve Face Points std::array facePoints; ERROR_CHECK( result->GetFacePointsInColorSpace( FacePointType::FacePointType_Count, &facePoints[0] ) ); drawFacePoints( colorMat, facePoints, 5, colors[count] ); // Retrieve Face Bounding Box RectI boundingBox; ERROR_CHECK( result->get_FaceBoundingBoxInColorSpace( &boundingBox ) ); drawFaceBoundingBox( colorMat, boundingBox, colors[count] ); // Retrieve Face Rotation Quaternion Vector4 rotationQuaternion; ERROR_CHECK( result->get_FaceRotationQuaternion( &rotationQuaternion ) ); drawFaceRotation( colorMat, rotationQuaternion, boundingBox, 1.0, colors[count] ); // Retrieve Face Properties std::array detectionResults; ERROR_CHECK( result->GetFaceProperties( FaceProperty::FaceProperty_Count, &detectionResults[0] ) ); drawFaceProperties( colorMat, detectionResults, boundingBox, 1.0, colors[count] ); } ); } // Draw Face Points inline void Kinect::drawFacePoints( cv::Mat& image, const std::array& points, const int radius, const cv::Vec3b& color, const int thickness ) { if( image.empty() ){ return; } // Draw Points Concurrency::parallel_for_each( points.begin(), points.end(), [&]( const PointF point ){ const int x = static_cast( point.X + 0.5f ); const int y = static_cast( point.Y + 0.5f ); cv::circle( image, cv::Point( x, y ), radius, static_cast( color ), thickness, cv::LINE_AA ); } ); } // Draw Face Bounding Box inline void Kinect::drawFaceBoundingBox( cv::Mat& image, const RectI& box, const cv::Vec3b& color, const int thickness ) { if( image.empty() ){ return; } // Draw Bounding Box const int width = box.Right - box.Left; const int height = box.Bottom - box.Top; cv::rectangle( image, cv::Rect( box.Left, box.Top, width, height ), color, thickness, cv::LINE_AA ); } // Draw Face Rotation Quaternion inline void Kinect::drawFaceRotation( cv::Mat& image, Vector4& quaternion, const RectI& box, const double fontScale,const cv::Vec3b& color, const int thickness ) { if( image.empty() ){ return; } // Convert Quaternion to Degree int pitch, yaw, roll; quaternion2degree( &quaternion, &pitch, &yaw, &roll ); // Draw Rotation const int offset = 30; if( box.Left && box.Bottom ){ std::string rotation = "Pitch, Yaw, Roll : " + std::to_string( pitch ) + ", " + std::to_string( yaw ) + ", " + std::to_string( roll ); cv::putText( image, rotation, cv::Point( box.Left, box.Bottom + offset ), cv::FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, cv::LINE_AA ); } } // Convert Quaternion to Degree inline void Kinect::quaternion2degree( const Vector4* quaternion, int* pitch, int* yaw, int* roll ) { const double x = quaternion->x; const double y = quaternion->y; const double z = quaternion->z; const double w = quaternion->w; *pitch = static_cast( std::atan2( 2 * ( y * z + w * x ), w * w - x * x - y * y + z * z ) / M_PI * 180.0f ); *yaw = static_cast( std::asin( 2 * ( w * y - x * z ) ) / M_PI * 180.0f ); *roll = static_cast( std::atan2( 2 * ( x * y + w * z ), w * w + x * x - y * y - z * z ) / M_PI * 180.0f ); } // Draw Face Properties inline void Kinect::drawFaceProperties( cv::Mat& image, std::array& results, const RectI& box, const double fontScale, const cv::Vec3b& color, const int thickness ) { if( image.empty() ){ return; } // Draw Properties int offset = 30; for( int count = 0; count < FaceProperty::FaceProperty_Count; count++ ){ if( box.Left && box.Bottom ){ offset += 30; std::string result = labels[count] + " : " + result2string( results[count] ); cv::putText( image, result, cv::Point( box.Left, box.Bottom + offset ), cv::FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, cv::LINE_AA ); } } } // Convert Detection Result to String inline std::string Kinect::result2string( DetectionResult& result ) { switch( result ){ case DetectionResult::DetectionResult_Yes: return "Yes"; case DetectionResult::DetectionResult_Maybe: return "Maybe"; case DetectionResult::DetectionResult_No: return "No"; case DetectionResult::DetectionResult_Unknown: return "Unknown"; default: std::runtime_error( "not detection result of face property" ); } return ""; } // Show Data void Kinect::show() { // Show Face showFace(); } // Show Face inline void Kinect::showFace() { if( colorMat.empty() ){ return; } // Resize Image cv::Mat resizeMat; const double scale = 0.5; cv::resize( colorMat, resizeMat, cv::Size(), scale, scale ); // Show Image cv::imshow( "Face", resizeMat ); }