OCR mit Windows-Boardmitteln (ab Windows 10)

    • VB.NET
    • .NET (FX) 4.5–4.8

    Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

      OCR mit Windows-Boardmitteln (ab Windows 10)

      Hi@all

      Windows 10 bietet eine einfache OCR, um in Bildern enthaltenen Text, auszulesen. Dieses Beispiel zeigt wie es funktioniert. Für eine einfache Texterkennung in Bildern reicht das grundsätzlich aus. Dabei werden verschiedene Bildformate unterstützt (vermutlich alle, die von WIC auch unterstützt werden). Die Erkennungsrate ist recht gut. Am Ende kommt man an die einzelnen Textzeilen, die darin enthaltenen Wörter und an welcher Position die Wörter im Bild gestanden haben. Für weitere Sprachen, die die OCR nutzen soll, müssen entsprechende Sprachpakete vom MS nachgeladen werden. Bei mir sind Deutsch und Englisch vorhanden gewesen.

      Das ganze ist wie immer ohne zusätzliche Verweise oder Fremdpakete und darf wie immer gern verbessert und erweitert werden.
      Bilder
      • OCR.png

        35,55 kB, 655×482, 279 mal angesehen
      Dateien
      • VBN_OCR.zip

        (140,5 kB, 184 mal heruntergeladen, zuletzt: )
      Mfg -Franky-
      Ich hab (noch) keine Ahnung, wie es (genau) funktioniert, aber tolle Sache. Hab jetzt mal n Foto einer alten Zeitung hergenommen. Ergebnis: überraschend gut! Ich bin gespannt, wie das mit meinen Spezialdokumenten funktioniert …

      Gut, auskommentierte Codeblöcke und verbesserbare Projektcodegrundeinstellungen hinterlassen ein paar Fragezeichen, aber die Funktionalität ist schnell und auf den ersten Blick überzeugend. Vielen Dank!
      (Obwohl ich mir da wieder mal die Frage stelle: Wie machst Du das nur immer wieder?!?)
      Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

      Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
      @VaporiZed

      Das ganze basiert auf einem AutoHotKey-Script: autohotkey.com/boards/viewtopic.php?f=6&t=72674 Ich hab das nur ein wenig ausgebaut und da das alles auf COM aufsetzt, ist das für mich einfach umzusetzen.

      Öhm, böses F-Wort: fu**. Da hab ich doch glatt vergessen den bösen Namespace raus zu nehmen und ein Häkchen zu setzen. ;)

      Der auskommentierte Codeblock zeigt halt weitere Möglichkeiten. Da kommst an jede einzelne Textzeile, darüber wieder an jedes einzelne Wort und die Position und Dimension wo das Wort im Bild gestanden hat. Vllt Sinnvoll wenn es ein zweispaltiger Text war und man diese Angaben nutzen möchte, um das Wort zb in einer RTF zu positionieren damit auch wieder zwei Spalten draus werden. Oder mit den Angaben die Wörter auf dem Bild markieren. z.B im Zusammenhang mit den in Windows vorhandenen SpellChecker um falsch erkannte Wörter sichtbar zu machen. Oder oder. Einfach mal die Fantasie spielen lassen. PDF zu Bitmap, Bitmap zu Text für zb Stichwortsuche. Nur so als Idee.

      Und zu Deiner letzten Frage: Ich versuche, soweit wie es geht, auf Drittkomponenten zu verzichten wenn das System bereits entsprechendes anbietet. Ich hab den Code dazu selbst in der Hand und kann das so gestalten wie ich das brauche. Außerdem macht es Spaß Sachen auszuprobieren, die im Framework nicht vorhanden sind. ;)
      Mfg -Franky-

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „-Franky-“ ()

      @-Franky- Ich hab noch ein wenig gespielt und folgendes festgestellt:
      Der Font der zu erkennenden Schrift spielt eine gewisse Rolle.
      Text im Notepad++ mit Courier New wird anders erkannt wie derselbe Text in Word mit Arial, wenn von beiden ein Screenshot gemacht wird.
      Mehr Pixel pro Buchstabe bringt natürlich klar eine bessere Erkennung.
      In jedem Falle ist eine Rechtschreibkontrolle zwingend erforderlich.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      @Der flotte Johann Dafür gibt es den Hilfreich-Bitton.
      ====
      Nicht für mich, sondern für @-Franky- ;)
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „RodFromGermany“ ()

      Hi@all

      Mir ist da noch ein grober Fehler unterlaufen. IOcrResult::get_TextAngle gibt kein Double zurück, sondern ein Pointer auf ein weiteres Interface über das man dann einen Double auslesen kann. Da ich keine Lust habe das ganze nochmal hochzuladen, hier die entsprechenden Änderungen am Code damit der TextAngle den korrekten Wert liefert.

      In der Enum VTable_Interfaces folgendes hinzufügen:

      VB.NET-Quellcode

      1. ' IReferenceDouble
      2. IReferenceDouble_GetValue = 6


      Entsprechend folgendes auf IntPtr abändern:

      VB.NET-Quellcode

      1. Private Delegate Function IOcrResult_GetTextAngle(<[In]> this As IntPtr,
      2. <Out> ByRef value As IntPtr) As Integer
      3. Private Function OcrResult_GetTextAngle(this As IntPtr,
      4. ByRef value As IntPtr) As Boolean
      5. Dim pVTablePtr As IntPtr
      6. Dim bolRet As Boolean = False
      7. If this <> IntPtr.Zero AndAlso GetVTablePtr(this, VTable_Interfaces.IOcrResult_GetTextAngle, pVTablePtr) Then
      8. If CType(Marshal.GetDelegateForFunctionPointer(pVTablePtr, GetType(IOcrResult_GetTextAngle)),
      9. IOcrResult_GetTextAngle).Invoke(this, value) = S_OK Then bolRet = True
      10. End If
      11. Return bolRet
      12. End Function


      Ein Delegate und eine Funktion hinzufügen:

      VB.NET-Quellcode

      1. Private Delegate Function IReferenceDouble_GetValue(<[In]> this As IntPtr,
      2. <Out> ByRef value As Double) As Integer
      3. Private Function ReferenceDouble_GetValue(this As IntPtr,
      4. ByRef value As Double) As Boolean
      5. Dim pVTablePtr As IntPtr
      6. Dim bolRet As Boolean = False
      7. If this <> IntPtr.Zero AndAlso GetVTablePtr(this, VTable_Interfaces.IReferenceDouble_GetValue, pVTablePtr) Then
      8. If CType(Marshal.GetDelegateForFunctionPointer(pVTablePtr, GetType(IReferenceDouble_GetValue)),
      9. IReferenceDouble_GetValue).Invoke(this, value) = S_OK Then bolRet = True
      10. End If
      11. Return bolRet
      12. End Function


      und zu guter letzt die Function GetOcrResults durch folgede ersetzen:

      VB.NET-Quellcode

      1. Private Function GetOcrResults(pIRandomAccessStream As IntPtr) As Boolean
      2. Dim bolRet As Boolean = False
      3. Dim pISoftwareBitmap As IntPtr = IntPtr.Zero
      4. If GetSoftwareBitmapFromRandomAccessStream(pIRandomAccessStream, pISoftwareBitmap) Then
      5. Dim pIOcrResult As IntPtr = IntPtr.Zero
      6. If OcrEngine_RecognizeAsync(m_pIOcrEngine, pISoftwareBitmap, pIOcrResult) Then
      7. If WaitForAsync(pIOcrResult) Then
      8. GetUsedOcrLanguage()
      9. Dim pIReferenceDouble As IntPtr = IntPtr.Zero
      10. If OcrResult_GetTextAngle(pIOcrResult, pIReferenceDouble) Then
      11. ReferenceDouble_GetValue(pIReferenceDouble, m_tOcrResults.TextAngle)
      12. Release(pIReferenceDouble)
      13. End If
      14. Dim hString As IntPtr = IntPtr.Zero
      15. If OcrResult_GetText(pIOcrResult, hString) Then
      16. m_tOcrResults.TextComplete = Marshal.PtrToStringUni(WindowsGetStringRawBuffer(hString, 0))
      17. End If
      18. bolRet = GetTextLinesFromOcrResult(pIOcrResult)
      19. End If
      20. Release(pIOcrResult)
      21. End If
      22. CloseAndRelease(pISoftwareBitmap)
      23. End If
      24. Return bolRet
      25. End Function
      Mfg -Franky-
      Auch wenn es schon ein paar Tage her ist:
      Ich habe ein wenig damit rumgespielt und festgestellt, dass einzeilige Texte nicht konvertiert werden.
      Macht man aus dem Einzeiler im Paint einen Zweizeiler (Textverdoppelung), funktioniert das wieder.

      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hi

      Hmm, kannst Du mal ein paar Bilder hier ranhängen das man Dein Problem nachvollziehen kann? Dann würde ich mir das mal anschauen. Auf die eigentliche OCR hat man ja kaum Zugriff. Nur auf das Ergebnis das die OCR zurück liefert und die Erkennung ist von mehreren Faktoren abhängig (DPI, Schräglage usw.).
      Mfg -Franky-

      -Franky- schrieb:

      ein paar Bilder hier ranhängen
      Hängen an Post #10.
      Ein Einzeiler, der nicht funktioniert und der doppelte Einzeiler, der funktioniertz.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hi

      Jau, IOcrResult.GetText gibt im letzten Parameter (hString) = 0 zurück. Also kein Text erkannt. Die Funktion IOcrResult.GetText / IOcrResult.GetLines sind aber erfolgreich (S_OK) durchgelaufen. Wenn Du die entsprechende Zeile in Notepad mit entsprechend großer Schriftgröße packst, wird auch die einzelne Zeile erkannt. Allerdings eher sehr schlecht. Die Windows eigene OCR ziehlt eher auf "normale" Wörter/Text, wie das hier, ab und nicht auf Text einer Programmiersprache. Ist halt kein Abbyy Finereader. ;)
      Mfg -Franky-
      Klaro.
      Wenn man es weiß, kann man ja immer einen Mehrzeiler reinpacken.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!