Track current frame features and find the relative transformation
| 104 | |
| 105 | // Track current frame features and find the relative transformation |
| 106 | bool CVStabilization::TrackFrameFeatures(cv::Mat frame, size_t frameNum){ |
| 107 | // Check if there are black frames |
| 108 | if(cv::countNonZero(frame) < 1){ |
| 109 | return false; |
| 110 | } |
| 111 | |
| 112 | // Initialize prev_grey if not |
| 113 | if(prev_grey.empty()){ |
| 114 | prev_grey = frame; |
| 115 | return true; |
| 116 | } |
| 117 | |
| 118 | // OpticalFlow features vector |
| 119 | std::vector <cv::Point2f> prev_corner, cur_corner; |
| 120 | std::vector <cv::Point2f> prev_corner2, cur_corner2; |
| 121 | std::vector <uchar> status; |
| 122 | std::vector <float> err; |
| 123 | // Extract new image features |
| 124 | cv::goodFeaturesToTrack(prev_grey, prev_corner, 200, 0.01, 30); |
| 125 | // Track features |
| 126 | cv::calcOpticalFlowPyrLK(prev_grey, frame, prev_corner, cur_corner, status, err); |
| 127 | // Remove untracked features |
| 128 | for(size_t i=0; i < status.size(); i++) { |
| 129 | if(status[i]) { |
| 130 | prev_corner2.push_back(prev_corner[i]); |
| 131 | cur_corner2.push_back(cur_corner[i]); |
| 132 | } |
| 133 | } |
| 134 | // In case no feature was detected |
| 135 | if(prev_corner2.empty() || cur_corner2.empty()){ |
| 136 | last_T = cv::Mat(); |
| 137 | // prev_grey = cv::Mat(); |
| 138 | return false; |
| 139 | } |
| 140 | |
| 141 | // Translation + rotation only |
| 142 | cv::Mat T = cv::estimateAffinePartial2D(prev_corner2, cur_corner2); // false = rigid transform, no scaling/shearing |
| 143 | |
| 144 | double da, dx, dy; |
| 145 | // If T has nothing inside return (probably a segment where there is nothing to stabilize) |
| 146 | if(T.size().width == 0 || T.size().height == 0){ |
| 147 | return false; |
| 148 | } |
| 149 | else{ |
| 150 | // If no transformation is found, just use the last known good transform |
| 151 | if(T.data == NULL){ |
| 152 | if(!last_T.empty()) |
| 153 | last_T.copyTo(T); |
| 154 | else |
| 155 | return false; |
| 156 | } |
| 157 | // Decompose T |
| 158 | dx = T.at<double>(0,2); |
| 159 | dy = T.at<double>(1,2); |
| 160 | da = atan2(T.at<double>(1,0), T.at<double>(0,0)); |
| 161 | } |
| 162 | |
| 163 | // Filter transformations parameters, if they are higher than these: return |
nothing calls this directly
no test coverage detected