From 9d319095a963293409e6bec4c5ffd641b030b38d Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Thu, 12 Dec 2024 15:43:12 -0500 Subject: [PATCH 01/13] apparently wrap needs a non-default constructor --- include/puara/utils/wrap.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/puara/utils/wrap.h b/include/puara/utils/wrap.h index 60e4345..766d24c 100644 --- a/include/puara/utils/wrap.h +++ b/include/puara/utils/wrap.h @@ -90,6 +90,8 @@ class Unwrap class Wrap { public: + Wrap(double pMin, double pMax) : min {pMin}, max {pMax}{} + double min{}; double max{}; From 77ab3e4d5dac693b5c3f66e2d3273e8af85e2fe7 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Fri, 13 Dec 2024 16:36:18 -0500 Subject: [PATCH 02/13] starting the refactor --- include/puara/descriptors/touch.h | 44 +++------------------------- include/puara/utils/blobDetection.h | 45 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 include/puara/utils/blobDetection.h diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index 912fabe..3177f7d 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -24,11 +25,8 @@ class Touch int touchSizeEdge = 4; // amount of touch stripes for top and bottom portions (arbitrary) int lastState_blobPos[4]{}; - int maxBlobs = 4; // max amount of blobs to be detected - int blobAmount{}; // amount of detected blobs - int blobCenter[4]{}; // shows the "center" (index) of each blob (former blobArray) - int blobPos[4]{}; // starting position (index) of each blob - float blobSize[4]{}; // "size" (amount of stripes) of each blob + BlobDetection blob; + int blobPos[4]{}; // starting position (index) of each blob int brushCounter[4]{}; // Arrays of LeakyIntegrator instances @@ -74,7 +72,7 @@ class Touch } // 1D blob detection: used for brush - blobDetection1D(discrete_touch, touchSize); + blob.blobDetection1D(discrete_touch, touchSize, blobPos); // brush: direction and intensity of capsense brush motion // rub: intensity of rub motion @@ -155,39 +153,5 @@ class Touch return ((float)sum) / (lastStrip - firstStrip); } - - //TODO: move to utils - void blobDetection1D(int* discrete_touch, int touchSize) - { - blobAmount = 0; - int sizeCounter = 0; - int stripe = 0; - for(int i = 0; i < 4; i++) - { - blobCenter[i] = 0; - blobPos[i] = 0; - blobSize[i] = 0; - } - - for(; stripe < touchSize; stripe++) - { - if(blobAmount < maxBlobs) - { - if(discrete_touch[stripe] == 1) - { // check for beggining of blob... - sizeCounter = 1; - blobPos[blobAmount] = stripe; - while(discrete_touch[stripe + sizeCounter] == 1) - { // then keep checking for end - sizeCounter++; - } - blobSize[blobAmount] = sizeCounter; - blobCenter[blobAmount] = stripe + (sizeCounter / 2); - stripe += sizeCounter + 1; // skip stripes already read - blobAmount++; - } - } - } - } }; } diff --git a/include/puara/utils/blobDetection.h b/include/puara/utils/blobDetection.h new file mode 100644 index 0000000..13140e6 --- /dev/null +++ b/include/puara/utils/blobDetection.h @@ -0,0 +1,45 @@ + +namespace puara_gestures +{ + +struct BlobDetection +{ + int maxBlobs = 4; // max amount of blobs to be detected + int blobAmount{}; // amount of detected blobs + int blobCenter[4]{}; // shows the "center" (index) of each blob (former blobArray) + float blobSize[4]{}; // "size" (amount of stripes) of each blob + + void blobDetection1D(int* discrete_touch, int touchSize, int* blobPos) + { + blobAmount = 0; + int sizeCounter = 0; + int stripe = 0; + for(int i = 0; i < 4; i++) + { + blobCenter[i] = 0; + blobPos[i] = 0; + blobSize[i] = 0; + } + + for(; stripe < touchSize; stripe++) + { + if(blobAmount < maxBlobs) + { + if(discrete_touch[stripe] == 1) + { // check for beggining of blob... + sizeCounter = 1; + blobPos[blobAmount] = stripe; + while(discrete_touch[stripe + sizeCounter] == 1) + { // then keep checking for end + sizeCounter++; + } + blobSize[blobAmount] = sizeCounter; + blobCenter[blobAmount] = stripe + (sizeCounter / 2); + stripe += sizeCounter + 1; // skip stripes already read + blobAmount++; + } + } + } + } +}; +} \ No newline at end of file From 2d13db43cb10bb9c2e4215f3dce3b36854307801 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Mon, 16 Dec 2024 14:28:46 -0500 Subject: [PATCH 03/13] Substantial refactor. - replace some hard-coded variables by a maxNumBlobs variable - Directly return a movement vector from the blob detector, so client code doesn't have to store previous blob positions - everything needs to be thoroughly tested --- include/puara/descriptors/touch.h | 64 +++++++++++++------------- include/puara/utils/blobDetection.h | 70 +++++++++++++++++------------ tests/testing_touch.cpp | 7 +-- 3 files changed, 76 insertions(+), 65 deletions(-) diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index 3177f7d..9b1fce1 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -12,30 +12,29 @@ namespace puara_gestures class Touch { public: + static const int maxNumBlobs = BlobDetection::maxNumBlobs; float touchAll = 0.0f; // f, 0--1 float touchTop = 0.0f; // f, 0--1 float touchMiddle = 0.0f; // f, 0--1 float touchBottom = 0.0f; // f, 0--1 float brush = 0.0f; // f, 0--? (~cm/s) - double multiBrush[4]{}; // ffff, 0--? (~cm/s) + double multiBrush[maxNumBlobs]{}; // ffff, 0--? (~cm/s) float rub{}; // f, 0--? (~cm/s) - double multiRub[4]{}; // ffff, 0--? (~cm/s) + double multiRub[maxNumBlobs]{}; // ffff, 0--? (~cm/s) // touch array - int touchSizeEdge - = 4; // amount of touch stripes for top and bottom portions (arbitrary) - int lastState_blobPos[4]{}; + int touchSizeEdge = 4; // amount of touch stripes for top and bottom portions (arbitrary) + BlobDetection blob; - int blobPos[4]{}; // starting position (index) of each blob - int brushCounter[4]{}; + int brushCounter[maxNumBlobs]{}; // Arrays of LeakyIntegrator instances - utils::LeakyIntegrator multiBrushIntegrator[4]; - utils::LeakyIntegrator multiRubIntegrator[4]; + utils::LeakyIntegrator multiBrushIntegrator[maxNumBlobs]; + utils::LeakyIntegrator multiRubIntegrator[maxNumBlobs]; Touch() { - for(int i = 0; i < 4; ++i) + for(int i = 0; i < maxNumBlobs; ++i) { multiBrushIntegrator[i] = utils::LeakyIntegrator(0.0f, 0.0f, 0.7f, 100, 0); multiRubIntegrator[i] = utils::LeakyIntegrator(0.0f, 0.0f, 0.7f, 100, 0); @@ -65,28 +64,27 @@ class Touch // normalized between 0 and 1 touchBottom = touchAverage(discrete_touch, (touchSize - touchSizeEdge), touchSize); - // Save last blob detection state before reading new data - for(int i = 0; i < (sizeof(blobPos) / sizeof(blobPos[0])); ++i) - { - lastState_blobPos[i] = blobPos[i]; - } + //NOW HERE -- not too sure what the heck that loop is, but that i is probably just == 4 lol + //I need to continue moving the blobPos logic to the blobDetector + //I should add a getBlobPos to it so this client doesn't have to store it itself - // 1D blob detection: used for brush - blob.blobDetection1D(discrete_touch, touchSize, blobPos); + // 1D blob detection: used for brush + const auto movement = blob.blobDetection1D(discrete_touch, touchSize); // brush: direction and intensity of capsense brush motion // rub: intensity of rub motion // in ~cm/s (distance between stripes = ~1.5cm) - for(int i = 0; i < (sizeof(blobPos) / sizeof(blobPos[0])); ++i) + for(int i = 0; i < maxNumBlobs; ++i) { - float movement = blobPos[i] - lastState_blobPos[i]; - if(blobPos[i] == -1) - { - multiBrush[i] = 0; - multiRub[i] = 0; - brushCounter[i] = 0; - } - else if(movement == 0) + //TODO: unclear how we ever could get here? + // if(blobPos[i] == -1) + // { + // multiBrush[i] = 0; + // multiRub[i] = 0; + // brushCounter[i] = 0; + // } + // else + if(movement[i] == 0) { if(brushCounter[i] < 10) { @@ -107,11 +105,11 @@ class Touch // (std::abs(movement * 0.15)), multiRub[i], 0.7, leakyRubFreq, // leakyRubTimer); // - multiBrush[i] = multiBrushIntegrator[i].integrate(movement * 0.15); - multiRub[i] = multiRubIntegrator[i].integrate(std::abs(movement * 0.15)); + multiBrush[i] = multiBrushIntegrator[i].integrate(movement[i] * 0.15); + multiRub[i] = multiRubIntegrator[i].integrate(std::abs(movement[i] * 0.15)); } } - else if(std::abs(movement) > 1) + else if(std::abs(movement[i]) > 1) { // multiBrush[i] = multiBrushIntegrator[i].integrate( // 0, multiBrush[i], 0.6, leakyBrushFreq, leakyBrushTimer); @@ -126,14 +124,14 @@ class Touch // (std::abs(movement * 0.15)) * 0.15, multiRub[i], 0.99, leakyRubFreq, // leakyRubTimer); - multiBrush[i] = multiBrushIntegrator[i].integrate(movement * 0.15); - multiRub[i] = multiRubIntegrator[i].integrate((std::abs(movement * 0.15))); + multiBrush[i] = multiBrushIntegrator[i].integrate(movement[i] * 0.15); + multiRub[i] = multiRubIntegrator[i].integrate((std::abs(movement[i] * 0.15))); brushCounter[i] = 0; } } - brush = utils::arrayAverageZero(multiBrush, 4); - rub = utils::arrayAverageZero(multiRub, 4); + brush = utils::arrayAverageZero(multiBrush, maxNumBlobs); + rub = utils::arrayAverageZero(multiRub, maxNumBlobs); } float touchAverage(float* touchArrayStrips, int firstStrip, int lastStrip) diff --git a/include/puara/utils/blobDetection.h b/include/puara/utils/blobDetection.h index 13140e6..789d4cd 100644 --- a/include/puara/utils/blobDetection.h +++ b/include/puara/utils/blobDetection.h @@ -1,45 +1,57 @@ - +#pragma once namespace puara_gestures { -struct BlobDetection +class BlobDetection { - int maxBlobs = 4; // max amount of blobs to be detected - int blobAmount{}; // amount of detected blobs - int blobCenter[4]{}; // shows the "center" (index) of each blob (former blobArray) - float blobSize[4]{}; // "size" (amount of stripes) of each blob +public: + static const int maxNumBlobs = 4; // max amount of blobs to be detected + +#include - void blobDetection1D(int* discrete_touch, int touchSize, int* blobPos) + std::vector blobDetection1D(const int* const touchArray, const int size) { - blobAmount = 0; - int sizeCounter = 0; - int stripe = 0; - for(int i = 0; i < 4; i++) + int blobCenter[maxNumBlobs]{}; // shows the "center" (index) of each blob + float blobSize[maxNumBlobs]{}; // "size" (amount of stripes) of each blob + int blobAmount{}; // amount of detected blobs + int sizeCounter{}; + + for(int i = 0; i < maxNumBlobs; i++) { - blobCenter[i] = 0; + //cache the last blobPos before clearing it + lastState_blobPos[i] = blobPos[i]; blobPos[i] = 0; - blobSize[i] = 0; } - for(; stripe < touchSize; stripe++) + for(int stripe = 0; stripe < size; ++stripe) { - if(blobAmount < maxBlobs) + if(touchArray[stripe] == 1) { - if(discrete_touch[stripe] == 1) - { // check for beggining of blob... - sizeCounter = 1; - blobPos[blobAmount] = stripe; - while(discrete_touch[stripe + sizeCounter] == 1) - { // then keep checking for end - sizeCounter++; - } - blobSize[blobAmount] = sizeCounter; - blobCenter[blobAmount] = stripe + (sizeCounter / 2); - stripe += sizeCounter + 1; // skip stripes already read - blobAmount++; - } + sizeCounter = 1; + blobPos[blobAmount] = stripe; + + while(touchArray[stripe + sizeCounter] == 1) + sizeCounter++; + + blobSize[blobAmount] = sizeCounter; + blobCenter[blobAmount] = stripe + (sizeCounter / 2); + stripe += sizeCounter + 1; + + if(++blobAmount >= maxNumBlobs) + break; } } + + //return the movement since the last time blobDetection1D was called + std::vector movement(blobAmount, 0); + for(int i = 0; i < blobAmount; ++i) + movement[i] = blobPos[i] - lastState_blobPos[i]; + + return movement; } + +private: + int blobPos[maxNumBlobs]{}; + int lastState_blobPos[maxNumBlobs]{}; }; -} \ No newline at end of file +} diff --git a/tests/testing_touch.cpp b/tests/testing_touch.cpp index fb78453..675bbad 100644 --- a/tests/testing_touch.cpp +++ b/tests/testing_touch.cpp @@ -8,11 +8,12 @@ int main() { Touch touch; - int touchSize = 16; - int discrete_touch[16] = {0}; + const int touchSize = 16; + int discrete_touch[touchSize] = {0}; - // simulate a touch (1) at a position 5 + // simulate a blob of size 2 starting at position 5 discrete_touch[5] = 1; + discrete_touch[6] = 1; // Update the touch data touch.updateTouchArray(discrete_touch, touchSize); From f337d018a626171bb2d9e0bab36721c0205a3f25 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Mon, 16 Dec 2024 15:36:20 -0500 Subject: [PATCH 04/13] rename the file, do more exhaustive tests, all seem good --- CMakeLists.txt | 1 + include/puara/descriptors/touch.h | 12 ++-- include/puara/utils/blobDetection.h | 57 ----------------- include/puara/utils/blobDetector.h | 94 +++++++++++++++++++++++++++++ tests/testing_touch.cpp | 15 +++++ 5 files changed, 114 insertions(+), 65 deletions(-) delete mode 100644 include/puara/utils/blobDetection.h create mode 100644 include/puara/utils/blobDetector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d30a4bf..1973592 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(puara_gestures include/puara/descriptors/tilt.h include/puara/descriptors/touch.h + include/puara/utils/blobDetector.h include/puara/utils/calibration.h include/puara/utils/circularbuffer.h include/puara/utils/leakyintegrator.h diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index 9b1fce1..27ae7f7 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include @@ -12,7 +12,7 @@ namespace puara_gestures class Touch { public: - static const int maxNumBlobs = BlobDetection::maxNumBlobs; + static const int maxNumBlobs = BlobDetector::maxNumBlobs; float touchAll = 0.0f; // f, 0--1 float touchTop = 0.0f; // f, 0--1 float touchMiddle = 0.0f; // f, 0--1 @@ -25,7 +25,7 @@ class Touch // touch array int touchSizeEdge = 4; // amount of touch stripes for top and bottom portions (arbitrary) - BlobDetection blob; + BlobDetector blob; int brushCounter[maxNumBlobs]{}; // Arrays of LeakyIntegrator instances @@ -64,12 +64,8 @@ class Touch // normalized between 0 and 1 touchBottom = touchAverage(discrete_touch, (touchSize - touchSizeEdge), touchSize); - //NOW HERE -- not too sure what the heck that loop is, but that i is probably just == 4 lol - //I need to continue moving the blobPos logic to the blobDetector - //I should add a getBlobPos to it so this client doesn't have to store it itself - // 1D blob detection: used for brush - const auto movement = blob.blobDetection1D(discrete_touch, touchSize); + const auto movement = blob.detect1D(discrete_touch, touchSize); // brush: direction and intensity of capsense brush motion // rub: intensity of rub motion diff --git a/include/puara/utils/blobDetection.h b/include/puara/utils/blobDetection.h deleted file mode 100644 index 789d4cd..0000000 --- a/include/puara/utils/blobDetection.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -namespace puara_gestures -{ - -class BlobDetection -{ -public: - static const int maxNumBlobs = 4; // max amount of blobs to be detected - -#include - - std::vector blobDetection1D(const int* const touchArray, const int size) - { - int blobCenter[maxNumBlobs]{}; // shows the "center" (index) of each blob - float blobSize[maxNumBlobs]{}; // "size" (amount of stripes) of each blob - int blobAmount{}; // amount of detected blobs - int sizeCounter{}; - - for(int i = 0; i < maxNumBlobs; i++) - { - //cache the last blobPos before clearing it - lastState_blobPos[i] = blobPos[i]; - blobPos[i] = 0; - } - - for(int stripe = 0; stripe < size; ++stripe) - { - if(touchArray[stripe] == 1) - { - sizeCounter = 1; - blobPos[blobAmount] = stripe; - - while(touchArray[stripe + sizeCounter] == 1) - sizeCounter++; - - blobSize[blobAmount] = sizeCounter; - blobCenter[blobAmount] = stripe + (sizeCounter / 2); - stripe += sizeCounter + 1; - - if(++blobAmount >= maxNumBlobs) - break; - } - } - - //return the movement since the last time blobDetection1D was called - std::vector movement(blobAmount, 0); - for(int i = 0; i < blobAmount; ++i) - movement[i] = blobPos[i] - lastState_blobPos[i]; - - return movement; - } - -private: - int blobPos[maxNumBlobs]{}; - int lastState_blobPos[maxNumBlobs]{}; -}; -} diff --git a/include/puara/utils/blobDetector.h b/include/puara/utils/blobDetector.h new file mode 100644 index 0000000..8688649 --- /dev/null +++ b/include/puara/utils/blobDetector.h @@ -0,0 +1,94 @@ +#pragma once +namespace puara_gestures +{ + +struct BlobDetector +{ + /** The maximum number of blobs that the algorithm should detect. */ + static const int maxNumBlobs = 4; + + /** The start index of detected blobs. */ + int blobStartPos[maxNumBlobs]{}; + + /** The cached start index of detected blobs, from the previous time detect1D + * was called. + */ + int lastState_blobPos [maxNumBlobs]{}; + + /** "size" (amount of stripes) of each blob */ + int blobSize[maxNumBlobs]{}; + + /** shows the "center"(index)of each blob */ + float blobCenter[maxNumBlobs]{}; + + /** amount of detected blobs */ + int blobAmount{}; + + /** + * @brief Detects contiguous regions (blobs) of `1`s in a 1D binary array and computes their movement. + * + * This function identifies blobs in the input binary array `touchArray`, calculates their start + * positions, sizes, and centers, and returns the movement of the blobs compared to their positions + * from the previous function call. + * + * @param touchArray Pointer to the 1D binary array representing touch data. Each element is expected to be 0 or 1. + * @param size The size of the `touchArray`. + * @return A vector of integers representing the movement of each blob's start position since the + * last invocation of `detect1D`. The size of the returned vector is `maxNumBlobs`. + * + * @note + * - The function updates the global variables `blobStartPos`, `blobSize`, `blobCenter`, + * and `lastState_blobPos`. + * - The number of blobs detected is limited by `maxNumBlobs`. + * - If the number of blobs exceeds `maxNumBlobs`, additional blobs are ignored. + * + * @warning + * - Ensure that `touchArray` has at least `size` elements to avoid out-of-bounds access. + * - The function relies on external global variables (`blobStartPos`, `blobSize`, `blobCenter`, + * `lastState_blobPos`, `maxNumBlobs`, `blobAmount`). Ensure they are initialized appropriately + * before calling the function. + */ + std::vector detect1D(const int* const touchArray, const int size) + { + + for(int i = 0; i < maxNumBlobs; i++) + { + //cache the last blobStartPos before clearing it + lastState_blobPos[i] = blobStartPos[i]; + blobStartPos[i] = 0; + } + + for(int stripe = 0; stripe < size;) + { + if(touchArray[stripe] == 1) + { + //start the blob + blobStartPos[blobAmount] = stripe; + + //continue the blob until we no longer have 1s + int sizeCounter = 1; + while(touchArray[stripe + sizeCounter] == 1 && (stripe + sizeCounter) <= size) + sizeCounter++; + + blobSize[blobAmount] = sizeCounter; + blobCenter[blobAmount] = stripe + (sizeCounter - 1.f) / 2.f; + stripe += sizeCounter; + + if(++blobAmount >= maxNumBlobs) + break; + } + else + { + ++stripe; + } + } + + //return the movement since the last time detect1D was called + std::vector movement(maxNumBlobs, 0); + for(int i = 0; i < maxNumBlobs; ++i) + movement[i] = blobStartPos[i] - lastState_blobPos[i]; + + return movement; + } +}; +} diff --git a/tests/testing_touch.cpp b/tests/testing_touch.cpp index 675bbad..16bed8b 100644 --- a/tests/testing_touch.cpp +++ b/tests/testing_touch.cpp @@ -11,10 +11,25 @@ int main() const int touchSize = 16; int discrete_touch[touchSize] = {0}; + // simulate a blob of size 1 starting at position 0 + discrete_touch[0] = 1; + // simulate a blob of size 2 starting at position 5 discrete_touch[5] = 1; discrete_touch[6] = 1; + // simulate a blob of size 3 starting at position 8 + discrete_touch[8] = 1; + discrete_touch[9] = 1; + discrete_touch[10] = 1; + + // simulate a blob of size 1 at position 12 -- commented out to test the end of the array in the next blob + //discrete_touch[12] = 1; + + // simulate a blob of size 2 starting at position 14 + discrete_touch[14] = 1; + discrete_touch[15] = 1; + // Update the touch data touch.updateTouchArray(discrete_touch, touchSize); From 7cdc6c83ec8a01fd0975fe15045c0291c6a33c27 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 08:12:30 -0500 Subject: [PATCH 05/13] fix missing initialization bug. Add documentation --- include/puara/utils/blobDetector.h | 40 ++++++++++++++++++++++++++++-- library.json | 4 +++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 library.json diff --git a/include/puara/utils/blobDetector.h b/include/puara/utils/blobDetector.h index 8688649..0014187 100644 --- a/include/puara/utils/blobDetector.h +++ b/include/puara/utils/blobDetector.h @@ -1,7 +1,41 @@ #pragma once + +#include namespace puara_gestures { +/** + * @struct BlobDetector + * @brief A structure for detecting contiguous regions (blobs) of `1`s in binary arrays. + * + * The `BlobDetector` identifies contiguous blobs in a binary input array where elements are either + * `0` or `1`. + * For each blob, it computes: + * - The start position (`blobStartPos`) + * - The size in terms of consecutive `1`s (`blobSize`) + * - The center index (`blobCenter`) + * - Movement compared to the previous detection (`lastState_blobPos`) + * @warning Most of these values are reset when a detection function, e.g., detect1D(), is called, + * and calculated during the detection funtion calls -- so their value is only really valid right + * after such a call. There is no locking mechanism on any of these values so it is on the client + * to ensure there is no race conditions. + * + * @details + * The struct maintains internal arrays to store information about detected blobs, including their + * start positions, sizes, and centers. It also tracks blob positions from the previous invocation + * of the detection function to compute movement values. + * + * ## Key Functionalities: + * - **Blob Detection:** Detects contiguous regions of `1`s in a binary input array. + * - **Movement Calculation:** Computes the positional changes (movement) of blobs compared to + * their last positions. + * - **Data Management:** Maintains internal state between function calls to facilitate movement + * tracking. + * + * @note + * - The number of blobs processed is limited by `maxNumBlobs` (default is `4`). + * - If the input contains more blobs than `maxNumBlobs`, the additional blobs are ignored. + */ struct BlobDetector { /** The maximum number of blobs that the algorithm should detect. */ @@ -13,7 +47,7 @@ struct BlobDetector /** The cached start index of detected blobs, from the previous time detect1D * was called. */ - int lastState_blobPos [maxNumBlobs]{}; + int lastState_blobPos[maxNumBlobs]{}; /** "size" (amount of stripes) of each blob */ int blobSize[maxNumBlobs]{}; @@ -50,12 +84,14 @@ struct BlobDetector */ std::vector detect1D(const int* const touchArray, const int size) { - + blobAmount = 0; for(int i = 0; i < maxNumBlobs; i++) { //cache the last blobStartPos before clearing it lastState_blobPos[i] = blobStartPos[i]; blobStartPos[i] = 0; + blobSize[i] = 0; + blobCenter[i] = 0; } for(int stripe = 0; stripe < size;) diff --git a/library.json b/library.json new file mode 100644 index 0000000..d7feb08 --- /dev/null +++ b/library.json @@ -0,0 +1,4 @@ +{ + "name": "puara-gestures", + "version": "0.0.0+20241216081434" +} \ No newline at end of file From 3def1e10089b2698c7e645d6fa01bb4eb0ff1577 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 10:38:06 -0500 Subject: [PATCH 06/13] cleanup and add moved touch test --- include/puara/descriptors/touch.h | 8 -------- include/puara/utils/blobDetector.h | 22 ++++++++++---------- tests/testing_touch.cpp | 32 ++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index 27ae7f7..d73403f 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -72,14 +72,6 @@ class Touch // in ~cm/s (distance between stripes = ~1.5cm) for(int i = 0; i < maxNumBlobs; ++i) { - //TODO: unclear how we ever could get here? - // if(blobPos[i] == -1) - // { - // multiBrush[i] = 0; - // multiRub[i] = 0; - // brushCounter[i] = 0; - // } - // else if(movement[i] == 0) { if(brushCounter[i] < 10) diff --git a/include/puara/utils/blobDetector.h b/include/puara/utils/blobDetector.h index 0014187..f30a5ed 100644 --- a/include/puara/utils/blobDetector.h +++ b/include/puara/utils/blobDetector.h @@ -8,7 +8,7 @@ namespace puara_gestures * @struct BlobDetector * @brief A structure for detecting contiguous regions (blobs) of `1`s in binary arrays. * - * The `BlobDetector` identifies contiguous blobs in a binary input array where elements are either + * The `BlobDetector` identifies contiguous blobs in a binary input array where elements are either * `0` or `1`. * For each blob, it computes: * - The start position (`blobStartPos`) @@ -60,26 +60,26 @@ struct BlobDetector /** * @brief Detects contiguous regions (blobs) of `1`s in a 1D binary array and computes their movement. - * - * This function identifies blobs in the input binary array `touchArray`, calculates their start - * positions, sizes, and centers, and returns the movement of the blobs compared to their positions + * + * This function identifies blobs in the input binary array `touchArray`, calculates their start + * positions, sizes, and centers, and returns the movement of the blobs compared to their positions * from the previous function call. - * + * * @param touchArray Pointer to the 1D binary array representing touch data. Each element is expected to be 0 or 1. * @param size The size of the `touchArray`. - * @return A vector of integers representing the movement of each blob's start position since the + * @return A vector of integers representing the movement of each blob's start position since the * last invocation of `detect1D`. The size of the returned vector is `maxNumBlobs`. - * + * * @note - * - The function updates the global variables `blobStartPos`, `blobSize`, `blobCenter`, + * - The function updates the global variables `blobStartPos`, `blobSize`, `blobCenter`, * and `lastState_blobPos`. * - The number of blobs detected is limited by `maxNumBlobs`. * - If the number of blobs exceeds `maxNumBlobs`, additional blobs are ignored. - * + * * @warning * - Ensure that `touchArray` has at least `size` elements to avoid out-of-bounds access. - * - The function relies on external global variables (`blobStartPos`, `blobSize`, `blobCenter`, - * `lastState_blobPos`, `maxNumBlobs`, `blobAmount`). Ensure they are initialized appropriately + * - The function relies on external global variables (`blobStartPos`, `blobSize`, `blobCenter`, + * `lastState_blobPos`, `maxNumBlobs`, `blobAmount`). Ensure they are initialized appropriately * before calling the function. */ std::vector detect1D(const int* const touchArray, const int size) diff --git a/tests/testing_touch.cpp b/tests/testing_touch.cpp index 16bed8b..8c28656 100644 --- a/tests/testing_touch.cpp +++ b/tests/testing_touch.cpp @@ -30,13 +30,37 @@ int main() discrete_touch[14] = 1; discrete_touch[15] = 1; - // Update the touch data + // Update the touch data and print the computed values touch.updateTouchArray(discrete_touch, touchSize); - - // Output the computed values std::cout << "touchAll: " << touch.touchAll << std::endl; std::cout << "brush: " << touch.brush << std::endl; std::cout << "rub: " << touch.rub << std::endl; - // multi touch + //reset the touch array, and next we'll repeat the above blobs but offset by 1 to simulate movement + for(int i = 0; i < touchSize; ++i) + discrete_touch[i] = 0; + + // simulate a blob of size 1 starting at position 1 + discrete_touch[1] = 1; + + // simulate a blob of size 2 starting at position 6 + discrete_touch[6] = 1; + discrete_touch[7] = 1; + + // simulate a blob of size 3 starting at position 9 + discrete_touch[9] = 1; + discrete_touch[10] = 1; + discrete_touch[11] = 1; + + // simulate a blob of size 1 at position 13 -- commented out to test the end of the array in the next blob + //discrete_touch[13] = 1; + + // simulate a blob of size 1 starting at position 15 + discrete_touch[15] = 1; + + // Update the touch data and print the computed values + touch.updateTouchArray(discrete_touch, touchSize); + std::cout << "touchAll: " << touch.touchAll << std::endl; + std::cout << "brush: " << touch.brush << std::endl; + std::cout << "rub: " << touch.rub << std::endl; } From 73c095f315b6832917dd6750c9e1fb5ddfa5f517 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 10:44:24 -0500 Subject: [PATCH 07/13] rename blobDetector --- include/puara/descriptors/touch.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index d73403f..c091977 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -25,7 +25,7 @@ class Touch // touch array int touchSizeEdge = 4; // amount of touch stripes for top and bottom portions (arbitrary) - BlobDetector blob; + BlobDetector blobDetector; int brushCounter[maxNumBlobs]{}; // Arrays of LeakyIntegrator instances @@ -65,7 +65,7 @@ class Touch touchBottom = touchAverage(discrete_touch, (touchSize - touchSizeEdge), touchSize); // 1D blob detection: used for brush - const auto movement = blob.detect1D(discrete_touch, touchSize); + const auto movement = blobDetector.detect1D(discrete_touch, touchSize); // brush: direction and intensity of capsense brush motion // rub: intensity of rub motion From d0d6a785cfb35e609408eeb47b87bb6fa770f10e Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 10:45:23 -0500 Subject: [PATCH 08/13] remove library.json for now --- library.json | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 library.json diff --git a/library.json b/library.json deleted file mode 100644 index d7feb08..0000000 --- a/library.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "puara-gestures", - "version": "0.0.0+20241216081434" -} \ No newline at end of file From 4084901989b27463254f7b0128ae49a8a07483a4 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 14:06:36 -0500 Subject: [PATCH 09/13] prComments --- include/puara/descriptors/touch.h | 5 +++-- include/puara/utils/blobDetector.h | 29 ++++++++++++++++++----------- library.json | 4 ++++ tests/testing_touch.cpp | 2 -- 4 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 library.json diff --git a/include/puara/descriptors/touch.h b/include/puara/descriptors/touch.h index c091977..61550bb 100644 --- a/include/puara/descriptors/touch.h +++ b/include/puara/descriptors/touch.h @@ -5,6 +5,7 @@ #include #include +#include namespace puara_gestures { @@ -12,7 +13,7 @@ namespace puara_gestures class Touch { public: - static const int maxNumBlobs = BlobDetector::maxNumBlobs; + static constexpr int maxNumBlobs = BlobDetector::maxNumBlobs; float touchAll = 0.0f; // f, 0--1 float touchTop = 0.0f; // f, 0--1 float touchMiddle = 0.0f; // f, 0--1 @@ -70,7 +71,7 @@ class Touch // brush: direction and intensity of capsense brush motion // rub: intensity of rub motion // in ~cm/s (distance between stripes = ~1.5cm) - for(int i = 0; i < maxNumBlobs; ++i) + for(int i = 0; i < movement.size(); ++i) { if(movement[i] == 0) { diff --git a/include/puara/utils/blobDetector.h b/include/puara/utils/blobDetector.h index f30a5ed..cabf7b0 100644 --- a/include/puara/utils/blobDetector.h +++ b/include/puara/utils/blobDetector.h @@ -1,6 +1,7 @@ #pragma once -#include +#include + namespace puara_gestures { @@ -39,7 +40,7 @@ namespace puara_gestures struct BlobDetector { /** The maximum number of blobs that the algorithm should detect. */ - static const int maxNumBlobs = 4; + static constexpr int maxNumBlobs = 4; /** The start index of detected blobs. */ int blobStartPos[maxNumBlobs]{}; @@ -49,7 +50,7 @@ struct BlobDetector */ int lastState_blobPos[maxNumBlobs]{}; - /** "size" (amount of stripes) of each blob */ + /** size (amount of stripes) of each blob */ int blobSize[maxNumBlobs]{}; /** shows the "center"(index)of each blob */ @@ -66,9 +67,11 @@ struct BlobDetector * from the previous function call. * * @param touchArray Pointer to the 1D binary array representing touch data. Each element is expected to be 0 or 1. - * @param size The size of the `touchArray`. - * @return A vector of integers representing the movement of each blob's start position since the - * last invocation of `detect1D`. The size of the returned vector is `maxNumBlobs`. + * @param touchArraySize The size of the `touchArray`, representing the number of touch sensor in the array. + * This is expected to be larger than maxNumBlobs, which by definition will be a portion of the number + * of sensors, or at most equal to the number of sensors. + * @return A small_vector of integers representing the movement of each blob's start position since the + * last invocation of `detect1D`. * * @note * - The function updates the global variables `blobStartPos`, `blobSize`, `blobCenter`, @@ -82,7 +85,8 @@ struct BlobDetector * `lastState_blobPos`, `maxNumBlobs`, `blobAmount`). Ensure they are initialized appropriately * before calling the function. */ - std::vector detect1D(const int* const touchArray, const int size) + boost::container::small_vector + detect1D(const int* const touchArray, const int touchArraySize) { blobAmount = 0; for(int i = 0; i < maxNumBlobs; i++) @@ -94,7 +98,7 @@ struct BlobDetector blobCenter[i] = 0; } - for(int stripe = 0; stripe < size;) + for(int stripe = 0; stripe < touchArraySize;) { if(touchArray[stripe] == 1) { @@ -103,11 +107,14 @@ struct BlobDetector //continue the blob until we no longer have 1s int sizeCounter = 1; - while(touchArray[stripe + sizeCounter] == 1 && (stripe + sizeCounter) <= size) + while((stripe + sizeCounter) <= touchArraySize + && touchArray[stripe + sizeCounter] == 1) + { sizeCounter++; + } blobSize[blobAmount] = sizeCounter; - blobCenter[blobAmount] = stripe + (sizeCounter - 1.f) / 2.f; + blobCenter[blobAmount] = stripe + (sizeCounter - 1.0) / 2.0; stripe += sizeCounter; if(++blobAmount >= maxNumBlobs) @@ -120,7 +127,7 @@ struct BlobDetector } //return the movement since the last time detect1D was called - std::vector movement(maxNumBlobs, 0); + boost::container::small_vector movement(maxNumBlobs, 0); for(int i = 0; i < maxNumBlobs; ++i) movement[i] = blobStartPos[i] - lastState_blobPos[i]; diff --git a/library.json b/library.json new file mode 100644 index 0000000..d7feb08 --- /dev/null +++ b/library.json @@ -0,0 +1,4 @@ +{ + "name": "puara-gestures", + "version": "0.0.0+20241216081434" +} \ No newline at end of file diff --git a/tests/testing_touch.cpp b/tests/testing_touch.cpp index 8c28656..649ead6 100644 --- a/tests/testing_touch.cpp +++ b/tests/testing_touch.cpp @@ -1,7 +1,5 @@ #include -#include - using namespace puara_gestures; int main() From 428dac6c671cd8dc2c145b290a82610ac02801e8 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 14:51:51 -0500 Subject: [PATCH 10/13] prComments --- include/puara/utils/blobDetector.h | 3 ++- tests/testing_touch.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/puara/utils/blobDetector.h b/include/puara/utils/blobDetector.h index cabf7b0..3cae64f 100644 --- a/include/puara/utils/blobDetector.h +++ b/include/puara/utils/blobDetector.h @@ -37,8 +37,9 @@ namespace puara_gestures * - The number of blobs processed is limited by `maxNumBlobs` (default is `4`). * - If the input contains more blobs than `maxNumBlobs`, the additional blobs are ignored. */ -struct BlobDetector +class BlobDetector { +public: /** The maximum number of blobs that the algorithm should detect. */ static constexpr int maxNumBlobs = 4; diff --git a/tests/testing_touch.cpp b/tests/testing_touch.cpp index 649ead6..32b5c41 100644 --- a/tests/testing_touch.cpp +++ b/tests/testing_touch.cpp @@ -6,7 +6,7 @@ int main() { Touch touch; - const int touchSize = 16; + constexpr int touchSize = 16; int discrete_touch[touchSize] = {0}; // simulate a blob of size 1 starting at position 0 From 12a02fadd09c036dd0bef979fab7b5b82d282cc0 Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 15:23:16 -0500 Subject: [PATCH 11/13] remove extra file --- library.json | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 library.json diff --git a/library.json b/library.json deleted file mode 100644 index d7feb08..0000000 --- a/library.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "puara-gestures", - "version": "0.0.0+20241216081434" -} \ No newline at end of file From 695be193d434130c700c0af41c1792bd01cfd37f Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Tue, 17 Dec 2024 15:23:52 -0500 Subject: [PATCH 12/13] add library.json to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b5fabc7..61eb52e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ build/ .vscode/ *.user *code-workspace +library.json From d0677fe80aed355112543ed0b44138481d13367b Mon Sep 17 00:00:00 2001 From: Vincent Berthiaume Date: Thu, 19 Dec 2024 10:19:25 -0500 Subject: [PATCH 13/13] remove extraneous wrap constructor --- include/puara/utils/wrap.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/puara/utils/wrap.h b/include/puara/utils/wrap.h index 766d24c..60e4345 100644 --- a/include/puara/utils/wrap.h +++ b/include/puara/utils/wrap.h @@ -90,8 +90,6 @@ class Unwrap class Wrap { public: - Wrap(double pMin, double pMax) : min {pMin}, max {pMax}{} - double min{}; double max{};