Gabi und Sascha
Kategorien : Alle | Berlin | Bücher | Fotografie | Java | Linkhalde | Weichware | Verfassung

Ich habe ein kleines Programm geschrieben, um CSV Dateien mit SQL Befehlen von der Kommenadozeile ad-hoc zu untersuchen: sql4csv. Ziel war es ein Query wie das folgende von der Bash Kommandozeile ab zu setzen:


    > scq select distinct author from books.csv

Das Ergebnis wird dann wieder in Form einer CSV Datei ausgegeben:


    author  
    Douglas Adams  
    Terry Pratchet

Bei der Entwicklung habe ich Wert auf einfache Verwendung gelegt. So soll es nicht nötig sein die Werttypen (integer, numeric oder Datumsangaben) der Spalten vor der Benutzung. Vielmehr soll dies das Tools möglichst selbst erkennen und die Spaltentypen entsprechend anpassen. Damit sollen auch Abfragen wie


    > scq select ABC from xyz.csv where VALUE < 10

möglich sind.

Für integer und numeric Typen ist das auch ohne grosse Probleme möglich. Kniffelig ist es bei Datums- und Zeitabgaben. Hier gibt es zig unterschiedliche Formate. Deswegen habe ich mich für einen pragmatischen Weg der Umsetzung entschieden: es werden aktuell die drei für mich wichtigsten Datumsformate für den Gregorianischen Kalender unterstützt :-)

Datums- und Zeitformate

  • Y - steht für das Jahr. Jahre werden immer vierstellig angegeben
  • M - steht für den Monat
  • D - steht für den Tag im Monat
  • h - steht für Stunden
  • m - steht für Minuten
  • s - steht für Sekunden

Datumsangaben

YYYY-MM-TT

ISO 8601 ähnlich.

Unterstützt wird auch eine sogenannte lazy Schreibweise, bei der auf einen führende Null (0) bei Zahlen unter 10 verzichtet werden kann. Dies bedeutet, dass auch ein Datum 2016-9-6 als 6. September 2016 erkannt wird.

MM/DD/YYYY

Amerikanische Datumsschreibweise.

Wie bei der ISO 8601 Schreibweise wird auch hier eine lazy Schreibweise ohne führende Null unterstützt.

DD.MM.YYYY

Entspricht der numerischen DIN 5008.

Wie bei der ISO 8601 Schreibweise wird auch hier eine lazy Schreibweise ohne führende Null unterstützt.

Zeitangaben

Zeiten werden immer mit einem Doppelpunkt getrennt. Dabei unterstützt sql4csv nur die Reihenfolge hh:mm:ss. Dieses Format allerdings auch lazy, also ohne führende Null und die Sekunde kann ebenfalls weggelassen werden. In diesem Fall wird die Sekunde intern auf Null gesetzt..

Zeitstempel

Zeitstempel sind eine Kombination aus Datum und Zeit. sql4csv erlaubt alle Kombinationen von Datums- und Zeitangaben. Dabei kann als Separator das ISO 8601 T verwendet werden oder ein Leerzeichen.

Beispiele

  • 2016-7-3 1:16
  • 8/30/1969T23:5:07
  • 11.11.2011 11:11:11

Implementierung

sql4csv wurde in Java 8 implementiert. Ich habe es auch geschrieben, um die neuen Sprachfeatures von Java 8 in der Praxis zu lernen und anzuwenden. So kommen intensiv Lambdas zum Einsatz und auch Methodenreferenzen. Die gesamte Datums- und Zeitbearbeitung basiert auf dem java.time API.

Als Datenbank verwende ich Derby als in-memory Datenbank. Ich verwende nicht SQLite - wie dies einige andere Implementierungen für ein solches Tool tun - da dies entweder eine vorhandene Installation von SQLite voraussetzt oder ich die Binaries für die unterschiedlichsten Plattformen mitliefern müsste. Das ist zu kompliziert und wird der Einfachheit des Werkzeuges nicht gerecht.

Probleme

SQL Queries und die Bash als Kommandozeileninterpreter vertragen sich nur mässig miteinander. Beispielsweise interpretiert die Bash das Asterisk Zeichen (*) anders als in SQL vorgesehen. Und diese Interpretation kann auch nicht einfach ausgeschaltet werden. Ein Query wie


    > scq select * from books.csv where author = 'Douglas Adams '

ist nicht möglich. Die Bash ersetzt das * Zeichen durch die Dateinamen des aktuellen Verzeichnisses. Als Abhilfe kann das Hilfstool scq-cols verwendet werden:


    > scq select $(scq-cols books.csv) from books.csv where author = 'Douglas Adams'

Das ist nicht schön, aber eine pragmatische Lösung. Nach einigen malen benutzen hatte ich mich daran gewöhnt.

Ebenso müssen runde Klammern (z.B. für Gruppierungen) und spitze Klammern <> für grösser und kleiner Vergleiche durch eine Backslash (\) maskiert werden. Insgesamt kann durch diese Einschränkungen die Lesbarkeit des Queries beeinträchtigt werden.

Download und Installation

Im sql4csv Repository auf Github findet ihr eine Download und Installationsanleitung, um das Tools selbst einmal ausprobieren zu können.

Gerade schlug mir Netbeans vor das folgende Codeschnipsel in einen Lambda Ausdruck umzuwandeln.


    private final Map originalToReplacement = new TreeMap<>(new Comparator<String>() {
        @Override
        public int compare(final String s1, final String s2) {
            return s1.length() - s2.length();
        }
    });

Das Ergebnis würde so aussehen:

    private final Map originalToReplacement =
            new TreeMap<>((String s1, String s2) -> s1.length() - s2.length());

Keine Frage, die Lambdaschreibweise ist wesentlich kürzer. Allerdings finde ich sie auch noch nicht so verständlich wie die lange Version. Fürs Erste habe ich mich entscheiden in diesem Fall keinen Lambda Ausdruck zu verwenden.

["ANDROID GBC BALL COUNTER LOGO - BÄLLE (FUSSBALL, BASKELBALL) IN EINEM SIGMA ZEICHEN.] In the last few weeks I had developed an Android based counter for Lego® Great Ball Contraption systems. The counter should measure contactless the throughput of passing balls.

The hypothesis was: a colored or white Lego ball moves in front of a black background. The Android system camera captures every X milliseconds an image. The first image is captured with no passing ball and the image data is stored in memory for comparison. Every following image is checked for color changed against the first image. If the amount of pixels with a changed color (against the background from the first image) reached a percentage threshold, the ball count will be increased by one. Because of the camera sensor noise the color change value must also reach a threshold to be measured. In the implementation these two parameters can be configured. This improves the detection rate depending on the light environment of the GBC setup.

Measure the color change also reduces false positive ball counts because of environment light changes.

Nevertheless, Lego® also offers not only colored balls but also black and white only balls (footballs/soccer balls). If the user has also black and white balls he can also switch on a brightness detection based on the luminance. This follows the same rules like the color change detection but has a different threshold configuration parameter. Usage of the brightness detection might increase the false positive rate.

After a ball detection

After the systems has detected a passing ball in front of the camera, the system stops analyzing the given images for an amount of time. Otherwise it might happen that the same ball is counted twice.

The delay is depending on the layout of the GBC system and for this the delay time is also configurable.

Two good parameters are:

Capture delay
Delay between two image captures of the camera.
Value: 30ms
Capture delay after detection
The delay of time between the detection of a ball in an image and the next time checking again for a passing ball.
Value: 150ms

This allows a theoretical throughput of 5 Lego balls per second. Note: GBC is defined with 1 Lego ball per second. But as you know we ignore the standard in our constructions. Because of this the Android GBC Ball Counter implementation contains also a balls per second calculation.

Limitation

[SCREENSHOT ANDROID GBC BALL COUNTER] If two balls are passing very close succession there are false negative counts. This means, the two balls are counted as one ball. This is the greatest limitation of this non-contact method. The problem can be limited only by structural measures on GBC system.

Implementation

Image format

I use the YUV 4:2:0 8 bit image format delivered by the Camera2 Android API. This API was introduced with Android 5.0 (Lollipop).

The YUV image format has some advantages over the JPEG format: it doesn't pipe the image data through the RGB calculation and compression routines which takes a lot of time and other resources and doesn't produce more important information.

Android 5.0 Bug

Due to a bug in Android 5.0 the YUV subsystem doesn't deliver correct UV (chrominance) information. only the first 600+ bytes contains color information. The rest of the bytes are always zero. Only the Y (luminance) values are correct. This means: for Android 5.0 the implementation only supports the brightness ball passing detection algorithm.

More information

The implementation of the GBC is open source under the terms of the GNU General Public License 3 and the source code is available on Github. There you can dive deeper into the ball detection strategy.

How it works in practice

Ich habe heute Android 6.0 (Marshmallow) auf meinem Motorola Moto G (2. Generation) installiert. Hauptsächlich wegen eines Bugfixes im YUV_420_888 Image capturing. Das Camera2 API liefert bei Android 5.0 (Lollipop) keine korrekte Farbinformation (siehe auch hier). Diese Farbinformation benötigt ich aber, um den Lego® GBC Ball Counter weiter zu optimieren.

Bei der Installation hatte ich angegeben, dass die SD-Card als interner Speicher verwendet werden soll. Dadurch werden Daten beispielsweise nicht im Speicher des Smartphone gespeichert, sondern auf der Speicherkarte selbst. Vorteil: der interne Speicher des Gerätes wird weniger belastet. Nachteil: mit dem Android Device Monitor aus dem Android Studio kann ich nicht mehr direkt auf das Verzeichnis "/storage/emulated/0/Android/data/de.speexx.lego.gbc.ballcounter/files" zugreifen. Damit kann ich nicht einfach die Beispielbilder, die ich gespeichert habe, herunter laden.

Android 6.0 kann die Daten trotzdem erreichen und kopieren. Dazu muss ich die Einstellungen öffnen. Und dort dann über

Speicher & USB → SD‑Karte von SanDisk* → Erkunden → Android → data → de.speexx.lego.gbc.ballcounter

navigieren. Im Unterverzeichnis files liegen dann die erzeugten *.yuv Dateien.

Da Android mit der Endung yuv nichts anfangen kann, können die Dateien auch nicht geöffnet werden. Allerdings können sie mit einem längeren berühren des Namens ausgewählt werden, auch mehrere Dateien. Die so ausgewählten Dateien können dann geteilt werden. Ich habe die Dateien in Google Drive geteilt und dann von dort wieder herunter geladen.

Ziemlich komplizierte Prozedur und sicherlich nicht für die regelmässige Anwendung geeignet.

Gute Nachricht

Die Chrominanzwerte U und V sind jetzt vorhanden und auch die Strides Angaben machen jetzt Sinn: jeweils 4 Luminanzwerte mit einem U und einem V Wert.

Todo

In den nächsten Tagen werden ich den GBC Ball Counter aufwärtskompatibel anpassen.


* Name SanDisk kann eventuell abweichen.