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);