From 92d43a42b19f9683d1f008e8b6d78391d6c68e12 Mon Sep 17 00:00:00 2001
From: Joana Plewnia <joana.plewnia@kit.edu>
Date: Wed, 5 Feb 2025 17:00:07 +0100
Subject: [PATCH] added EqualitySnapshotFilter - navigates to all leaf nodes of
 the dict and accepts the snapshot if at least one leaf is unequal to the last
 acepted snapshot - is dependent on the definition of equality of the leaf
 objects

---
 .../libraries/armem/server/CMakeLists.txt     |   4 +-
 .../server/ltm/processors/Processors.cpp      |   8 +
 .../filter/equalityFilter/EqualityFilter.cpp  | 237 ++++--------------
 .../filter/equalityFilter/EqualityFilter.h    |  20 +-
 .../similarityFilter/SimilarityFilter.cpp     | 229 +++++++++++++++++
 .../similarityFilter/SimilarityFilter.h       |  45 ++++
 6 files changed, 336 insertions(+), 207 deletions(-)
 create mode 100644 source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.cpp
 create mode 100644 source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.h

diff --git a/source/RobotAPI/libraries/armem/server/CMakeLists.txt b/source/RobotAPI/libraries/armem/server/CMakeLists.txt
index 728c22ba6..7f77dd305 100644
--- a/source/RobotAPI/libraries/armem/server/CMakeLists.txt
+++ b/source/RobotAPI/libraries/armem/server/CMakeLists.txt
@@ -60,8 +60,8 @@ set(LIB_FILES
 
     ltm/processors/filter/Filter.cpp
     ltm/processors/filter/frequencyFilter/FrequencyFilter.cpp
+    ltm/processors/filter/similarityFilter/SimilarityFilter.cpp
     ltm/processors/filter/equalityFilter/EqualityFilter.cpp
-    #ltm/processors/filter/similarityFilter/SimilarityFilter.cpp
     ltm/processors/filter/importanceFilter/ImportanceFilter.cpp
 
     ltm/processors/extractor/Extractor.cpp
@@ -153,8 +153,8 @@ set(LIB_HEADERS
 
     ltm/processors/filter/Filter.h
     ltm/processors/filter/frequencyFilter/FrequencyFilter.h
+    ltm/processors/filter/similarityFilter/SimilarityFilter.h
     ltm/processors/filter/equalityFilter/EqualityFilter.h
-    #ltm/processors/filter/similarityFilter/SimilarityFilter.h
     ltm/processors/filter/importanceFilter/ImportanceFilter.h
 
     ltm/processors/extractor/Extractor.h
diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp
index a2405db2d..24e69eeb4 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/processors/Processors.cpp
@@ -10,6 +10,7 @@
 #include "filter/equalityFilter/EqualityFilter.h"
 #include "filter/frequencyFilter/FrequencyFilter.h"
 #include "filter/importanceFilter/ImportanceFilter.h"
+#include "filter/similarityFilter/SimilarityFilter.h"
 
 namespace armarx::armem::server::ltm
 {
@@ -39,6 +40,13 @@ namespace armarx::armem::server::ltm
             f->configure(config[processor::filter::SnapshotImportanceFilter::NAME]);
             snapFilters.push_back(std::move(f));
         }
+        if (config.contains(processor::filter::SnapshotEqualityFilter::NAME))
+        {
+            ARMARX_IMPORTANT << "ADDING SNAPSHOT EQUALITY FILTER";
+            auto f = std::make_unique<processor::filter::SnapshotEqualityFilter>();
+            f->configure(config[processor::filter::SnapshotEqualityFilter::NAME]);
+            snapFilters.push_back(std::move(f));
+        }
 
         // Converters
         if (config.contains(processor::converter::data::image::PngConverter::NAME))
diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp
index 0d5090c7a..d5e1aa733 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp
+++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.cpp
@@ -1,229 +1,86 @@
 #include "EqualityFilter.h"
 
-#include <list>
-
-#include <IceUtil/Time.h>
-
-#include "RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h"
-#include "RobotAPI/libraries/aron/core/data/variant/primitive/Float.h"
-
 namespace armarx::armem::server::ltm::processor::filter
 {
     bool
-    SnapshotSimilarityFilter::accept(const armem::wm::EntitySnapshot& e, bool simulatedVersion)
+    SnapshotEqualityFilter::accept(const armem::wm::EntitySnapshot& e, bool simulatedVersion)
     {
         auto start = std::chrono::high_resolution_clock::now();
 
-        int num_instances = 0;
-        std::vector<armarx::aron::data::NDArrayPtr> images_snapshot;
-        std::vector<armarx::aron::data::FloatPtr> floats_snapshot;
-        std::vector<float> distances;
+        MemoryID entityID = e.id().getEntityID();
+
+        bool accept_because_first = false;
+        bool accept_because_different = false;
+        int instance_count = 0;
+        std::vector<aron::data::DictPtr> currentData;
+
+        if (this->dataLastCommit[entityID].size() < 1)
+        {
+            accept_because_first = true;
+            ARMARX_INFO << "first snapshot -> accept";
+            e.forEachInstance(
+                [this, &accept_because_different, &instance_count, &currentData](
+                    armem::wm::EntityInstance& i)
+                {
+                    auto data = aron::data::Dict::DynamicCastAndCheck(i.data());
+                    currentData.push_back(data);
+                });
+            this->dataLastCommit[entityID] = std::move(currentData);
+            return true;
+        }
 
         e.forEachInstance(
-            [&num_instances, &images_snapshot, &floats_snapshot](armem::wm::EntityInstance& i)
+            [this, &accept_because_different, &instance_count, &currentData, &entityID](
+                armem::wm::EntityInstance& i)
             {
                 auto data = aron::data::Dict::DynamicCastAndCheck(i.data());
-                for (auto key : data->getAllKeys())
+                if (this->dataLastCommit[entityID].size() > instance_count)
                 {
-                    aron::data::Descriptor img_desc;
-                    try
-                    {
-                        auto d = data->at(key);
-                        ;
-                        img_desc = data->at(key)->getDescriptor();
-                    }
-                    catch (...)
-                    {
-                        ARMARX_INFO << "Problem with accessing image description";
-                        img_desc = aron::data::Descriptor::NDARRAY;
-                    }
-                    if (img_desc == aron::data::Descriptor::NDARRAY)
-                    {
-                        auto img_nd = aron::data::NDArray::DynamicCastAndCheck(data->at(key));
-                        images_snapshot.insert(images_snapshot.end(), img_nd);
-                        num_instances++;
-                    }
-                    else if (img_desc == aron::data::Descriptor::FLOAT)
+                    armarx::aron::data::DictPtr lastData =
+                        this->dataLastCommit[entityID][instance_count];
+                    currentData.push_back(data);
+                    if (*data == *lastData)
                     {
-                        auto fl = aron::data::Float::DynamicCastAndCheck(data->at(key));
-                        floats_snapshot.push_back(fl);
-                        num_instances++;
+                        ARMARX_INFO << "Data in EntityInstance is the same, not updating Instance";
                     }
                     else
                     {
-                        ARMARX_INFO << "data-type not yet supported. \n"
-                                    << "Only ndarray and float data types are supported for "
-                                       "equality filters yet.";
+                        //ARMARX_INFO << VAROUT(*data);
+                        //ARMARX_INFO << VAROUT(*lastData);
+                        //if one instance differs we accept the whole snapshot
+                        ARMARX_INFO << "Data is not the same";
+                        accept_because_different = true;
                     }
                 }
+                instance_count++;
             });
 
-        if (images.size() < 2)
+        if (accept_because_different)
         {
-            ARMARX_INFO << "Adding first images, because nothing to compare";
-            images.push_back(images_snapshot);
-            this->stats.accepted += 1;
-            auto end = std::chrono::high_resolution_clock::now();
-            stats.end_time = end;
-            stats.additional_time += (end - start);
+            ARMARX_INFO << "Accepting this snapshot: " << e.id();
+            this->dataLastCommit[entityID] = std::move(currentData);
             return true;
         }
-        else if (images.size() < max_images)
-        {
-            ARMARX_INFO << "Not enough elements yet to do full comparison of last " << max_images
-                        << " elements";
-            images.push_back(images_snapshot);
-            this->stats.accepted += 1;
-            auto end = std::chrono::high_resolution_clock::now();
-            stats.end_time = end;
-            stats.additional_time += (end - start);
-            return true;
-        }
-
-
-        std::vector<armarx::aron::data::NDArrayPtr> lastCommittedImages;
-        int sizeOfCommited = 0;
-        for (int i = 0; i < max_images; i++)
-        {
-            std::vector<armarx::aron::data::NDArrayPtr> lastCommitImages =
-                images.at(images.size() - i - 1);
-            sizeOfCommited = lastCommitImages.size();
-            for (int j = 0; j < lastCommitImages.size(); j++)
-            {
-                lastCommittedImages.push_back(lastCommitImages.at(j));
-            }
-            // we just concatenate all images (instances)
-        }
-
-        ARMARX_CHECK(sizeOfCommited == images_snapshot.size()); //make sure we have enough instances
 
-        for (int i = 0; i < images_snapshot.size(); i++)
-        {
-            armarx::aron::data::NDArrayPtr new_image = images_snapshot.at(i);
-            std::vector<armarx::aron::data::NDArrayPtr> commited_images;
-            for (int j = 0; j < max_images; j++)
-            {
-                int index = i + 2 * j;
-                auto image = lastCommittedImages.at(index);
-                commited_images.emplace_back(image);
-            }
-
-            float distance = aron::similarity::NDArraySimilarity::calculate_similarity_multi(
-                commited_images, new_image, this->similarity_type);
-
-            distances.insert(distances.end(), distance);
-        }
-
-        //check for criterion:
-        float sum_distances = 0;
-        float max_distance = 0;
-        for (auto d : distances)
-        {
-            sum_distances += d;
-            if (d > max_distance)
-            {
-                max_distance = d;
-            }
-        }
-
-        bool max =
-            true; //set true if only maximum distance value is important and false if sum of distances is important
-        bool accept = false;
-
-        if (max)
-        {
-            accept = (max_distance > this->threshold);
-        }
-        else
-        {
-            accept = (sum_distances > this->threshold);
-        }
-
-        if (accept)
-        {
-            images.pop_front(); //delete first element
-            images.push_back(images_snapshot);
-            this->stats.accepted += 1;
-            auto end = std::chrono::high_resolution_clock::now();
-            stats.additional_time += (end - start);
-            stats.end_time = end;
-            return true;
-        }
-        else
-        {
-            this->stats.rejected += 1;
-            auto end = std::chrono::high_resolution_clock::now();
-            stats.additional_time += (end - start);
-            stats.end_time = end;
-            return false;
-        }
+        return false;
     }
 
     void
-    SnapshotSimilarityFilter::configure(const nlohmann::json& json)
+    SnapshotEqualityFilter::configure(const nlohmann::json& json)
     {
-        if (json.find(PARAM_THRESHOLD) != json.end())
-        {
-            threshold = json.at(PARAM_THRESHOLD);
-            ARMARX_INFO << VAROUT(threshold);
-            stats.additional_info += "Threshold-Parameter: ";
-            stats.additional_info += std::to_string(threshold);
-        }
-        if (json.find(PARAM_SIM_MEASURE) != json.end())
-        {
-            std::string type_string = json.at(PARAM_SIM_MEASURE);
-            if (type_string == "MSE")
-            {
-                this->similarity_type = aron::similarity::NDArraySimilarity::Type::MSE;
-                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::MSE;
-                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::MSE;
-            }
-            else if (type_string == "MAE")
-            {
-                this->similarity_type = aron::similarity::NDArraySimilarity::Type::MAE;
-                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::MAE;
-                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::MAE;
-            }
-            else if (type_string == "Chernoff")
-            {
-                this->similarity_type = aron::similarity::NDArraySimilarity::Type::CHERNOFF;
-                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
-                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::CHERNOFF;
-            }
-            else if (type_string == "Cosine")
-            {
-                this->similarity_type = aron::similarity::NDArraySimilarity::Type::COSINE;
-                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
-                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::COSINE;
-            }
-            else
-            {
-                ARMARX_WARNING << "Undefined similarity measure detected in JSON file";
-                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::NONE;
-                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
-            }
-            ARMARX_INFO << VAROUT(this->similarity_type);
-        }
-        if (json.find(PARAM_MAX_OBJECTS) != json.end())
-        {
-            max_images = json.at(PARAM_MAX_OBJECTS);
-            ARMARX_INFO << VAROUT(max_images);
-            stats.number_of_compared_objects = max_images;
-        }
-
-        stats.start_time = std::chrono::high_resolution_clock::now();
+        ARMARX_DEBUG << "No init for euqality filter needed";
     }
 
     SnapshotFilter::FilterStatistics
-    SnapshotSimilarityFilter::getFilterStatistics()
+    SnapshotEqualityFilter::getFilterStatistics()
     {
-        return stats;
+        return this->stats;
     }
 
     std::string
-    SnapshotSimilarityFilter::getName()
+    SnapshotEqualityFilter::getName()
     {
-        return this->NAME;
+        return armarx::armem::server::ltm::processor::filter::SnapshotEqualityFilter::NAME;
     }
 
-} // namespace armarx::armem::server::ltm::processor::filter
+} // namespace armarx::armem::server::ltm::processor::filter
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h
index e621f7121..64f984680 100644
--- a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h
+++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/equalityFilter/EqualityFilter.h
@@ -5,7 +5,6 @@
 
 // Base Class
 #include "../Filter.h"
-
 // Aron
 #include <chrono>
 
@@ -15,15 +14,12 @@
 
 namespace armarx::armem::server::ltm::processor::filter
 {
-    class SnapshotSimilarityFilter : public SnapshotFilter
+    class SnapshotEqualityFilter : public SnapshotFilter
     {
     public:
-        static const constexpr char* NAME = "SnapshotSimilarityFilter";
-        static const constexpr char* PARAM_THRESHOLD = "Threshold";
-        static const constexpr char* PARAM_SIM_MEASURE = "SimilarityMeasure";
-        static const constexpr char* PARAM_MAX_OBJECTS = "NumberOfObjectsToCompare";
+        static const constexpr char* NAME = "SnapshotEqualityFilter";
 
-        SnapshotSimilarityFilter() = default;
+        SnapshotEqualityFilter() = default;
 
         virtual bool accept(const armem::wm::EntitySnapshot& e, bool simulatedVersion) override;
         void configure(const nlohmann::json& json) override;
@@ -32,14 +28,8 @@ namespace armarx::armem::server::ltm::processor::filter
         std::string getName() override;
 
     private:
-        //std::map<MemoryID, std::vector<aron::data::DictPtr>> dataLastCommit;
-        std::deque<std::vector<armarx::aron::data::NDArrayPtr>> images;
-        std::deque<std::vector<armarx::aron::data::FloatPtr>> floats;
+        std::map<MemoryID, std::vector<aron::data::DictPtr>> dataLastCommit;
         std::map<MemoryID, long> timestampLastCommitInMs;
-        std::double_t threshold;
         FilterStatistics stats;
-        std::size_t max_images = 2;
-        aron::similarity::NDArraySimilarity::Type similarity_type;
-        aron::similarity::FloatSimilarity::Type float_similarity_type;
     };
-} // namespace armarx::armem::server::ltm::processor::filter
+} // namespace armarx::armem::server::ltm::processor::filter
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.cpp b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.cpp
new file mode 100644
index 000000000..26876c7c4
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.cpp
@@ -0,0 +1,229 @@
+#include "SimilarityFilter.h"
+
+#include <list>
+
+#include <IceUtil/Time.h>
+
+#include "RobotAPI/libraries/aron/core/data/variant/complex/NDArray.h"
+#include "RobotAPI/libraries/aron/core/data/variant/primitive/Float.h"
+
+namespace armarx::armem::server::ltm::processor::filter
+{
+    bool
+    SnapshotSimilarityFilter::accept(const armem::wm::EntitySnapshot& e, bool simulatedVersion)
+    {
+        auto start = std::chrono::high_resolution_clock::now();
+
+        int num_instances = 0;
+        std::vector<armarx::aron::data::NDArrayPtr> images_snapshot;
+        std::vector<armarx::aron::data::FloatPtr> floats_snapshot;
+        std::vector<float> distances;
+
+        e.forEachInstance(
+            [&num_instances, &images_snapshot, &floats_snapshot](armem::wm::EntityInstance& i)
+            {
+                auto data = aron::data::Dict::DynamicCastAndCheck(i.data());
+                for (auto key : data->getAllKeys())
+                {
+                    aron::data::Descriptor img_desc;
+                    try
+                    {
+                        auto d = data->at(key);
+                        ;
+                        img_desc = data->at(key)->getDescriptor();
+                    }
+                    catch (...)
+                    {
+                        ARMARX_INFO << "Problem with accessing image description";
+                        img_desc = aron::data::Descriptor::NDARRAY;
+                    }
+                    if (img_desc == aron::data::Descriptor::NDARRAY)
+                    {
+                        auto img_nd = aron::data::NDArray::DynamicCastAndCheck(data->at(key));
+                        images_snapshot.insert(images_snapshot.end(), img_nd);
+                        num_instances++;
+                    }
+                    else if (img_desc == aron::data::Descriptor::FLOAT)
+                    {
+                        auto fl = aron::data::Float::DynamicCastAndCheck(data->at(key));
+                        floats_snapshot.push_back(fl);
+                        num_instances++;
+                    }
+                    else
+                    {
+                        ARMARX_INFO << "data-type not yet supported. \n"
+                                    << "Only ndarray and float data types are supported for "
+                                       "equality filters yet.";
+                    }
+                }
+            });
+
+        if (images.size() < 2)
+        {
+            ARMARX_INFO << "Adding first images, because nothing to compare";
+            images.push_back(images_snapshot);
+            this->stats.accepted += 1;
+            auto end = std::chrono::high_resolution_clock::now();
+            stats.end_time = end;
+            stats.additional_time += (end - start);
+            return true;
+        }
+        else if (images.size() < max_images)
+        {
+            ARMARX_INFO << "Not enough elements yet to do full comparison of last " << max_images
+                        << " elements";
+            images.push_back(images_snapshot);
+            this->stats.accepted += 1;
+            auto end = std::chrono::high_resolution_clock::now();
+            stats.end_time = end;
+            stats.additional_time += (end - start);
+            return true;
+        }
+
+
+        std::vector<armarx::aron::data::NDArrayPtr> lastCommittedImages;
+        int sizeOfCommited = 0;
+        for (int i = 0; i < max_images; i++)
+        {
+            std::vector<armarx::aron::data::NDArrayPtr> lastCommitImages =
+                images.at(images.size() - i - 1);
+            sizeOfCommited = lastCommitImages.size();
+            for (int j = 0; j < lastCommitImages.size(); j++)
+            {
+                lastCommittedImages.push_back(lastCommitImages.at(j));
+            }
+            // we just concatenate all images (instances)
+        }
+
+        ARMARX_CHECK(sizeOfCommited == images_snapshot.size()); //make sure we have enough instances
+
+        for (int i = 0; i < images_snapshot.size(); i++)
+        {
+            armarx::aron::data::NDArrayPtr new_image = images_snapshot.at(i);
+            std::vector<armarx::aron::data::NDArrayPtr> commited_images;
+            for (int j = 0; j < max_images; j++)
+            {
+                int index = i + 2 * j;
+                auto image = lastCommittedImages.at(index);
+                commited_images.emplace_back(image);
+            }
+
+            float distance = aron::similarity::NDArraySimilarity::calculate_similarity_multi(
+                commited_images, new_image, this->similarity_type);
+
+            distances.insert(distances.end(), distance);
+        }
+
+        //check for criterion:
+        float sum_distances = 0;
+        float max_distance = 0;
+        for (auto d : distances)
+        {
+            sum_distances += d;
+            if (d > max_distance)
+            {
+                max_distance = d;
+            }
+        }
+
+        bool max =
+            true; //set true if only maximum distance value is important and false if sum of distances is important
+        bool accept = false;
+
+        if (max)
+        {
+            accept = (max_distance > this->threshold);
+        }
+        else
+        {
+            accept = (sum_distances > this->threshold);
+        }
+
+        if (accept)
+        {
+            images.pop_front(); //delete first element
+            images.push_back(images_snapshot);
+            this->stats.accepted += 1;
+            auto end = std::chrono::high_resolution_clock::now();
+            stats.additional_time += (end - start);
+            stats.end_time = end;
+            return true;
+        }
+        else
+        {
+            this->stats.rejected += 1;
+            auto end = std::chrono::high_resolution_clock::now();
+            stats.additional_time += (end - start);
+            stats.end_time = end;
+            return false;
+        }
+    }
+
+    void
+    SnapshotSimilarityFilter::configure(const nlohmann::json& json)
+    {
+        if (json.find(PARAM_THRESHOLD) != json.end())
+        {
+            threshold = json.at(PARAM_THRESHOLD);
+            ARMARX_INFO << VAROUT(threshold);
+            stats.additional_info += "Threshold-Parameter: ";
+            stats.additional_info += std::to_string(threshold);
+        }
+        if (json.find(PARAM_SIM_MEASURE) != json.end())
+        {
+            std::string type_string = json.at(PARAM_SIM_MEASURE);
+            if (type_string == "MSE")
+            {
+                this->similarity_type = aron::similarity::NDArraySimilarity::Type::MSE;
+                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::MSE;
+                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::MSE;
+            }
+            else if (type_string == "MAE")
+            {
+                this->similarity_type = aron::similarity::NDArraySimilarity::Type::MAE;
+                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::MAE;
+                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::MAE;
+            }
+            else if (type_string == "Chernoff")
+            {
+                this->similarity_type = aron::similarity::NDArraySimilarity::Type::CHERNOFF;
+                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
+                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::CHERNOFF;
+            }
+            else if (type_string == "Cosine")
+            {
+                this->similarity_type = aron::similarity::NDArraySimilarity::Type::COSINE;
+                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
+                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::COSINE;
+            }
+            else
+            {
+                ARMARX_WARNING << "Undefined similarity measure detected in JSON file";
+                stats.similarity_type = aron::similarity::NDArraySimilarity::Type::NONE;
+                this->float_similarity_type = aron::similarity::FloatSimilarity::Type::NONE;
+            }
+            ARMARX_INFO << VAROUT(this->similarity_type);
+        }
+        if (json.find(PARAM_MAX_OBJECTS) != json.end())
+        {
+            max_images = json.at(PARAM_MAX_OBJECTS);
+            ARMARX_INFO << VAROUT(max_images);
+            stats.number_of_compared_objects = max_images;
+        }
+
+        stats.start_time = std::chrono::high_resolution_clock::now();
+    }
+
+    SnapshotFilter::FilterStatistics
+    SnapshotSimilarityFilter::getFilterStatistics()
+    {
+        return stats;
+    }
+
+    std::string
+    SnapshotSimilarityFilter::getName()
+    {
+        return this->NAME;
+    }
+
+} // namespace armarx::armem::server::ltm::processor::filter
diff --git a/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.h b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.h
new file mode 100644
index 000000000..e621f7121
--- /dev/null
+++ b/source/RobotAPI/libraries/armem/server/ltm/processors/filter/similarityFilter/SimilarityFilter.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <map>
+#include <vector>
+
+// Base Class
+#include "../Filter.h"
+
+// Aron
+#include <chrono>
+
+#include "RobotAPI/libraries/aron/similarity/data/image/FloatSimilarity.h"
+#include "RobotAPI/libraries/aron/similarity/data/image/NDArraySimilarity.h"
+#include <RobotAPI/libraries/aron/core/data/variant/container/Dict.h>
+
+namespace armarx::armem::server::ltm::processor::filter
+{
+    class SnapshotSimilarityFilter : public SnapshotFilter
+    {
+    public:
+        static const constexpr char* NAME = "SnapshotSimilarityFilter";
+        static const constexpr char* PARAM_THRESHOLD = "Threshold";
+        static const constexpr char* PARAM_SIM_MEASURE = "SimilarityMeasure";
+        static const constexpr char* PARAM_MAX_OBJECTS = "NumberOfObjectsToCompare";
+
+        SnapshotSimilarityFilter() = default;
+
+        virtual bool accept(const armem::wm::EntitySnapshot& e, bool simulatedVersion) override;
+        void configure(const nlohmann::json& json) override;
+
+        FilterStatistics getFilterStatistics() override;
+        std::string getName() override;
+
+    private:
+        //std::map<MemoryID, std::vector<aron::data::DictPtr>> dataLastCommit;
+        std::deque<std::vector<armarx::aron::data::NDArrayPtr>> images;
+        std::deque<std::vector<armarx::aron::data::FloatPtr>> floats;
+        std::map<MemoryID, long> timestampLastCommitInMs;
+        std::double_t threshold;
+        FilterStatistics stats;
+        std::size_t max_images = 2;
+        aron::similarity::NDArraySimilarity::Type similarity_type;
+        aron::similarity::FloatSimilarity::Type float_similarity_type;
+    };
+} // namespace armarx::armem::server::ltm::processor::filter
-- 
GitLab