Dienstag, 30. Juni 2026

Umzug

 Das Blog ist seit geraumer Zeit vollständig auf meine private Domain umgezogen und unter http://andreas-romeyke.de/blog erreichbar. 

Samstag, 27. November 2021

Brandgefährliche Technik

Anbei das Steckernetzteil eines DVBSky USB S2 TV-Adapters nach dem Einstecken in eine Steckdosenleiste. Die Bilder sprechen für sich.





 

 

 

 

Das Netzteil ist angeblich CE geprüft.

Wie man in den Bildern sieht, konnte der Netzspannung führende Stift ungeschützt und direkt auf den Kühlkörper treffen.

Fehlerursache war die in der Mitte zwischen dem Stecker geführte Schraube, die in eine Plastehülse des äußeren Gehäuses führen sollte, dort aber ausgebrochen ist.

Der Stick ist vermutlich ebenfalls hinüber, glücklicherweise kam es zu keinem Brand und der PC und die Sat-Anlage wurden nicht beschädigt.

Dennoch, wie kann man so einen Murks fabrizieren? :(


Mittwoch, 13. November 2019

Improve md5 calculation -- an unexpected journey

In a project it was necessary to calculate the md5 checksums of files as fast as possible. Under Perl5 there is the module Digest::MD5.

The suggested way to use this module is not the fastest. The reason is that the method addfile() does not use the buffer optimally.

In the following I have tested all possible variants: the suggested addfile approach, the buffer optimized, the File::Map based and the system call to 'md5sum' variant:


#!/usr/bin/env perl 
# bench to check how fast is memory mapped access

use strict;
use warnings;
use utf8;
use Benchmark qw(:all) ;
use File::Map qw( map_file);
use Digest::MD5;
use File::Slurp;

sub md5offile_mapped {
    my $fn = shift;
    map_file my $data, $fn, '<';
    my $md5obj = Digest::MD5->new;
    $md5obj->add($data);
    return $md5obj->hexdigest;
}

sub md5offile_orig {
    my $fn = shift;
    my $fh;
    open($fh, '<', $fn) || die ("Can't open '$fn', $!");
    binmode($fh);
    my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
        $atime,$mtime,$ctime,$blksize,$blocks)
    = stat $fh;
    my $buffer;
    my $md5obj = Digest::MD5->new;
    while (read($fh, $buffer, $blksize)) {
        $md5obj->add($buffer);
    }
    close $fh || die ("could not close file '$fn', $!");
    return $md5obj->hexdigest;
}

sub md5offile_addfile {
    my $fn = shift;
    my $fh;
    open($fh, '<', $fn) || die ("Can't open '$fn', $!");
    binmode($fh);
    my $md5obj = Digest::MD5->new;
    $md5obj->addfile( $fh );
    close $fh || die ("could not close file '$fn', $!");
    return $md5obj->hexdigest;
}

sub md5offile_md5file {
    my $fn = shift;
    return system("md5sum $fn >/dev/null 2>&1");
}


my $file = shift @ARGV;
read_file($file); # to warm cache

timethese(500, {
        'memory_mapped' => sub{ md5offile_mapped( $file ); },
        'original'      => sub{ md5offile_orig( $file ); },
        'add_file'      => sub{ md5offile_addfile( $file ); },
        'system'        => sub{ md5offile_md5file( $file ); },
;}
);




The variant "memory-mapped" is about 10% faster than the others. Here a result for checksumming a DNG-file with size of 13MB on a NVME device:

Benchmark: timing 500 iterations of add_file, memory_mapped, original, system...
     add_file: 12 wallclock secs (10.68 usr +  1.09 sys = 11.77 CPU) @ 42.48/s (n=500)
memory_mapped: 10 wallclock secs (10.43 usr +  0.23 sys = 10.66 CPU) @ 46.90/s (n=500)
     original: 12 wallclock secs (10.98 usr +  0.95 sys = 11.93 CPU) @ 41.91/s (n=500)
       system: 16 wallclock secs ( 0.13 usr 0.27 sys + 13.97 cusr  1.34 csys = 15.71 CPU) @ 31.83/s (n=500)


Unfortunately there is a problem with large files. The Digest::MD5 probably calculates the values wrong for scalars >1GB (see https://rt.cpan.org/Public/Bug/Display.html?id=123185). In this case, the memory mapped approach should not be used.

Dienstag, 14. Mai 2019

Asciiart via Perl komprimieren

Als kleine Fingerübung habe ich ff. Perl-Script geschrieben, welches zur "Komprimierung" von AsciiArt verwendet werden kann.

Sei die Vorlage:

            /| |\
        ,  ( `-´ )
       /(  _\   /____      []
      |  >(__|9|_____)     ||
       )(    | |  ___  ___ ||
      -==-   | | / _ \/ _ \||
             |8|| (_) |(_) ||
            /   \\___/\___(%%)
           ( ,-. )        |''|
            \| |/         ||||
                          `--'


So erzeugt das Script folgenden Perl-Code:

#!/usr/bin/perl
use v5.10;
say ;
say " "x12,"/| |\\";
say " "x8,",  ( `-´ )";
say " "x7,"/(  _\\   /","_"x4," "x6,"[]";
say " "x6,"|  >(__|9|","_"x5,")"," "x5,"||";
say " "x7,")("," "x4,"| |  ___  ___ ||";
say " "x6,"-==-   | | / _ \\/ _ \\||";
say " "x13,"|8|| (_) |(_) ||";
say " "x12,"/   \\\\___/\\___(%%)";
say " "x11,"( ,-. )"," "x8,"|''|";
say " "x12,"\\| |/"," "x9,"|"x4;
say " "x26,"`--'";
say ;
say ;
say ;1;


Alternativ kann der Fuzzy-Mode eingeschaltet werden, der ff. Code erzeugt:

#!/usr/bin/perl
use v5.10;
used in fuzzy mode
say "\n"," "x12,"/| |\\\n"," "x8,","," "x2,"( `-´ )\n"," "x7,"/("," "x2,"_\\"," "x3,"/","_"x4," "x6,"[]\n"," "x6,"|"," "x2,">(","_"x2,"|9|","_"x5,")"," "x5,"|"x2,"\n"," "x7,")("," "x4,"| |"," "x2,"_"x3," "x2,"_"x3," ","|"x2,"\n"," "x6,"-","="x2,"-"," "x3,"| | / _ \\/ _ \\","|"x2,"\n"," "x13,"|8","|"x2," (_) |(_) ","|"x2,"\n"," "x12,"/"," "x3,"\\"x2,"_"x3,"/\\","_"x3,"(","%"x2,")\n"," "x11,"( ,-. )"," "x8,"|","'"x2,"|\n"," "x12,"\\| |/"," "x9,"|"x4,"\n"," "x26,"`","-"x2,"'\n","\n","\n",;1;


Hier das Script:
#!/usr/bin/env perl 
#===============================================================================
#
#         FILE: compress_asciiart.pl
#
#        USAGE: ./compress_asciiart.pl  
#
#  DESCRIPTION: compresses asciiart (or any text) to small perlcode using RLE
#
#      OPTIONS: -f (enables fuzzing)
# REQUIREMENTS: ---
#         BUGS: ---
#        NOTES: ---
#       AUTHOR: Andreas Romeyke
# ORGANIZATION: 
#      VERSION: 1.0
#      CREATED: 08.04.2019
#     REVISION: ---
#===============================================================================

use strict;
use warnings;
use utf8;

print "#!/usr/bin/perl\n";
print "use v5.10;\n";
my $fuzzy=0;
my $runlength=3;
if (defined $ARGV[0] && $ARGV[0] eq "-f") {
    print STDERR "used in fuzzy mode\n";
    $runlength=1;
    $fuzzy=1;
}

sub subs {
    my $s1 = shift;
    my $s2 = shift;
    my $l = length($s2)+1;
    $s1=~s/\\/\\\\/g;
    $s1=~s/"/\\"/g;
    $s2=~s/\\/\\\\/g;
    $s2=~s/"/\\"/g;
    my $v;
    if ($l > $runlength) {
        return 
        qq(").
        qq($s1).
        "\"x$l,";
    } else {
        return
        qq(").
        qq($s1$s2).
        qq(",)
        ;
    }
}
print "say ";
foreach my $line () {
    chomp $line;
    $line=~s/(.)(\1*)/my $l=length($2);subs($1, $2);/eg;
    if ($fuzzy) {
        $line =~ s/$/\"\\n\",/;
    } else {
        $line =~ s/$/;\nsay /;
    }

    while ($line=~s/"([^"]+)","([^"]+)",/"$1$2",/g) {};
    $line=~s/,;\n/;\n/g;
    print $line;
}
print ";1;";
1;




Wer noch weitere Vorschläge hat, wie man noch eleganteren Code erzeugen kann, immer her damit :)

Montag, 28. Mai 2018

Vim, Ersetzen von "foo" durch Dateinamen der zu bearbeitenden Datei

Manchmal, zB. bei der Erstellung von C++-Klassen möchte man bestimmte Textstellen durch Texte ersetzen, die aus dem Dateinamen der Datei gewonnen werden.

Will man zB. in der Datei "datei.txt" alle Vorkommen von "foo" durch "datei" ersetzen, gelingt dies in Vim im Kommandomodus so:

%s/foo/\=expand('%:r:t')/

Mit "\=" weist man Vim an, nicht direkt den Ersetzungstext zu verwenden, sondern ein Vim-Kommando auszuführen.

"expand" liest hier den Dateinamen aus "%" aus, wendet Prefix- und Suffix-Magie (":r:t") an und gibt den Ersetzungsstring zurück.


Dienstag, 7. März 2017

Geschafft!

So, ich habe es geschafft. Meine Masterarbeit wurde nun endlich korrigiert und ich darf sie nun veröffentlichen:

http://andreas-romeyke.de/bkm/


Das Studium neben dem Beruf wäre nicht möglich gewesen ohne die großartige Unterstützung meiner Familie, aber auch meiner Kollegen von der SLUB. Inbesondere möchte ich meinem Kollegen Jörg danken, mit dem ich viele Gedanken austauschen konnte.

Wer mehr über digitale Langzeitarchivierung von ihm und mir lesen möchte, der schaue mal bei Kulturreste vorbei. :)

Donnerstag, 16. Februar 2017

Rezept, Testdaten 4k 16bit RGB für FFV1 v3 erzeugen

Für Tests im Rahmen der digitalen Langzeitarchivierung von Videodaten benötige ich große Videofiles, um daran Validitätswerkzeuge und auch den Ingest zu überprüfen.

Für die Langzeitarchivierung empfiehlt sich Matroska als Containerformat und FFV1 als verlustfreier Codec. Dieser wird aktuell durch die Cellar-Group bei der IETF standardisiert.
FFV1 v3 kommt in der ffmpeg Version 3.2.4 mit 16-Bit Unterstützung.


Mehr zu FFV1 v3 auch im Nachgang der "No Time to Wait"-Konferenz.

Im Folgenden mein Script zur Generierung einer 1200s langen Videodatei. Diese enthält künstlich erzeugtes Rauschen um halbwegs die Realität widerzuspiegeln.

Hier das Script:

#!/bin/bash
# erzeugt Video im MKV/FFV1v3 Format

DURATION=1200
FRAMERATE=24
THREADS=8
PXFORMAT="rgb48le"
FRAMESIZE="3840x2160"

/tests/ffmpeg-3.2.4/ffmpeg \
  -loglevel verbose \
  -f lavfi \
  -i "mandelbrot=s=$FRAMESIZE:r=$FRAMERATE" \
  -pix_fmt $PXFORMAT \
  -t $DURATION \
  -vf noise=alls=5:allf=t \
  -vcodec ffv1 \
  -level 3 -threads $THREADS -coder 1 -context 1 -g 1 -slices 24 -slicecrc 1 \
  -strict experimental \
  test_$PXFORMAT.mkv

zzuf -b40- -c -r0.001 <test_$PXFORMAT.mkv >fuzzy_$PXFORMAT.mkv

echo "created mandelbrot video $DURATION s a $FRAMERATE fps with framesize \
$FRAMESIZE in pixelformat $PXFORMAT as file test_$PXFORMAT.mkv, also created \
a fuzzified variant with r=0.001 broken bits as file fuzzy_$PXFORMAT.mkv" | tee report.txt


Zudem wird noch eine gefuzzte Datei erzeugt, die künstliche Bitfehler enthält.

Die Datei wird in 4K-Auflösung erzeugt, das PXFORMAT=rgb48le definiert 16Bit pro RGB-Farbkanal, der Filter "-vf noise=alls=5:allf=t" erzeugt Gaussches Rauschen, welches pro Frame variert. Für FFV1 gibt Level 3 an, dass die Version 3 (für Langzeitarchivierung geeignet) verwendet werden soll. Es wird nur eine GOP=1 verwendet (-g 1), jedes Frame wird in 24 Slices geteilt, die jeweils durch CRC Prüfsummen gesichert sind.  Die Angabe "-strict experimental" schaltet die 16-Bit-Option für FFV1 frei.

Der Fuzzer zzuf überspringt die ersten 40 Bytes der Datei und erzeugt dann mit einer Rate von 0.001 fehlerhafte Bits.
Diese Datei wird später mit Validierungs- und Reparaturwerkzeugen verwendet, um die Robustheit des FFV1/MKV Gespanns zu testen.


Samstag, 31. Dezember 2016

Schicht's Kochbuch Bd. 1

Dieser Tage hatte ich einen alten Artikel von mir gelesen, in dem ich aus "Schicht's Kochbuch" die Sachertorte vorgestellt habe.

Das alte Heftchen ist mittlerweile in einem erbärmlichen Zustand. Es besteht aus Holzschliff und das Papier zerfällt langsam (mehr darüber in http://www.spektrum.de/magazin/gefaehrdung-restaurierung-und-konservierung-von-schriftgut/822535).

Da ich über die Feiertage etwas Zeit hatte, habe ich mich hingesetzt und "Schicht's Kochbuch Bd. I" digitalisiert. Die Scandaten belegten ca. 1,2 GB.

Für das Postprocessing habe ich wie schon beim Dschiu-dschitsu Projekt das Programm Scantailor verwendet.

Die entstandenen TIFF-Seiten hatte ich diesmal doch via didjvu zu einem djvu-File konvertiert:

$> didjvu bundle -o Schichts_Kochbuch_Bd1.djvu *.tif

Mit ocrodjvu habe ich dann noch den OCR-Layer hinzugefügt:

$> ocrodjvu -l deu -e tesseract --in-place Schichts_Kochbuch_Bd1.djvu

Die Kompressionsrate ist beachtlich, aus knapp 98MB TIFF-Dateien entsteht eine nur 3.358.164 Byte große djvu-Datei (eine PDF-Datei wird ca. 19MB groß). Die Texte sind nahezu fehlerfrei von tesseract erkannt wurden.

Alles in allem brauchte ich für die ca. 77 Seiten knapp 10h für Digitalisierung und Nachbearbeitung.

Das Buch ist unter http://andreas-romeyke.de/Schichts_Kochbuch_Bd1.djvu zu finden.

Update  2018-04-02


Durch einen Hinweis von Stefan (unbekannterweise) konnte ich zwei Fehler korrigieren, so stimmte die Reihenfolge der Seiten 24b-26 (die betreffende Lage war lose und falsch eingeordnet) nicht und die Seite 47 war unvollständig gescannt. Leider bin ich erst jetzt dazu gekommen, die beiden Probleme zu korrigieren. Die neue Datei findet sich an og. Stelle (9MB).

Danke nochmal an Stefan für den Hinweis!

Donnerstag, 29. Oktober 2015

Hilfe, ich verstehe nicht in welcher Auflösung ich scannen muß!

mindestens 2 Pixel Abstand zwischen Glyphen,
aber auch mindestens 2 Pixel für dünne
Bestandteile eines Glyphen

Allgemein

mit der Angabe dpi (dots per inch) definiert man die Auflösung eines digitalen Bildes. Man gibt an welcher Länge eine gewissen Anzahl von Pixeln eines Bildes entsprechen. In den Digitalisierungsrichtlinien zB. der DFG wird oft eine Auflösung von 300 dpi angegeben. Dies bezieht sich immer auf 1:1 Vorlagen, sprich, wenn Original und (digitale) Reproduktion die gleiche Größe besitzen. 300pi sind dann ein guter Kompromiß zwischen Dateigröße und Schärfegrad, bzw Nicht-mehr-Pixeligkeit beim 1:1 Druck.

Die Auflösung ist daher auch ein Maß der Ortsfrequenz des digitalen Bildes. Die Wahl der Scanauflösung bestimmt daher auch die Anfälligkeit des Digitalisats für Aliasing-Effekte in Abhängigkeit der Details des Originals.

Für die Berechnung gilt, wenn die Druckgröße von der Scangröße abweicht, wie dies zB. bei der Microverfilmung passiert oder bei Reproduktionsvergrößerungen, muß man etwas mehr genauer hinschauen.


                   Anzahl der Pixel
Auflösung = ----------------
                   Breite der Vorlage

Beispiel 1:1 Kopie

Liegt das Original in 10 x 10 inch vor und man möchte eine 1:1 Kopie im Druck darstellen, dann reichen die zB. bei der DFG angegebenen 300dpi, da dies dann 3000 x 3000 Pixeln entspricht.

 

Beispiel Bildschirmansicht

Viele Bildschirme kommen mit einer Auflösung von 100 dpi (früher 75 oder 90 dpi). Wenn man also ein Dokument 10x10 inch mit 300dpi gescannt hat, dann macht dies 3000x3000 pixel. Der Monitor kann aber nur 100dpi anzeigen, daher wird der Scan am Monitor mit je 3000dots/100 dpi = 30 inch Größe  angezeigt.

 

Beispiel Microfilm und Vergrößerung

wenn es sich um Microfilm handelt, wären 200dpi *erst recht* zuwenig. Die 300dpi wurden für eine 1:1 Repräsentation festgelegt.

Wenn Du vom Microfilm scannst, willst Du aber auf das Original vergrößern, dh.die notwendige DPI-Zahl ergibt sich aus der Zielgröße.

Ein Original der Größe 10x10 inch wurde auf Microfilm der Größe 0,1x0,1 inch verfilmt. Die Verfilmung soll gescannt werden, damit man Reproduktionen des Originals von 20x20 inch anfertigen kann.

Bei einer Druckauflösung von 300dpi müsste man also die 20x20 inch Reproduktion anfertigen. Das macht aber die 200fache (2x größer als Original und jenes 100x größer als Microverfilmung)  Vergrößerung der Microverfilmung aus, du brauchst daher  200*300dpi = 60.000dpi.

Ist auch logisch, denn wenn Du 0,1 inch mit zum Beispiel 200dpi scannen würdest, bekämst Du 200dpi * 0,1 inch = 20 Pixel heraus. Diese 20 Pixel würdest Du im Beispiel auf 20 inch verteilen, womit ein Pixel genau 1 inch groß wäre.

Wenn Du aber die 0,1 inch mit 60.000dpi scannst, bekommst Du 60.000dpi * 0,1 inch = 6000 pixel heraus, die  Du in der Vergrößerung auf 20 inch verteilst, was 6000dots/20inch = 300dpi Druckauflösung entspricht.

Sonntag, 18. Oktober 2015

Dschiu-Dschitsu


Das nebenstehende Büchlein hatte ich vor ein paar Wochen auf dem Flohmarkt erstanden.

Unter der Adresse http://andreas-romeyke.de/Dschiudschitsu.djvu habe ich die digitalisierte Datei als DJVu frei zur Verfügung gestellt (einen Urheberrechtsvermerk konnte ich bei der DNB nicht finden, IMHO sollte es mittlerweile gemeinfrei sein)

Das Büchlein wurde mittels xsane gescannt, dann mit tiff2pdf, pdf2djvu in ein DJVu konvertiert.

Mit didjvu würde man bessere Ergebnisse erzielen, leider erzeugt das Programm zZ. aber invertierte Seiten, wenn man es mit monochromen TIFFs füttert.

Die OCR erfolgte über ocrodjvu unter Zuhilfenahme von tesseract 3.03 und "-l deu-frak". Ein Postprocessing erfolgte nicht, einzig die Überschriften und Bildunterschriften wurden manuell mit djvusmooth nachkorrigiert.

Die Metadaten wurden über djvused hinzugefügt.

Anbei nochmal eine Zusammenfassung der Metadaten (nach Angabe der DNB):

  • Author:  "Shunsho, Daiji"
  • Titel: "Dschiu-Dschitsu"
  • Erscheinungsjahr:   1926
    Teil der: "Miniatur-Bibliothek ; 721/722"
  • Verlag: "Leipzig : Verlag für Kunst und Wissenschaft, 1926."
Wenn jemand den Volltext korrigiert, ich wäre an der korrigierten Fassung interessiert. Wer og. Digitalisat weiterverwenden will, dem bitte ich zur Aufrechterhaltung meiner Motivation um eine kleine Erwähnung. :)

Montag, 12. Oktober 2015

Der Mythos Audio in Digitalisierungsempfehlungen

Das Problem


Ich arbeite im Bereich der digitalen Langzeitarchivierung und bei den Diskussionen, in welcher Form wir Filmmaterial (zB. 16mm Lichtton) haben wollen, bekomme ich immer wieder Digitalisierungsempfehlungen  um die Ohren gehauen, die mir als Informatiker mit nachrichtentechnischem Hintergrund nicht einleuchten.

Für Bildmaterial gibt Kodak an, daß man in 3600dpi scannen sollte, damit man die höchste Ortsfrequenz, die der Film auflöst noch erfasst hat. Das ist für mich einsichtig.

Jetzt wird es kurios. Nach einigen Recherchen beträgt die Bandbreite für Ton auf 16mm Film in Lichttontechnik nur 5kHz. Nach Shannon-Niquist reicht es also den Ton mit 10kHz zu digitalisieren, gehen wir auf nächsthöhere übliche Frequenz, dann wären wir bei 16kHz.

Als ich dies vorschlug regte sich massiver Widerstand, "Ja, aber die und die sagen 96kHz!"

Und tatsächlich:
* ALCTS empfiehlt mindestens 96kHz: http://www.ala.org/alcts/resources/preserv/minimum-digitization-capture-recommendations#audio
* IASA empfiehlt 48kHz, besser seien mindestens 96kHz  http://www.iasa-web.org/tc04/audio-preservation

Hmm, vielleicht wäre eine Erklärung, daß Shannon sein Theorem auf ideale Filter stützt, die in der Praxis nicht vorkommen. Doch neuere Literatur zeigt, daß Shannon-Niquist auch heute noch Gültigkeit hat, auch unter Bedingungen von nicht-idealen Filtern:
Sampling—50 Years After Shannon
M. Unser
Proceedings of the IEEE, vol. 88, no. 4, pp. 569-587, April 2000.
This paper presents an account of the current state of sampling, 50 years after Shannon's formulation of the sampling theorem. The emphasis is on regular sampling where the grid is uniform. This topic has benefited from a strong research revival during the past few years, thanks in part to the mathematical connections that were made with wavelet theory. To introduce the reader to the modern, Hilbert-space formulation, we re-interpret Shannon's sampling procedure as an orthogonal projection onto the subspace of bandlimited functions. We then extend the standard sampling paradigm for a representation of functions in the more general class of "shift-invariant" functions spaces, including splines and wavelets. Practically, this allows for simpler—and possibly more realistic—interpolation models, which can be used in conjunction with a much wider class of (anti-aliasing) pre-filters that are not necessarily ideal lowpass. We summarize and discuss the results available for the determination of the approximation error and of the sampling rate when the input of the system is essentially arbitrary; e.g., non-bandlimited. We also review variations of sampling that can be understood from the same unifying perspective. These include wavelets, multi-wavelets, Papoulis generalized sampling, finite elements, and frames. Irregular sampling and radial basis functions are briefly mentioned.

Woher die Diskrepanz?

Nach etwas mehr Recherche sieht es so aus, daß Digitalisierungsempfehlungen für Audio zwar oft 48, 96 oder gar 192kHz Samplingrate empfehlen, nicht aber hinschreiben, warum das sinnvoll wäre.

Nach einigen Gesprächen scheint sich ein klareres Bild zu ergeben. Man sampelt die Audioquellen mit dem n-fachen der Grenzfrequenz, um statt im analogen Bereich lieber digital zu filtern. Für digitale Filterung ist es aber nötig höher abzutasten (damit man mehr "Datenpunkte" für den Filter bekommt)

Was aber nun das eigentliche Problem ist, die hochgesampelten und ggf. digitalgefilterten Daten werden nicht wieder heruntergesampelt auf die untere (notwendige) Samplingrate. Gehen wir von Hifi Audio aus, dann hat man da vlt. Frequenzen von bis zu 24kHz im Audiosignal (die man haben will) und Rauschen und sonstige Störgeräusche oberhalb 24kHz, die man nicht haben will . Bei einer analogen Filterung müßte man nun einen steil wirkenden Tiefpaß mit der Grenzfrequenz von 24kHz einsetzen. Das Problem ist, daß  zB. ein einfacher Butterworth-Filter das Signal ab der Grenzfrequenz nur um 3dB dämpft. Die gedämpften Anteile ab der Grenzfrequenz werden aber mit digitalisiert und verletzen dann das Niquist-Kriterium und sorgen für Aliasing-Effekte.

Wenn man dagegen digital filtert, kann man die Grenzfrequenz durch das Überabtasten (oversampling) erstmal nach oben schieben und ein billiges analoges Filter nehmen. Der eigentliche interessante Bereich (die 24kHz) wird dann mit digitalen Filtern "herausgearbeitet". Auch kann man digitale Filter so konstruieren, daß diese nicht zu Schwingungen angeregt werden und Quantisierungsfehler nur geringen Einfluß haben.



Warum Digitalisierungempfehlungen nicht wirklich hilfreich sind

Ich will im Archiv das Signal aufbewahren, mit welchem ich das Original rekonstruieren kann. Dabei muss ich ressourcenschonend arbeiten, da wir zur Absicherung mehrere Kopien an unterschiedlichen Stellen vorrätig halten müssen.

Das Problem ist nun, daß man nun für ein 24kHz Signal  192.000 Samples pro Sekunde bekommt und in den Digitalisierungsempfehlungen nur das Upsamplen (ohne Begründung) drin steht, aber weder Angaben zur digitalen Filterung, noch zum eigentlich notwendigen Downsampling (genauer Decimation) gemacht werden.

Der Witz ist, daß die Argumente, die für den Audiobereich für das Upsampling genannt werden, in gleichem Maße auch für den Videobereich gelten. Nur daß wir es hier mit drei Dimensionen zu tun hätten: Upsampling in horizontaler, in vertikaler und in zeitlicher Auflösung. Dies würde bedeuten, daß man bei der Digitalisierung von Kodak-Film nicht mit 3600dpi, sondern mit n*1800 dpi (wenn wir Audio 24kHz auf 192kHz als Vorbild nehmen würden, dann mit 8-fachem Oversampling, d.h. mit 14.400 dpi scannen müßten. Wir würden also bei den Einzelbildern eine 4*4=16fach höhere Datenmenge bekommen. Wenn man das noch bei zeitlicher Komponente macht (statt 24 fps mit 4*24=96fps) bekämen wir 64fach höhere Datenmenge. Wir könnten dann zwar nach Lust und Laune digital im örtlichen und zeitlichen Bereich filtern, würden dafür aber an den nächsten Baum geknüpft :)

Wer weiterlesen mag, wie das alles im Detail funktioniert, dem empfehle ich als Einstieg den Wikipediaartikel https://en.wikipedia.org/wiki/Decimation_(signal_processing) und https://de.wikipedia.org/wiki/Überabtastung

Mittwoch, 17. Dezember 2014

Perl RegEx mit variable length look-behind um Römische Zahlen in Text bedingt zu ersetzen

HerrenbergStiftskirche060427
Quelle: Wikimedia, Lizenznachweis sh. Link Bild

Das Problem


In einem Text sollen Römische Zahlen durch die selbstdefinierte Asciidoc-Notation roman::number[] ausgezeichnet werden. Asciidoc erlaubt zur Zeit allerdings nicht weitere Markups innerhalb einer Bildauszeichnung.

Sprich:

.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]

funktioniert, aber
.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.]

nicht, da in Asciidoc Tags der Form image:foo.png[baz] innerhalb von baz keine anderen asciidoc-Tags enthalten darf.

Römische Zahlen finden


Wenn wir nach römischen Zahlen suchen, könnten wir Reguläre Ausdrücke (RegEx) benutzen. In Perl sähe eine RegEx dann beispielsweise so aus:

my $roman_number = qr{
(
    (I{1,3})|  # I … III
    (I?V)|     # IV … V
    (VI{1,3})| # VI … VIII
    (I?X)      # IX … X
)
}x;


Teststring


Bevor wir weitermachen, sollten wir uns einen Teststring definieren, der alle möglichen Varianten enthält und es uns erlaubt die RegExes zu überprüfen:

my $string=<<TEST;
.Konrad I. von
.Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.
break::folding[test] .Konrad I. von Wettin. break::folding[test2] Luitgard, Konrads I. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]
Im Frühjahr
fertig. Im Frühjahr
mahlin. Im Frühling 1147 nahm er mit vielen der ſächſiſchen Fürſten das
als der Imker
I. Foo
Foo I.
Foo II.
Foo III.
Foo IV.
Foo V.
Foo VII.
Foo VIII.
Foo IX.
Foo X.
Foo XIII.
Foo XIV.
Foo XX.
Foo XV.
BarI.
BarII.
IBaz
Vettel
Xanthippe
Baz IIII.
Baz IIV.
Baz IIIV.
Baz IIX.
Baz XIIII
Baz VV.
Baz VX.
Baz IXIX.
Baz IVX.
Baz IIX.
Baz VIIX.
Baz XIVI.
TEST

Lookbehind und Lookahead


Unsere oben definierte RegEx allein reicht für obiges Beispiel nicht, da wir zB. nicht innerhalb einer []-Klammer römische Zahlen ersetzen wollen. Eine Abhilfe wäre, wenn wir im String beliebig zurückschauen könnten, ob eine Klammer noch offen ist.

In Perl sind zwar beliebig tiefe lookahead-Bedingungen in Regulären Ausdrücken erlaubt, allerdings nicht in lookbehind-Bedingungen.

Sprich, mit (?<=foo)bar würden wir auf bar matchen, wenn vorher der fixe String foo auftaucht. Aber (?<=fo+)bar funktioniert unter Perl5 nicht.

Lookahead hat diese Einschränkungen nicht, wenn ich also auf foo matchen will, aber nur, wenn bar oder baar oder ba…ar folgen, dann kann ich foo(?=ba+r) schreiben.

variable length lookbehind über variable length look ahead


Über einen Post in einem Forum bin ich auf eine Lösung gestolpert: Drehe den String und die RegEx um. Statt:

"foobar" =~ s/(?<=fo+)bar/baz/; #funktioniert nicht in Perl5

also alles umdrehen zu:

"raboof" =~s/rab(?=o+f)/zab/; # zaboof -> reverse zaboof = foobaz

Die Lösung


Zurück zum Problem mit Asciidoc und römischen Zahlen, die Lösung sieht in Gänze nun wie folgt aus:

my $rstring = reverse $string;
my $roman_revregex=qr{
    (?<![IVXa-zſßäöü])(          #lookbehind
    (I{1,3})|            # I ... III
    (I{1,3}V)|           # VI ... VIII
    (VI{0,1})|           # IV ... V
    (XI{0,1})|           # IX .. X
    (I{1,3}X)|           # XI .. XIII
    (VI{0,1}X)|          # XIV ... XV
    (I{1,3}VX)|          # XVI ... XVIII
    (XX)                # XX
    )(?=\ )(?![^\[\]]*\[) # lookahead
    }x;
$rstring=~s#$roman_revregex#\]$1\[rebmun::namor#g;
$string = reverse $rstring;
print $string, "\n\n";

Dies ergibt dann folgenden String:

.Konrad roman::number[I]. von
.Konrad roman::number[I]. von Wettin. Luitgard, Konrads roman::number[I]. Gemahlin.
break::folding[test] .Konrad roman::number[I]. von Wettin. break::folding[test2] Luitgard, Konrads roman::number[I]. Gemahlin.
[caption=""]
image:img/011_Konrad_Luitgard.svg[Konrad I. von Wettin. Luitgard, Konrads I. Gemahlin.]
Im Frühjahr
fertig. Im Frühjahr
mahlin. Im Frühling 1147 nahm er mit vielen der ſächſiſchen Fürſten das
als der Imker
I. Foo
Foo roman::number[I].
Foo roman::number[II].
Foo roman::number[III].
Foo roman::number[IV].
Foo roman::number[V].
Foo roman::number[VII].
Foo roman::number[VIII].
Foo roman::number[IX].
Foo roman::number[X].
Foo roman::number[XIII].
Foo roman::number[XIV].
Foo roman::number[XX].
Foo roman::number[XV].
BarI.
BarII.
IBaz
Vettel
Xanthippe
Baz IIII.
Baz IIV.
Baz IIIV.
Baz IIX.
Baz XIIII
Baz VV.
Baz VX.
Baz IXIX.
Baz IVX.
Baz IIX.
Baz VIIX.
Baz XIVI.

Dienstag, 9. Dezember 2014

Seitenfehler im Ebookreader PRS300 von Sony

Lange hatte ich mich gewundert. In meinem Projekt ›Bunte Bilder aus dem Sachſenlande« hatte ich etliche Mühen auf mich genommen, um möglichst exzellente Grafiken aus der Originalvorlage zu erzeugen und diese als SVG bereitzustellen, damit die Ebookreader diese Vektorgrafiken auf ihre bevorzugte Auflösung rendern können.

Das Programm epubcheck meldete keinerlei Fehler mehr und auf den diversen Ebookreadern auf meinem PC wurde das Epub2 soweit korrekt angezeigt.

Nur einzig und allein auf meinem Sony PRS300 hatte ich ein komisches Verhalten. Das Inhaltsverzeichnis wurde geladen und angezeigt. Doch sobald ich auf eine Seite ging, kam das Symbol "Seitenfehler". Wenn ich zwischendurch auf ein anderes Buch ging und später auf die Seite zurück, war manchmal der Seitenfehler verschwunden und die Seite korrekt gerendert. Nur beim Zurückkehren auf das Inhaltsverzeichnis, beim Vor- oder Zurückblättern  tauchte der Fehler wieder auf.

In einem letzten Test erzeugte ich ein Ebook, welches statt SVGs Bilder im PNG-Format abspeicherte. Und siehe da, das Ebook ließ sich nutzen.

Auf alle Fälle wäre ich jedem dankbar, der das Verhalten mit seinem Ebookreader mal versucht nachzustellen oder mir vielleicht eine Übersicht über die Einschränkungen der verschiedenen erhältlichen Ebookreader nennen kann. Über entsprechende Hinweise wäre ich sehr dankbar.

Dienstag, 2. Dezember 2014

Sachertorte

Es ist Weihnachtszeit und da der letzte Beitrag etwas her ist, gibt es heute ein Rezept aus „Schicht's Kochbuch – ausgewählte Rezepte“
Das Buch ist eigentlich eines von drei Heftchen, hier aus dem 1. Band, Mehlspeisen, im Druck von A. Haase, Prag. Die DNB verzeichnet als Erscheinungsjahr 1928-1931 (http://d-nb.info/56088897X).


Charakteristisch ist die minimalistische Darstellung der Rezepte.Hier das Rezept für Sachertorte aus Seite 38b:



Das Rezept in maschinenlesbarer Form:

Sacher-Torte.

Zutaten: 16 dkg Visan, 15 dkg Zucker, 8 dkg Kakao, 6 Eier, 15 dkg
Mehl, Sacherbuttercreme (siehe Creme), Schokoladenfondant (siehe Fondant).

Zub ereitung; DasVisan wird mit dem Zucker schaumig gemischt,
die Eidotter nach und nach dazugegeben, dann den Kakao daruntergemischt.

*Dazu kommt der Schnee von den Eiklar und zuletzt das Mehl. Bei mäßiger '

Hitze backen; nach dem Auskühlen in zwei Blätter schneiden und, mit Sacher-
buttercreme füllen, mit Schokoladenfondant überziehen und auf jedes Torten-
stück eine Praline aufsetzen. w ’

W o r a uf k o m mt e s a n? Die Torte vor dem Füllen einen Tag stehen
lassen. '

Was kann mißlingen? Die Masse läuft aus der Form, wenn sie
nicht genau in Papier eingeschlagen wird.
Die Sacher-Buttercreme wird auf S. 31 beschrieben:


Das Rezept in maschinenlesbarer Form:

 Sacherbuttercreme.

Z u t a t e n: 12 1/2 dkg Visan, 12 1/2 dkg Zucker, 2 Eigelb, 10 dkg Tunkmasse.
Z u b e r e i t u n g: Das Eigelb wird schaumig geschlagen, der Zucker wird
zum schwachen Flug gekocht und in einem schwachen Strahl in die flaumige Eigelbmasse hineingezogen; das Ganze dann kalt geschlagen. Nachher rührt
man es in das Visan, welches unterdessen schaumig gerührt wurde. Nun mischt man noch die aufgelöste Tunkmasse darunter.
W o r a u f  k o m m t e s a n? Das Eigelb gut aufschlagen.
Was kann m iß l in gen? Die Tunkmasse wird bröslig, wenn sie zu
warm aufgeweicht wird.
Das Ergebnis entstammt (ohne weitere Korrektur) der OCR mit dem folgenden Aufruf von Tesseract 3.03:
$> tesseract Schichts_Kochbuch_Bd1_38b.png Schichts_Kochbuch_Bd1_38b -l deu
 

Samstag, 1. November 2014

SVG 1.0 nach SVG 1.1

Da EPUB 2.0 auf SVG 1.1 referenziert, sollten wir auch SVGs in der erwarteten Version erzeugen. Auf das Problem bin ich gestoßen, als ich für das »Bunte Bilder aus dem Sachſenlande« - Projekt mal den epubcheck aufgerufen hatten und ff. Meldungen bekam:

$> epubcheck bunte_bilder.epub
Validating against EPUB version 2.0 - custom validation
Validating using EPUB version 2.0 rules.
ERROR(RSC-005): bunte_bilder.epub/OEBPS/img/003_Wappen.svg(6,38): Error while parsing file 'value of attribute "version" is invalid; must be equal to "1.1"'.

Abhilfe schafft ff. Aufruf von inkscape:

$> inkscape -z -E=tmp.eps svg1.0.svg
$> inkscape -z -l=svg1.1.svg tmp.eps

Die Zweiteilung mit Umweg über EPS ist notwendig, weil inkscape SVGs dann nicht in neue Version konvertiert, wenn diese valide ist und alle Elemente in neuer Version gültig sind. Mit "-z" unterdrückt man die GUI und "-E" exportiert nach EPS, "-l" nach SVG.

Um alle Bilder im Verzeichnis zu konvertieren, nutzt man ff. Schleife in der Bash:

$> for i in *.svg; do inkscape -z -E=tmp.eps $i; inkscape -z -l=$i tmp.eps; rm -f tmp.eps; done

Wer noch andere Varianten/Tools kennt, melde sich bitte. :)

Freitag, 13. Juni 2014

tiff Reparatur - Helferlein

In einem früheren Beitrag »baseline TIFF« hatte ich den Aufbau von TIFFs beschrieben.

Eines der häufigsten Probleme, die bei der Validierung von TIFFs auftauchen, sind falsche Datum-Zeichenketten im datetime-Tag.

Unter https://github.com/SLUB-digitalpreservation/fixit_tiff findet ihr ein Werkzeug, welches diese Art der Probleme versucht zu beheben.

Zur Zeit werden die folgenden falschen Datums-Zeichenketten erkannt und korrigiert:

  • '18.03.2010 09:59:17' => '2010:03:18 09:59:17'
  • '2010-03-18 09:59:17' => '2010:03:18 09:59:17'
Das datetime-Tag ist laut Standard spezifiert als folgende Zeichenkette: 'YYYY:MM:DD hh:mm:ss' wobei
  • YYYY dem vierstelligen Jahr,
  • MM dem Monat
  • DD dem Tag
  • hh den Stunden
  • mm den Minuten
  • ss den Sekunden
entspricht und ggf. führende Nullen gesetzt werden.
Das Tool kann auch alle Tags, die nicht zum baseline Profil gehören aus den TIFFs entfernen.

Über Feedback würde ich mich freuen. :)



Freitag, 6. Juni 2014

Exportieren lokales subversion repository nach github

Warum?

Da ich intern bisher auf subversion entwickle, Code aber auf GitHub stellen möchte, brauche ich eine¹ Möglichkeit diese Projekte möglichst kompatibel nach git zu exportieren. git-svn erlaubt diese Nutzung und erhält die Versionshistorie. Eine Re-Integration nach subversion ist ebenfalls möglich.

Die Infos stammen zum Teil aus Tutorial zu git-svn unter http://viget.com/extend/effectively-using-git-with-subversion.

Eine kleine, nette Einführung zu git gibt es unter http://rogerdudler.github.io/git-guide/index.de.html

¹ Erm, ja. Github kann auch via subversion Repositories verwalten. Allerdings müsste man dann das Projekt komplett dort hosten. Die obige Lösung umgeht dies.


git-svn installieren

git-svn ist unter Debian im gleichnamigen Paket zu finden und mittels

$> aptitude install git-svn
zu installieren.
Es ist ratsam vor der ersten Verwendung im .bashrc den Suchpfad für git-svn zu hinterlegen, da Debian das Programm unter /usr/lib/git-core/ installiert.


Exportieren von subversion in git Arbeitsverzeichnis


Das jeweilige Projekt, welches exportiert werden soll, sollte vollständig auf dem Subversionserver vorliegen. Sinnvoll ist es über die URL des Projektes zu gehen. Im Beispiel wäre das https://localhost/svn/trunk/fixit/fixit_tiff, welches auf das fixit_tiff Repository zeigt.

Mit folgendem Kommando erzeugt man im /tmp Directory das neue Git-Arbeitsverzeichnis für fixit_tiff:


$> mkdir /tmp/git
$> cd /tmp/git
$> /usr/lib/git-core/git-svn clone https://localhost/svn/trunk/fixit/fixit_tiff ./fixit_tiff
Zur Überprüfung können wir mit git log anschauen, ob unsere History etc. korrekt übernommen wurde:

$> cd fixit_tiff
$> git log 
commit 92f8cf068d7bdf8e2a39aab8e3db31f3c055bcd4
Author: romeyke <romeyke@c63e1d0e-0205-4395-96c5-23d0ee883611>
Date:   Wed May 28 15:17:12 2014 +0000

    - compiles with debugging code
    - added TIFFGetAllTagListCount () because TIFFGetTagListCount() only works w
    - added TIFFGetAllTagListEntry () because TIFFGetTagListEntry() only works w
    - added print_baseline_tags()
    - added print_required_tags()
    - added check_required()
    - check_*() opens tif-files only in read mode
    - improved logic, because we call check*() explicitely, also after repair
    
    git-svn-id: https://localhost/svn/trunk/

commit dd30cfa15101c61111ce62f6e83b0bfee3cb10bb
…

Übertragen auf github

Auf github sollte schon ein entsprechendes Repository angelegt sein. Zuerst müssen wir git nun mitteilen, daß wir auf einen anderen Master gehen:

$> export yourusername=maxmustermann
$> export yourreponame=fixit_tiff
$> git remote add origin https://github.com/${yourusername}/${yourreponame}.git

Mit folgendem Kommando vollführen wir dann den Export aus unserem obigen git-Arbeitsverzeichnis:

$> git push origin master
Bei Problemen schlage man unter http://stackoverflow.com/questions/12799719/how-to-upload-a-project-to-github nach (Lächeln)

Meine Repos sind unter https://github.com/art1pirat/ zu finden

Samstag, 29. März 2014

Silbentrennung für Ebooks

ISOIEC-9995-7-076--IEC-60417-6073--Symbol-for-Soft-Hyphen
Soft-Hyphen Keyboard Symbol
Quelle: Wikipedia, CC0
Ja, der Titel ist geklaut. Vor ca. zwei Wochen war ich wieder einmal auf den Chemnitzer Linuxtagen und bin dort auf den Vortrag von Georg Pfeiffer »Perfekte Silbentrennung in E-Books mit präreformatorischen Texten« gestoßen.

Da ich ja ua. die »Bunte Bilder aus dem Sachſenlande« als E-Book aufbereite, benötige ich für meine Texte ebenfalls eine "perfekte" Silbentrennung. Georg hat in seinem Vortrag auf das Projekt »Trennmuster« der TeX-Leute hingewiesen. Das hat mich neugierig gemacht.

Nach dem Herunterladen des Projektes (was sehr lange dauert, da die Wortlisten knapp 15MB groß sind) mittels

$> git clone git://repo.or.cz/wortliste.git

findet man die Trennmuster in den Dateien pre-1901 und wortliste. Die letztere ist für mich eher uninteressant, da diese nur Wörter nach den jeweiligen Rechtschreibreformen enthält. Die pre-1901 ist recht einfach aufgebaut, hier ein Auszug:

aber<mah-li-gen
ab<füh-re-ten
ab<ge<fer-ti-get
ab<ge<than
ab<ge<theilt
ab<hoh-len
ab<thei-len
ab<theil-ten
Ab<thei-lung
Ab<thei-lun-gen


Das Zeichen '<' bezeichnet die Trennung, falls es sich um eine Vorsilbe handelt. Das Zeichen '-' gibt eine normale Trennung an, das Zeichen '=' (im Beispiel nicht vorhanden) eine Trennung zwischen zusammengesetzten Worten.

Für ein Ebook sind mir diese unterschiedlichen Trennungen egal, so das ich, wie Georg, an all den Trennstellen ein Weiches Trennzeichen setzen möchte.  Unicode kennt solch ein Zeichen als Code U+00AD. Als HTML-Entität wäre es &shy;. Das weiche Trennzeichen erlaubt es, Trennanweisungen zu kodieren, für den Fall, daß das Anzeigeprogramm gezwungen ist, den Text umzubrechen. Es ist also nur an Zeilenumbrüchen als Trennzeichen zu erkennen und sonst im Text unsichtbar.

In meinem Perlscript zur Verarbeitung des Roh-Textes zu einem eigenen Asciidoc lese ich die Datei pre-1901 ein, es entsteht ein Hash %hyphens, der als Schlüssel das ungetrennte Wort verwendet und als Wert die getrennte Version mit weichen Trennzeichen. Dabei werden nicht die Feinheiten, die mit der Trennmuster-Datei möglich wäre unterschieden, sondern eine vereinfachte Variante kodiert.
Aus 'ab<thei-len' würde also der Schlüssel 'abtheilen' und die Trennvariante (hier mit '-' statt Unicode) 'ab-thei-len' als Wert entstehen.


 sub find_hyphens {
    my $filename="hints/pre-1901";
    open (my $fh, "<", "$filename");
    binmode $fh, ":utf8";
    while (<$fh>) {
        chomp;
        # replace '-' to &shy;
        s#([a-z])-$#$1\x{00ad}#g; # &shy; U+00AD
        my $hyphenized=$_; # simplifed hyphenized

        $hyphenized=~s/[<>=-]/\x{00ad}/g;
        my $orig=$_;
        $orig=~s/[<>=-]//g; # original, dehyphenized word
        $hyphens{$orig}=$hyphenized;
    }
    close $fh;
}

Im weiteren Programm bekomme ich die Textzeilen zeilenweise übergeben. Mit folgendem Snippet lese ich dann die Wörter und ersetze sie durch ihre weich-getrennte Version:
        # inject hyphens (for ebooks)
   foreach my $word (keys %hyphens) {
        my $hyphenized = $hyphens{$word};
        s#\b$word\b#$hyphenized#g;
   }
Voila!

Als Nebeneffekt bekommt das Trennzeichenprojekt meine Wortliste aus dem Buchprojekt. Auf alle Fälle war diese Erfahrung ein gutes Beispiel dafür, wie man sich in der Welt der Freien Software gegenseitig befruchten kann. Danke für die Idee an Georg!

Freitag, 31. Januar 2014

Und die Bilder?

Das Buch „Bunte Bilder aus dem Sachſenlande“ habe ich nun soweit vollkorrigiert und bin gerade dabei alles zusammenzustellen, damit in der nächsten Stufe über asciidoc, docbook-xml ein EPub oder LaTeX Dokument erstellt werden kann.

Zurzeit bin ich noch am überlegen, wie ich mit Bildern umgehe. Verwende ich die Bilder direkt aus dem Original? Oder bearbeite ich diese nach und monochromisiere sie? Stelle ich sie frei? Verwende ich PNG oder vectorisiere ich die Bilder um diese dann als SVG abzuspeichern?

Königin Carola von Sachſen,
Protektorin des Peſtalozzi-Vereins


Ich bin mir hierbei noch nicht sicher. Habt ihr Vorschläge?

Mittwoch, 25. Dezember 2013

Was Training so ausmacht


Bin dank Clemens Neudecker auf das im Rahmen des succeed Projektes entwickelte Tool ocrevalUAtion gestoßen. Damit kann man seine OCR-Ergebnisse mit dem Original vergleichen und bekommt eine Übersicht über die typischen OCR-Fehler.

Ich habe mal eine Seite aus Bunte Bilder aus dem Sachſenlande genommen und hier sind die Werte für untrainiertes Tesseract 3.02.03 mit dem mitgelieferten "deu-frak":


CER7,74
CER-DL7,74
WER27,65
WER (bag of words)27,43
 
Dabei bedeutet CER: Character error rate, CER-DL: Character error rate nach Damerau-Levenshtein und WER: Word error rate.

Hier sind also nur knapp 92% aller Zeichen richtig und gar nur 72% aller Wörter.

Nun die im Laufe des Bunte Bilder Projektes auf den Buchtitel trainierte Variante:

CER2,83
CER-DL2,83
WER7,78
WER (bag of words)9,07

Es sind nun 97% aller Zeichen richtig und fast 91% aller Wörter! Fazit: Trainieren lohnt sich!

Dies deckt sich auch mit den Berechnung aus meinem früheren Beitrag "OCR Qualität bestimmen" bzw. aus Teil 9, wo die Worterkennungsrate 93% betrug.

Das Tool berechnet aber auch für jedes vorkommende Zeichen die Fehlerwahrscheinlichkeit, was hilft sein Augenmerk auf diese typischen Probleme zu lenken. Hier ein Beispiel des untrainierten Tesseract. Ins Auge fällt, daß dies (wie bereits beschrieben) kein langes-s erkennt. Sichtbar sind auch die Problemzeichen 'n', 'u' und 'ü':

Error rate per character and type

CharacterHex codeTotalSpuriousConfusedLostError rate
204632010,65
!210100Infinity
"220100Infinity
)2920000,00
*2a201050,00
,2c3314221,21
-2d602033,33
.2e2901313,79
131610016,67
23240000,00
53540000,00
83830000,00
93950000,00
A4160000,00
B42110109,09
D44100000,00
E4560000,00
F4690000,00
G4760000,00
H4860000,00
I494040100,00
J4a50000,00
K4b80000,00
L4c10000,00
M4d50000,00
N4e40000,00
O4f20000,00
P5030000,00
R5270000,00
S532603011,54
T5450000,00
U5540000,00
V5670000,00
W5770000,00
Z5a70000,00
a611230201,63
b62410102,44
c63660101,52
d641100000,00
e654300411,16
f664005012,50
g67710000,00
h681210403,31
i69178230012,92
j6a3400133,33
k6b210104,76
l6c912002,20
m6d64019029,69
n6e2497705,62
o6f480000,00
p70110000,00
r721480000,00
s73372005,41
t741330100,75
u75105011111,43
v76180000,00
w77310000,00
x7810000,00
y7910000,00
z7a380000,00
«ab0100Infinity
»bb0100Infinity
Äc4201050,00
ßdf70000,00
äe4130000,00
öf6110000,00
üfc2109042,86
ſ17f900900100,00
20132020100,00
20140100Infinity
201c3030100,00
201e3030100,00