Suche Tipps zur Texterkennung/OCR/Kantenerkennung



  • Hallo Programmierer,

    ich habe von meinem Praktikumsbetrieb eine Aufgabe gestellt, die in die Richtung OCR geht.
    Ich habe ein ausgefülltes Arztrezept und muss dieses einscannen und dann die Daten auslesen (Name, Vorname, Verscheibungen usw)
    Zur veranschaulichung ein Bild:
    http://imageshack.us/f/709/rezept.png/
    Das einscannen und auslesen der Daten habe ich hinbekommen mit einer Schnittstelle von Google:
    tesseract 3.0
    Mein Problem ist es jetzt, wenn das Rezept schief eingescannt wird, dass es dann nicht mehr funktioniert.
    Ich müsste Quasi die Kanten erkennen und das Bild gerade ausrichten (War unsere Überlegung)
    Wie würdet ihr das angehen?

    EDIT: Ich habe versucht das mit Sobel anzugehen, aber damit krieg ich das Bild auch nicht wirklich gerade - besser gesagt ich hab überhaupt keine Ahnung, wie mich das ans Ziel bringen soll.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (auch C++0x) in das Forum Rund um die Programmierung verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Praktikant666 schrieb:

    Mein Problem ist es jetzt, wenn das Rezept schief eingescannt wird, dass es dann nicht mehr funktioniert.
    Ich müsste Quasi die Kanten erkennen und das Bild gerade ausrichten (War unsere Überlegung)
    Wie würdet ihr das angehen?
    Ich habe versucht das mit Sobel anzugehen, aber damit krieg ich das Bild auch nicht wirklich gerade

    Du hast Glück, denn in dem Bild gibt es viele horizontale Geraden. Ich schlage deshalb folgendes vor:

    1. Du suchst Dir einen Farbkanal oder eine Darstellung (z.B. HSI), in der die Geraden besonders offensichtlich werden. Du musst sie vom Hintergrund unterscheiden können. Dann lässt Du irgendein Schwellwertverfahren auf diese Darstellung des Rezepts los, so dass Du nur noch die roten Geraden als Vordergrund erkennst. Du solltest dann daraus ein Binärbild generieren, in dem die Geraden (+X) schwarz sind und alles anderes weiß.

    2. Dann machst Du eine Hough-Transformation für Geraden. Eine Hough-Transformation findet bestimmte geometrische Formen in einem Bild und stellt diese in einem anderen Bild als Tupel von Parametern dar. Bei Geraden sind diese Parameter zum Beispiel Winkel und Abstand vom Ursprung. In dieser Darstellung gibt es dann Maxima bei bestimmten Winkeln. Das sind genau die Winkel, die Du benötigst, um das Rezept wieder gerade zu drehen.

    Ich habe so etwas ähnliches schon einmal gemacht und kann Dir deshalb sagen, dass das so auch funktioniert. Die roten Geraden erkennst Du am Besten über eine Kombination des H und S Kanals in einer HSI (bzw. HSV) Darstellung des Bildes.



  • Vorerst möchte ich mich bei dir für die schnelle Antwort bedanken!

    1. Du suchst Dir einen Farbkanal oder eine Darstellung (z.B. HSI), in der die Geraden besonders offensichtlich werden. Du musst sie vom Hintergrund unterscheiden können. Dann lässt Du irgendein Schwellwertverfahren auf diese Darstellung des Rezepts los, so dass Du nur noch die roten Geraden als Vordergrund erkennst. Du solltest dann daraus ein Binärbild generieren, in dem die Geraden (+X) schwarz sind und alles anderes weiß.

    Ich musste erst einmal einige Begriffe googeln, damit ich mir überhaupt etwas vorstellen konnte - ich muss zugeben, es ist etwas zu viel auf einmal, von dem ich keine Ahnung habe.
    Die vertikalen-roten Linien lassen sich doch schon gut von dem "rosa" unterscheiden, wozu ist eine andere Darstellung durch einen HSI Kanal nötig?
    Ein Binärbild generieren würde ich dann noch hinbekommen, jedoch weiß ich nicht ganz, was du mit "in dem die Geraden (+X) schwarz sind" meinst.

    Kurz gefasst:
    Dieser Lösungsweg ist bestimmt gut, jedoch würde ich gerne auf etwas "leichteres" zurückgreifen, falls es doch soetwas geben sollte.



  • Um Geraden erkennen zu können, musst Du zuerst wissen, welche Pixel zu einer Geraden gehören könnten. Deswegen brauchst Du ein Binärbild also praktisch ein Schwarz-Weiß-Bild, bei dem die Pixel, die zu Geraden gehören könnten, vom Rest unterscheidbar sind. Da Du aber sicherlich nicht zu 100% genau die Pixel von den Geraden kriegst, habe ich (+X) geschrieben. Zum Beispiel ist die Schrift auch in rot.

    In einem Binärbild ist praktisch der für Dich relevante Vordergrund vom Hintergrund getrennt. Hintergrund ist bei Dir alles, was weiß oder rosa ist, der Vordergrund ist das, was in Deinem Rezept rot ist. Du bist schon einen großen Schritt weiter, wenn Du ein Bild hast, in dem das eine komplett weiß ist, das andere schwarz.

    Ich denke, das ist so oder so der erste Schritt, egal wie es dann weiter geht. Versuch mal, aus Dem Bild des Rezeptes so ein Bild zu generieren.

    Du kannst da vermutlich nicht einfach auf "rot" testen. Denn "Weiß" beinhaltet auch rot, genau wie rosa. Deswegen dachte ich an den Umweg über den HSI Farbraum. Aber vielleicht reicht es auch, wenn Du ein Schwellwertverfahren auf Basis des blau-Wertes oder des grün-Wertes probierst. rot hat wenig blau und grün, im Gegensatz zu weiß.



  • PS: Was für ein Praktikum machst Du da?



  • Du kannst dir ja mal OpenCV anschauen. Das kann auch Hough-Transformationen, gute Beispiele sind auch dabei. Dann ist die sehr gute und elegante Lösung von Gregor auch gar nicht mehr so aufwendig zu implementieren.
    Ansonsten könntest du auch einfach das rosa Rechteck segmentieren, entweder mit nem Kantendetektor wie Canny oder über nen Schwellenwert, und das Bild über den Winkel vom minmalen umschließenden rotierten Rechteck zurechtdrehen.
    Haste gerade mal ein Bild von einem schief gescannten Rezept da? Personenbezogene Daten kannst du ja vorher rauskritzeln. 😉



  • Mhh, da wollt ich dann natürlich ausprobieren, obs wirklich so einfach geht, wie ich schreibe. 😉

    Hab mir aus deinem Beispielbild mal das hier im Gimp gemacht:
    http://i54.tinypic.com/xnc3m8.png

    Dazu dann den code hier zusammengeschrieben:

    #include "opencv2/core/core.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    
    #include <iostream>
    
    using namespace cv;
    using namespace std;
    
    string defaultFile( "VerdrehtesRezept.png" );
    
    void help()
    {
    	cout << "\nRezepte Zurechtdrehen ;)\n"
    			"Call:\n"
    			"./bla.exe [image_name -- default " << defaultFile << endl;
    }
    
    int main(int argc, char ** argv)
    {
    	string filename = argc >=2 ? argv[1] : defaultFile;
    
    	Mat imgOrig = imread( filename );
    	if( imgOrig.empty() )
    	{
    		help();
    		return -1;
    	}
    
    	Mat HSV;
    	cvtColor( imgOrig, HSV, CV_RGB2HSV );
    	vector<Mat> HSVVec( 3 );
    	split( HSV, HSVVec );
    	Mat img( HSVVec.at( 1 ) );
    	Mat thres;
    
    	threshold( img, thres, 20, 255, THRESH_BINARY );
    
    	vector<vector<Point> > contours;
    	findContours( img, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE );
    
    	imwrite( filename + ".thresholded.png", thres );
    
    	if ( contours.empty() )
    	{
    		cout << "Nix gefunden." << endl;
    		return 1;
    	}
    
    	RotatedRect rect( minAreaRect( contours.front() ) );
    	Mat rotMat( getRotationMatrix2D( Point2f( img.cols / 2, img.rows / 2 ), 90+rect.angle, 1.0 ) );
    
    	Mat rotated;
    	warpAffine( imgOrig, rotated, rotMat, Size( img.cols, img.rows ) );
    
    	imwrite( filename + ".rotated.png", rotated );
    }
    

    Also Ausgabe kommt erstmal das hier raus (Schwellenwertbild):
    http://i53.tinypic.com/23v17v9.png

    Und dann das hier:
    http://i51.tinypic.com/2zir045.png

    Das Programm ist jetzt nicht superschick, aber tut in dem Fall, was es soll. 😉
    Vermutlich musst du mit dem Schwellenwert was rumprobieren, möglicherweise nen adaptiven wählen, und das Festlegen der Zielbildgröße kann man bestimmt auch noch netter gestalten, aber vielleicht hilfts dir ja weiter. 🙂



  • Dobi schrieb:

    Ansonsten könntest du auch einfach das rosa Rechteck segmentieren, entweder mit nem Kantendetektor wie Canny oder über nen Schwellenwert, und das Bild über den Winkel vom minmalen umschließenden rotierten Rechteck zurechtdrehen.

    Die Lösung gefällt mir auch sehr gut. 👍



  • Danke nochmal für alle Antworten!
    Mein Praktikumsverwalter hat heute Morgen gemeint, ich soll das in den Hintergrund schieben und mich nich so lange damit aufhalten.
    Aus diesem Grund komm ich nicht direkt dazu, etwas auszuprobieren.

    Ich werde es aber noch machen m+ssen, dann werde ich auf euch zurück kommen!

    Gregor schrieb:

    PS: Was für ein Praktikum machst Du da?

    Ein Teil meiner 3 jährigen Ausbildung als Fachinformatiker im Bereich Anwendungsentwicklung ist Praxisbezogene Arbeit. Somit habe ich ein 6 Monatiges Praktikum bei einer Firma, die sich auf Hotelsoftware / Physiosoftware spezealisiert hat.

    Falls ich heute oder morgen dazu komme, werde ich Code von Dobi zu Hause implementieren und mich etwas damit spielen.

    Ansonsten: Danke nochmal an eure Mühe, ich werd mich mit Ergebnissen Melden


Log in to reply