영어로 읽기

다음을 통해 공유


Windows 앱 SDK OCR(텍스트 인식) 시작

중요

이 기능은 아직 사용할 수 없습니다. 그것은 Windows 앱 SDK 곧 실험 채널 릴리스에서 제공 될 것으로 예상된다.

Windows 앱 SDK 실험 채널에는 개발 초기 단계의 API 및 기능이 포함됩니다. 실험적 채널의 모든 API는 광범위한 수정 및 호환성이 손상되는 변경이 적용되며 언제든지 후속 릴리스에서 제거될 수 있습니다. 프로덕션 환경에서는 사용할 수 없으며 실험적 기능을 사용하는 앱은 Microsoft Store에 게시할 수 없습니다.

OCR(광학 문자 인식)라고도 하는 텍스트 인식은 이미지 내에서 텍스트를 감지 및 추출하고 컴퓨터에서 읽을 수 있는 문자 스트림으로 변환할 수 있는 AI(인공 지능) 지원 API 집합을 통해 Windows 앱 SDK 지원 됩니다.

이러한 API는 문자, 단어, 선, 다각형 텍스트 경계를 식별하고 각 일치 항목에 대한 신뢰도 수준을 제공할 수 있습니다. 또한 NPU(신경 처리 장치)가 있는 디바이스에서 하드웨어 가속을 통해서만 지원되므로 Windows 플랫폼 SDK의 레거시 Windows.Media.Ocr.OcrEngine API보다 빠르고 정확합니다.

API 세부 정보는 Windows 앱 SDK AI 지원 OCR(텍스트 인식)에 대한 API 참조를 참조하세요.

Windows 앱 SDK GitHub 리포지토리에서 새 문제를 만들어 이러한 API 및 해당 기능에 대한 피드백을 제공합니다. (제목에 OCR을 포함해야 합니다.)

필수 조건

Windows 앱 SDK 및 AI 텍스트 인식으로 무엇을 할 수 있나요?

Windows 앱 SDK 새로운 AI 텍스트 인식 기능을 사용하여 이미지의 텍스트를 식별하고 인식합니다. 인식된 텍스트의 텍스트 경계 및 신뢰도 점수를 가져올 수도 있습니다.

파일에서 ImageBuffer 만들기

이 예제에서는 이미지 파일에서 ImageBufferLoadImageBufferFromFileAsync가져오는 함수를 호출 합니다.

LoadImageBufferFromFileAsync 함수에서 다음 단계를 완료합니다.

  1. 지정된 파일 경로에서 StorageFile 개체를 만듭니다.
  2. OpenAsync를 사용하여 StorageFile에서 스트림을 엽니다.
  3. 스트림에 대한 BitmapDecoder 를 만듭니다.
  4. 비트맵 디코더에서 GetSoftwareBitmapAsync를 호출하여 SoftwareBitmap 개체를 가져옵니다.
  5. CreateBufferAttachedToBitmap에서 이미지 버퍼를 반환합니다.
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);
}

비트맵 이미지에서 텍스트 인식

다음 예제에서는 SoftwareBitmap 개체의 일부 텍스트를 단일 문자열 값으로 인식하는 방법을 보여줍니다.

  1. 함수 호출을 통해 TextRecognizer 개체를 EnsureModelIsReady 만듭니다. 이 개체는 시스템에 언어 모델이 있는지도 확인합니다.
  2. 이전 코드 조각에서 가져온 비트맵을 사용하여 함수를 호출합니다 RecognizeTextFromSoftwareBitmap .
  3. 이미지 파일에서 CreateBufferAttachedToBitmap을 호출하여 ImageBuffer 개체를 가져옵니다.
  4. RecognizeTextFromImage를 호출하여 ImageBuffer에서 인식된 텍스트를 가져옵니다.
  5. wstringstream 개체를 만들고 인식된 텍스트와 함께 로드합니다.
  6. 문자열을 반환합니다.

참고

EnsureModelIsReady 함수는 텍스트 인식 모델의 준비 상태를 확인하고 필요한 경우 설치하는 데 사용됩니다.

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();
}

단어 경계 및 신뢰도 가져오기

여기서는 SoftwareBitmap 개체에 있는 각 단어의 BoundingBox를 Grid 요소의 색으로 구분된 다각형 컬렉션으로 시각화하는 방법을 보여 줍니다.

참고

이 예제에서는 TextRecognizer 개체가 이미 만들어지고 함수에 전달되었다고 가정합니다.

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);
        }
    }
}

추가 리소스

Windows App SDK 및 WinRT API를 사용하여 파일 및 폴더에 액세스