从俯仰角检测头部点头姿势

时间:2017-10-28 10:09:37

标签: c++ opencv math image-processing linear-algebra

我正在制作一个Android应用程序,可以从头部点头姿势中检测出驾驶员的疲劳。

What I did:

  1. 我使用dlib库从图像中检测到68个面部地标。
  2. 使用solvePnP找出旋转矩阵,从那个矩阵我得到了滚动角,俯仰角和偏航角。 现在,我必须从俯仰角度检测头部。
  3. My Problem:

    1. 如何设置一个阈值,使低于或高于阈值的角度可以说是头部点头?
    2. 它导致一些负面角度。负角度在三维轴上意味着什么?
    3. 我的代码:

       void getEulerAngles(Mat &rotCamerMatrix,Vec3d &eulerAngles)
      {
           Mat cameraMatrix,rotMatrix,transVect,rotMatrixX,rotMatrixY,rotMatrixZ;
           double* _r = rotCamerMatrix.ptr<double>();
           double projMatrix[12] = {_r[0],_r[1],_r[2],0,
                        _r[3],_r[4],_r[5],0,
                        _r[6],_r[7],_r[8],0};
      
            decomposeProjectionMatrix( Mat(3,4,CV_64FC1,projMatrix),
                             cameraMatrix,
                             rotMatrix,
                             transVect,
                             rotMatrixX,
                             rotMatrixY,
                             rotMatrixZ,
                             eulerAngles);
      
       }
      int renderToMat(std::vector<full_object_detection>& dets, Mat& dst)
      {
           Scalar color;
           std::vector<cv::Point2d> image_points;
           std::vector<cv::Point3d> model_points;
           string disp;
      
           int sz = 3,l;
           color = Scalar(0,255,0);
           double p1,p2,p3,leftear,rightear,ear=0,yawn=0.00,yaw=0.00,pitch=0.00,roll=0.00;
           l=dets.size();
           //I am calculating only for one face.. so assuming l=1
           for(unsigned long idx = 0; idx < l; idx++)
           {
                image_points.push_back( 
                Point2d(dets[idx].part(30).x(),dets[idx].part(30).x() ) );
                image_points.push_back(Point2d(dets[idx].part(8).x(),dets[idx].part(8).x() ) );
                image_points.push_back(Point2d(dets[idx].part(36).x(),dets[idx].part(36).x() ) );
                image_points.push_back(Point2d(dets[idx].part(45).x(),dets[idx].part(45).x() ) );
                image_points.push_back(Point2d(dets[idx].part(48).x(),dets[idx].part(48).x() ) );
                image_points.push_back(Point2d(dets[idx].part(54).x(),dets[idx].part(54).x() ) );
           }
           double focal_length = dst.cols;
           Point2d center = cv::Point2d(dst.cols/2.00,dst.rows/2.00);
           cv::Mat camera_matrix = (cv::Mat_<double>(3.00,3.00) << focal_length, 0, center.x, 0, focal_length, center.y, 0, 
      0, 1);
           cv::Mat dist_coeffs = cv::Mat::zeros(4,1,cv::DataType<double>::type);
           cv::Mat rotation_vector; //s Rotation in axis-angle form
           cv::Mat translation_vector;
           cv::Mat rotCamerMatrix1;
      
           if(l!=0)
           {
                model_points.push_back(cv::Point3d(0.0f, 0.0f, 0.0f));
                model_points.push_back(cv::Point3d(0.0f, -330.0f, -65.0f));
                model_points.push_back(cv::Point3d(-225.0f, 170.0f, -135.0f));
                model_points.push_back(cv::Point3d(225.0f, 170.0f, -135.0f));
                model_points.push_back(cv::Point3d(-150.0f, -150.0f, -125.0f));
                model_points.push_back(cv::Point3d(150.0f, -150.0f, -125.0f));
                cv::solvePnP(model_points, image_points, camera_matrix, dist_coeffs,rotation_vector, translation_vector);
                Rodrigues(rotation_vector,rotCamerMatrix1);
                Vec3d eulerAngles;
                getEulerAngles(rotCamerMatrix1,eulerAngles);
      
                yaw   = eulerAngles[1];
                pitch = eulerAngles[0];
                roll  = eulerAngles[2];
               /*My problem begins here. I don't know how to set a threshold value for pitch so that I can say a value below or 
      above the pitch is a head nod!*/
      
           }
           return 0;
      }
      

1 个答案:

答案 0 :(得分:1)

首先,您必须了解3D环境中如何使用3个角度。基本上它们相对于原点旋转3D空间中的对象(原点可以根据上下文而改变),但是如何应用3个角度?

这个问题可以表达为:它们按顺序旋转对象。如果你应用偏航,那么俯仰然后滚动它可能会给你一个不同的物体方向,如果你以相反的顺序进行。话虽如此,您必须了解这些值代表什么,以了解如何处理它们。

现在,你问什么是一个好的门槛,这取决于它。什么?好吧,按照它们的应用顺序。例如,如果你首先以45度应用音高使其向下看,然后你应用180度的滚动,那么它就会向上看,所以定义一个阈值有点困难。

由于你有模型点,你可以创建一个3D旋转矩阵并将其应用于不同的俯仰角(其余角度将为0,因此这里的顺序不重要)并将其可视化并选择你考虑的是点头。这有点主观,所以你应该是这样做的。

现在,第二个问题。答案是,这取决于。这个时候呢?你可能会问。简单,你的系统是左撇子还是右撇子?在一个中,这意味着顺时针旋转,另一个逆时针旋转,负号改变方向。因此,在左手系统中,它将是顺时针方向,负号将是逆时针方向。右手系统将逆时针方向,负号将顺时针方向。

作为建议,您可以设置一个矢量(0,0,-1),假设您的z轴朝向后方。然后对其应用旋转并将其投影到平行于z轴的2D平面,这里采用矢量的尖端并查看此处的角度。这样你就可以确定你得到了什么。