Freigeben über


Erste Schritte mit KI-Texterkennung (OCR) im Windows App-SDK

Wichtig

Im neuesten experimentellen Kanal-Release für das Windows App SDK verfügbar.

Der experimentelle Kanal des Windows App SDK enthält APIs und Features in frühen Entwicklungsphasen. Alle APIs im experimentellen Kanal unterliegen umfangreichen Überarbeitungen und Breaking Changes und können jederzeit aus nachfolgenden Versionen entfernt werden. Die Verwendung experimenteller Features wird in Produktionsumgebungen nicht unterstützt. Apps, die sie verwenden, können im Microsoft Store nicht veröffentlicht werden.

  • Nicht gepackte Apps werden nicht unterstützt.

Die Texterkennung, auch als optische Zeichenerkennung (Optical Character Recognition, OCR) bezeichnet, wird vom Windows App-SDK über eine Reihe durch künstliche Intelligenz (KI) gesicherte APIs unterstützt, die Text in Bildern erkennen und extrahieren und in maschinenlesbare Zeichenströme konvertieren können.

Diese APIs können Zeichen, Wörter, Zeilen, polygonale Textgrenzen identifizieren und Konfidenzniveaus für jede Übereinstimmung bereitstellen. Sie werden auch ausschließlich von der Hardwarebeschleunigung in Geräten mit einer neuralen Verarbeitungseinheit (Neural Processing Unit, NPU) unterstützt, sodass sie schneller und genauer als die älteren Windows.Media.OcrEngine-APIs im Windows-Plattform-SDK sind.

API-Details enthält die API-Referenz für Texterkennung (OCR) im Windows App SDK.

Tipp

Senden Sie Ihr Feedback zu diesen APIs und deren Funktionalität, indem Sie ein neues Issue im GitHub-Repository des Windows App SDK erstellen (mit OCR im Titel) oder indem Sie auf ein vorhandenes Issue antworten.

Voraussetzungen

Was kann ich mit dem Windows App SDK und der KI-Texterkennung tun?

Mit den KI-Texterkennungsfeatures im Windows App SDK können Sie Text in einem Bild identifizieren und erkennen. Sie können auch die Textbegrenzungen und Konfidenzbewertungen für den erkannten Text abrufen.

Erstellen eines ImageBuffers aus einer Datei

In diesem Beispiel wird eine LoadImageBufferFromFileAsync-Funktion aufgerufen, um einen ImageBuffer aus einer Bilddatei abzurufen.

In der LoadImageBufferFromFileAsync-Funktion führen wir die folgenden Schritte aus:

  1. Erstellen Sie ein StorageFile-Objekt aus dem angegebenen Dateipfad.
  2. Öffnen Sie einen Stream in der StorageFile mit OpenAsync.
  3. Erstellen Sie einen neuen BitmapDecoder für den Stream.
  4. Rufen Sie GetSoftwareBitmapAsync für den Bitmap-Decoder auf, um ein SoftwareBitmap-Objekt abzurufen.
  5. Geben Sie einen Bildpuffer aus CreateBufferAttachedToBitmap zurück.
using Microsoft.Windows.Vision;
using Microsoft.Windows.Imaging;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;

public async Task<ImageBuffer> LoadImageBufferFromFileAsync(string filePath)
{
    StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
    IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
    BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
    SoftwareBitmap bitmap = await decoder.GetSoftwareBitmapAsync();

    if (bitmap == null)
    {
        return null;
    }

    return ImageBuffer.CreateBufferAttachedToBitmap(bitmap);
}
namespace winrt
{
    using namespace Microsoft::Windows::Vision;
    using namespace Microsoft::Windows::Imaging;
    using namespace Windows::Graphics::Imaging;
    using namespace Windows::Storage;
    using namespace Windows::Storage::Streams;
}

winrt::IAsyncOperation<winrt::ImageBuffer> LoadImageBufferFromFileAsync(
    const std::wstring& filePath)
{
    auto file = co_await winrt::StorageFile::GetFileFromPathAsync(filePath);
    auto stream = co_await file.OpenAsync(winrt::FileAccessMode::Read);
    auto decoder = co_await winrt::BitmapDecoder::CreateAsync(stream);
    auto bitmap = co_await decoder.GetSoftwareBitmapAsync();
    if (bitmap == nullptr) {
        co_return nullptr;
    }
    co_return winrt::ImageBuffer::CreateBufferAttachedToBitmap(bitmap);
}

Erkennen von Text in einem Bitmapbild

Das folgende Beispiel zeigt, wie ein Text in einem SoftwareBitmap-Objekt als einzelne Zeichenkette erkannt werden kann:

  1. Erstellen Sie ein TextRecognizer-Objekt über einen Aufruf der EnsureModelIsReady-Funktion, wodurch auch bestätigt wird, dass ein Sprachmodell in dem System vorhanden ist.
  2. Mit der im vorherigen Codeausschnitt abgerufenen Bitmap rufen wir die RecognizeTextFromSoftwareBitmap Funktion auf.
  3. Rufen Sie CreateBufferAttachedToBitmap in der Bilddatei auf, um ein ImageBuffer-Objekt abzurufen.
  4. Rufen Sie RecognizeTextFromImage auf, um den erkannten Text aus dem ImageBuffer abzurufen.
  5. Erstellen Sie ein wstringstream-Objekt, und laden Sie es mit dem erkannten Text.
  6. Gibt die Zeichenfolge zurück.

Hinweis

Die Funktion EnsureModelIsReady wird verwendet, um den Bereitschaftsstatus des Texterkennungsmodells zu überprüfen (und bei Bedarf zu installieren).

using Microsoft.Windows.Vision;
using Microsoft.Windows.Imaging;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;

public async Task<string> RecognizeTextFromSoftwareBitmap(SoftwareBitmap bitmap)
{
    TextRecognizer textRecognizer = await EnsureModelIsReady();
    ImageBuffer imageBuffer = ImageBuffer.CreateBufferAttachedToBitmap(bitmap);
    RecognizedText recognizedText = textRecognizer.RecognizeTextFromImage(imageBuffer);
    StringBuilder stringBuilder = new StringBuilder();

    foreach (var line in recognizedText.Lines)
    {
        stringBuilder.AppendLine(line.Text);
    }

    return stringBuilder.ToString();
}

public async Task<TextRecognizer> EnsureModelIsReady()
{
    if (!TextRecognizer.IsAvailable())
    {
        var loadResult = await TextRecognizer.MakeAvailableAsync();
        if (loadResult.Status != PackageDeploymentStatus.CompletedSuccess)
        {
            throw new Exception(loadResult.ExtendedError().Message);
        }
    }

    return await TextRecognizer.CreateAsync();
}
namespace winrt
{
    using namespace Microsoft::Windows::Vision;
    using namespace Microsoft::Windows::Imaging;
    using namespace Windows::Graphics::Imaging;
}

winrt::IAsyncOperation<winrt::TextRecognizer> EnsureModelIsReady();

winrt::IAsyncOperation<winrt::hstring> RecognizeTextFromSoftwareBitmap(winrt::SoftwareBitmap const& bitmap)
{
    winrt::TextRecognizer textRecognizer = co_await EnsureModelIsReady();
    winrt::ImageBuffer imageBuffer = winrt::ImageBuffer::CreateBufferAttachedToBitmap(bitmap);
    winrt::RecognizedText recognizedText = textRecognizer.RecognizeTextFromImage(imageBuffer);
    std::wstringstream stringStream;
    for (const auto& line : recognizedText.Lines())
    {
        stringStream << line.Text().c_str() << std::endl;
    }
    co_return winrt::hstring{stringStream.view()};
}

winrt::IAsyncOperation<winrt::TextRecognizer> EnsureModelIsReady()
{
  if (!winrt::TextRecognizer::IsAvailable())
  {
    auto loadResult = co_await winrt::TextRecognizer::MakeAvailableAsync();
    if (loadResult.Status() != winrt::PackageDeploymentStatus::CompletedSuccess)
    {
        throw winrt::hresult_error(loadResult.ExtendedError());
    }
  }

  co_return winrt::TextRecognizer::CreateAsync();
}

Abrufen von Wortgrenzen und Konfidenz

Hier zeigen wir, wie man die BoundingBox eines jeden Wortes in einem SoftwareBitmap-Objekt als eine Sammlung von farbkodierten Polygonen auf einem Grid-Element visualisiert.

Hinweis

In diesem Beispiel wird davon ausgegangen, dass ein TextRecognizer-Objekt bereits erstellt und an die Funktion übergeben wurde.

using Microsoft.Windows.Vision;
using Microsoft.Windows.Imaging;
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;

public void VisualizeWordBoundariesOnGrid(
    SoftwareBitmap bitmap,
    Grid grid,
    TextRecognizer textRecognizer)
{
    ImageBuffer imageBuffer = ImageBuffer.CreateBufferAttachedToBitmap(bitmap);
    RecognizedText result = textRecognizer.RecognizeTextFromImage(imageBuffer);

    SolidColorBrush greenBrush = new SolidColorBrush(Microsoft.UI.Colors.Green);
    SolidColorBrush yellowBrush = new SolidColorBrush(Microsoft.UI.Colors.Yellow);
    SolidColorBrush redBrush = new SolidColorBrush(Microsoft.UI.Colors.Red);

    foreach (var line in result.Lines)
    {
        foreach (var word in line.Words)
        {
            PointCollection points = new PointCollection();
            var bounds = word.BoundingBox;
            points.Add(bounds.TopLeft);
            points.Add(bounds.TopRight);
            points.Add(bounds.BottomRight);
            points.Add(bounds.BottomLeft);

            Polygon polygon = new Polygon();
            polygon.Points = points;
            polygon.StrokeThickness = 2;

            if (word.Confidence < 0.33)
            {
                polygon.Stroke = redBrush;
            }
            else if (word.Confidence < 0.67)
            {
                polygon.Stroke = yellowBrush;
            }
            else
            {
                polygon.Stroke = greenBrush;
            }

            grid.Children.Add(polygon);
        }
    }
}
namespace winrt
{
    using namespace Microsoft::Windows::Vision;
    using namespace Microsoft::Windows::Imaging;
    using namespace Micrsooft::Windows::UI::Xaml::Controls;
    using namespace Micrsooft::Windows::UI::Xaml::Media;
    using namespace Micrsooft::Windows::UI::Xaml::Shapes;
}

void VisualizeWordBoundariesOnGrid(
    winrt::SoftwareBitmap const& bitmap,
    winrt::Grid const& grid,
    winrt::TextRecognizer const& textRecognizer)
{
    winrt::ImageBuffer imageBuffer = winrt::ImageBuffer::CreateBufferAttachedToBitmap(bitmap);
    
    winrt::RecognizedText result = textRecognizer.RecognizeTextFromImage(imageBuffer);

    auto greenBrush = winrt::SolidColorBrush(winrt::Microsoft::UI::Colors::Green);
    auto yellowBrush = winrt::SolidColorBrush(winrt::Microsoft::UI::Colors::Yellow);
    auto redBrush = winrt::SolidColorBrush(winrt::Microsoft::UI::Colors::Red);
    
    for (const auto& line : recognizedText.Lines())
    {
        for (const auto& word : line.Words())
        {
            winrt::PointCollection points;
            const auto& bounds = word.BoundingBox();
            points.Append(bounds.TopLeft);
            points.Append(bounds.TopRight);
            points.Append(bounds.BottomRight);
            points.Append(bounds.BottomLeft);

            winrt::Polygon polygon;
            polygon.Points(points);
            polygon.StrokeThickness(2);

            if (word.Confidence() < 0.33)
            {
                polygon.Stroke(redBrush);
            }
            else if (word.Confidence() < 0.67)
            {
                polygon.Stroke(yellowBrush);
            }
            else
            {
                polygon.Stroke(greenBrush);
            }

            grid.Children().Add(polygon);
        }
    }
}

Zusätzliche Ressourcen

Zugreifen auf Dateien und Ordner mit Windows App SDK und WinRT-APIs