diff --git a/dollar/Engine.cpp b/dollar/Engine.cpp index 92af993..714578e 100644 --- a/dollar/Engine.cpp +++ b/dollar/Engine.cpp @@ -54,7 +54,8 @@ static float pathDistance(const std::vector& _path1, const std::vector16, "NB element in a path must be > 16 ..."); setRotationInvariance(false); @@ -68,7 +69,7 @@ void dollar::Engine::setNumberPointInGesture(size_t _value) { 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); + it.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance, m_scaleKeepRatio); } } @@ -76,6 +77,34 @@ size_t dollar::Engine::getNumberPointInGesture() { return m_numPointsInGesture; } +void dollar::Engine::setPPlusDistance(float _value) { + if (_value == m_PPlusDistance) { + return; + } + m_PPlusDistance = _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 m_PPlusDistance; +} + +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; @@ -177,17 +206,17 @@ static float calculatePPlusDistance(const std::vector& _points, } } if (kkkBest != -1) { - if (bestDistance > 0.2*0.2) { - // reject the distance ... - } - 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; + // reject the distance ... if too big ... + if (bestDistance <= 0.2*0.2) { + 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; + } } } } @@ -276,7 +305,7 @@ bool dollar::Engine::loadGesture(const std::string& _filename) { } void dollar::Engine::addGesture(Gesture _gesture) { - _gesture.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance); + _gesture.configure(m_numPointsInGesture/RATIO_START_VECTOR, m_numPointsInGesture, m_paramterIgnoreRotation, m_PPlusDistance, m_scaleKeepRatio); m_gestures.push_back(std::move(_gesture)); } @@ -309,7 +338,7 @@ dollar::Results dollar::Engine::recognize(const std::vector>& 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); + 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 ... @@ -393,7 +422,7 @@ dollar::Results dollar::Engine::recognizeN(const std::vector>& dollar::Results dollar::Engine::recognizeP(const std::vector>& _strokes) { std::vector points = dollar::combineStrokes(_strokes); - points = dollar::normalizePath(points, m_numPointsInGesture, m_paramterIgnoreRotation); + 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]; @@ -456,10 +485,11 @@ dollar::Results dollar::Engine::recognizeP(const std::vector>& static void storeSVG(const std::string& _fileName, - const dollar::Gesture& gesture, - const std::vector>& _strokes, - const std::vector& _points, - std::vector> _links) { + const dollar::Gesture& gesture, + const std::vector>& _strokes, + const std::vector& _points, + std::vector> _links, + bool _keepAspectRatio) { std::string data("\n"); data += "\n"; for (auto &itLines : gesture.getPath()) { @@ -476,7 +506,7 @@ static void storeSVG(const std::string& _fileName, data += "\"\n"; data += " />\n"; } - for (auto &itLines : dollar::scaleToOne(_strokes)) { + for (auto &itLines : dollar::scaleToOne(_strokes, _keepAspectRatio)) { data += " >& _strokes) { - std::vector points = dollar::normalizePathToPoints(_strokes, m_PPlusDistance); + 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]; @@ -536,7 +566,7 @@ dollar::Results dollar::Engine::recognizePPlus(const 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); + //storeSVG("out_dollar/lib/recognizePPlus/" + gesture.getName() + "_" + etk::to_string(gesture.getId()) + ".svg", gesture, _strokes, points, dataPair, m_scaleKeepRatio); for (size_t kkk=0; kkk\n"); data += "\n"; for (auto &itLines : strokes) { @@ -185,23 +183,25 @@ void dollar::Gesture::set(const std::string& _name, uint32_t _subId, std::vector 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) { +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); + 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); + //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); + std::vector val = dollar::normalizePath(it, _nbSample, _ignoreRotation, _keepAspectRatio); m_enginePath.push_back(val); // calculate start vector: vec2 startv = dollar::getStartVector(val, _startAngleIndex); diff --git a/dollar/Gesture.h b/dollar/Gesture.h index 2ce5800..7afff18 100644 --- a/dollar/Gesture.h +++ b/dollar/Gesture.h @@ -14,6 +14,7 @@ namespace dollar { std::string m_name; uint32_t m_subId; std::vector> m_path; + std::vector> m_path2; public: Gesture(); bool load(const std::string& _filename); @@ -32,10 +33,10 @@ namespace dollar { return m_subId; } const std::vector>& getPath() const { - return m_path; + return m_path2; } std::vector>& getPath() { - return m_path; + return m_path2; } protected: std::vector> m_enginePath; // Singulized path with every conbinaison @@ -44,7 +45,7 @@ namespace dollar { std::vector m_enginePoints; public: // Configure the reference gesture for recognition... - void configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, float _distance); + void configure(float _startAngleIndex, size_t _nbSample, bool _ignoreRotation, float _distance, bool _keepAspectRatio); size_t getEngineSize() const { return m_enginePath.size(); } diff --git a/dollar/tools.cpp b/dollar/tools.cpp index 12f9f09..ad92c20 100644 --- a/dollar/tools.cpp +++ b/dollar/tools.cpp @@ -52,18 +52,23 @@ std::vector dollar::scaleToOne(const std::vector& _points, bool _kee dollar::Rectangle box(_points); std::vector out; vec2 scale(1.0f/box.getSize().x(), 1.0f/box.getSize().y()); + vec2 offset(0,0); if (_keepAspectRation == true) { float val = 1; - if (box.getSize().x() > 0) { + offset = box.getSize() * val; + if (box.getSize().x() > box.getSize().y()) { val = 1.0f/box.getSize().x(); + offset = vec2(0.0f, (1.0f-offset.y())*0.5f); } else { val = 1.0f/box.getSize().y(); + offset = vec2((1.0f-offset.x())*0.5f, 0.0f); } scale = vec2(val,val); } for (auto &it : _points) { vec2 tmp = it - box.getPos(); tmp *= scale; + //tmp += offset; out.push_back(tmp); } return out; @@ -73,12 +78,16 @@ std::vector> dollar::scaleToOne(const std::vector> out; vec2 scale(1.0f/box.getSize().x(), 1.0f/box.getSize().y()); + vec2 offset(0,0); if (_keepAspectRation == true) { float val = 1; - if (box.getSize().x() > 0) { + offset = box.getSize() * val; + if (box.getSize().x() > box.getSize().y()) { val = 1.0f/box.getSize().x(); + offset = vec2(0.0f, (1.0f-offset.y())*0.5f); } else { val = 1.0f/box.getSize().y(); + offset = vec2((1.0f-offset.x())*0.5f, 0.0f); } scale = vec2(val,val); } @@ -87,6 +96,7 @@ std::vector> dollar::scaleToOne(const std::vector dollar::normalyse(const std::vector& _points) { } -std::vector dollar::normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation) { +std::vector dollar::normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation, bool _keepAspectRatio) { _points = dollar::resample(_points, _nbSample); if (_ignoreRotation == true) { _points = rotateToZero(_points); } - _points = scaleToOne(_points); + _points = scaleToOne(_points, _keepAspectRatio); return translateBariCenterToZero(_points); } -std::vector dollar::normalizePathToPoints(std::vector> _points, float _distance) { +std::vector dollar::normalizePathToPoints(std::vector> _points, float _distance, bool _keepAspectRatio) { // Scale point to (0.0,0.0) position and (1.0,1.0) size - _points = dollar::scaleToOne(_points); + _points = dollar::scaleToOne(_points, _keepAspectRatio); std::vector out; for (auto &it : _points) { if (it.size() == 0) { diff --git a/dollar/tools.h b/dollar/tools.h index 2b36b5a..5e90828 100644 --- a/dollar/tools.h +++ b/dollar/tools.h @@ -47,7 +47,7 @@ namespace dollar { * @param[in] _keepAspectRation Keep the aspect ratio of the scaling * @return modify points */ - std::vector scaleToOne(const std::vector& _points, bool _keepAspectRation=false); + std::vector scaleToOne(const std::vector& _points, bool _keepAspectRation=true); /** * @brief Scale the list of point in a 1.0*1.0 box started at 0.0*0.0 * @param[in] _points input path @@ -98,18 +98,20 @@ namespace dollar { * @param[in] _points List of points in the path * @param[in] _nbSample Number of element to resample * @param[in] _ignoreRotation Ignore start rotation of the algorithm + * @param[in] _keepAspectRatio Keep Aspect ratio when scaling to the correct size (1.0,1.0) (it will be centered) * @return new list of points */ - std::vector normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation); + std::vector normalizePath(std::vector _points, size_t _nbSample, bool _ignoreRotation, bool _keepAspectRatio); /** * @brief Transform the path to be comparable, resample the path with a specific number of sample, and limit size at 1.0 square center around 0 * @note The difference with @ref normalizePath is thet we do not combinethe path together, that permit to not have unneded point between strokes... * @param[in] _points List of points in the path * @param[in] _distance Distance between points + * @param[in] _keepAspectRatio Keep Aspect ratio when scaling to the correct size (1.0,1.0) (it will be centered) * @return new list of points */ - std::vector normalizePathToPoints(std::vector> _points, float _distance); + std::vector normalizePathToPoints(std::vector> _points, float _distance, bool _keepAspectRatio); } diff --git a/tool/bench-corpus/main.cpp b/tool/bench-corpus/main.cpp index c63b012..86ed253 100644 --- a/tool/bench-corpus/main.cpp +++ b/tool/bench-corpus/main.cpp @@ -135,6 +135,7 @@ void annalyseResult(std::map list of (result, file test name) std::map>> agregateResults; int32_t nbRecognise = 0; + int32_t nbRecognise2 = 0; int32_t nbtested = 0; for (auto &it : files) { std::string label; @@ -180,15 +182,20 @@ bool testCorpus(const std::string& _srcGesture, const std::string& _srcCorpus) { } #else if (res.getName() == label) { - nbRecognise ++; + nbRecognise++; + nbRecognise2++; TEST_INFO(" " << res.getName() << " score=" << res.getConfidence()); - } else { + } else if (etk::toupper(res.getName()) == etk::toupper(label)) { + nbRecognise2++; + TEST_WARNING(" " << res.getName() << " score=" << res.getConfidence()); + }else { TEST_ERROR(" " << res.getName() << " score=" << res.getConfidence()); } #endif } annalyseResult(agregateResults); - TEST_PRINT("Recognise: " << nbRecognise << " / " << nbtested << " ==> " << (float(nbRecognise) / float(nbtested) * 100.0f) << " %"); + TEST_PRINT("Recognise: " << nbRecognise << " / " << nbtested << " ==> " << (float(nbRecognise) / float(nbtested) * 100.0f) << " %"); + TEST_PRINT("Recognise (a==A): " << nbRecognise2 << " / " << nbtested << " ==> " << (float(nbRecognise2) / float(nbtested) * 100.0f) << " %"); // All is done corectly return 0; } diff --git a/tool/generate-form/main.cpp b/tool/generate-form/main.cpp index 60797b8..14fa097 100644 --- a/tool/generate-form/main.cpp +++ b/tool/generate-form/main.cpp @@ -119,6 +119,11 @@ bool testCorpus(const std::string& _srcCorpus) { } //listOfElementInCorpus.clear(); //listOfElementInCorpus.push_back("z"); +// Value to stop grouping in the same element ... +float groupSize = 1.0; +groupSize = 1.0; +bool keepAspectRatio = false; + TEST_PRINT(" will done for: " << listOfElementInCorpus); for (auto &itTypeOfCorpus : listOfElementInCorpus) { TEST_PRINT("---------------------------------------------------------------------------"); @@ -141,19 +146,28 @@ bool testCorpus(const std::string& _srcCorpus) { it.resize(fileFiltered.size(), OUT_OF_RANGE); } // Generate Full Files: + std::string itTypeOfCorpusFileName = itTypeOfCorpus; + if (itTypeOfCorpusFileName == "/") { + itTypeOfCorpusFileName = "slash"; + } else if (itTypeOfCorpusFileName == "\\") { + itTypeOfCorpusFileName = "back-slash"; + } else if (itTypeOfCorpusFileName == "?") { + itTypeOfCorpusFileName = "question"; + } { std::vector listPath; for (size_t iii=0; iii> listPoints = dollar::loadPoints(fileFiltered[iii]); gest.set(itTypeOfCorpus, 0, listPoints); - gest.configure(10, 8, false, 0.1); + gest.configure(10, 8, false, 0.1, keepAspectRatio); dollar::Engine reco; + reco.setScaleKeepRatio(keepAspectRatio); reco.addGesture(gest); std::vector path = etk::split(fileFiltered[iii], '/'); std::string filename = path[path.size()-1]; @@ -177,9 +191,7 @@ bool testCorpus(const std::string& _srcCorpus) { TEST_PRINT("---------------------------------------------------------------------------"); int32_t residualValues = fileFiltered.size(); int32_t subId = 1; - // Value to stop grouping in the same element ... - float groupSize = 1.0; - groupSize = 1.0; + while (residualValues > 0) { std::vector countMinimum; countMinimum.resize(fileFiltered.size(), 0); @@ -201,6 +213,10 @@ bool testCorpus(const std::string& _srcCorpus) { } if (bestId == -1) { TEST_ERROR("No more elements ... residualValues=" << residualValues); + + // TODO : Add the rest of the elements ... + + //==> Exit loop residualValues = 0; continue; @@ -279,22 +295,28 @@ bool testCorpus(const std::string& _srcCorpus) { results[jjj][linkIds[iii]] = OUT_OF_RANGE; } } + if (linkIds.size() <= 3) { + TEST_ERROR("Group is too small ... residualValues=" << residualValues); + // TODO : Add the rest of the elements ... + //==> Exit loop + residualValues = 0; + continue; + } residualValues -= (linkIds.size() +1); - TEST_DEBUG("Generate output files (SVG with all added path in one file)"); // Generate Files: std::vector listPath; for (size_t iii=0; iii