Language/C# WPF

[WPF] Microsoft.Ink로 필기인식(숫자인식 Handwriting digit recognition) 해보기

멱군 2021. 5. 12. 18:55

WPF(Windows Presentation Foundation)에서는 Microsoft.Ink 라이브러리를 통해 필기 인식 기능을 제공한다. 특히, 사용자가 직접 쓴 숫자(Handwritten digit recognition)를 인식하는 작업을 수행할 때 이 라이브러리가 큰 도움이 된다. 이 글에서는 WPF 프로젝트에서 Microsoft.Ink를 활용하여 필기 숫자 인식 기능을 구현하는 방법에 대해 상세하게 설명한다.

 

 

1. 시작 전 필요한 참고

자료 필기 인식 기능 구현을 위한 주요 참고 자료는 Microsoft의 공식 문서에서 제공된다.

 

필기 인식 - WPF .NET Framework

WPF 플랫폼의 디지털 링크에 관련되므로 필기 인식의 기본 개념을 알아봅니다.

learn.microsoft.com

 

2. WPF 프로젝트 세팅 및 인터페이스 구성

프로젝트를 시작하기 위해서는 WPF 프로젝트를 생성하고, 필요한 XAML 요소를 추가해야 한다. Canvas, InkCanvas, TextBox, Button 등의 요소를 포함한 인터페이스를 구성한다. 인터페이스는 사용자가 숫자를 필기로 입력하고, 인식 버튼을 클릭하면 입력된 숫자를 인식하여 결과를 보여주는 구조로 이루어져 있다.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="379.289">
    <Canvas Name="theRootCanvas">
        <Border
      Background="White"
      BorderBrush="Black"
      BorderThickness="2"
      Height="300"
      Width="300"
      Canvas.Top="10"
      Canvas.Left="10">
            <InkCanvas Name="theInkCanvas"></InkCanvas>
        </Border>
        <TextBox Name="textBox1"
      Height="25"
      Width="225"
      Canvas.Top="325"
      Canvas.Left="10"></TextBox>
        <Button
      Height="25"
      Width="75"
      Canvas.Top="325"
      Canvas.Left="235"
      Click="buttonClick">Recognize</Button>
        <Button x:Name="btnClear" Content="Clear Canvas" Canvas.Left="10" Canvas.Top="367" Width="75" Click="btnClear_Click"/>
    </Canvas>
</Window>

그러면 위 그림처럼 프로그램 모양이 나온다.

 

3. 필기 인식 기능 구현

버튼의 동작을 구현하기 위해 'Recognize' 버튼과 'Clear Canvas' 버튼의 이벤트 핸들러를 추가한다. theInkCanvas.Strokes.Save() 메서드를 사용하여 필기 입력 내용을 저장하고, RecognizerContext를 사용하여 필기 내용을 인식한다. 인식 결과는 여러 개의 대체 항목(Alternates)으로 반환되며, 숫자만을 원할 경우, int.TryParse 메서드를 사용하여 숫자만을 필터링한다.

  • 'Recognize' 버튼
private void buttonClick(object sender, RoutedEventArgs e)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                theInkCanvas.Strokes.Save(ms);
                var myInkCollector = new InkCollector();
                var ink = new Ink();
                ink.Load(ms.ToArray());

                Recognizers recs = new Recognizers();
                Recognizer reco = recs.GetDefaultRecognizer();
                

                using (RecognizerContext context = new RecognizerContext())
                {
                    if (ink.Strokes.Count > 0)
                    {
                        context.Strokes = ink.Strokes;

                        RecognitionStatus status = RecognitionStatus.NoError;
                        RecognitionResult result = context.Recognize(out status);

                        if (status == RecognitionStatus.NoError)
                        {
                            string text = "";
                            foreach (RecognitionAlternate alt in result.GetAlternatesFromSelection())
                            {
                                text += alt.ToString() + "\r\n";                                
                            }
                            MessageBox.Show(text);
                        }
                        else
                            MessageBox.Show("Recognition failed");
                    }
                    else
                    {
                        MessageBox.Show("No stroke detected");
                    }
                }
            }
        }

 

  • 'Clear Canvas' 버튼
private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            theInkCanvas.Strokes.Clear();
        }

그러면,

처럼 캔버스 안에서 필기를 하면 해당하는 결과를 얻을 수 있다. 보통 제일 먼저 나오는 값이 최적의 결과치 이므로 result.TopString 의 값을 결과값으로 사용하면 된다.

 

4. 인식 결과 처리

RecognitionStatus를 통해 인식 상태를 확인하고, 성공적으로 인식되면 결과를 TextBox에 표시한다.

필기로 숫자만 입력을 받고 싶은데 1을 그렸는데,

다양한 결과값들이 나왔다.

그래서 숫자로 변환이 되는 값만 true로 지정하여 결과값을 사용함으로써 숫자를 인식하기로 했다.

private void buttonClick(object sender, RoutedEventArgs e)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                theInkCanvas.Strokes.Save(ms);
                var myInkCollector = new InkCollector();
                var ink = new Ink();
                ink.Load(ms.ToArray());

                Recognizers recs = new Recognizers();
                Recognizer reco = recs.GetDefaultRecognizer();
                

                using (RecognizerContext context = new RecognizerContext())
                {
                    if (ink.Strokes.Count > 0)
                    {
                        context.Strokes = ink.Strokes;

                        RecognitionStatus status = RecognitionStatus.NoError;
                        RecognitionResult result = context.Recognize(out status);

                        if (status == RecognitionStatus.NoError)
                        {
                            string text = "";
                            int nconvert = 0;
                            bool bfind = false;
                            foreach (RecognitionAlternate alt in result.GetAlternatesFromSelection())
                            {
                                text = alt.ToString();
                                if (int.TryParse(text, out nconvert))
                                {
                                    bfind = true;
                                    break;
                                }
                            }
                            if(bfind) textBox1.Text = nconvert.ToString();
                            else textBox1.Text = "인식하지 못했습니다.";
                            
                        }
                        else
                            MessageBox.Show("Recognition failed");
                    }
                    else
                    {
                        MessageBox.Show("No stroke detected");
                    }
                }
            }
        }

숫자 외의 값은 필터링하여 최종적으로 숫자만을 결과로 반환한다. 만약 인식에 실패하거나 입력된 필기가 없을 경우, 알림 메시지를 표시한다.

 

결론적으로,

Microsoft.Ink 라이브러리는 WPF에서 필기 인식 기능을 간단하게 구현할 수 있게 해준다. 특히, 숫자 인식 작업에 있어서 이 라이브러리를 활용하면, 높은 인식률과 함께 원하는 결과를 얻을 수 있다. 이러한 기능은 다양한 응용 프로그램에서 활용될 수 있으며, 사용자 경험을 향상시키는 데 기여한다.

아래파일은 본포스팅에서 사용한 WPF Microsoft.Ink로 필기인식 프로젝트이다. 필요하신 분들은 참고해도 좋을 듯하다.

Handwriting recognition.zip
0.19MB