The NumberSage project is a C# application that recognizes handwritten digits using a pre-trained ONNX model. The project leverages the Windows InkCanvas for drawing and Microsoft’s Machine Learning libraries for prediction.
Initial release.
- Draw digits on the InkCanvas.
- Load an ONNX model for digit recognition.
- Perform real-time digit recognition.
- Display prediction results and confidence scores.
- .NET Framework
- Microsoft.ML.OnnxRuntime
- Windows Machine Learning Code Generator (Extension)
- Load the solution file in Visual Studio.
- Go to [ Python Environments ] Window and click on the [ "Add environment" ] button.
- Click on the [ Existing Enviroment ] tab and set Enviroment to [ torch 3.7 64-bit ].
- Right-click on the project title and Click on [ Set as StartUp Project ] on the popup menu.
- Press [ F5 ] to Execute and debug the project.
- Right-click on the project title and Click on [ Set as StartUp Project ].
- Right-click on the project title and Click on [ Manage Nuget Packages... ] on the popup menu.
- Search for the [ Microsoft.ML.OnnxRuntime ] package and install it.
- Press [F5] to Execute and debug the project.
- Follow the instructions shown in the application.
- Initialize Components : The main form initializes and sets up the InkCanvas where the user can draw digits.
- Load Model : An ONNX model is loaded to perform the digit recognition.
- Draw Digit : Users draw digits on the InkCanvas.
- Normalize Input : The drawn digit is captured and normalized by dividing each pixel value by 255.
- Predict Digit : The normalized input is passed to the ONNX model which predicts the digit.
- Display Result : The predicted digit and confidence scores are displayed.
The constructor initializes the form and the InkCanvas.
public Main()
{
InitializeComponent();
InitializeCanvas();
}
Normalizes the input, performs prediction using the ONNX model, and displays the result.
private void Predict(float[] digit)
{
var x = new DenseTensor<float>(digit.Length);
for (int i = 0; i < digit.Length; i++)
x[i] = ((digit[i] / 255) - 0.1307f) / 0.3081f;
var input = NamedOnnxValue.CreateFromTensor<float>("0", x);
var output = _session.Run(new[] { input }).First().AsTensor<float>().ToArray();
var pred = Array.IndexOf(output, output.Max());
ShowResult(pred, output, 0, Exp);
}
Captures the drawn digit from the InkCanvas and prepares it for prediction.
private float[] GetWrittenDigit(int size = 28)
{
RenderTargetBitmap b = new RenderTargetBitmap(
(int)_inkCanvas.ActualWidth, (int)_inkCanvas.ActualHeight,
96d, 96d, PixelFormats.Default);
b.Render(_inkCanvas);
var bitmap = new WriteableBitmap(b).Resize(size, size, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
float[] data = new float[size * size];
for (int x = 0; x < bitmap.PixelWidth; x++)
{
for (int y = 0; y < bitmap.PixelHeight; y++)
{
var color = bitmap.GetPixel(x, y);
data[y * bitmap.PixelWidth + x] = 255 - ((color.R + color.G + color.B) / 3);
}
}
return data;
}
- Load Model : Click on the [ Load Model ] button and select an ONNX model file.
- Draw Digit : Draw a digit on the InkCanvas.
- Recognize : Click on the [ Recognize ] button to predict the drawn digit.
- Clear : Click on the [ Clear ] button to clear the canvas and start again.
Copyright ⓒ HappyBono 2021 - 2025. All rights Reserved.
This project is licensed under the MIT License. See the LICENSE
file for details.
This project references classes from: Basic MNIST Example from GitHub (PyTorch)