Seite 1 von 1

Parse String aus Image

Verfasst: Dienstag 5. Mai 2009, 12:00
von da.dom
Hallo Zusammen,

gibt es eine Möglichkeit (lib / generelles Vorgehen) um aus einem Bild ein Text zu extrahieren? Es geht hier nicht um irgendwelche unkenntlichen gemachten Texte (Botschutz etc.) Geht um mehrer Klarschrift Passagen die aus einem Bild extrahiert werden sollen (Position der Texte ist immer gleich)

Danke schon mal für Ideen und Anregungen
Dom

Verfasst: Dienstag 5. Mai 2009, 12:33
von helduel
Moin,

kurzes googeln ergab: http://code.google.com/p/pytesser/

Kannst ja mal schauen, ob dir das hilft.

Gruß,
Manuel

Verfasst: Dienstag 5. Mai 2009, 13:03
von da.dom
Hey, das sieht ja super aus, *kopfkratz* hab ich beim Google-Durchforsten scheinbar nicht gesehen/übersehen. Werd das ganze mal heute Abend Testen und sehen wie er mit Texten in Bildern klar kommt.

Dank Dir schon mal bis hierher
D

Verfasst: Dienstag 5. Mai 2009, 14:35
von Leonidas
Das Verfahren nennt sich uebrigens "OCR" (damit du ein Stichwort fuers Suchen hast).

Verfasst: Dienstag 5. Mai 2009, 16:27
von lunar
helduel hat geschrieben:kurzes googeln ergab: http://code.google.com/p/pytesser/
Von diesem Modul möchte ich abraten. Es ist ziemlich mies programmiert. Allerdings ist es auch nicht unverzichtbar, im Gegenteil: Es tut nicht mehr als Tesseract in einem Unterprozess aufzurufen. Das kann man auch in einer Viertelstunde selbst implementieren ...

Verfasst: Mittwoch 6. Mai 2009, 14:55
von da.dom
Die Lib ist erstmal sehr übersichtlich, die Programmierleistung die dahinter steht will ich mal nicht bewerten (15minuten wird bei mir wohl nicht reichen um das nach zu programmieren ;) )

Leider ist das Tool nicht besonders effizient wenn es um "unsaubere" Textvorlagen geht. Mein Problem besteht darin das der Text auf einem Hintergrundbild liegt und die Lib scheint das nicht besonders gut zu finden.

(achtung ich drifte thematisch etwas ab)
Jetzt wollte ich das Bild so vorbereiten das die Lib es vielleicht sauberer Verarbeiten kann. PIL : Hab die Textpassagen ausgeschnitten. Jetzt würde ich gerne ein schwarz-weiss Bild daraus machen, indem ich eine Farbe definiere die weiss sein soll, alles andere soll schwarz werden (oder umgekert) die Textfarbe ist: 180,207,234

Ich hab die PIL Lib mir mal etwas genauer angesehen und die "convert" methode gefunden die scheinbar so was macht. Leider komme ich nicht ganz dahinter wie sie funktioniert
im.convert(mode, matrix) => image

Converts an "RGB" image to "L" or "RGB" using a conversion matrix. The matrix is a 4- or 16-tuple.
Leider verstehe ich die matrix nicht so ganz, wie ich die farbe definiere, die in welche Farbe umgewandelt werden soll....oder bin ich da generell auf dem Holzweg :) ?

Danke schon mal
Dom

Verfasst: Mittwoch 6. Mai 2009, 15:24
von da.dom
ok vielleicht bin ich mit der Idee ja auch auf dem Holzweg gewesen, hab es jetzt mal zu Fuss gemacht...: (Verbesserungsvorschläge, alterantiv Lösungen, elegantere Ideen sind natürlich trotzdem gern gesehen (toll das reimt sich :) )

Code: Alles auswählen

from pytesser import *

IMAGE='einBild.jpg'
MATCH_COLOR=(180,207,234)

def filterColor(pixel,color,rangeset=90):
    if pixel[0] in range(color[0]-rangeset,color[0]+rangeset):
        if pixel[0] in range(color[1]-rangeset,color[1]+rangeset):
            if pixel[0] in range(color[2]-rangeset,color[2]+rangeset):
                return True

    return False



image = Image.open(IMAGE)
pixel=image.load();
w,h = image.size
for x in range(w):
    for y in range(h):
        match=filterColor(pixel[x,y],MATCH_COLOR)
        if match:
            pixel[x,y]=(255,255,255)
        else:
            pixel[x,y]=(0,0,0)
image.show()
Werd heute Abend mal testen ob pytesser mit einem solch optimierten Bild besser klar kommt.

Grüße
D

Verfasst: Mittwoch 6. Mai 2009, 15:36
von EyDu
Sicher, dass du in filterColor (was besser filter_color heißen sollte) nicht pixel[0], pixel[1] und pixel[2] meinst und nicht dreimal pixel[0]?

Code: Alles auswählen

def filter_color(pixel, color, rangeset=90):
    return any(-rangeset <= pixel[i]-color[i] < rangeset for i in range(3))
oder nicht ganz äquivalent:

Code: Alles auswählen

def filter_color(pixel, color, rangeset=90):
    return any(abs(pixel[i]-color[i]) < rangeset for i in range(3))

Üblich wäre aber wohl eher gegen die Helligkeit des Pixels zu testen: also den arithmetischen Mittelwert der RGB-Kanäle bilden und Prüfen, ob dieser einen bestimmten Wert überschreitet.

Edit: und natürlich sind *-Importe böse!

Verfasst: Mittwoch 6. Mai 2009, 15:55
von da.dom
EyDu hat geschrieben:Sicher, dass du in filterColor nicht pixel[0], pixel[1] und pixel[2] meinst und nicht dreimal pixel[0]?
Na klar :) war mir auch aufgefallen

Code: Alles auswählen

def filter_color(pixel, color, rangeset=90):
    return any(-rangeset <= pixel[i]-color[i] < rangeset for i in range(3))
*schnauf* ich weiss ja das ich Anfänger bin in Python, aber manchmal zweifel ich selbst an meinen Grundlagen-Kenntnissen :( Kann mir das Statement mal jemand erklären was welches Zeichen da bewirkt? any erwartet ein Iterierbares Objekt, aber was macht den Ausdruck da zu einem eben solchen? das "-" und "<=" "<" sagt mit so auf anhieb in der Kombination nichts :(
EyDu hat geschrieben: Edit: und natürlich sind *-Importe böse!
Versuche mich mal daran zu halte, leider weiss ich nie was ich denn genau brauche :)

Danke (mal wieder) für die guten Hilfestellungen !!!
D

Verfasst: Mittwoch 6. Mai 2009, 16:03
von Leonidas
da.dom hat geschrieben:*schnauf* ich weiss ja das ich Anfänger bin in Python, aber manchmal zweifel ich selbst an meinen Grundlagen-Kenntnissen :( Kann mir das Statement mal jemand erklären was welches Zeichen da bewirkt?
Das ist ein any(...) und innendrin eine Generator Expression (stell dir da noch ein ()-Paar oder ein []-Paar drumrum vor), die den Bereich prüft.

Verfasst: Mittwoch 6. Mai 2009, 16:06
von cofi
da.dom hat geschrieben:Versuche mich mal daran zu halte, leider weiss ich nie was ich denn genau brauche :)
Und genau deshalb solltest du die auch meiden, denn dann weisst du auch nie, was du gerade überschreibst ;)

Verfasst: Mittwoch 6. Mai 2009, 16:13
von BlackJack
Das `any()` sollte wohl eher ein `all()` sein, denn es sollen ja alle Komponenten ähnlich sein und nicht nur mindestens eine.

Mit den x/y-Kordinaten würde ich mich nicht weiter aufhalten, die sind ja nicht wichtig für die Umwandlung.

Code: Alles auswählen

from functools import partial
from PIL import Image


def color_test(color, pixel, threshold=90):
    return all(abs(a - b) < threshold for a, b in zip(color, pixel))


def main():
    image_filename = 'test.jpg'
    match_color = (180, 207, 234)
    source_image = Image.open(image_filename)
    target_image = Image.new('1', source_image.size)
    target_image.putdata(map(partial(color_test, match_color),
                             source_image.getdata()))
    target_image.save('test.pbm')


if __name__ == "__main__":
    main()

Verfasst: Mittwoch 6. Mai 2009, 16:40
von da.dom
Das wird ja fast kompliziert :) Schaue mir die geposteten Codes nachher noch mla genauer an, will ja was lernen :D Aber ich habe mal mein kleines TestBild durch die OCR Lib gejagt, mit meinem Coding, leider mit keinem zufriedenstellenden Ergebnis. Für meine Augen ist das Bild jetzt relativ gut ausgearbeitet, aber trotzdem liefert mir die LIB keine treffer. Hab das Bild mal angehängt, eigentlich sollte man so was doch parsen können, oder erwarte ich da zu viel?

Bild

Grüße
Dom

Verfasst: Mittwoch 6. Mai 2009, 16:43
von BlackJack
Wird es besser, wenn Du das Bild invertierst? Normaler wäre ja schwarzer Text auf weissem Untergrund.

Verfasst: Mittwoch 6. Mai 2009, 18:39
von da.dom
mh leider nein... er erkennt gar nichts. Die Beispielbilder die dabei sind, sind natürlich super klare Schriften. Kann man mit PIL noch was an der Bildschärfe vielleicht was machen ?

****

Hab das mit PIL mal gemacht, aber da gibt es nicht mehr viel dran zu drehen scheinbar. Das Bild ist, wie gesagt, ja meiner Meinung nach schon relativ deutlich :(

Jemand noch gute Ideen?

Verfasst: Mittwoch 6. Mai 2009, 19:56
von BlackJack
@da.dom: Also `gocr` erkennt das halbwegs wenn man's invertiert:

Code: Alles auswählen

bj@s8n:~$ pngtopnm xxsw.png | pnminvert | gocr -
6      1O
Die 0 (Null) ist als O (Oooh) erkannt worden, aber das ist ja auch wirklich nicht gut zu unterscheiden.

Verfasst: Donnerstag 7. Mai 2009, 20:51
von da.dom
Bin für jede funktionierende Alternative offen. Erklärst du mir auch wie ich das ganze in meinen Python Code einbinde? Stehe da gerade irgendwie auf dem Schlauch. Hab danach gegooglelt und das Archiv runter geladen....leider verstehe ich gerade nicht wie ich das ganze in Python anspreche :)

Verfasst: Donnerstag 7. Mai 2009, 21:04
von derdon
mit subprocess

Verfasst: Donnerstag 7. Mai 2009, 21:55
von Leonidas
derdon hat geschrieben:mit subprocess
Hint: Forensuche.
Hint: Dokumentation.
Hint: Wiki.

Damit sollte es einfach sein. Jetzt nocht ein brauchbares OCR aussuchen.