diff --git a/.gitignore b/.gitignore index 23bfdc7..ce0b5eb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ .idea bin/ lib/ -cmake-build-debug/ -cmake-build-release/ +cmake-build-*/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 26aa96b..64988d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,6 @@ file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" ) -list(FILTER SOURCE_FILES EXCLUDE REGEX ".*android\\.[cpp|hpp]") - set(OpenCV_DIR "D:\\opencv-4.1.1\\build\\install") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") diff --git a/src/AR/Ar.cpp b/src/AR/Ar.cpp index bab9c50..f8a0d3b 100644 --- a/src/AR/Ar.cpp +++ b/src/AR/Ar.cpp @@ -4,7 +4,7 @@ AR::~AR() = default; AR::AR() { recognitionInstance = new Recognition(); - trackingInstance = Tracking::create(); + trackingInstance = new Tracking(); } @@ -13,8 +13,7 @@ std::vector AR::process(cv::Mat frame) { } -int AR::addAndCreate(std::vector imgs) { - recognitionInstance->addAndCreateBagOfVisualWords(imgs); +int AR::addAll(std::vector imgs) { for (const auto &img: imgs) { recognitionInstance->addTrackImage(img); } @@ -22,15 +21,10 @@ int AR::addAndCreate(std::vector imgs) { } int AR::add(cv::Mat img) { - recognitionInstance->addVisualWord(img); recognitionInstance->addTrackImage(img); return 0; } -int AR::create() { - recognitionInstance->createBagOfVisualWords(); - return 0; -} bool AR::keepTracking(const cv::Mat &frame) { return trackingInstance->keepTracking(frame); diff --git a/src/AR/Ar.hpp b/src/AR/Ar.hpp index 3bb7fb2..62e1c3f 100644 --- a/src/AR/Ar.hpp +++ b/src/AR/Ar.hpp @@ -51,12 +51,12 @@ class AR { Tracking *getTrackingInstance() { return trackingInstance; } /** - * @brief Add and create marker image objects + * @brief Add marker image objects * * @param imgs marker images * @return int */ - int addAndCreate(std::vector imgs); + int addAll(std::vector imgs); /** * @brief Add marker image @@ -66,13 +66,6 @@ class AR { */ int add(cv::Mat img); - /** - * @brief Create tracking markers - * - * @return int - */ - int create(); - ~AR(); }; diff --git a/src/Recognition/FeatureDB.cpp b/src/Recognition/FeatureDB.cpp deleted file mode 100644 index a7a098c..0000000 --- a/src/Recognition/FeatureDB.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "FeatureDB.hpp" - -FeatureDB::FeatureDB() { -// descriptorMatcher = cv::DescriptorMatcher::create("FlannBased"); -// descriptorMatcher = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(20, 10, 2)); - descriptorMatcher = new cv::BFMatcher(cv::NORM_HAMMING); -// RADIUS = 0.2; - RADIUS = 0.9f; -} - -void FeatureDB::addFeatures(const cv::Mat &feature) { - descriptorMatcher->add(std::vector{feature}); -} - -void FeatureDB::clear() { - descriptorMatcher->clear(); -} - -FeatureDB::~FeatureDB() { - clear(); -} - -void FeatureDB::create(int amountCluster) { - if (amountCluster > 0) { - //TODO: k-means clustering - } - descriptorMatcher->train(); -} - -cv::Mat FeatureDB::search(const cv::Mat &feature) { - int size = feature.size().height; - - cv::Mat id(size, KNN_SIZE, CV_32SC1); - std::vector> matchId; - descriptorMatcher->knnMatch(feature, matchId, KNN_SIZE); - - for (int i = 0; i < size; ++i) { - cv::DMatch matchM = matchId[i][0]; - cv::DMatch matchN = matchId[i][1]; - if (matchM.distance >= matchN.distance * RADIUS) { - id.at(i, 0) = -1; - } else { - id.at(i, 0) = matchM.trainIdx; - } - } - - return id; -} - -int FeatureDB::size() const { - std::vector descriptor = descriptorMatcher->getTrainDescriptors(); - int num = 0; - std::for_each(descriptor.begin(), descriptor.end(), - [&num](const cv::Mat &mat) { - num += mat.rows; - } - ); - return num; -} - diff --git a/src/Recognition/FeatureDB.hpp b/src/Recognition/FeatureDB.hpp deleted file mode 100644 index 299cbb2..0000000 --- a/src/Recognition/FeatureDB.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#ifndef AR_CORE_FEATUREDB_HPP -#define AR_CORE_FEATUREDB_HPP - -#include -#include -#include "../Utils/CvUtils.hpp" - -/** - * @brief Class provides operations with features - * - */ -class FeatureDB { -private: - cv::Ptr descriptorMatcher; // Descriptor matcher - float RADIUS; // Descriptor matcher nn ratio - const int KNN_SIZE = 2; // knn size -public: - FeatureDB(); - - /** - * @brief Add marker image feature - * - * @param feature - */ - void addFeatures(const cv::Mat &feature); - - /** - * @brief Create BoVW - * - * @param amountCluster - */ - void create(int amountCluster = 0); - - /** - * @brief Clear train descriptor collection - * - */ - void clear(); - - /** - * @brief Search matches between features - * - * @param feature Frame features - * @return cv::Mat - */ - cv::Mat search(const cv::Mat &feature); - - /** - * @brief Get amount of features - * - * @return int - */ - int size() const; - - ~FeatureDB(); -}; - -#endif //AR_CORE_FEATUREDB_HPP diff --git a/src/Recognition/MarkerlessDB.cpp b/src/Recognition/MarkerlessDB.cpp new file mode 100644 index 0000000..c8975ea --- /dev/null +++ b/src/Recognition/MarkerlessDB.cpp @@ -0,0 +1,126 @@ +#include "MarkerlessDB.hpp" + +MarkerlessDB::MarkerlessDB() { + featureDetector = cv::AKAZE::create(); + (featureDetector.dynamicCast())->setThreshold(3e-3); + descriptorMatcher = new cv::BFMatcher(cv::NORM_HAMMING); + markerAmount = 0; + featureAmount = 0; + RADIUS = 0.8f; +} + +void MarkerlessDB::addFeatures(const cv::Mat &feature) { + descriptorMatcher->add(std::vector{feature}); +} + +MarkerlessDB::~MarkerlessDB() { +} + + +int MarkerlessDB::size() const { + int num = 0; + std::for_each(markers.begin(), markers.end(), + [&num](MarkerlessTrackable *e) { + num += e->numFeatures; + } + ); + return num; +} + +void MarkerlessDB::add(const cv::Mat &image) { + std::vector keyPoints; + cv::Mat descriptor; + extractFeatures(image, keyPoints, descriptor); + addFeatures(descriptor); + int id = markerAmount; + markers.push_back(new MarkerlessTrackable(id, descriptor, keyPoints, image.size())); + markerAmount++; +} + +void MarkerlessDB::extractFeatures(const cv::Mat &img, std::vector &keyPoints, cv::Mat &descriptor) { + featureDetector->detectAndCompute(img, cv::noArray(), keyPoints, descriptor); +} + +std::vector +MarkerlessDB::match(cv::Mat queryImage, int minNumMatch, float minProbability) { + std::vector results; + QueryItem result; + // Extract features from query image + cv::Mat descriptors; + std::vector keyPoints; + extractFeatures(queryImage, keyPoints, descriptors); + // Search matches + if (markerAmount < 1) + return results; + + int size = descriptors.size().height; // number of query image features + + std::vector>> descriptorMatches(markerAmount); + + // iterate over all available markers + // and find matches + for (auto marker: markers) { + std::vector> matchId; + descriptorMatcher->knnMatch(descriptors, marker->descriptors, matchId, KNN_SIZE); + for (int i = 0; i < size; ++i) { + cv::DMatch matchM = matchId[i][0]; + cv::DMatch matchN = matchId[i][1]; + if (matchM.distance < matchN.distance * RADIUS) { + descriptorMatches[marker->id].push_back(std::make_pair(matchM.trainIdx, matchN.queryIdx)); + } + } + } + + int thresholdDist = (int) round(sqrt(5e-4f * queryImage.size().width * queryImage.size().height / M_PI)); + float pp, prob; + int markerIdx, numMatches; + cv::Mat homography; + std::vector r, q; + const int amountFeatures = this->size(); + auto markerIt = descriptorMatches.begin(); + while (markerIt != descriptorMatches.end()) { + markerIdx = (markerIt - descriptorMatches.begin()); + numMatches = markerIt->size(); + if (numMatches > minNumMatch) { + pp = std::min(0.05f * markers[markerIdx]->numFeatures / amountFeatures, 1.f); + prob = CvUtils::binomialCDF(numMatches, markers[markerIdx]->numFeatures, pp); + + if (prob >= minProbability) { + + auto matchIt = (*markerIt).begin(); + while (matchIt != (*markerIt).end()) { + q.push_back(keyPoints[matchIt->second].pt); + r.push_back(markers[markerIdx]->keyPoints[matchIt->first].pt); + matchIt++; + } + + homography = cv::findHomography(cv::Mat(r), cv::Mat(q), cv::RANSAC, thresholdDist); + + if (!homography.empty()) { + std::vector posePoint = CvUtils::transformMarkerCoordToObjectCoord( + markers[markerIdx]->size, + homography); + if (CvUtils::_proveRect(posePoint)) { + result.imgId = markerIdx; + result.amountMatched = numMatches; + result.imgSize = markers[markerIdx]->size; + result.probability = prob; + result.homography = homography; + result.objPose = posePoint; + results.push_back(result); + } + } + } + } + r.clear(); + q.clear(); + markerIt++; + } + std::sort(results.begin(), results.end(), [](const QueryItem &a, const QueryItem &b) -> bool { + return a.probability > b.probability; + }); + + return results; +} + + diff --git a/src/Recognition/MarkerlessDB.hpp b/src/Recognition/MarkerlessDB.hpp new file mode 100644 index 0000000..6318dd5 --- /dev/null +++ b/src/Recognition/MarkerlessDB.hpp @@ -0,0 +1,57 @@ +#pragma once +#ifndef AR_CORE_MARKERLESSDB_HPP +#define AR_CORE_MARKERLESSDB_HPP + +#include +#include +#include "../Utils/CvUtils.hpp" +#include "MarkerlessTrackable.hpp" + +/** + * @brief Class provides operations with features + * + */ +class MarkerlessDB { +private: + cv::Ptr featureDetector; // Feature detector + std::vector markers; + cv::Ptr descriptorMatcher; // Descriptor matcher + float RADIUS; // Descriptor matcher nn ratio + const int KNN_SIZE = 2; // knn size + int markerAmount; // Number of markers + int featureAmount; // Number of features +public: + MarkerlessDB(); + + void add(const cv::Mat &image); + + std::vector + match(cv::Mat queryImage, int minNumMatch = 10, float minProbability = 0.75f); + + /** + * @brief Extract features from image + * + * @param img Image + * @param keyPoints [out] KeyPoints + * @param descriptor [out] Descriptors + */ + void extractFeatures(const cv::Mat &img, std::vector &keyPoints, cv::Mat &descriptor); + + /** + * @brief Add marker image feature + * + * @param feature + */ + void addFeatures(const cv::Mat &feature); + + /** + * @brief Get amount of features + * + * @return int + */ + int size() const; + + ~MarkerlessDB(); +}; + +#endif //AR_CORE_MARKERLESSDB_HPP diff --git a/src/Recognition/MarkerlessTrackable.cpp b/src/Recognition/MarkerlessTrackable.cpp new file mode 100644 index 0000000..f20eaf2 --- /dev/null +++ b/src/Recognition/MarkerlessTrackable.cpp @@ -0,0 +1,14 @@ +#include "MarkerlessTrackable.hpp" + +MarkerlessTrackable::~MarkerlessTrackable() { + +} + +MarkerlessTrackable::MarkerlessTrackable(const int id, const cv::Mat &descriptors, + const std::vector &keyPoints, const cv::Size &size) + : TrackableEntity(id) { + this->descriptors = descriptors; + this->keyPoints = keyPoints; + this->size = size; + this->numFeatures = keyPoints.size(); +} diff --git a/src/Recognition/MarkerlessTrackable.hpp b/src/Recognition/MarkerlessTrackable.hpp new file mode 100644 index 0000000..296df8f --- /dev/null +++ b/src/Recognition/MarkerlessTrackable.hpp @@ -0,0 +1,27 @@ + +#ifndef AR_CORE_MARKERLESSTRACKABLE_HPP +#define AR_CORE_MARKERLESSTRACKABLE_HPP + +#include +#include "TrackableEntity.hpp" + +class MarkerlessTrackable : TrackableEntity { +private: + /*********Features**************/ + cv::Mat descriptors; + std::vector keyPoints; + /********************************/ + int numFeatures; // number of features + cv::Size size; // size of marker image + + friend class MarkerlessDB; + +public: + MarkerlessTrackable(const int id, const cv::Mat &descriptors, const std::vector &keyPoints, + const cv::Size &size); + + ~MarkerlessTrackable(); +}; + + +#endif //AR_CORE_MARKERLESSTRACKABLE_HPP diff --git a/src/Recognition/Recognition.cpp b/src/Recognition/Recognition.cpp index d36d40a..d1dd0b2 100644 --- a/src/Recognition/Recognition.cpp +++ b/src/Recognition/Recognition.cpp @@ -2,282 +2,20 @@ Recognition::Recognition() { //TODO: init detector and descriptor - vw = new FeatureDB(); - featureDetector = cv::AKAZE::create(); - featureDetector.dynamicCast()->setThreshold(3e-3); - // featureDetector = cv::xfeatures2d::SURF::create(); - imageAmount = 0; - featureAmount = 0; -} - -void Recognition::addAndCreateBagOfVisualWords(const std::vector &imgs, int numClusters) { - std::vector keyPoints; - cv::Mat descriptor; - for (const auto &img : imgs) { - extractFeatures(img, keyPoints, descriptor); - vw->addFeatures(descriptor); - } - vw->create(numClusters); -} - -void Recognition::addVisualWord(const cv::Mat &img) { - std::vector keyPoints; - cv::Mat descriptor; - extractFeatures(img, keyPoints, descriptor); - vw->addFeatures(descriptor); -} - -void Recognition::createBagOfVisualWords(int numClusters) { - vw->create(numClusters); -} - -void Recognition::extractFeatures(const cv::Mat &img, std::vector &keyPoints, cv::Mat &descriptor) { - featureDetector->detectAndCompute(img, cv::noArray(), keyPoints, descriptor); + markerlessDb = new MarkerlessDB(); } int Recognition::addTrackImage(const cv::Mat &img) { - std::vector keyPoints; - cv::Mat descriptor; - extractFeatures(img, keyPoints, descriptor); - std::vector ids; - getFeatureIds(descriptor, ids); - int id = imageAmount; - int status = storeImageFeatures(id, img.size(), keyPoints, ids); - - if (status < 0) - return -1; - return 0; -} - -int Recognition::getFeatureIds(const cv::Mat &descriptor, std::vector &ids) { - if (descriptor.empty()) - return -1; - int size = descriptor.rows; - - cv::Mat id = vw->search(descriptor); - - for (int i = 0; i < size; ++i) { - ids.push_back(id.at(i, 0)); - } - - return 0; -} - -int Recognition::storeImageFeatures(int id, const cv::Size &size, std::vector keyPoints, - std::vector ids) { - FeatureInfo fInfo; - - ImageInfo iInfo; - iInfo.numFeatures = keyPoints.size(); - iInfo.size = size; - - // Image info - auto statusAdd = imageInfoStore.insert(std::pair(id, iInfo)); - - if (!statusAdd.second) - return -1; - - // Vote info - auto *voteTable = new std::vector; - voteStorage.insert(std::pair *>(id, voteTable)); - - fInfo.imgId = id; - int kpId, kpSize = keyPoints.size(); - - for (int i = 0; i < kpSize; ++i) { - if (ids[i] >= 0) { - kpId = getCandidateKpId(); - fInfo.keyPointId = kpId; - keyPointStore.insert(std::pair(kpId, keyPoints[i])); - featureStore.insert(std::pair(ids[i], fInfo)); - } - } - - imageAmount++; + markerlessDb->add(img); return 0; } std::vector Recognition::queryImage(const cv::Mat &img, int amountRes) { std::vector queryReturn; - std::vector kp; - cv::Mat descriptor; - - extractFeatures(img, kp, descriptor); - std::vector ids; - int status = getFeatureIds(descriptor, ids); - if (status < 0) - return queryReturn; - - queryReturn = searchImageId(kp, ids, img.size(), vw->size(), amountRes); + queryReturn = markerlessDb->match(img); return queryReturn; } -int Recognition::getCandidateKpId() { - int size = keyPointStore.size(); - if (featureAmount == size) { - featureAmount++; - return featureAmount; - } else if (featureAmount > size) { - for (int i = 1; i <= featureAmount; ++i) { - if (keyPointStore.count(i) == 0) { - return i; - } - } - } - return 0; -} - -std::vector -Recognition::searchImageId(std::vector keyPoints, std::vector ids, cv::Size size, int amountWords, - int amountRes) { - std::vector queryReturn; - voteQueryFeatures(keyPoints, ids); - std::vector tmp = getMatchResults(keyPoints, amountWords); - queryReturn = filterGeomResults(keyPoints, tmp, size, amountRes); - clearVote(); - return queryReturn; -} - -void Recognition::voteQueryFeatures(std::vector keyPoints, std::vector ids) { - std::multimap::iterator featureIt; - std::map *>::iterator voteIt; - FeatureVote vote; - FeatureInfo feature; - - int size = keyPoints.size(), idsIdx = 0; - - for (int i = 0; i < size; ++i) { - if (ids[idsIdx] >= 0) { - featureIt = featureStore.find(ids[idsIdx]); - while (featureIt != featureStore.end() && featureIt->first == ids[idsIdx]) { - feature = featureIt->second; - vote.featureId = i; - vote.keyPointId = feature.keyPointId; - voteIt = voteStorage.find(feature.imgId); - if (voteIt != voteStorage.end()) { - voteIt->second->push_back(vote); - } - featureIt++; - } - } - idsIdx++; - } -} - -std::vector Recognition::getMatchResults(std::vector keyPoints, int amountWords) { - std::vector queryResult; - QueryItem queryItem; - std::vector *voteTable; - int numMatch; // amount matches between query image and database image - int imgId; // database image id - int imgDBFeatureNum; // amount extracted features from database image - int featureNum = keyPoints.size(); // amount extracted features from query image - uint numMarkers = imageInfoStore.size(); // amount marker image in database - float pp, prob; - auto it = voteStorage.begin(); - while (it != voteStorage.end()) { - voteTable = it->second; - numMatch = voteTable->size(); - if (numMatch >= MIN_MATCH) { - imgId = it->first; - imgDBFeatureNum = imageInfoStore[imgId].numFeatures; -// pp = std::min((float) imgDBFeatureNum / amountWords, 1.f); - // >? Maybe instead imgDBFeatureNum set median value - pp = std::min(MIN_PROBABILITY_SUCCESS_MATCH * imgDBFeatureNum / amountWords, 1.f); - prob = binomialCDF(numMatch, featureNum, pp); - - if (prob >= MIN_PROBABILITY) { - queryItem.imgId = imgId; - queryItem.amountMatched = numMatch; - queryItem.imgSize = imageInfoStore[imgId].size; - queryItem.probability = prob; - queryResult.push_back(queryItem); - } - } - it++; - } - std::sort(queryResult.begin(), queryResult.end(), [](const QueryItem &a, const QueryItem &b) -> bool { - return a.probability > b.probability; - }); - return queryResult; -} - -std::vector -Recognition::filterGeomResults(std::vector keyPoints, std::vector pre, cv::Size size, - int amountRes) { - std::vector queryResult; - QueryItem queryItem; - int sizePre = pre.size(); - if (sizePre < 1) - return queryResult; - - int imgId, count = 0; - std::vector *voteTable; - std::vector q, r; - cv::Mat homography; - int thresholdDist = (int) round(sqrt(DISTANTION_TOLERANCE * size.width * size.height / M_PI)); - for (int i = 0; i < sizePre && count < amountRes; ++i) { - queryItem = pre[i]; - imgId = queryItem.imgId; - - voteTable = voteStorage[imgId]; - findPointPair(keyPoints, *voteTable, q, r); - homography = cv::findHomography(cv::Mat(r), cv::Mat(q), cv::RANSAC, thresholdDist); - // check empty homography matrix - if (!homography.empty()) { - std::vector posePoint = CvUtils::transformMarkerCoordToObjectCoord(imageInfoStore[imgId].size, - homography); - if (CvUtils::_proveRect(posePoint)) { - queryItem.homography = homography; - queryItem.objPose = posePoint; - queryResult.push_back(queryItem); - count++; - } - } - - r.clear(); - q.clear(); - } - - return queryResult; -} - -void Recognition::clearVote() { - auto it = voteStorage.begin(); - while (it != voteStorage.end()) { - it->second->clear(); - it++; - } -} - -float Recognition::binomialCDF(int x, int n, float p) -{ - if (p == 0 or p > 1 or p < 0) return 0.f; - // case then all points belong to same image - if (p == 1) p = p - 1e-6f; - - float cdf = 0.f; - float b = 0.f; - float logP = log(p); - float logNP = log(1.f-p); - for (int i = 0; i <=x; ++i) { - if (i > 0){ - b+=log(n-i+1) - log(i); - } - float logPMF = b + (float)i * logP + (float)(n - i)*logNP; - cdf += exp(logPMF); - } - return cdf; -} - -void Recognition::findPointPair(std::vector keyPoints, std::vector voteTable, - std::vector &q, std::vector &r) { - auto it = voteTable.begin(); - while (it != voteTable.end()) { - q.push_back(keyPoints[it->featureId].pt); - r.push_back(keyPointStore[it->keyPointId].pt); - it++; - } -} +Recognition::~Recognition() { -Recognition::~Recognition() = default; \ No newline at end of file +} \ No newline at end of file diff --git a/src/Recognition/Recognition.hpp b/src/Recognition/Recognition.hpp index 63c5e87..fa1c709 100644 --- a/src/Recognition/Recognition.hpp +++ b/src/Recognition/Recognition.hpp @@ -5,7 +5,8 @@ #include #include "../Utils/CvUtils.hpp" -#include "FeatureDB.hpp" +#include "MarkerlessDB.hpp" +#include "MarkerlessTrackable.hpp" #include /** @@ -14,46 +15,10 @@ */ class Recognition { private: - cv::Ptr featureDetector; // Feature detector - FeatureDB *vw; // 'Bag of visual words' object - int imageAmount; // Amount of marker images - int featureAmount; // Amount of features - int MIN_MATCH = 6; // Minimum number of required matches - float MIN_PROBABILITY = 0.6f; // Minimum probability of successful match - float DISTANTION_TOLERANCE = 5e-4; // Distance tolerance between corners - float MIN_PROBABILITY_SUCCESS_MATCH = MIN_PROBABILITY - * MIN_PROBABILITY * MIN_PROBABILITY; // Minimal success match probability percentage - - std::multimap featureStore; // {Image id: Feature} map - std::map keyPointStore; // {Image id: KeyPoint} map - std::map imageInfoStore; // {Image id: ImageInfo} map - std::map *> voteStorage; // {Image id: (KeyPoint<->Feature) binding} map - + MarkerlessDB *markerlessDb; // 'Bag of visual words' object public: Recognition(); - /** - * @brief Add and create a BoVW - * - * @param imgs Marker images - * @param numClusters Num of clusters - */ - void addAndCreateBagOfVisualWords(const std::vector &imgs, int numClusters = 0); - - /** - * @brief Add image to BoVW - * - * @param img Marker image - */ - void addVisualWord(const cv::Mat &img); - - /** - * @brief Create a Bag Of Visual Words - * - * @param numClusters amount of clusters - */ - void createBagOfVisualWords(int numClusters = 0); - /** * @brief Add image to marker database * @@ -70,117 +35,8 @@ class Recognition { * @return std::vector Query results */ std::vector queryImage(const cv::Mat &img, int amountRes = 1); - ~Recognition(); - -private: - - /** - * @brief calculates the CDF - *BIN(x, n, p) = n!/(x!*(n-x)!) p^x (1-p)^(n-x) - * - * @param x Random variable - * @param n Total number of trials - * @param p Probability of success of a single trial - * @return float CDF value - */ - float binomialCDF(int x, int n, float p); - - /** - * @brief Extract features from image - * - * @param img Image - * @param keyPoints [out] KeyPoints - * @param descriptor [out] Descriptors - */ - void extractFeatures(const cv::Mat &img, std::vector &keyPoints, cv::Mat &descriptor); - - /** - * @brief For descriptor get feature ids - * - * @param descriptor Descriptor - * @param ids [out] Feature ids - * @return int - */ - int getFeatureIds(const cv::Mat &descriptor, std::vector &ids); - - /** - * @brief Store marker image features - * - * @param id Id of marker - * @param size Size of marker image - * @param keyPoints Marker keypoints - * @param ids Id of features - * @return int - */ - int storeImageFeatures(int id, const cv::Size &size, std::vector keyPoints, std::vector ids); - - /** - * @brief Get the KeyPoint candidate - * - * @return int Keypoint id - */ - int getCandidateKpId(); - - /** - * @brief Make query - * - * @param keyPoints KeyPoints of frame - * @param ids Ids of features frame image - * @param size Frame size - * @param amountWords Amount of visual words - * @param amountRes Limit results - * @return std::vector Result of query - */ - std::vector - searchImageId(std::vector keyPoints, std::vector ids, cv::Size size, int amountWords, - int amountRes); - - /** - * @brief Find (image id <-> keypoint id <-> feature id) binds - * - * @param keyPoints KeyPoints of frame - * @param ids Ids of features - */ - void voteQueryFeatures(std::vector keyPoints, std::vector ids); - - /** - * @brief Clear (image id <-> keypoint id <-> feature id) binds - * - */ - void clearVote(); - - /** - * @brief Get the Match Results - * - * @param keyPoints KeyPoint - * @param amountWords Amount of visual words - * @return std::vector Result of query - */ - std::vector getMatchResults(std::vector keyPoints, int amountWords); - - /** - * @brief Filter results - * - * @param keyPoints KeyPoints - * @param pre Unfiltered results - * @param size Frame size - * @param amountRes Limit amount of results - * @return std::vector Query results - */ - std::vector - filterGeomResults(std::vector keyPoints, std::vector pre, cv::Size size, int amountRes); - /** - * @brief Push query and result keypoints to `q` and `r` vectors - * - * @param keyPoints Frame keypoints - * @param voteTable Vote table - * @param q [out] Query keypoints - * @param r [out] Result keypoints - */ - void - findPointPair(std::vector keyPoints, std::vector voteTable, std::vector &q, - std::vector &r); + ~Recognition(); }; #endif // __RECOGNITION__ \ No newline at end of file diff --git a/src/Recognition/TrackableEntity.cpp b/src/Recognition/TrackableEntity.cpp new file mode 100644 index 0000000..0fe3520 --- /dev/null +++ b/src/Recognition/TrackableEntity.cpp @@ -0,0 +1,5 @@ +#include "TrackableEntity.hpp" + +TrackableEntity::TrackableEntity(const int id) { + this->id = id; +} diff --git a/src/Recognition/TrackableEntity.hpp b/src/Recognition/TrackableEntity.hpp new file mode 100644 index 0000000..86d9a6a --- /dev/null +++ b/src/Recognition/TrackableEntity.hpp @@ -0,0 +1,12 @@ +#ifndef AR_CORE_TRACKABLEENTITY_HPP +#define AR_CORE_TRACKABLEENTITY_HPP + +class TrackableEntity { +protected: + int id; + + TrackableEntity(const int id); +}; + + +#endif //AR_CORE_TRACKABLEENTITY_HPP diff --git a/src/Tracking/Tracking.cpp b/src/Tracking/Tracking.cpp index 29f3a58..118d0ce 100644 --- a/src/Tracking/Tracking.cpp +++ b/src/Tracking/Tracking.cpp @@ -8,10 +8,6 @@ Tracking::Tracking() { MIN_FEATURE_POINTS = 6; } -Tracking *Tracking::create() { - return new Tracking(); -} - void Tracking::start(const cv::Mat &frame, const ObjectPosition &pos) { frame.copyTo(prevFrame); objectPosition = pos; diff --git a/src/Tracking/Tracking.hpp b/src/Tracking/Tracking.hpp index 9ae390b..18deeb9 100644 --- a/src/Tracking/Tracking.hpp +++ b/src/Tracking/Tracking.hpp @@ -34,13 +34,6 @@ class Tracking { public: Tracking(); - /** - * @brief Initializes new tracking instance - * - * @return Tracking* - instance - */ - static Tracking *create(); - /** * @brief Start tracking * diff --git a/src/Utils/CvUtils.hpp b/src/Utils/CvUtils.hpp index f8ae4dc..77c2796 100644 --- a/src/Utils/CvUtils.hpp +++ b/src/Utils/CvUtils.hpp @@ -501,6 +501,32 @@ class CvUtils { } return ret_vec; } + + /** + * @brief calculates the CDF + *BIN(x, n, p) = n!/(x!*(n-x)!) p^x (1-p)^(n-x) + * + * @param x Random variable + * @param n Total number of trials + * @param p Probability of success of a single trial + * @return float CDF value + */ + static float binomialCDF(int x, int n, float p) { + if (p == 0 or p > 1 or p < 0) return 0.f; + + float cdf = 0.f; + float b = 0.f; + float logP = log(p); + float logNP = log(1.f - p); + for (int i = 0; i <= x; ++i) { + if (i > 0) { + b += log(n - i + 1) - log(i); + } + float logPMF = b + (float) i * logP + (float) (n - i) * logNP; + cdf += exp(logPMF); + } + return cdf; + } }; #endif // __CVUTILS__ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6e465e6..6f72a1f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ #include "opencv2/opencv.hpp" #include "AR/Ar.hpp" #include +#include using namespace cv; @@ -44,13 +45,10 @@ int main(int, char **) { ar->add(mat_1); ar->add(mat_3); ar->add(mat_4); - ar->create(); - // start AR process single(mat_2); // start(); - return 0; } @@ -64,6 +62,7 @@ cv::Mat makeQueryMat(cv::Size size, int max_size, int &scale) { } int single(cv::Mat frame) { + auto startTime = std::chrono::steady_clock::now(); cv::Mat gray, query; int scale = 1; query = makeQueryMat(frame.size(), maxFrameSize, scale); @@ -76,7 +75,7 @@ int single(cv::Mat frame) { cv::resize(gray, query, query.size()); std::vector result = ar->process(query); if (!result.empty()) { - for (const auto& r: result) { + for (const auto &r: result) { std::vector objPose; std::cout << "Matched: imgId:" << r.imgId << std::endl; @@ -96,8 +95,10 @@ int single(cv::Mat frame) { cv::putText(frame, std::to_string(imgId), center, OPENCV_FONT, 3, val, 3); } } + std::cout << "Elapsed time: " << (std::chrono::duration_cast( + std::chrono::steady_clock::now() - startTime)).count() << "ms" << std::endl; cv::namedWindow("AR", WINDOW_NORMAL); - cv::resizeWindow("AR", 600,600); + cv::resizeWindow("AR", 600, 600); cv::imshow("AR", frame); cv::waitKey(); return 0; @@ -155,7 +156,7 @@ int start() { cv::putText(frame, std::to_string(imgId), center, OPENCV_FONT, 6, val, 6); } cv::namedWindow("AR", WINDOW_NORMAL); - cv::resizeWindow("AR", 600,600); + cv::resizeWindow("AR", 600, 600); cv::imshow("AR", frame); if (waitKey(1) == 27) break; //quit on ESC button