[PYTHON] LINE-Benachrichtigung durch Echtzeit-Videoerkennung mit DeepStream SDK

LINE-Benachrichtigung durch Hochgeschwindigkeits-Videoerkennung mit DeepStream SDK

Dieser Artikel ist der 7. Tag des Docomo Dovent-Kalenders 2019.

Mein Name ist Sakai von der NTT Docomo Service Innovation Department. In meiner Arbeit arbeite ich an der Forschung und Entwicklung einer Bilderkennungs-Engine mit Deep Learning und mache sie zu einem Service. Dieses Mal habe ich das Videoerkennungs-Beschleunigungstool "DeepStream SDK" mit GPU verwendet, um Autos aus Videos mit hoher Geschwindigkeit zu erkennen und LINE über die Ergebnisse zu informieren. Es fühlt sich so an, als könnten Sie so etwas wie eine KI-Kamera herstellen und damit Personen mit einer Überwachungskamera erkennen oder illegales Parken anhand von Kamerabildern erkennen.

動画gif

Ich habe auch das Messaging mit dem DeepStream SDK und AMQP in Frage gestellt, was ich im Web nicht in vielen Fällen finden konnte.

workflow.jpg

Motivation

In den letzten Jahren, als der Einsatz von Deep Learning in der Bilderkennungstechnologie zugenommen hat, ist die Bilderkennung von Videodaten allmählich populärer geworden. Die Videoerkennung mit Deep Learning erfordert jedoch mehr Maschinenspezifikationen als die normale Bilderkennung, und die Verarbeitungszeit ist tendenziell langsamer.

Wenn Sie in einem solchen Fall das [DeepSTtream SDK] von NVIDIA (https://developer.nvidia.com/deepstream-sdk) verwenden, können Sie die Videoerkennung und die Videoverarbeitung mithilfe der GPU beschleunigen. Jetzt, da es mit Docker verwendet werden kann, ist die Installation einfacher geworden, also habe ich es versucht.

DeepStream SDK

In Deep Learning Inference (+ Lernen) wird die GPU häufig zur Beschleunigung verwendet. DeepStream SDK ist ein SDK für die Hochgeschwindigkeits-Videoverarbeitung mit GPU. Verschiedene für die Videoverarbeitung erforderliche Funktionen werden in Form von Gstreamer-Plug-Ins bereitgestellt, die bei der Stream-Verarbeitung üblich sind.

Methode

Umgebung

Wir haben einen GPU-Server vorbereitet, der [NVIDIA Docker 2.0] verwenden kann (https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0)).

gpu war native support im Docker, aber Docker-Compose scheint die GPU nicht angeben zu können. , Übernahm die alte Laufzeitausdrucksspezifikationsmethode.

Dateiorganisation

deepstream-line
├── docker
│   ├── Dockerfile
│   ├── requirements.txt
│   └── src
│       └── receive.py
├── docker-compose-amqp.yml
├── docker-compose.yml
├── rabbitmq
├   ├── custom_definitions.json
├   └── rabbitmq.conf
└── videos
    └── test.h264

Videodaten können von der kostenlosen Videomaterial-Website Mixkit abgerufen werden. Ich benutze Chinatown Street bei Nacht.

Da es notwendig ist, einen h264-Stream zu erstellen, konvertieren Sie ihn mit ffmpeg.

ffmpeg -i ./2012-1080.mp4  -vcodec copy -an -bsf:v h264_mp4toannexb videos/test.h264

Starten Sie den AMQP-Server

Das DeepStream SDK kann das Erkennungsergebnis als Nachricht an Kafka, MQTT, AMQP usw. senden. Dieses Mal habe ich beschlossen, RabbitMQ mit Docker zu starten. RabbitMQ ist ein Messaging-Dienst vom Typ Pub / Sub, der aus den folgenden Elementen besteht.

rabbitmq.jpg

--producer: Der Absender der Nachricht. Dieses Mal ist das DeepStream SDK das Richtige --exchange: Ordnen Sie die gesendete Nachricht einer entsprechenden Warteschlange zu --queue: Warteschlange --consumer: Verwenden Sie die Nachricht, indem Sie in die Warteschlange gehen. Diesmal ein Python-Skript, das eine Benachrichtigung an LINE sendet

Bereiten Sie die AMQP-Konfigurationsdatei vor. Sowohl der Benutzer als auch das Passwort sind Gast.

rabbitmq/custom_definitions.json


{
    "rabbit_version": "3.8.0",
    "users": [{
        "name": "guest",
        "password_hash": "CV/8dVC+gRd5cY08tFu4h/7YlGWEdE5lJo4sn4CfbCoRz8ez",
        "hashing_algorithm": "rabbit_password_hashing_sha256",
        "tags": "administrator"
    }],
    "vhosts": [{
        "name": "/"
    }],
    "permissions": [{
        "user": "guest",
        "vhost": "/",
        "configure": ".*",
        "write": ".*",
        "read": ".*"
    }],
    "topic_permissions": [],
    "parameters": [],
    "global_parameters": [{
        "name": "cluster_name",
        "value": "rabbit@rabbitmq"
    }],
    "policies": [],
    "queues": [{
        "name": "test",
        "vhost": "/",
        "durable": true,
        "auto_delete": false,
        "arguments": {
            "x-queue-type": "classic"
        }
    }],
    "exchanges": [],
    "bindings": [{
        "source": "amq.topic",
        "vhost": "/",
        "destination": "test",
        "destination_type": "queue",
        "routing_key": "deepstream",
        "arguments": {}
    }]
}

In Warteschlangen wird der Name der Warteschlange zum Testen festgelegt. Darüber hinaus verwendet Exchange amq.topic, das standardmäßig festgelegt ist. Wenn eine Nachricht mit dem Thema "Deepstream" in Bindungen eingeht, wird sie an die Testwarteschlange weitergeleitet.

Bereiten Sie auch eine conf-Datei vor, um den json zu lesen.

rabbitmq/rabbitmq.conf


loopback_users.guest = false
listeners.tcp.default = 5672
management.tcp.port = 15672
management.load_definitions = /etc/rabbitmq/custom_definitions.json

Jetzt können Sie Nachrichten an Port 15672 austauschen, während Sie den JSON laden.

Starten Sie RabbitMQ mit Docker-Compose. Verwenden Sie beim Abrufen des offiziellen Basis-Images von RabbitMQ die Volume-Option, um das conf / json so bereitzustellen, dass es aus dem Container heraus sichtbar ist.

docker-compose-amqp.yml


version: "2.3"
services:
  rabbitmq:
    image: rabbitmq:3.8-management
    hostname: rabbitmq
    container_name: rabbitmq
    expose: #Veröffentlichen für andere Container
      - "5672"
      - "15672"
    ports: #
      - "5672:5672"
      - "15672:15672"
    volumes:
      - ./rabbitmq:/etc/rabbitmq
networks:
  default:

Durch Definieren eines Netzwerks ist es auch möglich, später eine Verbindung über das DeepStream SDK oder den Consumer-Container herzustellen. Beginnen Sie mit dem folgenden Befehl.

docker-compose -f docker-compose-amqp.yml up -d

Vorbereiten des DeepStream SDK

Für das DeepStream SDK verwenden wir das offizielle Image von NVIDIA GPU CLOUD.

使うイメージはnvcr.io/nvidia/deepstream:4.0.1-19.09-samplesです。

Ziehen Sie es im Voraus.

docker pull nvcr.io/nvidia/deepstream:4.0.1-19.09-samples

Dieses Bild enthält alles, was Sie benötigen, einschließlich des kompilierten DeepStream SDK, Samples, TensorRT und Gstreamer. Dieses Mal verwenden wir DeepStream Test 4 in den Beispiel-Apps, die in diesem Docker-Image enthalten sind. Dies ist eine Anwendung, die Autos / Personen erkennen und erkennen und dann alle 30 Frames das Erkennungsergebnis als Nachricht senden kann.

Directory: /sources/apps/sample_apps/deepstream-test4 Description: This builds on top of the deepstream-test1 sample for single H.264 stream - filesrc, decode, nvstreammux, nvinfer, nvosd, renderer to demonstrate the use of "nvmsgconv" and "nvmsgbroker" plugins in the pipeline for IOT connection. For test4, user have to modify kafka broker connection string for successful connection. Need to setup analytics server docker before running test4. The DeepStream Analytics Documentation has more information on setting up analytics servers.

Sie können die README-Datei und die Verwendung mit den folgenden Befehlen überprüfen.

docker run --gpus 0 --rm -it \
    nvcr.io/nvidia/deepstream:4.0.1-19.09-samples \
    cat /root/deepstream_sdk_v4.0.1_x86_64/sources/apps/sample_apps/deepstream-test4/README
#READ ME wird angezeigt
docker run --gpus 0 --rm -it \
    nvcr.io/nvidia/deepstream:4.0.1-19.09-samples \
    /opt/nvidia/deepstream/deepstream-4.0/bin/deepstream-test4-app
# /opt/nvidia/deepstream/deepstream-4.0/bin/deepstream-test4-app \
# -i <H264 filename> -p <Proto adaptor library> --conn-str=<Connection string

Laut README können Sie AMQP verwenden, indem Sie die Optionen "--proto-lib", "--conn-str", "--topic" festlegen.

1.Use --proto-lib or -p command line option to set the path of adaptor library. Adaptor library can be found at /opt/nvidia/deepstream/deepstream-/lib

kafka lib - libnvds_kafka_proto.so azure device client - libnvds_azure_proto.so AMQP lib - libnvds_amqp_proto.so

2.Use --conn-str command line option as required to set connection to >backend server. For Azure - Full Azure connection string For Kafka - Connection string of format: host;port;topic For Amqp - Connection string of format: host;port;username. Password to be provided in cfg_amqp.txt

3.Use --topic or -t command line option to provide message topic (optional). Kafka message adaptor also has the topic param embedded within the connection string format In that case, "topic" from command line should match the topic within connection string

In [AMQP-Server starten](#AMQP Server Start) ist der Host rabbitmq, der Port 15672 und der Benutzer der Gast. Daher sollte -c rabbitmq; 5672; Gastthema deepstream -c cfg_amqp.txt sein. Es wird sein.

"Libnvds_amqp_proto.so" wird in "/ opt / nvidia / deepstream / deepstream-4.0 / lib / libnvds_amqp_proto.so" im Docker-Image gespeichert.

Verbrauchervorbereitung

Bereiten Sie einen Container vor, um Nachrichten vom AMQP-Server abzurufen und Benachrichtigungen an LINE zu senden. Verwenden Sie LINE Notify, um Benachrichtigungen an LINE zu senden. Dies bedeutet, dass Sie beim Verknüpfen mit einem Webdienst eine Benachrichtigung vom offiziellen Konto "LINE Notify" erhalten, das von LINE bereitgestellt wird. Schreiben Sie das Äquivalent dieses "Webdienstes" in Python. Sie können eine Benachrichtigung senden, indem Sie ein dediziertes TOKEN erwerben und eine Nachricht an eine bestimmte URL senden, während Sie sich mit TOKEN authentifizieren. Dieses Mal habe ich TOKEN erhalten, indem ich auf [diesen Artikel] verwiesen habe (https://qiita.com/aoyahashizume/items/13848b013daa18f6461b). Das erworbene TOKEN wird in [Execute](# Execution) verwendet. Notieren Sie es sich also irgendwo.

docker/src/receive.py


import pika
import json
import requests
import os

LINE_URL = "https://notify-api.line.me/api/notify"
line_token = os.environ['LINE_TOKEN'] #Bringen Sie TOKEN aus Umgebungsvariablen
message_format = '''
Tageszeiten: {time:s}
Ort: {place:s}
Kamera: {camera:s}
Erkanntes Objekt: {object:s}
'''


def main():
    #Stellen Sie eine Verbindung zu mqtt her
    credentials = pika.PlainCredentials('guest', 'guest')
    connect_param = pika.ConnectionParameters(
        host='rabbitmq',  #docker-compsoe-Hostname für Container mit amqp
        credentials=credentials
    )
    connection = pika.BlockingConnection(connect_param)
    channel = connection.channel()

    #Token für die Leitungsauthentifizierung
    line_headers = {"Authorization": "Bearer {}".format(line_token)}

    for method_frame, properties, body in channel.consume(
        'test',
        inactivity_timeout=30  #Unterbrechen Sie, wenn 30 Sekunden lang keine neue Nachricht angezeigt wird
    ):
        if method_frame is None:
            break

        message = json.loads(body)
        if 'vehicle' in message['object'].keys():
            obj_data = '{} {} {}'.format(
                message['object']['vehicle']['make'],
                message['object']['vehicle']['model'],
                message['object']['vehicle']['color'],
            )
        elif 'person' in message['object'].keys():
            obj_data = 'Person {} {}'.format(
                message['object']['person']['age'],
                message['object']['person']['gender']
            )
        else:
            obj_data = ''
        payload = {
            "message": message_format.format(
                time=message['@timestamp'],
                place='{}_{}({})'.format(
                    message['place']['id'],
                    message['place']['name'],
                    message['place']['type'],
                ),
                camera=message['sensor']['id'],
                object=obj_data,
            )
        }
        r = requests.post(
            LINE_URL,
            headers=line_headers,
            params=payload
        )
        channel.basic_ack(method_frame.delivery_tag)

    #Brechen Sie den Verbraucher ab und kehren Sie zurück, wenn eine Nachricht aussteht
    requeued_messages = channel.cancel()
    print('Requeued %i messages' % requeued_messages)
    connection.close()


if __name__ == '__main__':
    main()

Bei payload = verarbeiten wir die vom DeepStream SDK über AMQP gesendete Nachricht. Nachrichten von DeepStream Test 4 werden alle 30 Frames im JSON-Format gesendet (DeepStream Test 4). Die Nachricht enthält Informationen zu einem der erkannten Objekte im folgenden Format: Wir haben uns entschlossen, die an Ort und Stelle gespeicherten Informationen zum Aufnahmeort, die in der Kamera gespeicherten Kamerainformationen, die Uhrzeit und die Objektinformationen abzurufen.

{
    "messageid": "a8c57c62-5e25-478d-a909-3ab064cbf11f",
    "mdsversion": "1.0",
    "@timestamp": "2019-11-17T13:42:39.807Z",
    "place": {
        "id": "1",
        "name": "XYZ",
        "type": "garage",
        "location": {
            "lat": 30.32,
            "lon": -40.55,
            "alt": 100.0
        },
        "aisle": {
            "id": "walsh",
            "name": "lane1",
            "level": "P2",
            "coordinate": {
                "x": 1.0,
                "y": 2.0,
                "z": 3.0
            }
        }
    },
    "sensor": {
        "id": "CAMERA_ID",
        "type": "Camera",
        "description": "\"Entrance of Garage Right Lane\"",
        "location": {
            "lat": 45.293701447,
            "lon": -75.8303914499,
            "alt": 48.1557479338
        },
        "coordinate": {
            "x": 5.2,
            "y": 10.1,
            "z": 11.2
        }
    },
    "analyticsModule": {
        "id": "XYZ",
        "description": "\"Vehicle Detection and License Plate Recognition\"",
        "source": "OpenALR",
        "version": "1.0",
        "confidence": 0.0
    },
    "object": {
        "id": "-1",
        "speed": 0.0,
        "direction": 0.0,
        "orientation": 0.0,
        "vehicle": {
            "type": "sedan",
            "make": "Bugatti",
            "model": "M",
            "color": "blue",
            "licenseState": "CA",
            "license": "XX1234",
            "confidence": 0.0
        },
        "bbox": {
            "topleftx": 585,
            "toplefty": 472,
            "bottomrightx": 642,
            "bottomrighty": 518
        },
        "location": {
            "lat": 0.0,
            "lon": 0.0,
            "alt": 0.0
        },
        "coordinate": {
            "x": 0.0,
            "y": 0.0,
            "z": 0.0
        }
    },
    "event": {
        "id": "4f8436ab-c611-4257-8b83-b9134c6cab0d",
        "type": "moving"
    },
    "videoPath": ""
}

Das Container-Image, das den oben genannten Consumer ausführt, wird mit Dockerfile erstellt. Nach der Installation von python3 haben wir das erforderliche Python-Paket mit pip installiert. Kopieren Sie zum Schluss den Quellcode und Sie sind fertig.

docker/Dockerfile


FROM ubuntu:18.04

RUN apt-get update \
    && apt-get install -y python3-pip python3-dev \
    && cd /usr/local/bin \
    && ln -s /usr/bin/python3 python \
    && pip3 install --upgrade pip \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

COPY requirements.txt /tmp/requirements.txt
RUN pip3 install -r /tmp/requirements.txt

COPY src /opt/src
WORKDIR /opt/src

CMD ["python3", "./receive.py"]

requirements.txt


pika
requests

Lauf

Starten Sie das DeepStream SDK und den Consumer mit Docker-Compose.

docker-compose.yml


version: "2.3"
services:
  deepstream:
    image: nvcr.io/nvidia/deepstream:4.0.1-19.09-samples
    runtime: nvidia
    hostname: deepstream
    container_name: deepstream
    command: >
      /opt/nvidia/deepstream/deepstream-4.0/bin/deepstream-test4-app
      -i /root/videos/test.h264
      -p /opt/nvidia/deepstream/deepstream-4.0/lib/libnvds_amqp_proto.so
      -c cfg_amqp.txt
      -t deepstream
      --conn-str rabbitmq;5672;guest
    cap_add:
      - SYSLOG
    working_dir: /root/deepstream_sdk_v4.0.1_x86_64/sources/apps/sample_apps/deepstream-test4
    networks:
      - deepstream-line_default
    volumes:
      - ./videos:/root/videos
      - /tmp/.X11-unix:/tmp/.X11-unix
    environment:
      - DISPLAY=$DISPLAY
  consumer:
    build: ./docker
    hostname: consumer
    container_name: consumer
    environment:
      LINE_TOKEN: "XXX"
    networks:
      - deepstream-line_default
networks:
  deepstream-line_default:
    external: true

"XXXXXXXX"Fügen Sie die erhaltene Marke in die Stelle ein. Sie erhalten jetzt Benachrichtigungen auf Ihrer LINE.



 Der Prozess wird gestartet, wenn Sie Folgendes ausführen.

```bash
xhost + #Die Anzeige der Ergebnisse kann über Docker angezeigt werden
docker-compose build #Consumer Build-Prozess
docker-compose up -d

Da dies eine Umgebung mit Anzeige voraussetzt, sind einige Änderungen [^ 2] erforderlich, um sie auf einem Server oder dergleichen auszuführen.

Ergebnis

Beim Erstellen des Dockers wird der Videoerkennungsprozess in der folgenden Form gestartet und eine Benachrichtigung an LINE gesendet.

result_all.gif

Dies ist die PC-Version von LINE. Wenn Sie jedoch ein Smartphone verwenden, erhalten Sie eine Benachrichtigung wie die folgende.

Screenshot_20191206-212712_LINE.jpg

schließlich

Wir haben vorgestellt, wie Sie mit dem DeepStream SDK eine Hochgeschwindigkeits-Videoerkennung durchführen und LINE-Benachrichtigungen senden. Diesmal habe ich einen normalen Server verwendet, aber mithilfe des Containers deepstream-l4t für Edge-GPUs wie Jetson Sie sollten in der Lage sein, dasselbe auf Ihrem Computer zu tun. Der Traum, so etwas wie eine KI-Kamera zu bauen, breitet sich aus.

Auch dieses Mal konnte ich das Erkennungsmodell meiner Wahl in der Anwendung auf der DeepStream SDK-Seite nicht verwenden oder das Format der Ausgabedaten nicht ändern. Ich würde es gerne vorstellen, wenn ich die Gelegenheit dazu habe.

Bis zum Ende Danke fürs Lesen.

[^ 1]: Eine Bibliothek zur Beschleunigung der Deep Learning-Inferenzverarbeitung auf NVIDIA-GPUs. Zuvor habe ich versucht, TensorRT 5.0 zu verwenden, Inferenz mit TensorRT 5.0.6 und JETSON NANO beschleunigen Ich schreibe Artikel wie Artikel (17434efa7ce045f767dd). [^ 2]: Wenn Sie auf einem Server ohne Anzeige ausgeführt werden, können Sie dies ausführen, indem Sie "Umgebung" aus "Deepstream" von docker-compose.yml entfernen und "Befehl" die Option "--no-display" hinzufügen. ..

Recommended Posts

LINE-Benachrichtigung durch Echtzeit-Videoerkennung mit DeepStream SDK
Gesichtserkennung in Echtzeit mit von getUserMedia [HTML5, openCV] aufgenommenem Video
Lesen Sie mit Python Zeile für Zeile aus der Datei