Objekterkennung

Dienste zur Erkennung von Objekten ermöglichen die Extraktion von Objekten wie Beispielsweise Fahrzeugen oder Personen, Mustern, gesuchten Bildausschnitten usw. aus Bildern mittels der Multimedia API.

Standardmäßig unterstützt ecu.test einfache Algorithmen zur Erkennung von Sub-Bildern innerhalb eines Bildes (Template Matching und feature-basiertes Matching). Es ist möglich, weitere Algorithmen zur Objekterkennung mittels UserPyModules zu integrieren. Beispielsweise KI-Modelle wie YOLO, die verschiedene Objektklasse wie Personen, Fahrzeuge, Tiere usw. erkennen können.

Benutzerdefinierte Objekterkennung

Die Objekterkennung in ecu.test benutzt einen Object Detector, um einzelne Bereiche innerhalb des Bildes zu identifizieren und diese als MatchList auszugeben. Dazu muss ein Pythonmodul zur Verfügung gestellt werden. Damit dieses als gültiger UserObjectDetector erkannt wird, sind mehrere Anforderungen zu erfüllen:

  • Das Modul muss sich im Ordner UserPyModules des aktuellen Workspaces befinden.

  • Auf oberster Ebene des Skripts muss die Variable MODULE_TYPE = ‚ObjectDetector‘ definiert sein.

  • Es muss eine ObjectDetector Klasse mit beliebigem Namen implementiert werden, welche das folgende Interface erfüllt:

    • __init__

    • GetId

    • GetDocumentation

    • DetectObjects

    • GetAvailableParameters

    • GetParameter

    • SetParamter

  • Es dürfen keine zwei Objekt-Detektoren mit der gleichen Id existieren.

Weitere Details zum Interface können dem Beispiel im folgenden Abschnitt entnommen werden.

Neu hinzugefügte bzw. modifizierte Objekt-Detektoren werden von ecu.test erkannt, nachdem die Benutzerbibliotheken aktualisiert worden sind. Dies geschieht im Hauptmenu „Extras“.

Um einen benutzerdefinierten Objekt-Detektor mittels der internen Multimedia API zu benutzen, kann eine Instanz per

  • api.Multimedia.GetObjectDetector

erzeugt werden. Die implementierten Methoden des Interfaces können direkt auf dem zurückgegebenen Objekt aufgerufen werden, z.B.

api.Multimedia.GetObjectDetector('ExampleObjectDetector').GetParamter('objects').

Minimalbeispiel zur Objekterkennung

Eine Beispielimplementierung eines benutzerdefinierten Objekt-Detektor kann im ecu.test-Installationsverzeichnis gefunden werden:

  • Templates/DefaultData/UserPyModules/UserObjectDetector/ExampleObjectDetector.py

Das Minimalbeispiel in ExampleObjectDetector.py beinhaltet den folgenden Code. Weitere Informationen zu den einzelnen Methoden können den Doc-Strings entnommen werden.

from __future__ import annotations

from typing import TYPE_CHECKING, Any

import numpy as np

if TYPE_CHECKING:
    import numpy.typing as npt

MODULE_TYPE = 'ObjectDetector'


class ExampleObjectDetector:

    def __init__(self):
        """
        The object detector can be created when *GetObjectDetector(detectorId)* is called on
        the internal multimedia API, where *detectorId* is the identifier returned by *GetId()*.
        """
        self._params: dict[str, Any] = {
            param['name']: param['default'] for param in self.GetAvailableParameters()
        }

    def DetectObjects(self, img: npt.NDArray) -> list[dict[str, int | float]]:
        """
        Calls the detection algorithm of you object detector. This example detector creates
        (pseudo-random) object matches in the image dimensions and returns it.

        :param img: Numpy image (width x height x channels)
        :return: A list of dictionaries that describe the (pseudo-random) objects in the image with
                 position, dimensions and confidence.
        """
        objects = []
        # retrieve image dimensions
        height, width = img.shape[:2]
        # create pseudo random number generator with fixed seed
        gen = np.random.default_rng(seed=42)
        # create objects at random positions. The number of objects is defined in the 'objects'
        # parameter
        for _ in range(self._params.get('objects', 10)):
            objWidth = gen.random() * 100
            objHeight = gen.random() * 100
            x = gen.random() * (width - objWidth)
            y = gen.random() * (height - objHeight)
            objects.append(
                {
                    'x': x,
                    'y': y,
                    'width': objWidth,
                    'height': objHeight,
                    'confidence': gen.random(),
                }
            )
        return objects

    @staticmethod
    def GetDocumentation() -> str:
        """
        Returns a short documentation for your ObjectDetector class.

        :return: A documentation string.
        """
        return (
            'This is an example object detector that detects a parameterized number of objects at '
            'random positions.'
        )

    @staticmethod
    def GetId() -> str:
        """
        The identifier of the object detector which is used to create the detector via the
        multimedia api.

        :return: Identifier of the object detector.
        """
        return 'ExampleObjectDetector'

    def GetAvailableParameters(self) -> list[dict[str, Any]]:
        """
        Returns a list of all configureable parameters. Each parameter must be described by a unique
        name and a default value. A short description is optional.

        :return: List of all available paramters
        """
        return [
            {
                'name': 'objects',
                'default': 10,
                'description': 'Number of objects to detect',
            }
        ]

    def GetParameter(self, name: str) -> Any:
        """
        Get the current value of a given parameter.

        :param name: Name of the parameter. Available parameters can be queried via
                     GetAvailableParameters() method.
        :return: Value of the given parameter.
        """
        return self._params.get(name, None)

    def SetParameter(self, name: str, value: Any) -> None:
        """
        Set a new value to the given parameter.

        :param name: Name of the parameter. Available parameters can be queried via
                     GetAvailableParameters() method.
        :param value: The new value of the given parameter.
        """
        self._params[name] = value