使用 C#.NET 的 OMR 扫描仪软件

光学标记识别 (OMR) 是一种自动捕获和分析标记在特殊类型文档表单上的数据的过程。这种特殊类型的文件可以由人们在调查表、测试表和其他纸质文件上标记/填写。在本文中,我们将学习如何使用 C# 开发基于 GUI 的 OMR Sheet Reader 应用程序。我们的解决方案将扫描的 OMR 表图像作为本地磁盘的输入,然后识别标记,最后以 CSV 格式导出标记的注册号和阴影答案。完成上述步骤后,我们将拥有 .NET 中的 C# 光学标记识别 (OMR) 软件。那么让我们开始吧。

文章应涵盖以下主题:

  1. C#光学标记识别(OMR)软件的特点
  2. C#光学标记识别.NET API和UI控件
  3. 开发OMR软件的步骤
  4. C#光学标记识别(OMR)软件演示
  5. 下载OMR软件源代码

C# 光学标记识别 (OMR) 软件的特点

我们的光学标记识别 (OMR) 软件将具有以下功能:

  1. 交互式调整识别参数并实时观察其效果。我们可以调整以下内容:
    • 识别阈值
    • 飞涨
    • 显示/隐藏气泡
  2. 选择并加载以下格式的扫描图像:
  3. 识别图像上的光学标记。
  4. 以 CSV 格式导出结果并将其保存到本地磁盘。

C# 光学标记识别 .NET API 和 UI 控制

Aspose.OMR for .NET API 允许设计、创建和识别答题纸、测试、MCQ 试卷、测验、反馈表、调查和选票。此外,它还提供了一个图形用户界面控件,可以添加到 .NET UI 应用程序中。我们将在 .NET UI 应用程序中集成 Aspose.OMR for .NET UI 控件,以开发 OMR 扫描仪/阅读器应用程序。请下载 API 的 DLL 或使用 NuGet 安装它。

PM> Install-Package Aspose.OMR

开发 OMR 软件的步骤

我们可以按照以下步骤开发基于 GUI 的 OMR 扫描仪/阅读器应用程序:

  • 首先,创建一个新项目并选择 WPF App (.NET Framework) 项目模板。
Create a new project and select the project template
  • 接下来,在配置新项目对话框中,输入项目名称,选择位置,并设置其他参数。
配置您的 WPF 应用程序项目

配置您的 WPF 应用程序项目

  • 然后,打开 NuGet 包管理器并安装 Aspose.OMR for .NET 包。
为 .NET 安装 Aspose.OMR

为 .NET 安装 Aspose.OMR

  • 接下来,将新文件 DialogHelper.cs 添加到项目中。
添加 DialogHelper 类

添加 DialogHelper.cs

  • 将以下代码添加到新创建的 DialogHelper.cs。
internal class DialogHelper
{
    ///<summary>
    /// 打开模板图像的对话框的过滤器字符串。
    ///</summary>
    private static readonly string ImageFilesFilterPrompt = "Image files |*.jpg; *.jpeg; *.png; *.gif; *.tif; *.tiff;";

    ///<summary>
    /// 保存识别结果的对话框的过滤字符串
    ///</summary>
    private static readonly string DataExportFilesFilterPrompt = "Comma-Separated Values (*.csv)" + " | *.csv";

    ///<summary>
    /// 显示打开图像文件对话框。
    ///</summary>
    ///<returns>所选文件的路径,或<c>无效的</c>如果没有选择文件。</returns>
    public static string ShowOpenImageDialog(string suggestedDir = null)
    {
        OpenFileDialog dialog = new OpenFileDialog();
        return ShowDialog(dialog, ImageFilesFilterPrompt, suggestedDir);
    }

    ///<summary>
    /// 显示保存识别结果文件对话框。
    ///</summary>
    ///<returns>所选文件的路径,或<c>无效的</c>如果没有选择文件。</returns>
    public static string ShowSaveDataDialog(string suggestedName)
    {
        SaveFileDialog dialog = new SaveFileDialog();
        return ShowDialog(dialog, DataExportFilesFilterPrompt, suggestedName);
    }

    ///<summary>
    /// 显示给定的对话框并将其结果作为<c>细绳</c>.
    ///</summary>
    ///<param name="dialog">要显示的对话框。</param>
    ///<param name="filter">文件类型过滤字符串。</param>
    ///<param name="suggestedDir">建议的对话框初始目录</param>
    ///<param name="suggestedName">建议的文件名</param>
    ///<returns>所选文件的路径,或<c>无效的</c>如果没有选择文件。</returns>
    private static string ShowDialog(FileDialog dialog, string filter, string suggestedDir = null, string suggestedName = null)
    {
        string fileName = null;

        dialog.Filter = filter;
        dialog.RestoreDirectory = true;
        if (suggestedName != null)
        {
            dialog.FileName = suggestedName;
        }

        if (suggestedDir != null)
        {
            dialog.InitialDirectory = suggestedDir;
        }

        bool? result = dialog.ShowDialog();
        if (result == true)
        {
            fileName = dialog.FileName;
        }

        return fileName;
    }
}
  • 接下来,使用以下 XAML 内容更新 MainWindow.xaml 文件。
<Window x:Class="OMR_APP.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:OMR_APP"
        mc:Ignorable="d"
        Title="Aspose OMR Demo" Height="880" Width="1100">
    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>

        <ToolBar Grid.Row="0" Background="LightGray">
            <TextBox Name="txtTemplatePath" Margin="5" Width="400" Height="30" Background="White"
                     HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
            </TextBox>
            <Button  Margin="5" Width="100" Height="30" Background="White"
                     Content="Get control" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
                     Click="GetButtonClicked"/>
            <Separator/>

            <Button  Margin="5" Width="100" Height="30" Background="White"
                     Content="Select Image" Click="SelectImageClicked"/>

            <Button  Margin="5" Width="100" Height="30" Background="White"
                     Content="Recognize Image" Click="RecognizeImageClicked"/>

            <Button  Margin="5" Width="100" Height="30" Background="White"
                     Content="Export Results" Click="ExportResultsClicked"/>
        </ToolBar>

        <ContentControl Grid.Row="1" x:Name="CustomContentControl"
                        HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>
  • 之后,替换 MainWindow.xaml.cs 文件中的以下内容。
///<summary>
/// 测试模板
///</summary>
private static readonly string TemplateFilePath = @"C:\Files\OMR\Sheet.omr";

///<summary>
///许可证Aspose.OMR.NET.lic文件的路径
///</summary>
private static readonly string LicensePath = @"";

private CorrectionControl control;

public MainWindow()
{
    InitializeComponent();

    // 设置并显示模板文件路径
    txtTemplatePath.Text = TemplateFilePath;

    // 设置许可证,提供许可证文件路径并取消注释以测试完整结果
    //许可证 lic = 新许可证();
    //lic.SetLicense(LicensePath);
}

public string UserImagePath { get; set; }

public string DataFolderPath { get; set; }


///<summary>
/// 加载并显示 CorrectionControl
///</summary>
private void GetButtonClicked(object sender, RoutedEventArgs e)
{
    string path = txtTemplatePath.Text;

    try
    {
        OmrEngine engine = new OmrEngine();
        TemplateProcessor processor = engine.GetTemplateProcessor(path);

        control = engine.GetCorrectionControl(processor);
        CustomContentControl.Content = control;
        control.Initialize();
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message,"Exception");
    }
}

///<summary>
/// 选择并显示图像 
///</summary>
private void SelectImageClicked(object sender, RoutedEventArgs e)
{
    if (control == null)
    {
        return;
    }

    string imagePath = DialogHelper.ShowOpenImageDialog(this.DataFolderPath);
    if (string.IsNullOrEmpty(imagePath))
    {
        return;
    }

    this.UserImagePath = imagePath;

    control.LoadAndDisplayImage(imagePath);
}

///<summary>
/// 识别加载的图像
///</summary>
private void RecognizeImageClicked(object sender, RoutedEventArgs e)
{
    if (control == null)
    {
        return;
    }

    control.RecognizeImage();
}

///<summary>
/// 将结果导出到 CSV
///</summary>
private void ExportResultsClicked(object sender, RoutedEventArgs e)
{
    if (control == null)
    {
        return;
    }

    string imageName = Path.GetFileNameWithoutExtension(this.UserImagePath);

    string path = DialogHelper.ShowSaveDataDialog(imageName);
    if (string.IsNullOrEmpty(path))
    {
        return;
    }

    control.ExportResults(path);

    MessageBox.Show("The exported resultant CSV file can be found here : " + path, "Operation Successful");
}
  • 最后,运行应用程序。

C# 光学标记识别 (OMR) 软件演示

以下是我们刚刚创建的 OMR Scanner/Reader 应用程序的演示。

C# OMR 软件演示

OMR 软件演示

下载 OMR 软件源代码

您可以从 GitHub 下载 OMR Scanner 应用程序的完整源代码。

获得免费许可证

您可以获得免费的临时许可证 试用该库而不受评估限制。

结论

在本文中,我们学习了如何

  • 在 .NET 应用程序中集成 Aspose.OMR for .NET UI 控件;
  • 在 C# 中开发 OMR 表阅读器应用程序。

此外,您可以使用 文档 了解更多关于 Aspose.OMR for .NET API 的信息。如有任何歧义,请随时在我们的 论坛 上与我们联系。

也可以看看