Open Source im professionellen Einsatz
Linux-Magazin 03/2017
© Ivan Smuk, 123RF

© Ivan Smuk, 123RF

Amazon Web Services einrichten – Teil 2

Schlussspurt in die Cloud

Auf Amazons Lambda-Service laufen selbst geschriebene Python-Skripte in Containerumgebungen – demonstriert im Snapshot am Beispiel eines AI-Programms zur Bewegungsanalyse in Überwachungsvideos.

861

Nach ersten Gehversuchen im Linux-Magazin 02/16 zum Einrichten eines AWS-Accounts, eines S3-Storage mit statischem Webserver sowie der ersten Lambda-Funktion folgt heute das Setup eines API-Servers auf Amazon zum Aufstöbern von interessanten Szenen in Videos einer Überwachungskamera.

Die per Webaufruf vom Browser oder von einem Kommandozeilentool wie »curl« getriggerte Lambda-Funktion holt dabei ein Video vom Netz, jagt es durch einen mittels Open-CV-Library implementierten AI-Algorithmus (Artificial Intelligence), erzeugt ein Bewegungsprofil und gibt die URL eines als Jpeg generierten Kontaktabzugs mit den wichtigsten Videobewegungen zurück (Abbildungen 1 und 2).

Abbildung 1: Das AI-Programm zur Bewegungsanalyse läuft auf einem Amazon-Server hinter einem REST-API.
Abbildung 2: Der auf AWS erzeugte Kontaktabzug zeigt die Sekunden im Überwachungsvideo, in denen sich tatsächlich etwas bewegt hat.

Sandkastenspiele

Im Gegensatz zu Amazons EC2-Instanzen mit ihren vollblütigen (wenngleich nur virtuellen) Linux-Servern bietet der Lambda-Service [2] nur eine containerisierte Umgebung. In ihr laufen Node-JS-, Python- oder Java-Programme in einem Sandkasten, den Amazon nach Belieben zwischen echten Servern herumschubst oder bei Inaktivität ganz wegputzt, um ihn beim nächsten Zugriff wieder hervorzuzaubern. Daten auf der virtuellen Platte des Containers liegen zu lassen und zu hoffen, sie beim nächsten Aufruf vorzufinden, ergäbe also eine instabile Applikation. Stattdessen kommunizieren Lambda-Funktionen mit AWS-Angeboten wie dem S3-Storage oder der Dynamo-Datenbank, um Daten zu sichern, und agieren ansonsten "stateless".

Was eine Applikation nicht in einem Python-Skript beschreiben kann, darf der Entwickler auch als Zip-Datei in den, so munkelt man, auf Centos basierten Container hochladen (Abbildung 3).

Abbildung 3: Hochladen der Zip-Datei auf den Lambda-Server über einen Amazon-S3-Bucket.

Eine Lambda-Funktion, die wie im Beispiel Artificial-Intelligence-Funktionen aus der Open-CV-Library nutzt, muss die nötigen Binaries oder Libraries vorher in einer dem Lambda-Container ähnlichen Unix-Umgebung kompilieren, verpacken, hochladen und später zur Laufzeit aus dem Python-Skript aufrufen. Dabei kommen vorhandene Python-Bindings zu Shared Libraries zum Einsatz oder das Python-Skript ruft vorkompilierte Binaries als externen Prozess auf.

Rank und schlank

Damit das AI-Programm aus [3] nach der Installation in der Amazon-Cloud nicht zu viel Rechenzeit und nach dem Überschreiten des kostenlosen Kontingents "Free Tier" auch Geld verbrät, sucht der Code in der gegenüber der vorigen Ausgabe verbesserten Version in Listing 1 nicht mehr in jedem Frame, also 50-mal pro Sekunde, nach Bewegungen, sondern hüpft in Zeile 99 in Schritten von einer halben Sekunde durch den Film. Nach einem Frame mit Bewegung springt Zeile 96 gar 2 Sekunden vorwärts. Im Gegensatz zu »vid.read()« dekodiert das in Zeile 50 aufgerufene »vid.grab()« nicht mehr aufwändig, sondern wirft ihn weg, um zum nächsten zu gelangen.

Listing 1

max-movement-lk.cpp

001 #include "opencv2/opencv.hpp"
002 #include <stdio.h>
003
004 using namespace std;
005 using namespace cv;
006
007 const int MAX_FEATURES = 500;
008 const int MAX_MOVEMENT = 100;
009
010 int move_test(Mat& oframe, Mat& frame) {
011     // Select features for optical flow
012   vector<Point2f> ofeatures;
013   goodFeaturesToTrack(oframe,
014     ofeatures, MAX_FEATURES, 0.1, 0.2 );
015
016     // Parameters for LK
017   vector<Point2f> new_features;
018   vector<uchar> status;
019   vector<float> err;
020   TermCriteria criteria(TermCriteria::COUNT
021       | TermCriteria::EPS, 20, 0.03);
022   Size window(10,10);
023   int max_level   = 3;
024   int flags       = 0;
025   double min_eigT = 0.004;
026
027     // Lucas-Kanade method
028   calcOpticalFlowPyrLK(oframe, frame,
029     ofeatures, new_features, status, err,
030     window, max_level, criteria, flags,
031     min_eigT );
032
033   double max_move = 0;
034   double movement = 0;
035   for(int i=0; i<ofeatures.size(); i++) {
036     Point pointA
037       (ofeatures[i].x, ofeatures[i].y);
038     Point pointB
039       (new_features[i].x, new_features[i].y);
040
041     movement = norm(pointA-pointB);
042     if(movement > max_move)
043         max_move = movement;
044   }
045   return max_move > MAX_MOVEMENT;
046 }
047
048 int frames_skip( VideoCapture vid, int n, int *i ) {
049     for( int c = 0; c < n; c++ ) {
050       if (!vid.grab())
051         break;
052       (*i)++;
053     }
054 }
055
056 int main(int argc, char *argv[]) {
057   int i = 0;
058   Mat frame;
059   Mat cframe;
060   Mat oframe;
061
062   if (argc != 2) {
063     cout << "USAGE: <cmd> <file_in>\n";
064     return -1;
065   }
066
067   VideoCapture vid(argv[1]);
068   if (!vid.isOpened()) {
069     cout << "Video corrupt\n";
070     return -1;
071   }
072
073   int fps = (int)vid.get(CV_CAP_PROP_FPS);
074
075   i++;
076   if(!vid.read(oframe)) return 1;
077
078   cvtColor(oframe, oframe, COLOR_BGR2GRAY);
079
080   while (1) {
081     if (!vid.read(frame))
082       break;
083     i++;
084
085     int movie_second = i / fps;
086
087     cframe = frame.clone();
088     cvtColor(frame,frame,COLOR_BGR2GRAY);
089     if(move_test(oframe, frame)) {
090       cout << movie_second << "\n";
091
092      char filename[80];
093      sprintf( filename, "%04d.jpg", i/fps );
094      imwrite( filename, cframe );
095
096       frames_skip( vid, 2*fps, &i );
097     } else {
098         // fast-forward to next 1/2 sec
099       frames_skip( vid, fps/2, &i );
100     }
101
102     oframe = frame;
103   }
104
105   return 0;
106 }

Und während die erste Version in [3] nur die Sekundenwerte im Video in die Ausgabe schrieb, an denen der Algorithmus Bewegungen erkannte, um nachfolgend über Tausendsassa Mplayer die zugehörigen Frames als Jpeg-Dateien zu extrahieren, schreiben die Zeilen 92 bis 94 erkannte Frames gleich mittels der Open CV beiliegenden Bildverarbeitungsfunktionen »imwrite()« im Format »0001.jpg« auf die virtuelle Festplatte. Ein zweiter Durchlauf sowie die Frickelei zur Installation von Mplayer in den Lambda-Container entfallen somit.

Aus diesen Jpeg-Bildern macht dann ein weiteres Python-Skript, »mk-montage.py« , unter Zuhilfenahme der Imagemagick-Library einen Kontaktabzug, ebenfalls im Jpeg-Format. Diese Datei legt das Lambda-Programm in Amazons S3-Cloud-Speicher ab und schickt dann einen Link darauf an den aufrufenden Client zurück.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 5 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Snapshot

    Laufen Applikationen in einem Cloudsystem wie den Amazon Web Services, spart sich der Betreiber die Verwaltung und kann sich stattdessen auf das Wesentliche der App konzentrieren. Mike Schilli führt im ersten Teil des Workshops die grundlegende Einrichtung des Webservice aus.

  • Online-Artikel: Funktionale Programmierung in Python

    Python gilt vielen als objektorientierte Sprache, doch unterstützt es auch andere Paradigmen. Rainer Grimm demonstriert in seinem kostenlosen Online-Artikel das funktionale Programmieren in Python.

  • Perl-Snapshot

    Statt auf langweilige Überwachungsvideos zu starren, auf denen zu 90 Prozent nichts passiert, setzt Perlmeister Michael Schilli lieber die Bilderkennungssoftware Open CV ein, die automatisch den Handlungsablauf an den interessantesten Stellen extrahiert.

  • Funktionale Programmierung (2): Python funktional

    Die meisten Entwickler verbinden Python mit dem objektorientierten Programmierstil. Doch die Sprache beschreitet vermehrt auch die Pfade der funktionalen Programmierung. Dieser Artikel zeigt, was Python in Sachen Closures, List Comprehension und Funktionen höherer Ordnung zu bieten hat.

  • C++11

    Lambda-Funktionen sind die praktischen Helfer der Sprache C++11. Schon nach kurzer Zeit möchte kein C++-Entwickler sie missen, denn mit ihnen ist ein Algorithmus rasch und ohne Umschweife formuliert. Außerdem darf er sie wie Objekte behandeln.

comments powered by Disqus

Ausgabe 04/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.