diff options
-rw-r--r-- | tracker-easy/point-extractor.cpp | 12 | ||||
-rw-r--r-- | tracker-easy/point-extractor.h | 3 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.cpp | 315 | ||||
-rw-r--r-- | tracker-easy/tracker-easy.h | 1 |
4 files changed, 173 insertions, 158 deletions
diff --git a/tracker-easy/point-extractor.cpp b/tracker-easy/point-extractor.cpp index c1f525c9..cc58c70c 100644 --- a/tracker-easy/point-extractor.cpp +++ b/tracker-easy/point-extractor.cpp @@ -78,20 +78,20 @@ namespace EasyTracker } // Contours detection - std::vector<std::vector<cv::Point> > contours; - cv::findContours(iFrameGray, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); + iContours.clear(); + cv::findContours(iFrameGray, iContours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); // Workout which countours are valid points - for (size_t i = 0; i < contours.size(); i++) + for (size_t i = 0; i < iContours.size(); i++) { if (aPreview) { - cv::drawContours(*aPreview, contours, (int)i, CV_RGB(255, 0, 0), 2); + cv::drawContours(*aPreview, iContours, (int)i, CV_RGB(255, 0, 0), 2); } cv::Rect bBox; - bBox = cv::boundingRect(contours[i]); + bBox = cv::boundingRect(iContours[i]); // Make sure bounding box matches our criteria if (bBox.width >= s.min_point_size @@ -116,7 +116,7 @@ namespace EasyTracker // Typically noise comming from zippers and metal parts on your clothing. // With a cap tracker it also successfully discards noise from glasses. // However it may not work as good with a clip user wearing glasses. - while (aPoints.size() > 3) // Until we have no more than three points + while (aPoints.size() > KPointCount) // Until we have no more than three points { int maxY = 0; size_t index = -1; diff --git a/tracker-easy/point-extractor.h b/tracker-easy/point-extractor.h index 7827bb30..3c65b193 100644 --- a/tracker-easy/point-extractor.h +++ b/tracker-easy/point-extractor.h @@ -34,6 +34,9 @@ namespace EasyTracker cv::Mat iFrameChannelSizeOne; // Our frame with a single 8 bits channel cv::Mat iFrameGray; + // + std::vector<std::vector<cv::Point> > iContours; + }; } diff --git a/tracker-easy/tracker-easy.cpp b/tracker-easy/tracker-easy.cpp index 4afb928a..b15db44e 100644 --- a/tracker-easy/tracker-easy.cpp +++ b/tracker-easy/tracker-easy.cpp @@ -122,197 +122,208 @@ namespace EasyTracker iDistCoeffsMatrix.at<double>(7, 0) = iCameraInfo.radialDistortionSixthOrder; // Radial sixth order } - - void Tracker::run() + /// + /// + /// + void Tracker::ProcessFrame() { - maybe_reopen_camera(); + // Create OpenCV matrix from our frame + // TODO: Assert channel size is one or two + iMatFrame = cv::Mat(iFrame.height, iFrame.width, CV_MAKETYPE((iFrame.channelSize == 2 ? CV_16U : CV_8U), iFrame.channels), iFrame.data, iFrame.stride); + iFrameCount++; - iFpsTimer.start(); + bool doPreview = check_is_visible(); + if (doPreview) + { + iPreview = iMatFrame; + } + + iPoints.clear(); + iPointExtractor.ExtractPoints(iMatFrame, (doPreview ? &iPreview.iFrameRgb : nullptr), iPoints); + + const bool success = iPoints.size() >= KPointCount; + + int topPointIndex = -1; - while (!isInterruptionRequested()) { - iTimer.start(); + QMutexLocker l(¢er_lock); - bool new_frame = false; + if (success) { - QMutexLocker l(&camera_mtx); + ever_success.store(true, std::memory_order_relaxed); - if (camera) + // Solve P3P problem with OpenCV + + //Bitmap origin is top left + iTrackedPoints.clear(); + // Tracked points must match the order of the object model points. + // Find top most point, that's the one with min Y as we assume our guy's head is not up side down + int minY = std::numeric_limits<int>::max(); + for (int i = 0; i < 3; i++) { - std::tie(iFrame, new_frame) = camera->get_frame(); + if (iPoints[i].y < minY) + { + minY = iPoints[i].y; + topPointIndex = i; + } } - - } - if (new_frame) - { - // Create OpenCV matrix from our frame - // TODO: Assert channel size is one or two - iMatFrame = cv::Mat(iFrame.height, iFrame.width, CV_MAKETYPE((iFrame.channelSize == 2 ? CV_16U : CV_8U), iFrame.channels), iFrame.data, iFrame.stride); - iFrameCount++; + int rightPointIndex = -1; + int maxX = 0; + + // Find right most point + for (int i = 0; i < 3; i++) + { + // Excluding top most point + if (i != topPointIndex && iPoints[i].x > maxX) + { + maxX = iPoints[i].x; + rightPointIndex = i; + } + } - const bool preview_visible = check_is_visible(); - if (preview_visible) + // Find left most point + int leftPointIndex = -1; + for (int i = 0; i < 3; i++) { - iPreview = iMatFrame; + // Excluding top most point + if (i != topPointIndex && i != rightPointIndex) + { + leftPointIndex = i; + break; + } } - iPoints.clear(); - iPointExtractor.ExtractPoints(iMatFrame, (preview_visible ? &iPreview.iFrameRgb : nullptr), iPoints); + // + iTrackedPoints.push_back(iPoints[rightPointIndex]); + iTrackedPoints.push_back(iPoints[leftPointIndex]); + iTrackedPoints.push_back(iPoints[topPointIndex]); - const bool success = iPoints.size() >= KPointCount; + dbgout << "Object: " << iModel << "\n"; + dbgout << "Points: " << iTrackedPoints << "\n"; - int topPointIndex = -1; - { - QMutexLocker l(¢er_lock); + // TODO: try SOLVEPNP_AP3P too, make it a settings option? + iAngles.clear(); + iBestSolutionIndex = -1; + int solutionCount = cv::solveP3P(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, iRotations, iTranslations, cv::SOLVEPNP_P3P); - if (success) + if (solutionCount > 0) + { + dbgout << "Solution count: " << solutionCount << "\n"; + int minPitch = std::numeric_limits<int>::max(); + // Find the solution we want amongst all possible ones + for (int i = 0; i < solutionCount; i++) { - ever_success.store(true, std::memory_order_relaxed); - - // Solve P3P problem with OpenCV - - //Bitmap origin is top left - iTrackedPoints.clear(); - // Tracked points must match the order of the object model points. - // Find top most point, that's the one with min Y as we assume our guy's head is not up side down - int minY = std::numeric_limits<int>::max(); - for (int i = 0; i < 3; i++) + dbgout << "Translation:\n"; + dbgout << iTranslations.at(i); + dbgout << "\n"; + dbgout << "Rotation:\n"; + //dbgout << rvecs.at(i); + cv::Mat rotationCameraMatrix; + cv::Rodrigues(iRotations[i], rotationCameraMatrix); + cv::Vec3d angles; + getEulerAngles(rotationCameraMatrix, angles); + iAngles.push_back(angles); + + // Check if pitch is closest to zero + int absolutePitch = std::abs(angles[0]); + if (minPitch > absolutePitch) { - if (iPoints[i].y < minY) - { - minY = iPoints[i].y; - topPointIndex = i; - } + // The solution with pitch closest to zero is the one we want + minPitch = absolutePitch; + iBestSolutionIndex = i; } - int rightPointIndex = -1; - int maxX = 0; + dbgout << angles; + dbgout << "\n"; + } - // Find right most point - for (int i = 0; i < 3; i++) - { - // Excluding top most point - if (i != topPointIndex && iPoints[i].x > maxX) - { - maxX = iPoints[i].x; - rightPointIndex = i; - } - } + dbgout << "\n"; + } + } - // Find left most point - int leftPointIndex = -1; - for (int i = 0; i < 3; i++) - { - // Excluding top most point - if (i != topPointIndex && i != rightPointIndex) - { - leftPointIndex = i; - break; - } - } + // Send solution data back to main thread + QMutexLocker l2(&data_lock); + if (iBestSolutionIndex != -1) + { + iBestAngles = iAngles[iBestSolutionIndex]; + iBestTranslation = iTranslations[iBestSolutionIndex]; + } + + } - // - iTrackedPoints.push_back(iPoints[rightPointIndex]); - iTrackedPoints.push_back(iPoints[leftPointIndex]); - iTrackedPoints.push_back(iPoints[topPointIndex]); + if (doPreview) + { + std::ostringstream ss; + ss << "FPS: " << iFps << "/" << iSkippedFps; + iPreview.DrawInfo(ss.str()); - dbgout << "Object: " << iModel << "\n"; - dbgout << "Points: " << iTrackedPoints << "\n"; + // + if (topPointIndex != -1) + { + // Render a cross to indicate which point is the head + iPreview.DrawCross(iPoints[topPointIndex]); + } + // Show full size preview pop-up + if (iSettings.debug) + { + cv::imshow("Preview", iPreview.iFrameRgb); + cv::waitKey(1); + } - // TODO: try SOLVEPNP_AP3P too, make it a settings option? - iAngles.clear(); - iBestSolutionIndex = -1; - int solutionCount = cv::solveP3P(iModel, iTrackedPoints, iCameraMatrix, iDistCoeffsMatrix, iRotations, iTranslations, cv::SOLVEPNP_P3P); + // Update preview widget + widget->update_image(iPreview.get_bitmap()); - if (solutionCount > 0) - { - dbgout << "Solution count: " << solutionCount << "\n"; - int minPitch = std::numeric_limits<int>::max(); - // Find the solution we want amongst all possible ones - for (int i = 0; i < solutionCount; i++) - { - dbgout << "Translation:\n"; - dbgout << iTranslations.at(i); - dbgout << "\n"; - dbgout << "Rotation:\n"; - //dbgout << rvecs.at(i); - cv::Mat rotationCameraMatrix; - cv::Rodrigues(iRotations[i], rotationCameraMatrix); - cv::Vec3d angles; - getEulerAngles(rotationCameraMatrix, angles); - iAngles.push_back(angles); - - // Check if pitch is closest to zero - int absolutePitch = std::abs(angles[0]); - if (minPitch > absolutePitch) - { - // The solution with pitch closest to zero is the one we want - minPitch = absolutePitch; - iBestSolutionIndex = i; - } - - dbgout << angles; - dbgout << "\n"; - } - - dbgout << "\n"; - } - } + auto[w, h] = widget->preview_size(); + if (w != preview_width || h != preview_height) + { + // Resize preivew if widget size has changed + preview_width = w; preview_height = h; + iPreview = Preview(w, h); + } + } + else + { + // No preview, destroy preview pop-up + if (iSettings.debug) + { + cv::destroyWindow("Preview"); + } + } - // Send solution data back to main thread - QMutexLocker l2(&data_lock); - if (iBestSolutionIndex != -1) - { - iBestAngles = iAngles[iBestSolutionIndex]; - iBestTranslation = iTranslations[iBestSolutionIndex]; - } + dbgout << "Frame time:" << iTimer.elapsed_seconds() << "\n"; - } + } - if (preview_visible) - { - std::ostringstream ss; - ss << "FPS: " << iFps << "/" << iSkippedFps; - iPreview.DrawInfo(ss.str()); + /// + /// + /// + void Tracker::run() + { + maybe_reopen_camera(); - // - if (topPointIndex != -1) - { - // Render a cross to indicate which point is the head - iPreview.DrawCross(iPoints[topPointIndex]); - } + iFpsTimer.start(); - // Show full size preview pop-up - if (iSettings.debug) - { - cv::imshow("Preview", iPreview.iFrameRgb); - cv::waitKey(1); - } + while (!isInterruptionRequested()) + { + iTimer.start(); - // Update preview widget - widget->update_image(iPreview.get_bitmap()); + bool new_frame = false; + { + QMutexLocker l(&camera_mtx); - auto[w, h] = widget->preview_size(); - if (w != preview_width || h != preview_height) - { - // Resize preivew if widget size has changed - preview_width = w; preview_height = h; - iPreview = Preview(w, h); - } - } - else + if (camera) { - // No preview, destroy preview pop-up - if (iSettings.debug) - { - cv::destroyWindow("Preview"); - } + std::tie(iFrame, new_frame) = camera->get_frame(); } + + } - dbgout << "Frame time:" << iTimer.elapsed_seconds() << "\n"; + if (new_frame) + { + ProcessFrame(); } else { diff --git a/tracker-easy/tracker-easy.h b/tracker-easy/tracker-easy.h index 06551533..a8c8e6be 100644 --- a/tracker-easy/tracker-easy.h +++ b/tracker-easy/tracker-easy.h @@ -56,6 +56,7 @@ namespace EasyTracker private: void CreateModelFromSettings(); void CreateCameraIntrinsicsMatrices(); + void ProcessFrame(); // From QThread void run() override; |