diff options
Diffstat (limited to 'tracker-pt/point_extractor.cpp')
-rw-r--r-- | tracker-pt/point_extractor.cpp | 161 |
1 files changed, 90 insertions, 71 deletions
diff --git a/tracker-pt/point_extractor.cpp b/tracker-pt/point_extractor.cpp index a1294c1e..1b06df5a 100644 --- a/tracker-pt/point_extractor.cpp +++ b/tracker-pt/point_extractor.cpp @@ -1,5 +1,5 @@ /* Copyright (c) 2012 Patrick Ruoff - * Copyright (c) 2014-2015 Stanislaw Halik <sthalik@misaki.pl> + * Copyright (c) 2015-2016 Stanislaw Halik <sthalik@misaki.pl> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -10,24 +10,35 @@ #include <QDebug> #ifdef DEBUG_EXTRACTION -# include "opentrack-compat/timer.hpp" +# include "compat/timer.hpp" #endif +#include <opencv2/videoio.hpp> + +#include <cmath> +#include <algorithm> +#include <cinttypes> + PointExtractor::PointExtractor() { blobs.reserve(max_blobs); - points.reserve(max_blobs); } -const std::vector<cv::Vec2f>& PointExtractor::extract_points(cv::Mat& frame) +void PointExtractor::extract_points(cv::Mat& frame, std::vector<cv::Vec2d>& points) { + using std::sqrt; + using std::max; + using std::round; + using std::sort; + const int W = frame.cols; const int H = frame.rows; - + if (frame_gray.rows != frame.rows || frame_gray.cols != frame.cols) { frame_gray = cv::Mat(frame.rows, frame.cols, CV_8U); - frame_bin = cv::Mat(frame.rows, frame.cols, CV_8U);; + frame_bin = cv::Mat(frame.rows, frame.cols, CV_8U); + frame_blobs = cv::Mat(frame.rows, frame.cols, CV_8U); } // convert to grayscale @@ -35,15 +46,11 @@ const std::vector<cv::Vec2f>& PointExtractor::extract_points(cv::Mat& frame) const double region_size_min = s.min_point_size; const double region_size_max = s.max_point_size; - - const int thres = s.threshold; - - contours.clear(); if (!s.auto_threshold) { + const int thres = s.threshold; cv::threshold(frame_gray, frame_bin, thres, 255, cv::THRESH_BINARY); - cv::findContours(frame_bin, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); } else { @@ -51,95 +58,107 @@ const std::vector<cv::Vec2f>& PointExtractor::extract_points(cv::Mat& frame) std::vector<int> { 0 }, cv::Mat(), hist, - std::vector<int> { 256/hist_c }, - std::vector<float> { 0, 256/hist_c }, + std::vector<int> { 256 }, + std::vector<float> { 0, 256 }, false); const int sz = hist.cols * hist.rows; - int val = 0; + int thres = 255; int cnt = 0; - constexpr int min_pixels = 250; - const auto pixels_to_include = std::max<int>(0, min_pixels * s.threshold/100.); + constexpr double min_radius = 4; + constexpr double max_radius = 15; + const double radius = max(0., (max_radius-min_radius) * s.threshold / 256); + const int pixels_to_include = int((min_radius + radius)*(min_radius+radius) * 3); auto ptr = reinterpret_cast<const float*>(hist.ptr(0)); - for (int i = sz-1; i >= 0; i--) + for (int i = sz-1; i > 0; i--) { cnt += ptr[i]; if (cnt >= pixels_to_include) { - val = i; + thres = i; break; } } - val *= hist_c; - val *= 240./256.; - //qDebug() << "val" << val; + //val *= 240./256.; + //qDebug() << "thres" << thres; - cv::threshold(frame_gray, frame_bin, val, 255, CV_THRESH_BINARY); - cv::findContours(frame_bin, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); + cv::threshold(frame_gray, frame_bin, thres, 255, CV_THRESH_BINARY); } blobs.clear(); + frame_bin.copyTo(frame_blobs); - for (auto& c : contours) + unsigned idx = 0; + for (int y=0; y < frame_blobs.rows; y++) { - const auto m = cv::moments(cv::Mat(c)); - const cv::Vec2d pos(m.m10 / m.m00, m.m01 / m.m00); + if (idx > max_blobs) break; - double radius; -// following based on OpenCV SimpleBlobDetector + const unsigned char* ptr_bin = frame_blobs.ptr(y); + for (int x=0; x < frame_blobs.cols; x++) { - std::vector<double> dists; - for (auto& k : c) + if (idx > max_blobs) break; + + if (ptr_bin[x] != 255) + continue; + idx = blobs.size() + 1; + cv::Rect rect; + cv::floodFill(frame_blobs, + cv::Point(x,y), + cv::Scalar(idx), + &rect, + cv::Scalar(0), + cv::Scalar(0), + 8); + int m00 = 0; + int m10 = 0; + int m01 = 0; + int cnt = 0; + + for (int i=rect.y; i < (rect.y+rect.height); i++) { - dists.push_back(cv::norm(pos - cv::Vec2d(k.x, k.y))); + unsigned char* ptr_blobs = frame_blobs.ptr(i); + const unsigned char* ptr_gray = frame_gray.ptr(i); + for (int j=rect.x; j < (rect.x+rect.width); j++) + { + if (ptr_blobs[j] != idx) continue; + ptr_blobs[j] = 0; + const int val = int(ptr_gray[j]); + m00 += val; + m01 += i * val; + m10 += j * val; + cnt++; + } } - 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) + if (m00 > 0) { - 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; + const double radius = sqrt(cnt / M_PI); + if (radius > region_size_max || radius < region_size_min) + continue; + const double norm = double(m00); + blob b(radius, cv::Vec2d(m10 / norm, m01 / norm), m00/sqrt(double(cnt))); + blobs.push_back(b); + { + char buf[64]; + sprintf(buf, "%.2fpx", radius); + cv::putText(frame, + buf, + cv::Point((int)round(b.pos[0]+30), (int)round(b.pos[1]+20)), + cv::FONT_HERSHEY_DUPLEX, + 1, + cv::Scalar(0, 0, 255), + 1); + } } } -// 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); - } + sort(blobs.begin(), blobs.end(), [](const blob& b1, const blob& b2) -> bool { return b2.brightness < b1.brightness; }); - blobs.push_back(blob(radius, pos, confid)); - - if (blobs.size() == max_blobs) - break; - } - - using b = const blob; - std::sort(blobs.begin(), blobs.end(), [](b& b1, b& b2) {return b1.confid > b2.confid;}); - - QMutexLocker l(&mtx); + points.reserve(max_blobs); points.clear(); - + for (auto& b : blobs) { - cv::Vec2f p((b.pos[0] - W/2)/W, -(b.pos[1] - H/2)/W); + cv::Vec2d p((b.pos[0] - W/2)/W, -(b.pos[1] - H/2)/W); points.push_back(p); } - - return points; } |