From a6f9f546a4ac3269027dd1b70bb215fe52252b41 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 29 Aug 2016 21:53:51 +0200 Subject: [PATCH] [DEV] separates algos to simplify codes --- dollar/Engine.cpp | 603 ++---------------------------------- dollar/Engine.h | 51 +-- dollar/EngineN.cpp | 240 ++++++++++++++ dollar/EngineN.h | 45 +++ dollar/EngineP.cpp | 178 +++++++++++ dollar/EngineP.h | 39 +++ dollar/EnginePPlus.cpp | 282 +++++++++++++++++ dollar/EnginePPlus.h | 48 +++ dollar/Gesture.cpp | 31 +- dollar/Gesture.h | 32 +- dollar/GestureN.cpp | 39 +++ dollar/GestureN.h | 46 +++ dollar/GestureP.cpp | 25 ++ dollar/GestureP.h | 31 ++ dollar/GesturePPlus.cpp | 24 ++ dollar/GesturePPlus.h | 31 ++ lutin_dollar.py | 7 + test/main.cpp | 38 +-- tool/generate-form/main.cpp | 57 +++- 19 files changed, 1144 insertions(+), 703 deletions(-) create mode 100644 dollar/EngineN.cpp create mode 100644 dollar/EngineN.h create mode 100644 dollar/EngineP.cpp create mode 100644 dollar/EngineP.h create mode 100644 dollar/EnginePPlus.cpp create mode 100644 dollar/EnginePPlus.h create mode 100644 dollar/GestureN.cpp create mode 100644 dollar/GestureN.h create mode 100644 dollar/GestureP.cpp create mode 100644 dollar/GestureP.h create mode 100644 dollar/GesturePPlus.cpp create mode 100644 dollar/GesturePPlus.h diff --git a/dollar/Engine.cpp b/dollar/Engine.cpp index b6a7516..493bea4 100644 --- a/dollar/Engine.cpp +++ b/dollar/Engine.cpp @@ -9,290 +9,25 @@ #include #include #include -#include -#include -#define MAX_FLOAT std::numeric_limits::max() -// simple decree to radian convertion -#define DEG_2_RAD(ddd) (ddd*M_PI/180.0) +#include +#include +#include -// Test is done on the square of 1.0f * 1.0f ==> the result depend on the diagonal size -#define DIAGONAL (1.414213562) -#define HALF_DIAGONAL (0.707106781) -// an other magic number ratio of starting vetor pos... ==> must be reworked ==> nbElementInVector/RATIO_START_VECTOR -#define RATIO_START_VECTOR (8) -// angle precision of the detecting the way of rotation -#define ANGLE_ROTATION (2.0f) -// Angle to start processing of a start vector comparaison -#define ANGLE_THRESHOLD_START_PROCESSING DEG_2_RAD(30.0) - -// A magic number: 0.5 * (-1.0 + sqrt(5.0)) -#define MAGIC_RATIO (0.618033989) - - - -static float angleBetweenUnitVectors(const vec2& _vect1, const vec2& _vect2) { - float n = _vect1.dot(_vect2); - // TODO : No needs - if (n < -1.0 || n > +1.0){ - n = round(n*100000.0f)/100000.0f; - } - return std::acos(n); // arc cosine of the vector dot product -} - -static float pathDistance(const std::vector& _path1, const std::vector& _path2) { - // assumes pts1.size == pts2.size - float distance = 0.0; - if (_path1.size() != _path2.size()) { - DOLLAR_ERROR("Path have not the same size: " << _path1.size() << " != " << _path2.size()); - return MAX_FLOAT; - } - for (size_t iii=0; iii<_path1.size(); ++iii) { - distance += (_path2[iii]-_path1[iii]).length(); - } - DOLLAR_VERBOSE("distance: " << distance << " size= " << _path1.size()); - return (distance / _path1.size()); -} dollar::Engine::Engine(): - m_PPlusDistance(0.10f), - m_PPlusExcludeDistance(0.2*0.2), - m_scaleKeepRatio(false) { - m_numPointsInGesture = 128; - DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); - setRotationInvariance(false); -} - - -void dollar::Engine::setNumberPointInGesture(size_t _value) { - if (_value == m_numPointsInGesture) { - return; - } - m_numPointsInGesture = _value; - DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); - for (auto &it: m_gestures) { - it.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance, m_scaleKeepRatio); - } -} - -size_t dollar::Engine::getNumberPointInGesture() { - return m_numPointsInGesture; -} - -void dollar::Engine::setPPlusDistance(float _value) { - if (_value*_value == m_PPlusDistance*) { - return; - } - m_PPlusDistance = _value*_value; - for (auto &it: m_gestures) { - it.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance, m_scaleKeepRatio); - } -} - -float dollar::Engine::getPPlusDistance() { - return std::sqrt(m_PPlusDistance); -} - -void dollar::Engine::setPPlusExcludeDistance(float _value) { - if (_value == m_PPlusExcludeDistance) { - return; - } - m_PPlusExcludeDistance = _value; -} - -float dollar::Engine::getPPlusExcludeDistance() { - return m_PPlusExcludeDistance; -} -void dollar::Engine::setScaleKeepRatio(bool _value) { - if (_value == m_scaleKeepRatio) { - return; - } - m_scaleKeepRatio = _value; - for (auto &it: m_gestures) { - it.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance, m_scaleKeepRatio); - } -} - -bool dollar::Engine::getScaleKeepRatio() { - return m_scaleKeepRatio; -} - -float dollar::Engine::distanceAtBestAngle(const std::vector& _points, const std::vector& _reference) { - float startRange = -m_angleRange; - float endRange = m_angleRange; - float x1 = MAGIC_RATIO * startRange + (1.0 - MAGIC_RATIO) * endRange; - float f1 = pathDistance(dollar::rotateBy(_points, x1), _reference); - float x2 = (1.0 - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange; - float f2 = pathDistance(dollar::rotateBy(_points, x2), _reference); - DOLLAR_VERBOSE("init: startRange=" << startRange << " endRange=" << endRange << " MAGIC_RATIO=" << MAGIC_RATIO << " x1=" << x1 << " f1=" << f1 << " x2=" << x2 << " f2=" << f2); - while (fabs(endRange - startRange) > ANGLE_ROTATION) { - if (f1 < f2) { - endRange = x2; - x2 = x1; - f2 = f1; - x1 = MAGIC_RATIO * startRange + (1.0f - MAGIC_RATIO) * endRange; - f1 = pathDistance(dollar::rotateBy(_points, x1), _reference); - } else { - startRange = x1; - x1 = x2; - f1 = f2; - x2 = (1.0f - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange; - f2 = pathDistance(dollar::rotateBy(_points, x2), _reference); - } - } - return std::min(f1, f2); -} - -static float cloudDistance(const std::vector& _points1, const std::vector& _points2, size_t _start) { - std::vector matched; - matched.resize(_points1.size(), false); - float out = 0; - size_t iii = _start; - do { - float min = MAX_FLOAT; - size_t index = 0; - for (size_t jjj=0; jjj& _points, const std::vector& _reference) { - float out = MAX_FLOAT; - float si = 0.5f; - float step = pow(_points.size(), si-1); - if (step < 1) { - // DOLLAR_ERROR(" step is too small ... " << step); - step = 1.0f; - } - for (size_t iii=0; iii<_points.size(); iii+=int32_t(step)) { - float d1 = cloudDistance(_points, _reference, iii); - float d2 = cloudDistance(_reference, _points, iii); - out = std::min(out, std::min(d1,d2)); - } - return out; // Distance to the nearest point must be < 2.0 (maximum distance visible) -} - - -static float calculatePPlusDistance(const std::vector& _points, - const std::vector& _reference, - std::vector>& _dataDebug) { - std::vector distance; // note: use square distance (faster, we does not use std::sqrt()) - distance.resize(_points.size(), MAX_FLOAT); - // point Id that is link on the reference. - std::vector usedId; - usedId.resize(_reference.size(), -1); - for (int32_t iii=0; iii<_points.size(); iii++) { - if (distance[iii] < 100.0) { - continue; - } - float bestDistance = MAX_FLOAT; - int32_t kkkBest = -1; - for (int32_t kkk=0; kkk<_reference.size(); ++kkk) { - float dist = (_points[iii]-_reference[kkk]).length2(); - if (usedId[kkk] != -1) { - if (dist < distance[usedId[kkk]]) { - if (dist < bestDistance) { - bestDistance = dist; - kkkBest = kkk; - } - } - } else { - if (dist < bestDistance) { - bestDistance = dist; - kkkBest = kkk; - } - } - } - if (kkkBest != -1) { - // reject the distance ... if too big ... - if (bestDistance <= m_PPlusExcludeDistance) { - int32_t previous = usedId[kkkBest]; - usedId[kkkBest] = iii; - distance[iii] = bestDistance; - //DOLLAR_INFO("set new link: " << iii << " with " << kkkBest << " d=" << bestDistance); - if (previous != -1) { - //DOLLAR_INFO(" Reject : " << previous); - distance[previous] = MAX_FLOAT; - iii = previous-1; - } - } - } - } - double fullDistance = 0; - int32_t nbTestNotUsed = 0; - int32_t nbReferenceNotUsed = 0; - // now we count the full distance use and the number of local gesture not use - for (auto &it : distance) { - if (it < 100.0) { - fullDistance += it; - } else { - nbTestNotUsed++; - } - } - // we count the number of point in the gesture reference not used: - for (auto &it : usedId) { - if (it == -1) { - nbReferenceNotUsed++; - } - } - // now we add panality: - fullDistance += float(nbTestNotUsed)* 0.1f; - fullDistance += float(nbReferenceNotUsed)* 0.1f; + m_nbResult(5) { - for (int32_t kkk=0; kkk& _points, const std::string& _method) { +dollar::Results dollar::Engine::recognize(const std::vector& _points) { std::vector> tmp; tmp.push_back(_points); - return recognize(tmp, _method); + return recognize2(tmp); +} +dollar::Results dollar::Engine::recognize(const std::vector>& _points) { + return recognize2(_points); } -#define MAX_RESULT_NUMBER (5) -dollar::Results dollar::Engine::recognize(const std::vector>& _strokes, const std::string& _method) { - // Check if we have gestures... - if (m_gestures.empty()) { - DOLLAR_WARNING("No templates loaded so no symbols to match."); - return Results(); - } - if ( _method == "$N-protractor" - || _method == "$N" +ememory::SharedPtr dollar::createEngine(const std::string& _method) { + if ( _method == "$N" || _method == "$1") { - return recognizeN(_strokes, _method); - } else if (_method == "$P") { - return recognizeP(_strokes); - } else if (_method == "$P+") { - return recognizePPlus(_strokes); + return ememory::makeShared(false); } - DOLLAR_WARNING("Un-recognise methode ... '" << _method << "' supported: [$1,$N,$N-protractor,$P,$P+]" ); - return Results(); + if (_method == "$N-protractor") { + return ememory::makeShared(true); + } + if (_method == "$P") { + return ememory::makeShared(); + } + if (_method == "$P+") { + return ememory::makeShared(); + } + return nullptr; } - - -dollar::Results dollar::Engine::recognizeN(const std::vector>& _strokes, const std::string& _method) { - std::vector points = dollar::combineStrokes(_strokes); - points = dollar::normalizePath(points, m_numPointsInGesture, m_paramterIgnoreRotation, m_scaleKeepRatio); - vec2 startv = dollar::getStartVector(points, m_numPointsInGesture/RATIO_START_VECTOR); - std::vector vector = normalyse(points); - // Keep maximum 5 results ... - float bestDistance[MAX_RESULT_NUMBER]; - int32_t indexOfBestMatch[MAX_RESULT_NUMBER]; - for (size_t iii=0; iii ANGLE_THRESHOLD_START_PROCESSING) { - continue; - } - float distance = MAX_FLOAT; - // for Protractor - if (_method=="$p-protractor") { - distance = optimalCosineDistance(vector, gesture.getEngineVector(jjj)); - } else { - // Golden Section Search (original $N) - distance = distanceAtBestAngle(points, gesture.getEnginePath(jjj)); - } - for (size_t kkk=0; kkkint32_t(kkk); --rrr) { - bestDistance[rrr] = bestDistance[rrr-1]; - indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; - } - indexOfBestMatch[kkk] = iii; - } - bestDistance[kkk] = distance; - break; - } else { - if (kkk == 0) { - DOLLAR_VERBOSE("[" << iii << "," << jjj << "] d=" << distance << " < bd=" << bestDistance << " "); - } - } - } - } - } - // Check if we have match ... - if (-1 == indexOfBestMatch[0]) { - DOLLAR_WARNING("Couldn't find a good match."); - return Results(); - } - Results res; - // transform distance in a % range - if (_method == "$p-protractor") { - for (size_t iii=0; iii>& _strokes) { - std::vector points = dollar::combineStrokes(_strokes); - points = dollar::normalizePath(points, m_numPointsInGesture, m_paramterIgnoreRotation, m_scaleKeepRatio); - // Keep maximum 5 results ... - float bestDistance[MAX_RESULT_NUMBER]; - int32_t indexOfBestMatch[MAX_RESULT_NUMBER]; - for (size_t iii=0; iiiint32_t(kkk); --rrr) { - bestDistance[rrr] = bestDistance[rrr-1]; - indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; - } - indexOfBestMatch[kkk] = iii; - } - bestDistance[kkk] = distance; - break; - } else { - if (kkk == 0) { - DOLLAR_VERBOSE("[" << iii << "," << jjj << "] d=" << distance << " < bd=" << bestDistance << " "); - } - } - } - } - // Check if we have match ... - if (-1 == indexOfBestMatch[0]) { - DOLLAR_WARNING("Couldn't find a good match."); - return Results(); - } - Results res; - for (size_t iii=0; iii>& _strokes, - const std::vector& _points, - std::vector> _links, - bool _keepAspectRatio) { - std::string data("\n"); - data += "\n"; - for (auto &itLines : gesture.getPath()) { - data += " refListPoint = gesture.getEnginePoints(); - for (auto &it : refListPoint) { - data += " \n"; - } - std::vector testListPoint = _points; - for (auto &it : testListPoint) { - data += " \n"; - } - for (auto &it : _links) { - data += " >& _strokes) { - std::vector points = dollar::normalizePathToPoints(_strokes, m_PPlusDistance, m_scaleKeepRatio); - // Keep maximum 5 results ... - float bestDistance[MAX_RESULT_NUMBER]; - int32_t indexOfBestMatch[MAX_RESULT_NUMBER]; - for (size_t iii=0; iii> dataPair; - distance = calculatePPlusDistance(points, gesture.getEnginePoints(), dataPair); - //storeSVG("out_dollar/lib/recognizePPlus/" + gesture.getName() + "_" + etk::to_string(gesture.getId()) + ".svg", gesture, _strokes, points, dataPair, m_scaleKeepRatio); - for (size_t kkk=0; kkkint32_t(kkk); --rrr) { - bestDistance[rrr] = bestDistance[rrr-1]; - indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; - } - indexOfBestMatch[kkk] = iii; - } - bestDistance[kkk] = distance; - break; - } else { - if (kkk == 0) { - DOLLAR_VERBOSE("[" << iii << "] d=" << distance << " < bd=" << bestDistance << " "); - } - } - } - } - // Check if we have match ... - if (-1 == indexOfBestMatch[0]) { - DOLLAR_WARNING("Couldn't find a good match."); - return Results(); - } - Results res; - for (size_t iii=0; iii #include #include +#include namespace dollar { class Engine { protected: - float m_PPlusDistance; + size_t m_nbResult; // Number of result in the recognition parsing public: - void setPPlusDistance(float _value); - float getPPlusDistance(); - protected: - float m_PPlusExcludeDistance; - public: - void setPPlusExcludeDistance(float _value); - float setPPlusExcludeDistance(); - protected: - bool m_scaleKeepRatio; // when rescale the path, keep the aspect ration for processing - public: - void setScaleKeepRatio(bool _value); - bool getScaleKeepRatio(); - protected: - float m_angleRange; - bool m_paramterIgnoreRotation; //!< Ignore the start rotation of the gesture - public: - void setRotationInvariance(bool _ignoreRotation); - protected: - size_t m_numPointsInGesture; //!< Number of point in a gesture to recognise patern ... - public: - void setNumberPointInGesture(size_t _value); - size_t getNumberPointInGesture(); - protected: - std::vector m_gestures; //!< List of all loaded gesture in the engine + void setNumberResult(size_t _value); + size_t getNumberResult(); public: Engine(); - float distanceAtBestAngle(const std::vector& _points, const std::vector& _reference); - Results recognize(const std::vector>& _paths, const std::string& _method="$N"); - Results recognize(const std::vector& _points, const std::string& _method="$N"); - float optimalCosineDistance(const std::vector& _vect1, const std::vector& _vect2); - bool loadPath(const std::string& _path); - bool loadGesture(const std::string& _filename); - void addGesture(Gesture _gesture); - private: - Results recognizeN(const std::vector>& _paths, const std::string& _method="$N"); - Results recognizeP(const std::vector>& _paths); - Results recognizePPlus(const std::vector>& _paths); + virtual ~Engine() = default; + dollar::Results recognize(const std::vector& _paths); + dollar::Results recognize(const std::vector>& _paths); + protected: + virtual dollar::Results recognize2(const std::vector>& _paths) = 0; + public: + virtual bool loadPath(const std::string& _path); + virtual bool loadGesture(const std::string& _filename) = 0; + virtual void addGesture(ememory::SharedPtr _gesture) = 0; }; + + ememory::SharedPtr createEngine(const std::string& _method="$N"); } diff --git a/dollar/EngineN.cpp b/dollar/EngineN.cpp new file mode 100644 index 0000000..ba9a7e6 --- /dev/null +++ b/dollar/EngineN.cpp @@ -0,0 +1,240 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#define MAX_FLOAT std::numeric_limits::max() +// simple decree to radian convertion +#define DEG_2_RAD(ddd) (ddd*M_PI/180.0) + +// Test is done on the square of 1.0f * 1.0f ==> the result depend on the diagonal size +#define DIAGONAL (1.414213562) +#define HALF_DIAGONAL (0.707106781) +// an other magic number ratio of starting vetor pos... ==> must be reworked ==> nbElementInVector/RATIO_START_VECTOR +#define RATIO_START_VECTOR (8) +// angle precision of the detecting the way of rotation +#define ANGLE_ROTATION (2.0f) +// Angle to start processing of a start vector comparaison +#define ANGLE_THRESHOLD_START_PROCESSING DEG_2_RAD(30.0) + +// A magic number: 0.5 * (-1.0 + sqrt(5.0)) +#define MAGIC_RATIO (0.618033989) + + + +static float angleBetweenUnitVectors(const vec2& _vect1, const vec2& _vect2) { + float n = _vect1.dot(_vect2); + // TODO : No needs + if (n < -1.0 || n > +1.0){ + n = round(n*100000.0f)/100000.0f; + } + return std::acos(n); // arc cosine of the vector dot product +} + +static float pathDistance(const std::vector& _path1, const std::vector& _path2) { + // assumes pts1.size == pts2.size + float distance = 0.0; + if (_path1.size() != _path2.size()) { + DOLLAR_ERROR("Path have not the same size: " << _path1.size() << " != " << _path2.size()); + return MAX_FLOAT; + } + for (size_t iii=0; iii<_path1.size(); ++iii) { + distance += (_path2[iii]-_path1[iii]).length(); + } + DOLLAR_VERBOSE("distance: " << distance << " size= " << _path1.size()); + return (distance / _path1.size()); +} + +dollar::EngineN::EngineN(bool _protractor): + m_protractor(_protractor), + m_numPointsInGesture(128) { + DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); + setRotationInvariance(false); +} + + +void dollar::EngineN::setNumberPointInGesture(size_t _value) { + if (_value == m_numPointsInGesture) { + return; + } + m_numPointsInGesture = _value; + DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); + for (auto &it: m_gestures) { + if (it == nullptr) { + continue; + } + it->configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation); + } +} + +size_t dollar::EngineN::getNumberPointInGesture() { + return m_numPointsInGesture; +} + +float dollar::EngineN::distanceAtBestAngle(const std::vector& _points, const std::vector& _reference) { + float startRange = -m_angleRange; + float endRange = m_angleRange; + float x1 = MAGIC_RATIO * startRange + (1.0 - MAGIC_RATIO) * endRange; + float f1 = pathDistance(dollar::rotateBy(_points, x1), _reference); + float x2 = (1.0 - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange; + float f2 = pathDistance(dollar::rotateBy(_points, x2), _reference); + DOLLAR_VERBOSE("init: startRange=" << startRange << " endRange=" << endRange << " MAGIC_RATIO=" << MAGIC_RATIO << " x1=" << x1 << " f1=" << f1 << " x2=" << x2 << " f2=" << f2); + while (fabs(endRange - startRange) > ANGLE_ROTATION) { + if (f1 < f2) { + endRange = x2; + x2 = x1; + f2 = f1; + x1 = MAGIC_RATIO * startRange + (1.0f - MAGIC_RATIO) * endRange; + f1 = pathDistance(dollar::rotateBy(_points, x1), _reference); + } else { + startRange = x1; + x1 = x2; + f1 = f2; + x2 = (1.0f - MAGIC_RATIO) * startRange + MAGIC_RATIO * endRange; + f2 = pathDistance(dollar::rotateBy(_points, x2), _reference); + } + } + return std::min(f1, f2); +} + + +float dollar::EngineN::optimalCosineDistance(const std::vector& _vect1, const std::vector& _vect2) { + if (_vect1.size() != _vect2.size()) { + DOLLAR_ERROR("Vector have not the same size: " << _vect1.size() << " != " << _vect2.size()); + return M_PI; + } + double somDot = 0; + double somCross = 0; + for (size_t iii=0; iii<_vect1.size(); ++iii) { + somDot += _vect1[iii].dot(_vect2[iii]); + somCross += _vect1[iii].cross(_vect2[iii]); + } + if (somDot == 0.0f) { + DOLLAR_ERROR("devide by 0"); + return M_PI; + } + float angle = std::atan(somCross / somDot); + return std::acos(somDot * std::cos(angle) + somCross * std::sin(angle)); +} + + + +void dollar::EngineN::setRotationInvariance(bool _ignoreRotation) { + m_paramterIgnoreRotation = _ignoreRotation; + if (m_paramterIgnoreRotation == true) { + m_angleRange = 45.0; + } else { + m_angleRange = 15.0; + } +} + +bool dollar::EngineN::loadGesture(const std::string& _filename) { + ememory::SharedPtr ref = ememory::makeShared(); + DOLLAR_DEBUG("Load Gesture: " << _filename); + if (ref->load(_filename) == true) { + addGesture(ref); + return true; + } + return false; +} + +void dollar::EngineN::addGesture(ememory::SharedPtr _gesture) { + ememory::SharedPtr gest = ememory::dynamicPointerCast(_gesture); + if (gest != nullptr) { + gest->configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation); + m_gestures.push_back(gest); + } +} + + +dollar::Results dollar::EngineN::recognize2(const std::vector>& _strokes) { + std::vector points = dollar::combineStrokes(_strokes); + points = dollar::normalizePath(points, m_numPointsInGesture, m_paramterIgnoreRotation, false); + vec2 startv = dollar::getStartVector(points, m_numPointsInGesture/RATIO_START_VECTOR); + std::vector vector = normalyse(points); + // Keep maximum 5 results ... + float bestDistance[m_nbResult]; + int32_t indexOfBestMatch[m_nbResult]; + for (size_t iii=0; iiigetName() << "'"); + ememory::SharedPtr gesture = m_gestures[iii]; + for (size_t jjj=0; jjjgetEngineSize(); ++jjj) { + if (gesture->getEnginePath(jjj).size() == 0) { + DOLLAR_ERROR("Reference path with no Value"); + continue; + } + // strokes start in the same direction + if(angleBetweenUnitVectors(startv, gesture->getEngineStartVector(jjj)) > ANGLE_THRESHOLD_START_PROCESSING) { + continue; + } + float distance = MAX_FLOAT; + // for Protractor + if (m_protractor == true) { + distance = optimalCosineDistance(vector, gesture->getEngineVector(jjj)); + } else { + // Golden Section Search (original $N) + distance = distanceAtBestAngle(points, gesture->getEnginePath(jjj)); + } + for (size_t kkk=0; kkkint32_t(kkk); --rrr) { + bestDistance[rrr] = bestDistance[rrr-1]; + indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; + } + indexOfBestMatch[kkk] = iii; + } + bestDistance[kkk] = distance; + break; + } else { + if (kkk == 0) { + DOLLAR_VERBOSE("[" << iii << "," << jjj << "] d=" << distance << " < bd=" << bestDistance << " "); + } + } + } + } + } + // Check if we have match ... + if (-1 == indexOfBestMatch[0]) { + DOLLAR_WARNING("Couldn't find a good match."); + return Results(); + } + Results res; + // transform distance in a % range + if (m_protractor == true) { + for (size_t iii=0; iiigetName(), score); + } + } + } else { + for (size_t iii=0; iiigetName(), score); + } + } + } + return res; +} + diff --git a/dollar/EngineN.h b/dollar/EngineN.h new file mode 100644 index 0000000..19381a1 --- /dev/null +++ b/dollar/EngineN.h @@ -0,0 +1,45 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dollar { + class EngineN : public dollar::Engine { + private: + bool m_protractor; + protected: + float m_angleRange; + bool m_paramterIgnoreRotation; //!< Ignore the start rotation of the gesture + public: + void setRotationInvariance(bool _ignoreRotation); + protected: + size_t m_numPointsInGesture; //!< Number of point in a gesture to recognise patern ... + public: + void setNumberPointInGesture(size_t _value); + size_t getNumberPointInGesture(); + protected: + std::vector> m_gestures; //!< List of all loaded gesture in the engine + public: + EngineN(bool _protractor); + dollar::Results recognize2(const std::vector>& _points) override; + bool loadGesture(const std::string& _filename) override; + void addGesture(ememory::SharedPtr _gesture) override; + protected: + float distanceAtBestAngle(const std::vector& _points, const std::vector& _reference); + float optimalCosineDistance(const std::vector& _vect1, const std::vector& _vect2); + }; +} + + diff --git a/dollar/EngineP.cpp b/dollar/EngineP.cpp new file mode 100644 index 0000000..3571868 --- /dev/null +++ b/dollar/EngineP.cpp @@ -0,0 +1,178 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#define MAX_FLOAT std::numeric_limits::max() + + +dollar::EngineP::EngineP(): + m_scaleKeepRatio(false), + m_numPointsInGesture(128) { + DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); + +} + + +void dollar::EngineP::setNumberPointInGesture(size_t _value) { + if (_value == m_numPointsInGesture) { + return; + } + m_numPointsInGesture = _value; + DOLLAR_ASSERT(m_numPointsInGesture>16, "NB element in a path must be > 16 ..."); + for (auto &it: m_gestures) { + if (it == nullptr) { + continue; + } + it->configure(m_numPointsInGesture); + } +} + +size_t dollar::EngineP::getNumberPointInGesture() { + return m_numPointsInGesture; +} + +void dollar::EngineP::setScaleKeepRatio(bool _value) { + if (_value == m_scaleKeepRatio) { + return; + } + m_scaleKeepRatio = _value; + for (auto &it: m_gestures) { + if (it == nullptr) { + continue; + } + it->configure(m_numPointsInGesture); + } +} + +bool dollar::EngineP::getScaleKeepRatio() { + return m_scaleKeepRatio; +} + +static float cloudDistance(const std::vector& _points1, const std::vector& _points2, size_t _start) { + std::vector matched; + matched.resize(_points1.size(), false); + float out = 0; + size_t iii = _start; + do { + float min = MAX_FLOAT; + size_t index = 0; + for (size_t jjj=0; jjj& _points, const std::vector& _reference) { + float out = MAX_FLOAT; + float si = 0.5f; + float step = pow(_points.size(), si-1); + if (step < 1) { + // DOLLAR_ERROR(" step is too small ... " << step); + step = 1.0f; + } + for (size_t iii=0; iii<_points.size(); iii+=int32_t(step)) { + float d1 = cloudDistance(_points, _reference, iii); + float d2 = cloudDistance(_reference, _points, iii); + out = std::min(out, std::min(d1,d2)); + } + return out; // Distance to the nearest point must be < 2.0 (maximum distance visible) +} + + +bool dollar::EngineP::loadGesture(const std::string& _filename) { + ememory::SharedPtr ref = ememory::makeShared(); + DOLLAR_DEBUG("Load Gesture: " << _filename); + if (ref->load(_filename) == true) { + addGesture(ref); + return true; + } + return false; +} + +void dollar::EngineP::addGesture(ememory::SharedPtr _gesture) { + ememory::SharedPtr gest = ememory::dynamicPointerCast(_gesture); + if (gest != nullptr) { + gest->configure(m_numPointsInGesture); + m_gestures.push_back(gest); + } +} + +dollar::Results dollar::EngineP::recognize2(const std::vector>& _strokes) { + std::vector points = dollar::combineStrokes(_strokes); + points = dollar::normalizePath(points, m_numPointsInGesture, false, m_scaleKeepRatio); + // Keep maximum 5 results ... + float bestDistance[m_nbResult]; + int32_t indexOfBestMatch[m_nbResult]; + for (size_t iii=0; iiigetName() << "'"); + ememory::SharedPtr gesture = m_gestures[iii]; + if (gesture->getPath().size() == 0) { + DOLLAR_ERROR("Reference path with no Value"); + continue; + } + float distance = MAX_FLOAT; + distance = calculateBestDistance(points, gesture->getPath()); + for (size_t kkk=0; kkkint32_t(kkk); --rrr) { + bestDistance[rrr] = bestDistance[rrr-1]; + indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; + } + indexOfBestMatch[kkk] = iii; + } + bestDistance[kkk] = distance; + break; + } else { + if (kkk == 0) { + DOLLAR_VERBOSE("[" << iii << "] d=" << distance << " < bd=" << bestDistance << " "); + } + } + } + } + // Check if we have match ... + if (-1 == indexOfBestMatch[0]) { + DOLLAR_WARNING("Couldn't find a good match."); + return Results(); + } + Results res; + for (size_t iii=0; iiigetName(), score); + } + } + return res; +} + diff --git a/dollar/EngineP.h b/dollar/EngineP.h new file mode 100644 index 0000000..28d387f --- /dev/null +++ b/dollar/EngineP.h @@ -0,0 +1,39 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace dollar { + class EngineP : public dollar::Engine { + protected: + bool m_scaleKeepRatio; // when rescale the path, keep the aspect ration for processing + public: + void setScaleKeepRatio(bool _value); + bool getScaleKeepRatio(); + protected: + size_t m_numPointsInGesture; //!< Number of point in a gesture to recognise patern ... + public: + void setNumberPointInGesture(size_t _value); + size_t getNumberPointInGesture(); + protected: + std::vector> m_gestures; //!< List of all loaded gesture in the engine + public: + EngineP(); + dollar::Results recognize2(const std::vector>& _paths) override; + bool loadGesture(const std::string& _filename) override; + void addGesture(ememory::SharedPtr _gesture) override; + }; +} + + diff --git a/dollar/EnginePPlus.cpp b/dollar/EnginePPlus.cpp new file mode 100644 index 0000000..a460309 --- /dev/null +++ b/dollar/EnginePPlus.cpp @@ -0,0 +1,282 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#define MAX_FLOAT std::numeric_limits::max() + + + +dollar::EnginePPlus::EnginePPlus(): + m_PPlusDistance(0.10f), + m_PPlusExcludeDistance(0.2*0.2), + m_scaleKeepRatio(false) { + +} + + +void dollar::EnginePPlus::setPPlusDistance(float _value) { + if (_value*_value == m_PPlusDistance) { + return; + } + m_PPlusDistance = _value*_value; + for (auto &it: m_gestures) { + if (it == nullptr) { + continue; + } + it->configure(m_PPlusDistance, m_scaleKeepRatio); + } +} + +float dollar::EnginePPlus::getPPlusDistance() { + return std::sqrt(m_PPlusDistance); +} + +void dollar::EnginePPlus::setPPlusExcludeDistance(float _value) { + if (_value == m_PPlusExcludeDistance) { + return; + } + m_PPlusExcludeDistance = _value; +} + +float dollar::EnginePPlus::getPPlusExcludeDistance() { + return m_PPlusExcludeDistance; +} +void dollar::EnginePPlus::setScaleKeepRatio(bool _value) { + if (_value == m_scaleKeepRatio) { + return; + } + m_scaleKeepRatio = _value; + for (auto &it: m_gestures) { + if (it == nullptr) { + continue; + } + it->configure(m_PPlusDistance, m_scaleKeepRatio); + } +} + +bool dollar::EnginePPlus::getScaleKeepRatio() { + return m_scaleKeepRatio; +} + + + +float dollar::EnginePPlus::calculatePPlusDistance(const std::vector& _points, + const std::vector& _reference, + std::vector>& _dataDebug) { + std::vector distance; // note: use square distance (faster, we does not use std::sqrt()) + distance.resize(_points.size(), MAX_FLOAT); + // point Id that is link on the reference. + std::vector usedId; + usedId.resize(_reference.size(), -1); + for (int32_t iii=0; iiiload(_filename) == true) { + addGesture(ref); + return true; + } + return false; +} + +void dollar::EnginePPlus::addGesture(ememory::SharedPtr _gesture) { + ememory::SharedPtr gest = ememory::dynamicPointerCast(_gesture); + if (gest != nullptr) { + gest->configure(m_PPlusDistance, m_scaleKeepRatio); + m_gestures.push_back(gest); + } +} + +static void storeSVG(const std::string& _fileName, + const ememory::SharedPtr& _gesture, + const std::vector>& _strokes, + const std::vector& _points, + std::vector> _links, + bool _keepAspectRatio) { + std::string data("\n"); + data += "\n"; + for (auto &itLines : dollar::scaleToOne(_gesture->getPath(), _keepAspectRatio)) { + data += " refListPoint = _gesture->getEnginePoints(); + for (auto &it : refListPoint) { + data += " \n"; + } + std::vector testListPoint = _points; + for (auto &it : testListPoint) { + data += " \n"; + } + for (auto &it : _links) { + data += " >& _strokes) { + std::vector points = dollar::normalizePathToPoints(_strokes, m_PPlusDistance, m_scaleKeepRatio); + // Keep maximum 5 results ... + float bestDistance[m_nbResult]; + int32_t indexOfBestMatch[m_nbResult]; + for (size_t iii=0; iiigetName() << "'"); + ememory::SharedPtr gesture = m_gestures[iii]; + if (gesture->getEnginePoints().size() == 0) { + //DOLLAR_ERROR("Reference path with no Value"); + continue; + } + float distance = MAX_FLOAT; + std::vector> dataPair; + distance = calculatePPlusDistance(points, gesture->getEnginePoints(), dataPair); + //storeSVG("out_dollar/lib/recognizePPlus/" + gesture->getName() + "_" + etk::to_string(gesture->getId()) + ".svg", gesture, _strokes, points, dataPair, m_scaleKeepRatio); + for (size_t kkk=0; kkkint32_t(kkk); --rrr) { + bestDistance[rrr] = bestDistance[rrr-1]; + indexOfBestMatch[rrr] = indexOfBestMatch[rrr-1]; + } + indexOfBestMatch[kkk] = iii; + } + bestDistance[kkk] = distance; + break; + } else { + if (kkk == 0) { + DOLLAR_VERBOSE("[" << iii << "] d=" << distance << " < bd=" << bestDistance << " "); + } + } + } + } + // Check if we have match ... + if (-1 == indexOfBestMatch[0]) { + DOLLAR_WARNING("Couldn't find a good match."); + return Results(); + } + Results res; + for (size_t iii=0; iiigetName(), score); + } + } + + return res; +} \ No newline at end of file diff --git a/dollar/EnginePPlus.h b/dollar/EnginePPlus.h new file mode 100644 index 0000000..11ec2f4 --- /dev/null +++ b/dollar/EnginePPlus.h @@ -0,0 +1,48 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace dollar { + class EnginePPlus : public dollar::Engine { + protected: + float m_PPlusDistance; + public: + void setPPlusDistance(float _value); + float getPPlusDistance(); + protected: + float m_PPlusExcludeDistance; + public: + void setPPlusExcludeDistance(float _value); + float getPPlusExcludeDistance(); + protected: + bool m_scaleKeepRatio; // when rescale the path, keep the aspect ration for processing + public: + void setScaleKeepRatio(bool _value); + bool getScaleKeepRatio(); + protected: + std::vector> m_gestures; //!< List of all loaded gesture in the engine + public: + EnginePPlus(); + dollar::Results recognize2(const std::vector>& _paths) override; + bool loadGesture(const std::string& _filename) override; + void addGesture(ememory::SharedPtr _gesture) override; + protected: + float calculatePPlusDistance(const std::vector& _points, + const std::vector& _reference, + std::vector>& _dataDebug); + }; +} + + diff --git a/dollar/Gesture.cpp b/dollar/Gesture.cpp index 077ae4c..0e8cfc3 100644 --- a/dollar/Gesture.cpp +++ b/dollar/Gesture.cpp @@ -167,9 +167,11 @@ void dollar::Gesture::storeSVG(const std::string& _fileName, bool _storeDot) { data += " />\n"; } if (_storeDot == true) { + /* for (auto &it : m_enginePoints) { data += " \n"; } + */ } data += "\n"; etk::FSNodeWriteAllData(_fileName, data); @@ -179,33 +181,4 @@ void dollar::Gesture::set(const std::string& _name, uint32_t _subId, std::vector m_name = _name; m_subId = _subId; m_path = _path; - m_enginePath.clear(); - m_engineVector.clear(); - m_engineStartV.clear(); - m_enginePoints.clear(); - m_path2.clear(); } - -void dollar::Gesture::configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, float _distance, bool _keepAspectRatio) { - m_enginePath.clear(); - m_engineVector.clear(); - m_engineStartV.clear(); - m_enginePoints.clear(); - m_path2 = dollar::scaleToOne(m_path, _keepAspectRatio); - // Generates dots: - m_enginePoints = dollar::normalizePathToPoints(m_path, _distance, _keepAspectRatio); - DOLLAR_VERBOSE("create " << m_enginePoints.size() << " points"); - // for debug only - //storeSVG("out_dollar/lib/gestures/" + m_name + "_" + etk::to_string(m_subId) + ".svg", true); - // Simplyfy paths - std::vector> uniPath = dollar::makeReferenceStrokes(m_path); - // normalize paths - for (auto &it : uniPath) { - std::vector val = dollar::normalizePath(it, _nbSample, _ignoreRotation, _keepAspectRatio); - m_enginePath.push_back(val); - // calculate start vector: - vec2 startv = dollar::getStartVector(val, _startAngleIndex); - m_engineStartV.push_back(startv); - m_engineVector.push_back(dollar::normalyse(val)); - } -} \ No newline at end of file diff --git a/dollar/Gesture.h b/dollar/Gesture.h index 7afff18..3a22d14 100644 --- a/dollar/Gesture.h +++ b/dollar/Gesture.h @@ -7,6 +7,7 @@ #pragma once #include #include +#include namespace dollar { class Gesture { @@ -14,9 +15,9 @@ namespace dollar { std::string m_name; uint32_t m_subId; std::vector> m_path; - std::vector> m_path2; public: Gesture(); + virtual ~Gesture() = default; bool load(const std::string& _filename); bool store(const std::string& _filename); void set(const std::string& _name, uint32_t _subId, std::vector> _path); @@ -32,35 +33,6 @@ namespace dollar { const uint32_t& getId() { return m_subId; } - const std::vector>& getPath() const { - return m_path2; - } - std::vector>& getPath() { - return m_path2; - } - protected: - std::vector> m_enginePath; // Singulized path with every conbinaison - std::vector> m_engineVector; - std::vector m_engineStartV; - std::vector m_enginePoints; - public: - // Configure the reference gesture for recognition... - void configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, float _distance, bool _keepAspectRatio); - size_t getEngineSize() const { - return m_enginePath.size(); - } - const std::vector& getEnginePath(size_t _id) const { - return m_enginePath[_id]; - } - const std::vector& getEngineVector(size_t _id) const { - return m_engineVector[_id]; - } - const vec2& getEngineStartVector(size_t _id) const { - return m_engineStartV[_id]; - } - const std::vector& getEnginePoints() const { - return m_enginePoints; - } }; std::vector> loadPoints(const std::string& _fileName, std::string* _label=nullptr, std::string* _type=nullptr); } diff --git a/dollar/GestureN.cpp b/dollar/GestureN.cpp new file mode 100644 index 0000000..d9f5595 --- /dev/null +++ b/dollar/GestureN.cpp @@ -0,0 +1,39 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + + + +dollar::GestureN::GestureN() { + +} + +void dollar::GestureN::configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, bool _keepAspectRatio) { + m_enginePath.clear(); + m_engineVector.clear(); + m_engineStartV.clear(); + m_path2 = dollar::scaleToOne(m_path, _keepAspectRatio); + // for debug only + //storeSVG("out_dollar/lib/gestures/" + m_name + "_" + etk::to_string(m_subId) + ".svg", true); + // Simplyfy paths + std::vector> uniPath = dollar::makeReferenceStrokes(m_path); + // normalize paths + for (auto &it : uniPath) { + std::vector val = dollar::normalizePath(it, _nbSample, _ignoreRotation, _keepAspectRatio); + m_enginePath.push_back(val); + // calculate start vector: + vec2 startv = dollar::getStartVector(val, _startAngleIndex); + m_engineStartV.push_back(startv); + m_engineVector.push_back(dollar::normalyse(val)); + } +} \ No newline at end of file diff --git a/dollar/GestureN.h b/dollar/GestureN.h new file mode 100644 index 0000000..209b77a --- /dev/null +++ b/dollar/GestureN.h @@ -0,0 +1,46 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once +#include +#include + +#include + +namespace dollar { + class GestureN : public dollar::Gesture { + protected: + std::vector> m_path2; + public: + GestureN(); + public: + const std::vector>& getPath() const { + return m_path2; + } + std::vector>& getPath() { + return m_path2; + } + protected: + std::vector> m_enginePath; // Singulized path with every conbinaison + std::vector> m_engineVector; + std::vector m_engineStartV; + public: + // Configure the reference gesture for recognition... + void configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, bool _keepAspectRatio=false); + size_t getEngineSize() const { + return m_enginePath.size(); + } + const std::vector& getEnginePath(size_t _id) const { + return m_enginePath[_id]; + } + const std::vector& getEngineVector(size_t _id) const { + return m_engineVector[_id]; + } + const vec2& getEngineStartVector(size_t _id) const { + return m_engineStartV[_id]; + } + }; +} diff --git a/dollar/GestureP.cpp b/dollar/GestureP.cpp new file mode 100644 index 0000000..c9b8586 --- /dev/null +++ b/dollar/GestureP.cpp @@ -0,0 +1,25 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +dollar::GestureP::GestureP() { + +} + + +void dollar::GestureP::configure(size_t _nbSample) { + m_enginePoints.clear(); + // Generates dots: + std::vector points = dollar::combineStrokes(m_path); + m_enginePoints = dollar::normalizePath(points, _nbSample, false, false); +} \ No newline at end of file diff --git a/dollar/GestureP.h b/dollar/GestureP.h new file mode 100644 index 0000000..508d8be --- /dev/null +++ b/dollar/GestureP.h @@ -0,0 +1,31 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once +#include +#include +#include + +namespace dollar { + class GestureP : public dollar::Gesture { + public: + GestureP(); + protected: + std::vector m_enginePoints; + public: + // Configure the reference gesture for recognition... + void configure(size_t _nbSample); + const std::vector& getEnginePoints() const { + return m_enginePoints; + } + const std::vector& getPath() const { + return m_enginePoints; + } + std::vector& getPath() { + return m_enginePoints; + } + }; +} diff --git a/dollar/GesturePPlus.cpp b/dollar/GesturePPlus.cpp new file mode 100644 index 0000000..eb16c6b --- /dev/null +++ b/dollar/GesturePPlus.cpp @@ -0,0 +1,24 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +dollar::GesturePPlus::GesturePPlus() { + +} + +void dollar::GesturePPlus::configure(float _distance, bool _keepAspectRatio) { + m_enginePoints.clear(); + // Generates dots: + m_enginePoints = dollar::normalizePathToPoints(m_path, _distance, _keepAspectRatio); + DOLLAR_VERBOSE("create " << m_enginePoints.size() << " points"); +} \ No newline at end of file diff --git a/dollar/GesturePPlus.h b/dollar/GesturePPlus.h new file mode 100644 index 0000000..fe47379 --- /dev/null +++ b/dollar/GesturePPlus.h @@ -0,0 +1,31 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2016, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#pragma once +#include +#include +#include + +namespace dollar { + class GesturePPlus : public dollar::Gesture { + public: + GesturePPlus(); + protected: + std::vector m_enginePoints; + public: + // Configure the reference gesture for recognition... + void configure(float _distance, bool _keepAspectRatio); + const std::vector& getEnginePoints() const { + return m_enginePoints; + } + const std::vector>& getPath() const { + return m_path; + } + std::vector>& getPath() { + return m_path; + } + }; +} diff --git a/lutin_dollar.py b/lutin_dollar.py index 9a0a321..9c12c16 100644 --- a/lutin_dollar.py +++ b/lutin_dollar.py @@ -31,7 +31,13 @@ def create(target, module_name): my_module.add_src_file([ 'dollar/debug.cpp', 'dollar/Engine.cpp', + 'dollar/EngineN.cpp', + 'dollar/EngineP.cpp', + 'dollar/EnginePPlus.cpp', 'dollar/Gesture.cpp', + 'dollar/GestureN.cpp', + 'dollar/GestureP.cpp', + 'dollar/GesturePPlus.cpp', 'dollar/Results.cpp', 'dollar/tools.cpp', 'dollar/Rectangle.cpp' @@ -51,6 +57,7 @@ def create(target, module_name): 'etk', 'ejson', 'esvg', + 'ememory', ]) return my_module diff --git a/test/main.cpp b/test/main.cpp index a095f98..072285a 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -21,18 +21,20 @@ int main(int _argc, const char *_argv[]) { } TEST(TestAll, plop) { + /* dollar::Gesture gest; gest.set("test", 55, dollar::loadPoints("DATA:test/P.json")); gest.configure(0.1, 64, false, 0.1f); + */ } /* * single-stroke gesture recognition */ TEST(TestAll, singleStroke_normal) { - dollar::Engine reco; - reco.loadPath("DATA:figure"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/arrow.json"), "$N"); + ememory::SharedPtr reco = dollar::createEngine("$N"); + reco->loadPath("DATA:figure"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/arrow.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); @@ -46,9 +48,9 @@ TEST(TestAll, singleStroke_normal) { } TEST(TestAll, singleStroke_protractor) { - dollar::Engine reco; - reco.loadPath("DATA:figure"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/arrow.json"), "$N-protractor"); + ememory::SharedPtr reco = dollar::createEngine("$N"); + reco->loadPath("DATA:figure"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/arrow.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); @@ -66,9 +68,9 @@ TEST(TestAll, singleStroke_protractor) { * multi-stroke gesture recognition */ TEST(TestAll, multiStroke_normal) { - dollar::Engine reco; - reco.loadPath("DATA:text"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/P.json"), "$N"); + ememory::SharedPtr reco = dollar::createEngine("$N"); + reco->loadPath("DATA:text"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/P.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); @@ -82,9 +84,9 @@ TEST(TestAll, multiStroke_normal) { } TEST(TestAll, multiStroke_protractor) { - dollar::Engine reco; - reco.loadPath("DATA:text"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/P.json"), "$N-protractor"); + ememory::SharedPtr reco = dollar::createEngine("$N-protractor"); + reco->loadPath("DATA:text"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/P.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); @@ -100,9 +102,9 @@ TEST(TestAll, multiStroke_protractor) { * $P algorithms */ TEST(TestAll, multiStroke_point) { - dollar::Engine reco; - reco.loadPath("DATA:text"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/P.json"), "$P"); + ememory::SharedPtr reco = dollar::createEngine("$P"); + reco->loadPath("DATA:text"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/P.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); @@ -118,9 +120,9 @@ TEST(TestAll, multiStroke_point) { * $P+ algorithms */ TEST(TestAll, multiStroke_pointPlus) { - dollar::Engine reco; - reco.loadPath("DATA:text"); - dollar::Results res = reco.recognize(dollar::loadPoints("DATA:test/P.json"), "$P+"); + ememory::SharedPtr reco = dollar::createEngine("$P+"); + reco->loadPath("DATA:text"); + dollar::Results res = reco->recognize(dollar::loadPoints("DATA:test/P.json")); EXPECT_EQ(res.haveMath(), true); if (res.haveMath() == false) { TEST_INFO(" Recognise noting ..."); diff --git a/tool/generate-form/main.cpp b/tool/generate-form/main.cpp index b2fe26b..e5b56eb 100644 --- a/tool/generate-form/main.cpp +++ b/tool/generate-form/main.cpp @@ -16,23 +16,36 @@ void usage(const std::string& _progName) { TEST_PRINT("usage:"); TEST_PRINT(" " << _progName << " [option] corpus_path"); + TEST_PRINT(" "); TEST_PRINT(" [option]"); TEST_PRINT(" -h --help Display this help"); + TEST_PRINT(" --keep_ratio Keep aspect ratio for the form recognition"); + TEST_PRINT(" --dist-check=flaot distance between points in the system recognition"); + TEST_PRINT(" --dist-excl=flaot distance to exclude points in the check algo"); + TEST_PRINT(" --group-size=flaot size of the distance between point to stop grouping in one form"); + TEST_PRINT(" --mode=string mode of reco"); + TEST_PRINT(" "); TEST_PRINT(" parameters (must be here)"); TEST_PRINT(" corpus_path Path of the corpus files"); + TEST_PRINT(" "); + TEST_PRINT(" example:"); + } bool testCorpus(const std::string& _srcCorpus); static bool keepAspectRatio = false; -static float distanceReference; // distance of the gesture reference [0.02, 0.3] -static float distanceCheck; // distance of the test points [0.02, 0.3] -static float distanceExclude; // distance of the exclusion point [0.1, 1.0] +static float distanceReference = 0.1; // distance of the gesture reference [0.02, 0.3] +static float distanceCheck = 0.1; // distance of the test points [0.02, 0.3] +static float distanceExclude = 0.2; // distance of the exclusion point [0.1, 1.0] +static float distanceGroupLimiting = 1.0; // square distance of the grouping genereation +static std::string modeReco = "P+"; -setScaleKeepRatio(keepAspectRatio); +setScaleKeepRatio(); setPPlusDistance(distanceReference); // to generate reference gesture setPPlusDistance(distanceCheck); // to generate test gesture -setPPlusExcludeDistance(distanceExclude); + + int main(int _argc, const char *_argv[]) { // init etk log system and file interface: etk::init(_argc, _argv); @@ -52,16 +65,33 @@ int main(int _argc, const char *_argv[]) { if (etk::start_with(arg,"--dist-ref=") == true) { std::string val(&arg[11]); distanceReference = etk::string_to_float(val); + TEST_PRINT("configure distanceReference=" << distanceReference); continue; } + // TODO: Must not be different ... if (etk::start_with(arg,"--dist-check=") == true) { std::string val(&arg[13]); distanceCheck = etk::string_to_float(val); + distanceReference = distanceCheck; + TEST_PRINT("configure distanceCheck=" << distanceCheck); continue; } if (etk::start_with(arg,"--dist-excl=") == true) { std::string val(&arg[12]); distanceExclude = etk::string_to_float(val); + TEST_PRINT("configure distanceExclude=" << distanceExclude); + continue; + } + if (etk::start_with(arg,"--group-size=") == true) { + std::string val(&arg[13]); + distanceGroupLimiting = etk::string_to_float(val); + TEST_PRINT("configure distanceGroupLimiting=" << distanceGroupLimiting); + continue; + } + if (etk::start_with(arg,"--mode=") == true) { + std::string val(&arg[7]); + modeReco = val; + TEST_PRINT("configure modeReco=" << modeReco); continue; } if ( arg[0] == '-' @@ -148,10 +178,7 @@ bool testCorpus(const std::string& _srcCorpus) { } //listOfElementInCorpus.clear(); //listOfElementInCorpus.push_back("slash"); -// Value to stop grouping in the same element ... -float groupSize = 1.0; -groupSize = 1.0; -bool keepAspectRatio = false; + TEST_PRINT(" will done for: " << listOfElementInCorpus); int32_t nbElementGenerated = 0; @@ -195,9 +222,11 @@ bool keepAspectRatio = false; dollar::Gesture gest; std::vector> listPoints = dollar::loadPoints(fileFiltered[iii]); gest.set(itTypeOfCorpus, 0, listPoints); - gest.configure(10, 8, false, 0.1, keepAspectRatio); + gest.configure(10, 8, false, distanceReference, keepAspectRatio); dollar::Engine reco; reco.setScaleKeepRatio(keepAspectRatio); + reco.setPPlusDistance(distanceCheck); + reco.setPPlusExcludeDistance(distanceExclude); reco.addGesture(gest); std::vector path = etk::split(fileFiltered[iii], '/'); std::string filename = path[path.size()-1]; @@ -208,7 +237,7 @@ bool keepAspectRatio = false; continue; } listPoints = dollar::loadPoints(fileFiltered[jjj]); - dollar::Results res = reco.recognize(listPoints, "$P+"); + dollar::Results res = reco.recognize(listPoints, "$" + modeReco); results[iii][jjj] = res.getConfidence(); results[jjj][iii] = res.getConfidence(); path = etk::split(fileFiltered[jjj], '/'); @@ -227,7 +256,7 @@ bool keepAspectRatio = false; countMinimum.resize(fileFiltered.size(), 0); for (size_t iii=0; iii permit to show if it is possible to do a better case ... std::vector linkIds; for (size_t jjj=0; jjj