Fix bugs
authorTae-Young Chung <ty83.chung@samsung.com>
Thu, 27 Jun 2024 05:36:57 +0000 (14:36 +0900)
committerTae-Young Chung <ty83.chung@samsung.com>
Thu, 27 Jun 2024 05:37:05 +0000 (14:37 +0900)
- Fix wrong camera parameter files
- Get rotation results as Euler angle (Rad) not Rodrigues
- Get translation results as double, not float

Change-Id: I6fd847399b91ce16c559aa411f8452c83dbea923
Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
.gitignore [new file with mode: 0644]
services/CMakeLists.txt
services/smart_pointer/include/HeadPoseEstimator.h
services/smart_pointer/res/camera_param_rs2.yaml [deleted file]
services/smart_pointer/res/camera_param_rs2_1920.yaml [new file with mode: 0755]
services/smart_pointer/res/camera_param_rs2_640.yaml [new file with mode: 0755]
services/smart_pointer/src/GazeEstimator.cpp
services/smart_pointer/src/HeadPoseEstimator.cpp
services/smart_pointer/src/SmartPointer.cpp
test/services/smartpointer.cpp

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..63e67e0
--- /dev/null
@@ -0,0 +1 @@
+install_rpm.sh
index 2e2b55771b02cd79bdc5b0d034983d242dfbab88..3bd813f20e5d95b5867a5a317f6ad4ddfd6ef667 100644 (file)
@@ -16,7 +16,8 @@ IF (${USE_SMARTPOINTER})
     LIST(APPEND SERVICE_HEADER_LIST ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/include)
     SET(SINGLEO_SERVICE_RESOURCE_FILES ${SINGLEO_SERVICE_RESOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/res/pdm.txt)
     SET(SINGLEO_SERVICE_RESOURCE_FILES ${SINGLEO_SERVICE_RESOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/res/camera_param_dummy.yaml)
-    SET(SINGLEO_SERVICE_RESOURCE_FILES ${SINGLEO_SERVICE_RESOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/res/camera_param_rs2.yaml)
+    SET(SINGLEO_SERVICE_RESOURCE_FILES ${SINGLEO_SERVICE_RESOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/res/camera_param_rs2_1920.yaml)
+    SET(SINGLEO_SERVICE_RESOURCE_FILES ${SINGLEO_SERVICE_RESOURCE_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/smart_pointer/res/camera_param_rs2_640.yaml)
 ENDIF()
 
 ADD_LIBRARY(${PROJECT_NAME} SHARED ${SINGLEO_SERVICE_SOURCE_FILES})
index bb507e3f741ef311a572a2eb18a0e0c5273cc008..23ad2eb5478d8fb12e73617515f416c451bce602 100644 (file)
@@ -50,6 +50,14 @@ private:
     std::vector<cv::Point3f> _pose_axes_3d;
     std::vector<singleo::services::smartpointer::Point2f> _pose_axes;
 
+    bool _isInitialized;
+    bool validRotationMatrix(cv::Mat &matrix);
+    cv::Vec3f rotationMatrixToEulerAngles(cv::Mat &matrix);
+    double calculateReProjectectionError();
+    void print3x3Matrix(cv::Mat &matrix, std::string name);
+    void print3x1Matrix(cv::Mat &matrix, std::string name);
+    void printVec3f(cv::Vec3f &vec, std::string name);
+
 public:
     HeadPoseEstimator(const std::vector<singleo::inference::FACE_COMPONENTS> &components);
     ~HeadPoseEstimator();
diff --git a/services/smart_pointer/res/camera_param_rs2.yaml b/services/smart_pointer/res/camera_param_rs2.yaml
deleted file mode 100755 (executable)
index f667215..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-%YAML:1.0
-camera_matrix: !!opencv-matrix
-  rows: 3
-  cols: 3
-  dt: f
-  data: [949.468, 0.0, 961.524,
-        0.0, 949.468, 524.013,
-        0.0, 0.0, 1.0]
-dist_coeff: !!opencv-matrix
-  rows: 5
-  cols: 1
-  dt: f
-  data: [0.0, 0.0, 0.0, 0.0, 0.0]
\ No newline at end of file
diff --git a/services/smart_pointer/res/camera_param_rs2_1920.yaml b/services/smart_pointer/res/camera_param_rs2_1920.yaml
new file mode 100755 (executable)
index 0000000..f667215
--- /dev/null
@@ -0,0 +1,13 @@
+%YAML:1.0
+camera_matrix: !!opencv-matrix
+  rows: 3
+  cols: 3
+  dt: f
+  data: [949.468, 0.0, 961.524,
+        0.0, 949.468, 524.013,
+        0.0, 0.0, 1.0]
+dist_coeff: !!opencv-matrix
+  rows: 5
+  cols: 1
+  dt: f
+  data: [0.0, 0.0, 0.0, 0.0, 0.0]
\ No newline at end of file
diff --git a/services/smart_pointer/res/camera_param_rs2_640.yaml b/services/smart_pointer/res/camera_param_rs2_640.yaml
new file mode 100755 (executable)
index 0000000..4bcf910
--- /dev/null
@@ -0,0 +1,13 @@
+%YAML:1.0
+camera_matrix: !!opencv-matrix
+  rows: 3
+  cols: 3
+  dt: f
+  data: [379.787, 0.0, 320.610,
+        0.0, 379.787, 233.605,
+        0.0, 0.0, 1.0]
+dist_coeff: !!opencv-matrix
+  rows: 5
+  cols: 1
+  dt: f
+  data: [0.0, 0.0, 0.0, 0.0, 0.0]
\ No newline at end of file
index 71afeea99f916d7efaaf49f3fbe1494e9793d236..1e6432b8a1281ad268c819a7127242ee219eb4de 100644 (file)
@@ -60,6 +60,7 @@ PoseVector &GazeEstimator::estimateHeadpose(BaseDataType &input)
     if (result._rects.empty())
         return _headPose;
 
+    // Euler (x,y,z)
      _headPose = _head_pose_estimator->estimate(result._landmarks[0]);
     vector<Point2f> poseAxes = _head_pose_estimator->getPoseAxes();
 
index 754a04a9dcf56f431297116032fa30dda68577cd..59e4c604d3ba4aa4e49a8f060dcda25404955a01 100644 (file)
@@ -57,7 +57,7 @@ HeadPoseEstimator::HeadPoseEstimator(const vector<FACE_COMPONENTS> &components)
     _rotation_vector = Mat(Size(3,1), CV_32FC1);
     _translation_vector = Mat(Size(3,1), CV_32FC1);
 
-    CameraParamManager cam_dummy("/usr/share/singleo/camera_param_rs2.yaml");
+    CameraParamManager cam_dummy("/usr/share/singleo/camera_param_rs2_640.yaml");
 
     _camera_matrix = Mat::zeros(Size(3,3), CV_32FC1);
     tuple<float, float> focalLength = cam_dummy.getFocalLengthXY();
@@ -93,6 +93,30 @@ HeadPoseEstimator::~HeadPoseEstimator()
 
 }
 
+void HeadPoseEstimator::print3x3Matrix(cv::Mat &matrix, std::string name)
+{
+    SINGLEO_LOGI("Print %s matrix", name.c_str());
+    SINGLEO_LOGI("%d x %d", matrix.cols, matrix.rows);
+    for (int r = 0; r < matrix.rows; ++r) {
+        SINGLEO_LOGD("%f, %f, %f", matrix.at<float>(r, 0), matrix.at<float>(r, 1), matrix.at<float>(r, 2));
+    }
+}
+
+void HeadPoseEstimator::print3x1Matrix(cv::Mat &matrix, std::string name)
+{
+    SINGLEO_LOGI("Print %s matrix", name.c_str());
+    SINGLEO_LOGI("%d x %d", matrix.cols, matrix.rows);
+    for (int r = 0; r < matrix.rows; ++r) {
+        SINGLEO_LOGD("%f", matrix.at<double>(r, 0));
+    }
+}
+
+void HeadPoseEstimator::printVec3f(cv::Vec3f &vec, std::string name)
+{
+    SINGLEO_LOGI("Print %s vector", name.c_str());
+    SINGLEO_LOGD("%.3f, %.3f, %.3f", vec[0], vec[1], vec[2]);
+}
+
 PoseVector HeadPoseEstimator::estimate(const vector<Point> &landmark2d)
 {
     Timer timer;
@@ -118,15 +142,22 @@ PoseVector HeadPoseEstimator::estimate(const vector<Point> &landmark2d)
             _rotation_vector, _translation_vector, true, cv::SOLVEPNP_ITERATIVE);
     SINGLEO_LOGI("2nd solvePnP takes %d ms", timer.check_ms());
 
-    return PoseVector{ Point3f{ _rotation_vector.at<float>(0), _rotation_vector.at<float>(1), _rotation_vector.at<float>(2)},
-                     Point3f{ _translation_vector.at<float>(0), _translation_vector.at<float>(1), _translation_vector.at<float>(2)} };
+    timer.reset();
+    cv::Rodrigues(_rotation_vector, _rotation_matrix);
+    auto rotation_eulerAngles = rotationMatrixToEulerAngles(_rotation_matrix);
+    SINGLEO_LOGI("Rodrigues takes %d ms", timer.check_ms());
+
+    return PoseVector{ Point3f{ rotation_eulerAngles[0], rotation_eulerAngles[1], rotation_eulerAngles[2]},
+                     Point3f{ static_cast<float>(_translation_vector.at<double>(0)),
+                              static_cast<float>(_translation_vector.at<double>(1)),
+                              static_cast<float>(_translation_vector.at<double>(2))} };
 }
 
 vector<Point2f> &HeadPoseEstimator::getPoseAxes()
 {
     std::vector<cv::Point2f> poseAxes2d;
     cv::projectPoints(_pose_axes_3d, _rotation_vector, _translation_vector, _camera_matrix, _camera_dist_coeff, poseAxes2d);
-    SINGLEO_LOGI("projectPoints %zd", poseAxes2d.size());
+
     for (size_t i = 0; i < poseAxes2d.size(); i++) {
         _pose_axes[i].x = poseAxes2d[i].x;
         _pose_axes[i].y = poseAxes2d[i].y;
@@ -135,11 +166,57 @@ vector<Point2f> &HeadPoseEstimator::getPoseAxes()
     return _pose_axes;
 }
 
+double HeadPoseEstimator::calculateReProjectectionError()
+{
+    std::vector<cv::Point2f> landmarks_2d;
+    cv::projectPoints(_landmarks_3d, _rotation_vector, _translation_vector, _camera_matrix, _camera_dist_coeff, landmarks_2d);
+    double error = 0.0f;
+
+    for (size_t  i = 0; i < _landmarks_2d.size(); i++) {
+        double diff = cv::norm(cv::Mat(_landmarks_2d[i]), cv::Mat(landmarks_2d[i]), cv::NORM_L2);
+        error += diff * diff;
+    }
+
+    return std::sqrt(error/_landmarks_2d.size());
+}
+
 std::vector<int> &HeadPoseEstimator::getFaceComponentsIndieces()
 {
     return _faceComponentIndices;
 }
 
+bool HeadPoseEstimator::validRotationMatrix(cv::Mat &matrix)
+{
+    Mat matrixT;
+    transpose(matrix, matrixT);
+    Mat shouldBeIdentity = matrixT * matrix;
+    Mat I = Mat::eye(3,3, shouldBeIdentity.type());
+
+    return  norm(I, shouldBeIdentity) < 1e-6;
+}
+
+Vec3f HeadPoseEstimator::rotationMatrixToEulerAngles(cv::Mat &matrix)
+{
+    float sy = sqrt(matrix.at<double>(0,0) * matrix.at<double>(0,0) +  matrix.at<double>(1,0) * matrix.at<double>(1,0) );
+
+    bool singular = sy < 1e-6; // If
+
+    float x, y, z;
+    if (!singular)
+    {
+        x = atan2(matrix.at<double>(2,1) , matrix.at<double>(2,2));
+        y = atan2(-matrix.at<double>(2,0), sy);
+        z = atan2(matrix.at<double>(1,0), matrix.at<double>(0,0));
+    }
+    else
+    {
+        x = atan2(-matrix.at<double>(1,2), matrix.at<double>(1,1));
+        y = atan2(-matrix.at<double>(2,0), sy);
+        z = 0;
+    }
+    return Vec3f(x, y, z);
+}
+
 } // smartpointer
 } // services
 } // singleo
index 24b86e3da9374fdf737345781c970cf860259955..0a7f73a321bf475829568f1493c37ba78aabb07f 100644 (file)
@@ -117,19 +117,21 @@ void SmartPointer::perform()
                ImageDataType input_data;
                _data_feeder->capture(input_data);
                preprocessor.update(input_data);
+               // Euler Angle (x,y,z)
                _head_pose = _gaze_estimator->estimateHeadpose(preprocessor.getData());
                // auto gestureResult = _gesture_recognizer->recognizeGesture(preprocessor.getData());
 
+               updateResult(_head_pose);
                _cursor.x = ++_cursor.x % get<0>(_displayInfo.getResolutionSize());
                _cursor.y = ++_cursor.y % get<1>(_displayInfo.getResolutionSize());
 
                _pointer->sendMouseEvent(_cursor.x, _cursor.y, ActionType::POINTER_MOVE);
-               updateResult(_head_pose);
+
                if (_user_cb) {
                        SINGLEO_LOGD("user callback in perform()");
                        _user_cb(input_data.ptr, input_data.width, input_data.height, input_data.byte_per_pixel, 
                        static_cast<void *>(&(_pointerPosition.pose._rot_vec)),
-                       nullptr /*static_cast<void *>(&gestureResult)*/);
+                       static_cast<void *>(&(_pointerPosition.pose._tran_vec))/*nullptr*/ /*static_cast<void *>(&gestureResult)*/);
                }
        }
 
index bb7b13e114fb4a2dc1f9f1bf33c0559f80911bd6..828529266f38c0ed4c72cdc51a3a33dc1ebdbf67 100644 (file)
@@ -59,20 +59,25 @@ void user_callback(void *user_data)
 }
 
 void data_feeder_cb(unsigned char *buffer, unsigned int width, unsigned int height, unsigned int bytes_per_pixel,
-                                  void *headPose, void *gesture)
+                                  void *headRot, void *headTrans)
 {
        cv::Mat result(cv::Size(width, height), CV_MAKETYPE(CV_8U, bytes_per_pixel), buffer);
        cv::Mat vizData;
        cv::cvtColor(result, vizData, cv::COLOR_BGR2RGBA);
 
-       Point3f *dof3d = static_cast<Point3f *>(headPose);
-       cout << "[Pitch, Yaw, Roll]: [ " << dof3d->x << ", " << dof3d->y << ", " << dof3d->z << " ]" << endl;
+       Point3f *dof3d_rot = static_cast<Point3f *>(headRot);
+       Point3f *dof3d_trans = static_cast<Point3f *>(headTrans);
+       cout << "[Pitch, Yaw, Roll]: [ " << dof3d_rot->x << ", " << dof3d_rot->y << ", " << dof3d_rot->z << " ]" << endl;
 
-       if (gesture) {
-               string *gesture_str = static_cast<string *>(gesture);
-               cv::putText(vizData, *gesture_str, cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0, 255), 2);
-               cout << "[Gesture Str]: " << *gesture_str << endl;
-       }
+       cout << setprecision(5) << "[X]: [ " << dof3d_trans->x << " ]" << endl;
+       cout << setprecision(5) << "[Y]: [ " << dof3d_trans->y << " ]" << endl;
+       cout << setprecision(5) << "[Z]: [ " << dof3d_trans->z << " ]" << endl;
+
+       // if (gesture) {
+       //      string *gesture_str = static_cast<string *>(gesture);
+       //      cv::putText(vizData, *gesture_str, cv::Point(30, 30), cv::FONT_HERSHEY_SIMPLEX, 0.5, cv::Scalar(0, 255, 0, 255), 2);
+       //      cout << "[Gesture Str]: " << *gesture_str << endl;
+       // }
 
        singleo_util_visualizer_2d(vizData, NULL);
 }