07 September 2010

Character Recognition

Vor gut zwei Jahren hab ich ja hier schon mal etwas zur Schrifterkennung geschrieben, das Programm cellwriter vorgestellt und einige Links rausgehauen. Mindestens seit der Zeit (aber eigentlich schon etwas länger) beschäftige ich mich hin und wieder mit dem Thema und irgendwann ist mir sogar unter der Dusche ein kleines Kriterium eingefallen, das einigermaßen dazu geeignet ist, einzelne geschriebene Zeichen (Glyphen) einem vorher trainierten Sample (und damit einem Zeichen/Character) zuzuordnen.

Genauer geht es hierbei um eine On-line Recognition und wie bei cellwriter um einzelne Zeichen, also ohne Segmentierung. Ich darf schon behaupten in den letzten Jahren viel rumprobiert zu haben: Angefangen mit einem kleinen Zeichenfeld in php-gtk, das einzelne svg-Bildchen auswarf, zwischendurch (weil es mit der Handschrift nicht so klappte) einige Tests mit Zeichen aus einem ttf, umgewandelt in bmp und svg, hier mal eine Änderung, da mal eine neue (Verbesserungs-)Idee (wieder unter der Dusche), schließlich dann mit xournal als Zeichenfläche, dessen xoj-Dateien ich in svg übersetzte, irgendwann dann mal HMMs probiert und in die Ecke geworfen, über CRM114 gestoplert, ein paar Verteilungen mit R berechnet, über SVMs nachgedacht und schließlich (wieder) bei Bayes gelandet. Gebastel, Gefrickel, ganz schlimm!

Inzwischen habe ich mir mit ruby und gtk ein kleines Programm zusammengestrickt um mein Kriterium zu testen. Für die Bayes-Klassifikation benutze ich den classifier von Lucas Carlson, meine kleine (beta, beta, beta!) Oberfläche dient sowohl zum Erstellen und Speichern der Samples als auch zur Klassifikation der eingegebenen Zeichen. Und, was soll ich sagen? Gegen eine aufwendigere Analyse (wie z.B. in cellwriter) stinkt mein kleines, allein betrachtetes Kriterium natürlich ab, aber - die richtigen Samples vorausgesetzt - kann man so schon den ein oder anderen gekritzelten Buchstaben klassifizieren.

Es geht hier ja auch nicht um eine vollständige Handschriftenerkennung sondern nur darum, meine Idee zu testen - und gegenüber den sehr sehr ernüchternden Ergebnissen von anno dazumal macht das Ding heute schon einiges her. Wie man auf dem Bild (schlecht) erkennen kann (siehe im linken Fenster ganz unten in der Statuszeile bzw. im rechten Fenster das Zeichen, das in der Liste ganz oben steht), ordnet mein Programm der geschriebenen Glyphe immerhin das richtige Zeichen (a) zu - und das bei einem Sample-Bestand von 26 Kleinbuchstaben. Die Grenzen meines Analysekriteriums sind mir auch einigermaßen klar: Ein ä wird sich damit z.B. von einem a nicht unterscheiden lassen. Für eine ordentliche Handschriftenerkennung muß man schon noch ein paar andere Kriterien bemühen. Meine (inzwischen alte) Idee ist jedenfalls erstmal umgesetzt und für mich damit wieder ein kleiner Abschnitt in Sachen "Gebastel an Handschriftenerkennung" abgeschlossen.

Labels: , , , ,

25 Mai 2010

Überwachungsstaat mit nmap und notify-send

...wie das im Netz so ist: Man sucht nach einer Lösung für ein Problem und findet nebenbei auch noch etwas anderes Interessantes. Oder, ne, ich fang mal anders an: Neulich hatte ich hier einen kleinen Netzausfall. Es lag daran, daß der Router sich nach einer Zwangstrennung nicht mehr richtig einwählen konnte, ein Softreset half. Auf der Fehlersuche pingte ich mich so durchs Netz und musste feststellen, daß ich den Laptop wohl nicht richtig runtergefahren hatte - er hing noch unbeschäftigt im Wlan rum. Da fiel mir auf, daß es doch vielleicht nicht schlecht wäre, über die Rechner im lokalen Netz ein bisschen Überblick zu behalten - aber wie das so ist, die guten Vorsätze sind schnell vergessen.

Heute stolperte ich dann (auf der Suche nach etwas völlig anderem) über einen Blogpost von Stefan Haller, der ein kleines Script geschrieben hat, um bestimmte Rechner anzupingen sich das Ergebnis dann via notify-send anzeigen zu lassen.

Ich habe die ganze Sache ein bisschen abgeändert und ein Ruby-Script geschrieben, daß nicht nur vorgegebene Rechner anpingt, sondern mit nmap (in einem bestimmten Intervall) das ganze Subnetz durchsucht. Das Script vergleicht dieses Ergebnis dann mit dem vorherigen und wenn sich etwas ändert, gibt es entsprechende Meldungen mit notify-send aus.
Jetzt bekomme ich mit, wenn ein neuer Rechner ins Netz kommt oder sich verabschiedet, vielleicht bau ich auch noch einen Knopf, der auf Anfrage das Ergebnis des letzten nmap ausgibt. Das Script funktioniert soweit, ob ich es wirklich nutze (und ob das ständige Überwachen per nmap so eine gute Idee ist) steht noch aus.

Labels: ,

08 März 2010

GPS-Skyview mit GnomeCanvas und Ruby

Um mir GnomeCanvas mal ein bisschen anzusehen und das ein oder andere auszuprobieren hab ich mal ein kleines Testprogramm zusammengebastelt, das aus den Daten von gpsd einen Skyview erstellt, wie man ihn z.B. aus xgps kennt. Für die Daten habe ich dabei das gps gem von Nolan Darilek benutzt, das leider von sich aus nur die Anzahl der zur Zeit "aktiven" Satelliten durchreicht. Ich habe die Schnittstelle, die sich die Daten von gpds via localhost:2947 holt, also etwas aufgebohrt, damit ich schließlich auf die vollständige Liste der Satelliten (incl. PRN, SNR, Elevation, Azimuth) zugreifen konnte.

In meinem kleinen Programm werden die Satelliten dann als Ellipsen dargestellt, die zur Positionsbestimmung aktiven Satelliten mit schwarzer Umrandung, die anderen mit grauer (im Bild z.B. die 28). In der Ellipse wird jeweils die PRN angezeigt, je nach SNR sind die Ellipsen rot, gelb oder grün gefüllt. "Abhanden gekommene" Satelliten werden mit ihrer letzten Position in grau dargestellt (im Bild z.B. 2 und 4). Unter dem Canvas befindet sich noch ein Label mit der aktuellen Uhrzeit und lat und lon.

Die Umrechnung von Elevation und Azimuth ins karthesische Koordinatensystem hab ich aus dem Plasmoid GPSD client von "palo" von C++ nach Ruby übersetzt, auch das kleine Satelliten-Window-Icon stammt aus diesem Programm.

Die verwendeten Programme und Codeschnipsel stehen zwar alle unter GPL, ich werde mein Resultat trotzdem nicht veröffentlichen - u.a., weil mein Script ein schrecklich unsortierter Codehaufen ist, aber es tut. Wer trotzdem Interesse an meinem kleinen Script haben sollte, darf sich aber gerne melden.

Sollte ich demnächst (hoffen wir mal auf den Frühling und nettere Temperaturen) mal wieder mit Fahrrad, Netbook und tangoGPS unterwegs sein, nehm ich mein kleines Script natürlich mit.

Labels: , , ,

13 Februar 2010

Stanford-postagger und Ruby Teil2

Sobald die Klasse PosTagger nun übersetzt ist, kann sie von Ruby aus angesprochen werden.

Hierzu brauchen wir die Ruby-Java-Bridge (Zeile 4), setzen den Classpath auf den POS-Tagger (Zeile 9) und importieren dann unsere Klasse PosTagger (Zeile 10). Danach kann man die Methode tag aus der Java-Klasse benutzen, die uns einen getagten String zurückgibt. Die private Ruby-Methode get_token dient hier dazu, diesen String zu zerlegen um als Resultat ein Array aus Wortformen und Wortarten (bzw. Penn Treebank tags) zu erhalten.
Die hier gezeigten Scriptschnipsel sind nicht schön und auch noch nicht wirklich fertig, aber vielleicht helfen sie ja der ein oder dem anderen.

Labels: , ,

Stanford-postagger und Ruby Teil1

Wie der Titel dieses Posts schon verrät geht es darum, den Stanford Log-linear Part-Of-Speech Tagger von Ruby aus anzusprechen. Genauer gesagt würde ich dem POS-Tagger gerne von Ruby aus einen Text zum taggen übergeben und brauche das Ergebnis dann als schönes Ruby-Array in dem jeder Wortform dann die entsprechende Wortart zugeordnet ist. Zuerst rief ich den POS-Tagger aus Ruby einfach via CLI auf, da der Tagger aber eine gewisse Zeit zum starten braucht, erwies sich diese Vorgehensweise zum Taggen von mehreren Texten als eher unvorteilhaft. Nun gibt es für Ruby aber die Ruby-Java-Bridge, mit der sich Javaklassen gleich in Ruby benutzen lassen. Leider braucht der stanford-tagger für deutsche Texte einige Parameter, die ich in Ruby nicht zu setzen in der Lage war. Ich habe dafür also in Java folgende kleine Klasse geschrieben, die den Tagger für deutsche Texte initialisiert und die ich dann mit Ruby ansprechen kann:

In den Zeilen 15 und 17 werden die entsprechenden Parameter gesetzt (z.B. als Modell der german.tagger mit den entsprechenden german.tagger.props). Der stanford-tagger liegt hier im Unterverzeichnis stanford-postagger, das Modell darunter in models, diese Verzeichnisse und Parameter gilt es also entsprechend anzupassen.

Labels: , ,

10 Dezember 2009

Ruby, Shapefiles und SVG

Durch den Blogpost auf dianacht.de wurde ich darauf aufmerksam, daß es bei NaturalEarth freie Shapefiles und Rasterdaten gibt, um schöne Karten zu bauen. Nun gibt es ja die Shapefile C library und auch entsprechende bindings für Ruby - was lag also näher, als sich mal so ein Shapefile zu ziehen, das mit Ruby auszulesen und daraus ein SVG zu erstellen?
Na also, nichts eigentlich.
Gesagt, getan: Da Küstenlinien recht anschaulich sind, zog ich mir die in 1:50, jagte die ausgelesenen Daten durch ein Rubyscript und erzeugte nebenbei mit SVuGy ein SVG, indem die Arcs aus dem Shapefile einfach in Polylines umgewandelt wurden. Das Resultat war ein knapp 3MB großes SVG, das Bild zeigt einen Ausschnitt mit einem Zoomfaktor von ca. 2000% und einer Liniendicke (in SVG) für die Küstenlinien (Polylines) von 0.1 (das häßliche grün kommt durch manuelles Nachcolorieren und dient nur der Anschauung) - das Ganze wurde nachträglich auf ein paar verträgliche Pixel runtergerastert.
Natürlich lassen sich mit den Daten von NaturalEarth noch viele andere schöne Dinge anstellen, hier aber erst mal nur der kleine shapelib-Test.

Labels: , , , ,

05 Dezember 2009

Ruby, GTK und TreeView

Aus aktuellem Anlaß habe ich mir mal angesehen, wie man mit Ruby und Gtk eine GUI zusammenschraubt. Ein Teil der Daten, mit denen ich arbeite, soll tabellarisch angezeigt werden, weshalb ich mich damit beschäftigt habe, wie man so eine Tabelle baut und mit Daten füttert. Als kleine Beispielanwendung hab ich mir eine Wettervorhersage geschrieben, die ihre Daten (für Trier) per RSS von yr.no bezieht. Den mit RSS::Parser.parse ausgelesenen Feed habe ich mit ein paar Datumsmethoden, Stringmethoden und regulären Ausdrücken vorverarbeitet und ins Deutsche übersetzt, diese Daten werden dann im GUI als Tabelle angezeigt.
Als Grundgerüst gibt es erst einmal ein normales Fenster mit Gtk::Window.new mit dem einzigen verbundenen Event für ein Gtk.main_quit, darin dann ein Gtk::ScrolledWindow - also alles ganz simpel und beispielhaft gehalten.
Die eigentliche Tabelle als Gtk::TreeView liegt in dem Scrollfenster und beinhaltet vier einfache Textspalten und eine, in der zusätzlich ein Icon angezeigt wird. Für die Texte nutzt man den Gtk::CellRendererText, für das Icon den Gtk::CellRendererPixbuf. Die ganze Spalte wird dann z.B. so erzeugt:

spalte = Gtk::TreeViewColumn.new # neue Spalte
spalte.title = "Wetter" # Spaltentitel setzen
renderer_pix = Gtk::CellRendererPixbuf.new # renderer für das Icon
spalte.pack_start(renderer_pix, false)
spalte.add_attribute(renderer_pix, 'pixbuf', 1) # Icon zur Spalte hinzufügen
renderer_txt = Gtk::CellRendererText.new # renderer für den Text
spalte.pack_start(renderer_txt, true)
spalte.add_attribute(renderer_txt, "text", 2) # Text zur Spalte hinzufügen
treeview.append_column(spalte) # Spalte zum treeview hinzufügen

Für unsere Daten legen wir dann einen einfachen Gtk::ListStore an, in diesem speziellen Fall mit store = Gtk::ListStore.new(String, Gdk::Pixbuf, String, String, String) für die vier Strings und das Icon. Das letzte Attribut in spalte.add_attribute (s.o.) steht dann jeweils für die Position der Daten in dem ListStore.
Die Daten werden Zeile für Zeile mit store.append und store.set_value (einfach per each) in den ListStore geschrieben und danach das Model mit dem View verbunden (treeview.model = store).
Wie man auf dem Bild erkennen kann, werden dann die Wetterdaten in den entsprechenden Zeilen und Spalten der Tabelle angezeigt. Die zweite Spalte enthält den Text aus dem Store (Index 2) und das Icon (Index 1). Die dritte und vierte Spalte sind mit set_property('xalign',1.0) (an den Renderer) jeweils rechtsbündig ausgerichtet.
Die Icons stammen aus dem schönen silk iconset von famfamfam.com.
Tutorials gibt es beim Ruby-Gnome2 Projekt: The TreeView Widget und Ruby/GTK Treeview Tutorial.

Labels: , , , ,