From e6eb0bb0bc3f766953affe28cda7f8afbaab0985 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Tue, 18 Aug 2015 05:52:26 +0200 Subject: pt, aruco: another take at focal length formula Aspect ratio is meant to be viewport's ratio, not diagonal to axis. --- ftnoir_tracker_pt/ftnoir_tracker_pt.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) mode change 100644 => 100755 ftnoir_tracker_pt/ftnoir_tracker_pt.cpp (limited to 'ftnoir_tracker_pt/ftnoir_tracker_pt.cpp') diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp old mode 100644 new mode 100755 index e10cfea0..4fa70ccf --- a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp @@ -57,8 +57,9 @@ bool Tracker_PT::get_focal_length(float& ret) { static constexpr double pi = 3.14159265359; const int w = info.res_x, h = info.res_y; - const double diag = sqrt(w * w + h * h)/w, diag_fov = static_cast(s.fov) * pi / 180.; - const double fov = 2.*atan(tan(diag_fov/2.0)/sqrt(1. + diag*diag)); + const double diag = sqrt(1. + h/(double)w * h/(double)w); + const double diag_fov = static_cast(s.fov) * pi / 180.; + const double fov = 2.*atan(tan(diag_fov/2.0)/diag); ret = .5 / tan(.5 * fov); return true; } -- cgit v1.2.3 From 21cd2c012ef23ec3f4b374d82056f1fa1694d904 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Sat, 22 Aug 2015 19:02:57 +0200 Subject: props changed only Some source files had executable bit on. Remove it. --- CMakeLists.txt | 0 bin/NPClient.dll | Bin bin/NPClient64.dll | Bin bin/freetrackclient.dll | Bin clientfiles/make-csv.pl | 0 csv/csv.cpp | 0 facetracknoir/keyboard.h | 0 facetracknoir/process_detector.cpp | 0 facetracknoir/process_detector.h | 0 ftnoir_filter_kalman/ftnoir_filter_kalman.h | 0 ftnoir_protocol_fsuipc/ftnoir_protocol_fsuipc.cpp | 0 ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp | 0 ftnoir_tracker_aruco/include/markerdetector.h | 0 ftnoir_tracker_pt/ftnoir_tracker_pt.cpp | 0 ftnoir_tracker_udp/ftnoir_tracker_udp.cpp | 0 opentrack-compat/process-list.hpp | 0 opentrack/simple-mat.hpp | 0 opentrack/tracker.cpp | 0 opentrack/win32-shortcuts.cpp | 0 opentrack/win32-shortcuts.h | 0 pose-widget/glwidget.cpp | 0 pose-widget/glwidget.h | 0 qfunctionconfigurator/functionconfig.cpp | 0 23 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 CMakeLists.txt mode change 100755 => 100644 bin/NPClient.dll mode change 100755 => 100644 bin/NPClient64.dll mode change 100755 => 100644 bin/freetrackclient.dll mode change 100755 => 100644 clientfiles/make-csv.pl mode change 100755 => 100644 csv/csv.cpp mode change 100755 => 100644 facetracknoir/keyboard.h mode change 100755 => 100644 facetracknoir/process_detector.cpp mode change 100755 => 100644 facetracknoir/process_detector.h mode change 100755 => 100644 ftnoir_filter_kalman/ftnoir_filter_kalman.h mode change 100755 => 100644 ftnoir_protocol_fsuipc/ftnoir_protocol_fsuipc.cpp mode change 100755 => 100644 ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp mode change 100755 => 100644 ftnoir_tracker_aruco/include/markerdetector.h mode change 100755 => 100644 ftnoir_tracker_pt/ftnoir_tracker_pt.cpp mode change 100755 => 100644 ftnoir_tracker_udp/ftnoir_tracker_udp.cpp mode change 100755 => 100644 opentrack-compat/process-list.hpp mode change 100755 => 100644 opentrack/simple-mat.hpp mode change 100755 => 100644 opentrack/tracker.cpp mode change 100755 => 100644 opentrack/win32-shortcuts.cpp mode change 100755 => 100644 opentrack/win32-shortcuts.h mode change 100755 => 100644 pose-widget/glwidget.cpp mode change 100755 => 100644 pose-widget/glwidget.h mode change 100755 => 100644 qfunctionconfigurator/functionconfig.cpp (limited to 'ftnoir_tracker_pt/ftnoir_tracker_pt.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 diff --git a/bin/NPClient.dll b/bin/NPClient.dll old mode 100755 new mode 100644 diff --git a/bin/NPClient64.dll b/bin/NPClient64.dll old mode 100755 new mode 100644 diff --git a/bin/freetrackclient.dll b/bin/freetrackclient.dll old mode 100755 new mode 100644 diff --git a/clientfiles/make-csv.pl b/clientfiles/make-csv.pl old mode 100755 new mode 100644 diff --git a/csv/csv.cpp b/csv/csv.cpp old mode 100755 new mode 100644 diff --git a/facetracknoir/keyboard.h b/facetracknoir/keyboard.h old mode 100755 new mode 100644 diff --git a/facetracknoir/process_detector.cpp b/facetracknoir/process_detector.cpp old mode 100755 new mode 100644 diff --git a/facetracknoir/process_detector.h b/facetracknoir/process_detector.h old mode 100755 new mode 100644 diff --git a/ftnoir_filter_kalman/ftnoir_filter_kalman.h b/ftnoir_filter_kalman/ftnoir_filter_kalman.h old mode 100755 new mode 100644 diff --git a/ftnoir_protocol_fsuipc/ftnoir_protocol_fsuipc.cpp b/ftnoir_protocol_fsuipc/ftnoir_protocol_fsuipc.cpp old mode 100755 new mode 100644 diff --git a/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp b/ftnoir_tracker_aruco/ftnoir_tracker_aruco.cpp old mode 100755 new mode 100644 diff --git a/ftnoir_tracker_aruco/include/markerdetector.h b/ftnoir_tracker_aruco/include/markerdetector.h old mode 100755 new mode 100644 diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp old mode 100755 new mode 100644 diff --git a/ftnoir_tracker_udp/ftnoir_tracker_udp.cpp b/ftnoir_tracker_udp/ftnoir_tracker_udp.cpp old mode 100755 new mode 100644 diff --git a/opentrack-compat/process-list.hpp b/opentrack-compat/process-list.hpp old mode 100755 new mode 100644 diff --git a/opentrack/simple-mat.hpp b/opentrack/simple-mat.hpp old mode 100755 new mode 100644 diff --git a/opentrack/tracker.cpp b/opentrack/tracker.cpp old mode 100755 new mode 100644 diff --git a/opentrack/win32-shortcuts.cpp b/opentrack/win32-shortcuts.cpp old mode 100755 new mode 100644 diff --git a/opentrack/win32-shortcuts.h b/opentrack/win32-shortcuts.h old mode 100755 new mode 100644 diff --git a/pose-widget/glwidget.cpp b/pose-widget/glwidget.cpp old mode 100755 new mode 100644 diff --git a/pose-widget/glwidget.h b/pose-widget/glwidget.h old mode 100755 new mode 100644 diff --git a/qfunctionconfigurator/functionconfig.cpp b/qfunctionconfigurator/functionconfig.cpp old mode 100755 new mode 100644 -- cgit v1.2.3 From 19ccb520c0216f3e98e8d8f0ed4c504fb1c24f10 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Fri, 4 Sep 2015 10:13:25 +0200 Subject: pt: change extraction code Point size is now specified by its radius. Points are extracted in one pass, using multiple passes caused missed detection for some users. Circularity is now displayed as part of overlay. Points are now sorted by circularity, which is our confidence metric. Tracker code ignores additional points, keeping only those with the highest confidence metric. --- ftnoir_tracker_pt/ftnoir_tracker_pt.cpp | 4 + ftnoir_tracker_pt/point_extractor.cpp | 234 ++++++++++---------------------- 2 files changed, 73 insertions(+), 165 deletions(-) (limited to 'ftnoir_tracker_pt/ftnoir_tracker_pt.cpp') diff --git a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp index 4fa70ccf..19d1bd7f 100644 --- a/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp +++ b/ftnoir_tracker_pt/ftnoir_tracker_pt.cpp @@ -93,6 +93,10 @@ void Tracker_PT::run() QMutexLocker lock(&mutex); std::vector points = point_extractor.extract_points(frame); + + // blobs are sorted in order of circularity + if (points.size() > PointModel::N_POINTS) + points.resize(PointModel::N_POINTS); bool success = points.size() == PointModel::N_POINTS; diff --git a/ftnoir_tracker_pt/point_extractor.cpp b/ftnoir_tracker_pt/point_extractor.cpp index c1dd9a54..fcdbbaed 100644 --- a/ftnoir_tracker_pt/point_extractor.cpp +++ b/ftnoir_tracker_pt/point_extractor.cpp @@ -28,215 +28,119 @@ std::vector PointExtractor::extract_points(cv::Mat& frame) cv::Mat frame_gray; cv::cvtColor(frame, frame_gray, cv::COLOR_RGB2GRAY); - int min_size = s.min_point_size; - int max_size = s.max_point_size; + const int region_size_min = s.min_point_size; + const int region_size_max = s.max_point_size; - unsigned int region_size_min = 3.14*min_size*min_size/4.0; - unsigned int region_size_max = 3.14*max_size*max_size/4.0; - - // testing indicates threshold difference of 45 from lowest to highest - // that's applicable to poor lighting conditions. - - static constexpr int diff = 20; - static constexpr int steps = 5; - static constexpr int successes = 5; - - int thres = s.threshold; - - struct blob { - std::vector pos; - std::vector confids; - std::vector areas; - - cv::Vec2d effective_pos() const - { - double x = 0; - double y = 0; - double norm = 0; - for (unsigned i = 0; i < pos.size(); i++) - { - const double w = confids[i] * areas[i]; - x += pos[i][0] * w; - y += pos[i][1] * w; - norm += w; - } - cv::Vec2d ret(x, y); - ret *= 1./norm; - return ret; - } - - double effective_area() const - { - double norm = 0, ret = 0; - for (unsigned i = 0; i < areas.size(); i++) - { - const double w = confids[i]; - norm += w; - ret += w * areas[i]; - } - return ret/norm; - } - }; + const int thres = s.threshold; struct simple_blob { - double radius_2; + double radius; cv::Vec2d pos; double confid; bool taken; double area; - simple_blob(double radius, const cv::Vec2d& pos, double confid, double area) : radius_2(radius*radius), pos(pos), confid(confid), taken(false), area(area) + simple_blob(double radius, const cv::Vec2d& pos, double confid, double area) : radius(radius), pos(pos), confid(confid), taken(false), area(area) { //qDebug() << "radius" << radius << "pos" << pos[0] << pos[1] << "confid" << confid; } bool inside(const simple_blob& other) { cv::Vec2d tmp = pos - other.pos; - return tmp.dot(tmp) < radius_2; - } - static std::vector merge(cv::Mat& frame, std::vector& blobs) - { -#ifdef DEBUG_EXTRACTION - static Timer t; - bool debug = t.elapsed_ms() > 100; - if (debug) t.start(); -#endif - - std::vector ret; - for (unsigned i = 0; i < blobs.size(); i++) - { - auto& b = blobs[i]; - if (b.taken) - continue; - b.taken = true; - blob b_; - b_.pos.push_back(b.pos); - b_.confids.push_back(b.confid); - b_.areas.push_back(b.area); - - for (unsigned j = i+1; j < blobs.size(); j++) - { - auto& b2 = blobs[j]; - if (b2.taken) - continue; - if (b.inside(b2) || b2.inside(b)) - { - b2.taken = true; - b_.pos.push_back(b2.pos); - b_.confids.push_back(b2.confid); - b_.areas.push_back(b2.area); - } - } - if (b_.pos.size() >= successes) - ret.push_back(b_); - - char buf[64]; - sprintf(buf, "%d%% %d px", (int)(b_.pos.size()*100/successes), (int)(2.*sqrt(b_.effective_area()) / sqrt(3.14))); - const auto pos = b_.effective_pos(); - cv::putText(frame, buf, cv::Point(pos[0]+30, pos[1]+20), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 255), 1); - } -#ifdef DEBUG_EXTRACTION - if (debug) - { - double diff = 0; - for (unsigned j = 0; j < ret.size(); j++) - { - auto& b = ret[j]; - cv::Vec2d pos = b.effective_pos(); - for (unsigned i = 0; i < b.pos.size(); i++) - { - auto tmp = pos - b.pos[i]; - diff += std::abs(tmp.dot(tmp)); - } - } - qDebug() << "diff" << diff; - } -#endif - return ret; + return sqrt(tmp.dot(tmp)) < radius; } }; // mask for everything that passes the threshold (or: the upper threshold of the hysteresis) cv::Mat frame_bin = cv::Mat::zeros(H, W, CV_8U); - const int min = std::max(0, thres - diff/2); - const int max = std::min(255, thres + diff/2); - const int step = std::max(1, diff / steps); - std::vector blobs; - - // this code is based on OpenCV SimpleBlobDetector - for (int i = min; i < max; i += step) + std::vector> contours; { cv::Mat frame_bin_; - cv::threshold(frame_gray, frame_bin_, i, 255, cv::THRESH_BINARY); + cv::threshold(frame_gray, frame_bin_, thres, 255, cv::THRESH_BINARY); frame_bin.setTo(170, frame_bin_); - - std::vector> contours; cv::findContours(frame_bin_, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); - - int cnt = 0; - - for (auto& c : contours) + } + + int cnt = 0; + + for (auto& c : contours) + { + if (cnt++ > 30) + break; + + const auto m = cv::moments(cv::Mat(c)); + const double area = m.m00; + if (area == 0.) + continue; + const cv::Vec2d pos(m.m10 / m.m00, m.m01 / m.m00); + + double radius; +// following based on OpenCV SimpleBlobDetector { - if (cnt++ > 30) - break; - - auto m = cv::moments(cv::Mat(c)); - const double area = m.m00; - if (area == 0.) - continue; - cv::Vec2d pos(m.m10 / m.m00, m.m01 / m.m00); - if (area < region_size_min || area > region_size_max) - continue; - - double radius = 0; - + std::vector dists; for (auto& k : c) { - cv::Vec2d pos_(k.x, k.y); - cv::Vec2d tmp = pos_ - pos; - radius = std::max(radius, sqrt(1e-2 + tmp.dot(tmp))); + dists.push_back(cv::norm(pos - cv::Vec2d(k.x, k.y))); } - double confid = 1; + std::sort(dists.begin(), dists.end()); + radius = (dists[(dists.size() - 1)/2] + dists[dists.size()/2])/2; + } + + if (radius < region_size_min || radius > region_size_max) + continue; + + double confid = 1; + { + double denominator = std::sqrt(std::pow(2 * m.mu11, 2) + std::pow(m.mu20 - m.mu02, 2)); + const double eps = 1e-2; + if (denominator > eps) { - double denominator = std::sqrt(std::pow(2 * m.mu11, 2) + std::pow(m.mu20 - m.mu02, 2)); - const double eps = 1e-2; - if (denominator > eps) - { - double cosmin = (m.mu20 - m.mu02) / denominator; - double sinmin = 2 * m.mu11 / denominator; - double cosmax = -cosmin; - double sinmax = -sinmin; - - double imin = 0.5 * (m.mu20 + m.mu02) - 0.5 * (m.mu20 - m.mu02) * cosmin - m.mu11 * sinmin; - double imax = 0.5 * (m.mu20 + m.mu02) - 0.5 * (m.mu20 - m.mu02) * cosmax - m.mu11 * sinmax; - confid = imin / imax; - } + double cosmin = (m.mu20 - m.mu02) / denominator; + double sinmin = 2 * m.mu11 / denominator; + double cosmax = -cosmin; + double sinmax = -sinmin; + + double imin = 0.5 * (m.mu20 + m.mu02) - 0.5 * (m.mu20 - m.mu02) * cosmin - m.mu11 * sinmin; + double imax = 0.5 * (m.mu20 + m.mu02) - 0.5 * (m.mu20 - m.mu02) * cosmax - m.mu11 * sinmax; + confid = imin / imax; } - blobs.push_back(simple_blob(radius, pos, confid, area)); } +// end SimpleBlobDetector + + { + char buf[64]; + sprintf(buf, "%.2fpx %.2fc", radius, confid); + cv::putText(frame, buf, cv::Point(pos[0]+30, pos[1]+20), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 255), 1); + } + + blobs.push_back(simple_blob(radius, pos, confid, area)); } // clear old points points.clear(); + + using b = const simple_blob; + std::sort(blobs.begin(), blobs.end(), [](b& b1, b& b2) {return b1.confid > b2.confid;}); - for (auto& b : simple_blob::merge(frame, blobs)) + for (auto& b : blobs) { - auto pos = b.effective_pos(); - cv::Vec2f p((pos[0] - W/2)/W, -(pos[1] - H/2)/W); + cv::Vec2f p((b.pos[0] - W/2)/W, -(b.pos[1] - H/2)/W); points.push_back(p); } + // draw output image std::vector channels_; cv::split(frame, channels_); - // draw output image - cv::Mat frame_bin_ = frame_bin * .5; std::vector channels; - channels.push_back(channels_[0] + frame_bin_); - channels.push_back(channels_[1] - frame_bin_); - channels.push_back(channels_[2] - frame_bin_); - cv::merge(channels, frame); + { + cv::Mat frame_bin__ = frame_bin * .5; + channels.push_back(channels_[0] + frame_bin__); + channels.push_back(channels_[1] - frame_bin__); + channels.push_back(channels_[2] - frame_bin__); + cv::merge(channels, frame); + } return points; } -- cgit v1.2.3