使用光流来面对地标和稳定


浮华丶
2025-03-13 01:27:21 (8天前)
  1. 我在窗口显示面部和一些特殊点时编写程序(68)。

我使用Haar casscade和FaceLandmarkLBF。我的程序有问题。当脸部有稳定的位置时,脸部点是抖动(摇晃)….

2 条回复
  1. 0# 不想吃东西 | 2019-08-31 10-32



    只有LK跟踪可能还不够。我正在编写一些简单的应用程序,用于校正带有线性卡尔曼滤波器的LK后的地标(

    编辑2
    </强>

    1. - 删除prev地标):



    1.   #include <opencv2/opencv.hpp>
    2. include

      ///
      class PointState
      {
      public:
      PointState(cv::Point2f point)
      :
      m_point(point),
      m_kalman(4, 2, 0, CV_64F)
      {
      Init();
      }

    3. void Update(cv::Point2f point)
    4. {
    5.     cv::Mat measurement(2, 1, CV_64FC1);
    6.     if (point.x < 0 || point.y < 0)
    7.     {
    8.         Predict();
    9.         measurement.at<double>(0) = m_point.x;  //update using prediction
    10.         measurement.at<double>(1) = m_point.y;
    11.         m_isPredicted = true;
    12.     }
    13.     else
    14.     {
    15.         measurement.at<double>(0) = point.x;  //update using measurements
    16.         measurement.at<double>(1) = point.y;
    17.         m_isPredicted = false;
    18.     }
    19.     // Correction
    20.     cv::Mat estimated = m_kalman.correct(measurement);
    21.     m_point.x = static_cast<float>(estimated.at<double>(0));   //update using measurements
    22.     m_point.y = static_cast<float>(estimated.at<double>(1));
    23.     Predict();
    24. }
    25. cv::Point2f GetPoint() const
    26. {
    27.     return m_point;
    28. }
    29. bool IsPredicted() const
    30. {
    31.     return m_isPredicted;
    32. }
    33. private:
      cv::Point2f m_point;
      cv::KalmanFilter m_kalman;

    34. double m_deltaTime = 0.2;
    35. double m_accelNoiseMag = 0.3;
    36. bool m_isPredicted = false;
    37. void Init()
    38. {
    39.     m_kalman.transitionMatrix = (cv::Mat_<double>(4, 4) <<
    40.         1, 0, m_deltaTime, 0,
    41.         0, 1, 0, m_deltaTime,
    42.         0, 0, 1, 0,
    43.         0, 0, 0, 1);
    44.     m_kalman.statePre.at<double>(0) = m_point.x; // x
    45.     m_kalman.statePre.at<double>(1) = m_point.y; // y
    46.     m_kalman.statePre.at<double>(2) = 1; // init velocity x
    47.     m_kalman.statePre.at<double>(3) = 1; // init velocity y
    48.     m_kalman.statePost.at<double>(0) = m_point.x;
    49.     m_kalman.statePost.at<double>(1) = m_point.y;
    50.     cv::setIdentity(m_kalman.measurementMatrix);
    51.     m_kalman.processNoiseCov = (cv::Mat_<double>(4, 4) <<
    52.         pow(m_deltaTime, 4.0) / 4.0, 0, pow(m_deltaTime, 3.0) / 2.0, 0,
    53.         0, pow(m_deltaTime, 4.0) / 4.0, 0, pow(m_deltaTime, 3.0) / 2.0,
    54.         pow(m_deltaTime, 3.0) / 2.0, 0, pow(m_deltaTime, 2.0), 0,
    55.         0, pow(m_deltaTime, 3.0) / 2.0, 0, pow(m_deltaTime, 2.0));
    56.     m_kalman.processNoiseCov *= m_accelNoiseMag;
    57.     cv::setIdentity(m_kalman.measurementNoiseCov, cv::Scalar::all(0.1));
    58.     cv::setIdentity(m_kalman.errorCovPost, cv::Scalar::all(.1));
    59. }
    60. cv::Point2f Predict()
    61. {
    62.     cv::Mat prediction = m_kalman.predict();
    63.     m_point.x = static_cast<float>(prediction.at<double>(0));
    64.     m_point.y = static_cast<float>(prediction.at<double>(1));
    65.     return m_point;
    66. }
    67. };

    68. ///
      void TrackPoints(cv::Mat prevFrame, cv::Mat currFrame,
      const std::vector& currLandmarks,
      std::vector& trackPoints)
      {
      // Lucas-Kanade
      cv::TermCriteria termcrit(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30, 0.01);
      cv::Size winSize(7, 7);

    69. std::vector<uchar> status(trackPoints.size(), 0);
    70. std::vector<float> err;
    71. std::vector<cv::Point2f> newLandmarks;
    72. std::vector<cv::Point2f> prevLandmarks;
    73. std::for_each(trackPoints.begin(), trackPoints.end(), [&](const PointState& pts) { prevLandmarks.push_back(pts.GetPoint()); });
    74. cv::calcOpticalFlowPyrLK(prevFrame, currFrame, prevLandmarks, newLandmarks, status, err, winSize, 3, termcrit, 0, 0.001);
    75. for (size_t i = 0; i < status.size(); ++i)
    76. {
    77.     if (status[i])
    78.     {
    79.         trackPoints[i].Update((newLandmarks[i] + currLandmarks[i]) / 2);
    80.     }
    81.     else
    82.     {
    83.         trackPoints[i].Update(currLandmarks[i]);
    84.     }
    85. }
    86. }

    87. ///
      int main(int argc, char** argv)
      {
      cv::CascadeClassifier faceDetector(“haarcascade_frontalface_alt2.xml”);

    88. cv::Ptr<cv::face::Facemark> facemark = cv::face::FacemarkLBF::create();    
    89. facemark->loadModel("lbfmodel.yaml");
    90. cv::VideoCapture cam(0, cv::CAP_DSHOW);
    91. cv::namedWindow("Facial Landmark Detection", cv::WINDOW_NORMAL);
    92. cv::Mat frame;
    93. cv::Mat currGray;
    94. cv::Mat prevGray;
    95. std::vector<PointState> trackPoints;
    96. trackPoints.reserve(68);
    97. while (cam.read(frame))
    98. {
    99.     std::vector<cv::Rect> faces;
    100.     cv::cvtColor(frame, currGray, cv::COLOR_BGR2GRAY);
    101.     faceDetector.detectMultiScale(currGray, faces, 1.1, 3, cv::CASCADE_FIND_BIGGEST_OBJECT);
    102.     std::vector<std::vector<cv::Point2f>> landmarks;
    103.     bool success = facemark->fit(frame, faces, landmarks);
    104.     if (success)
    105.     {
    106.         if (prevGray.empty())
    107.         {
    108.             trackPoints.clear();
    109.             for (cv::Point2f lp : landmarks[0])
    110.             {
    111.                 trackPoints.emplace_back(lp);
    112.             }
    113.         }
    114.         else
    115.         {
    116.             if (trackPoints.empty())
    117.             {
    118.                 for (cv::Point2f lp : landmarks[0])
    119.                 {
    120.                     trackPoints.emplace_back(lp);
    121.                 }
    122.             }
    123.             else
    124.             {
    125.                 TrackPoints(prevGray, currGray, landmarks[0], trackPoints);
    126.             }
    127.         }
    128.         for (const PointState& tp : trackPoints)
    129.         {
    130.             cv::circle(frame, tp.GetPoint(), 3, tp.IsPredicted() ? cv::Scalar(0, 0, 255) : cv::Scalar(0, 255, 0), cv::FILLED);
    131.         }
    132.         for (cv::Point2f lp : landmarks[0])
    133.         {
    134.             cv::circle(frame, lp, 2, cv::Scalar(255, 0, 255), cv::FILLED);
    135.         }
    136.     }
    137.     cv::imshow("Facial Landmark Detection", frame);
    138.     if (cv::waitKey(1) == 27)
    139.         break;
    140.     prevGray = currGray;
    141. }
    142. return 0;
    143. }

    144. </code>


    因此,margenta点 - 原始地标和绿点 - 在LK + Kalman之后得到纠正:

    结果视频




    您可以使用2个常量更改卡尔曼选项:




    1. double m_deltaTime = 0.2;
      double m_accelNoiseMag = 0.3;

    2. </code>


    这是延迟和噪音。


登录 后才能参与评论