diff --git a/include/petrack.h b/include/petrack.h
index ba1932079de41dcce4439701a350e991b58720cc..8a6363cb0ce54e3f5df609af8282b11cca4e1eb6 100644
--- a/include/petrack.h
+++ b/include/petrack.h
@@ -26,6 +26,7 @@
 #include <QMainWindow>
 #include <QMouseEvent>
 #include <opencv2/opencv.hpp>
+#include <optional>
 
 #ifdef STEREO
 #include "calibStereoFilter.h"
@@ -488,4 +489,10 @@ private:
     std::vector<std::string> mAuthors;
 };
 
+namespace util
+{
+std::optional<QSet<int>> splitStringToInt(const QString &input);
+}
+
+
 #endif
diff --git a/src/petrack.cpp b/src/petrack.cpp
index 23b6f68414550b5fa166577b9cfbfc5d4a722a90..fc65b5dacc0d84156735bb3f03adf5f7964b776d 100644
--- a/src/petrack.cpp
+++ b/src/petrack.cpp
@@ -3977,51 +3977,89 @@ QSet<int> Petrack::getPedestrianUserSelection()
     if(mControlWidget->trackShowOnly->checkState() == Qt::Checked)
     {
         QSet<int> onlyVisible;
+        // subtraction needed as in UI ID start at 1 and internally at 0
         onlyVisible.insert(mControlWidget->trackShowOnlyNr->value() - 1);
         return onlyVisible;
     }
     if(mControlWidget->trackShowOnlyList->checkState() == Qt::Checked)
     {
-        QStringList list = mControlWidget->trackShowOnlyNrList->text().split(",", Qt::SkipEmptyParts);
-        QSet<int>   onlyVisible;
-        foreach(QString s, list)
+        auto enteredIDs = util::splitStringToInt(mControlWidget->trackShowOnlyNrList->text());
+        if(enteredIDs.has_value())
         {
-            bool ok = false;
-            int  nr = s.toInt(&ok);
-            if(ok /* && nr <= maxPed && nr > 0*/) // einzelne ID
+            QSet<int> selectedIDs;
+            for(auto id : enteredIDs.value())
             {
-                onlyVisible.insert(nr - 1);
+                // subtraction needed as in UI ID start at 1 and internally at 0
+                selectedIDs.insert(id - 1);
             }
-            else // error or IDs range (e.g. 1-3, 6-10, etc.)
-            {
-                QStringList range = s.split("-", Qt::SkipEmptyParts);
-                int         last, first = range[0].toInt(&ok);
+            mControlWidget->trackShowOnlyNrList->setStyleSheet("");
+            return selectedIDs;
+        }
+        else
+        {
+            mControlWidget->trackShowOnlyNrList->setStyleSheet("border: 1px solid red");
+        }
+    }
+    return QSet<int>();
+}
 
-                if(ok /* && first <= maxPed && nr > 0*/)
+/**
+ * @brief Splits the given text to get a set of integers.
+ *
+ * The given text will be split on ',' and then each element will be checked if it is a range. Ranges are marked with
+ * '-' as divider. Only positive integer values are allowed.
+ *
+ * Examples:
+ * '1,5,6' -> (1, 5, 6)
+ * '1-5' -> (1, 2, 3, 4, 5)
+ *
+ * @param input given text
+ * @return Set of int in the given text
+ */
+std::optional<QSet<int>> util::splitStringToInt(const QString &input)
+{
+    QSet<int> ids;
+
+    for(const auto &id : input.split(",", Qt::SkipEmptyParts))
+    {
+        bool ok        = false;
+        int  enteredID = id.toInt(&ok);
+        if(ok && enteredID >= 0) // parse single values
+        {
+            ids.insert(enteredID);
+        }
+        else // error or IDs range (e.g. 1-3, 6-10, etc.)
+        {
+            if(id.startsWith("-"))
+            {
+                ok = false;
+            }
+            auto range = id.split("-");
+            int  first = range[0].toInt(&ok);
+            ok         = ok && range.size() == 2 && !range[1].isEmpty();
+            if(ok)
+            {
+                int last = range[1].toInt(&ok);
+                if(ok)
                 {
-                    last = range[1].toInt(&ok);
-                    if(ok /* && last <= maxPed && nr > 0*/)
+                    if(first > last)
                     {
-                        if(first > last)
-                        {
-                            std::swap(first, last);
-                        }
+                        std::swap(first, last);
+                    }
 
-                        for(int i = first; i <= last; i++)
-                        {
-                            onlyVisible.insert(i - 1);
-                        }
+                    for(int i = first; i <= last; i++)
+                    {
+                        ids.insert(i);
                     }
                 }
             }
-            if(!ok)
-            {
-                debout << "Warning: error while reading showOnlyVisible list from input line!" << std::endl;
-            }
         }
-        return onlyVisible; // in anzeige wird ab 1 gezaehlt, in datenstruktur ab 0
+        if(!ok)
+        {
+            return std::nullopt;
+        }
     }
-    return QSet<int>();
+    return ids;
 }
 
 /**
diff --git a/tests/unit_test/CMakeLists.txt b/tests/unit_test/CMakeLists.txt
index 8b9088c44cb7bad704f5b1b06852408f90072d09..558dec9661301f10cfd5eb60c4cc716d515e6c3f 100644
--- a/tests/unit_test/CMakeLists.txt
+++ b/tests/unit_test/CMakeLists.txt
@@ -9,6 +9,5 @@ target_sources(petrack_tests PRIVATE
     tst_moCapController.cpp
     tst_recognition.cpp
     tst_codeMarkerWidget.cpp
+    tst_petrack.cpp
 )
-
-
diff --git a/tests/unit_test/tst_control.cpp b/tests/unit_test/tst_control.cpp
index c370b38617bb156f964768b2f123b937b1ee472c..b48ab0a46d031ccb1d9b3dad7f2478f127e3c833 100644
--- a/tests/unit_test/tst_control.cpp
+++ b/tests/unit_test/tst_control.cpp
@@ -297,3 +297,95 @@ TEST_CASE("Loading from and saving to XML node", "[config]")
         }
     }
 }
+
+SCENARIO("Change the show only people list", "[ui][config][tracking][path]")
+{
+    Petrack           pet{};
+    QPointer<Control> control = pet.getControlWidget();
+    control->trackShowOnlyList->setCheckState(Qt::Checked);
+
+    GIVEN("No filter given")
+    {
+        REQUIRE(control->trackShowOnlyList->isChecked());
+        REQUIRE(control->trackShowOnlyNrList->text().isEmpty());
+
+        WHEN("Enter valid filter (single values)")
+        {
+            QSet<int> enteredIDs{1, 4, 6, 7};
+            QSet<int> expectedIDs;
+            for(auto id : enteredIDs)
+            {
+                expectedIDs.insert(id - 1);
+            }
+
+            std::stringstream input;
+            std::copy(enteredIDs.begin(), enteredIDs.end(), std::ostream_iterator<int>(input, ","));
+
+            QTest::keyClicks(control->trackShowOnlyNrList, input.str().c_str(), Qt::NoModifier, 50);
+            auto receivedIDs = pet.getPedestrianUserSelection();
+
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(expectedIDs == receivedIDs);
+                REQUIRE(control->trackShowOnlyNrList->styleSheet().isEmpty());
+            }
+        }
+
+        WHEN("Enter valid filter (range)")
+        {
+            QSet<int> enteredIDs{1, 2, 3, 4};
+            QSet<int> expectedIDs;
+            for(auto id : enteredIDs)
+            {
+                expectedIDs.insert(id - 1);
+            }
+
+            QString input("1-4");
+
+            QSet<int> receivedIDs;
+            QTest::keyClicks(control->trackShowOnlyNrList, input, Qt::NoModifier, 50);
+            receivedIDs = pet.getPedestrianUserSelection();
+
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(expectedIDs == receivedIDs);
+                REQUIRE(control->trackShowOnlyNrList->styleSheet().isEmpty());
+            }
+        }
+
+        WHEN("Enter invalid filter")
+        {
+            QString input("1-");
+
+            THEN("the border should be red")
+            {
+                QTest::keyClicks(control->trackShowOnlyNrList, input, Qt::NoModifier, 50);
+                auto receivedIDs = pet.getPedestrianUserSelection();
+                REQUIRE(receivedIDs.isEmpty());
+                REQUIRE(control->trackShowOnlyNrList->styleSheet().contains("border: 1px solid red"));
+            }
+        }
+
+        WHEN("Enter filter (element-wise)")
+        {
+            QString input("1, 3,4,10, 20-40, 50-45, 100");
+            THEN("no exception should be thrown")
+            {
+                for(auto character : input.toStdString())
+                {
+                    QTest::keyClick(control->trackShowOnlyNrList, character, Qt::NoModifier, 10);
+
+                    QSet<int> receivedIDs = pet.getPedestrianUserSelection();
+                    if(receivedIDs.isEmpty())
+                    {
+                        REQUIRE(control->trackShowOnlyNrList->styleSheet().contains("border: 1px solid red"));
+                    }
+                    else
+                    {
+                        REQUIRE(control->trackShowOnlyNrList->styleSheet().isEmpty());
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tests/unit_test/tst_petrack.cpp b/tests/unit_test/tst_petrack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..62dd57d4ffd441129d2ee962081be00b7f3f9144
--- /dev/null
+++ b/tests/unit_test/tst_petrack.cpp
@@ -0,0 +1,162 @@
+/*
+ * PeTrack - Software for tracking pedestrians movement in videos
+ * Copyright (C) 2010-2022 Forschungszentrum Jülich GmbH,
+ * Maik Boltes, Juliane Adrian, Ricardo Martin Brualla, Arne Graf, Paul Häger, Daniel Hillebrand,
+ * Deniz Kilic, Paul Lieberenz, Daniel Salden, Tobias Schrödter, Ann Katrin Seemann
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "petrack.h"
+
+#include <catch2/catch.hpp>
+
+SCENARIO("Getting the IDs of the pedestrian from user input", "[petrack][util]")
+{
+    WHEN("Enter valid pedestrian ID filter")
+    {
+        AND_WHEN("single values")
+        {
+            QSet<int>         expectedIDs{1, 4, 6, 7};
+            std::stringstream input;
+            std::copy(expectedIDs.begin(), expectedIDs.end(), std::ostream_iterator<int>(input, ","));
+
+            auto receivedIDs = util::splitStringToInt(QString(input.str().c_str()));
+
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("range")
+        {
+            QSet<int> expectedIDs{1, 2, 3, 4};
+            QString   input("1-4");
+
+            auto receivedIDs = util::splitStringToInt(input);
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("range (reverse order)")
+        {
+            QSet<int> expectedIDs{1, 2, 3, 4};
+            QString   input("4-1");
+
+            auto receivedIDs = util::splitStringToInt(input);
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("range + single values")
+        {
+            QSet<int> expectedIDs{1, 2, 3, 4, 5, 8, 10};
+            QString   input("1-5,8,10");
+
+            auto receivedIDs = util::splitStringToInt(input);
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("single values + range")
+        {
+            QSet<int> expectedIDs{1, 3, 5, 8, 9, 10, 11};
+            QString   input("1,3,5,8-11");
+
+            auto receivedIDs = util::splitStringToInt(input);
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("single values + range (with spaces")
+        {
+            QSet<int> expectedIDs{1, 3, 5, 8, 9, 10, 11};
+            QString   input("1,  3 ,5, 8 -11");
+
+            auto receivedIDs = util::splitStringToInt(input);
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("duplicate values")
+        {
+            QSet<int> expectedIDs{1, 2, 3, 4};
+            QString   input("1-4,1");
+
+            auto receivedIDs = util::splitStringToInt(input);
+
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+        AND_WHEN("range same start and end")
+        {
+            QSet<int> expectedIDs{1};
+            QString   input("1-1");
+
+            auto receivedIDs = util::splitStringToInt(input);
+
+            THEN("the entered ids should be returned")
+            {
+                REQUIRE(receivedIDs.has_value());
+                REQUIRE(expectedIDs == receivedIDs.value());
+            }
+        }
+    }
+
+    WHEN("Enter invalid pedestrian ID filter")
+    {
+        AND_WHEN("negative ID")
+        {
+            QString input("-1");
+            auto    receivedIDs = util::splitStringToInt(input);
+
+            THEN("std::nullopt should be returned") { REQUIRE_FALSE(receivedIDs.has_value()); }
+        }
+        AND_WHEN("invalid range")
+        {
+            QString input("1-");
+            auto    receivedIDs = util::splitStringToInt(input);
+
+            THEN("std::nullopt should be returned") { REQUIRE_FALSE(receivedIDs.has_value()); }
+        }
+        AND_WHEN("too many -'s")
+        {
+            QString input("1-2-");
+            auto    receivedIDs = util::splitStringToInt(input);
+
+            THEN("std::nullopt should be returned") { REQUIRE_FALSE(receivedIDs.has_value()); }
+        }
+        AND_WHEN("not int values (single values)")
+        {
+            QString input("1, 5, a, b, 6");
+            auto    receivedIDs = util::splitStringToInt(input);
+
+            THEN("std::nullopt should be returned") { REQUIRE_FALSE(receivedIDs.has_value()); }
+        }
+    }
+}
\ No newline at end of file