You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将UWP InkCanvas的分辨率降低至28x28像素?

UWP InkCanvas手写数字转为28x28像素位图解决方案

问题背景

我正在开发手写数字识别的神经网络程序,需要在UWP的InkCanvas上捕获手写数字。目前将InkCanvas保存为Bitmap时分辨率远大于28x28,但神经网络输入层是784个节点(对应28x28像素),原分辨率会导致输入节点数超标。

现在我通过MS Paint在28x28画布绘制数字并保存为BMP供程序处理,需要实现将UWP InkCanvas的输出直接转为实际像素数为28x28的位图(不是只修改宽高参数)。

解决方案

要实现目标,核心是对InkCanvas渲染后的图像进行高质量缩放,步骤如下:

  1. 先将InkCanvas渲染到RenderTargetBitmap获取原始像素数据;
  2. 通过BitmapDecoder解码原始图像,再用BitmapEncoder结合BitmapTransform将图像缩放到28x28;
  3. 使用高质量插值模式保证缩放后笔迹的清晰度,避免变形。

修改后的完整代码

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();

        // 设置初始窗口大小
        ApplicationView.PreferredLaunchViewSize = new Windows.Foundation.Size(1000, 800);
        ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;

        // 设置支持的输入设备类型
        inkCanvas.InkPresenter.InputDeviceTypes = Windows.UI.Core.CoreInputDeviceTypes.Mouse;

        // 设置初始笔迹属性
        InkDrawingAttributes drawingAttributes = new InkDrawingAttributes();
        drawingAttributes.Color = Windows.UI.Colors.White;
        drawingAttributes.Size = new Windows.Foundation.Size(2, 2);
        drawingAttributes.IgnorePressure = false;
        drawingAttributes.FitToCurve = true;
        inkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(drawingAttributes);
    }

    private async void saveInkCanvasBitmap()
    {
        RenderTargetBitmap bitmap = new RenderTargetBitmap();
        await bitmap.RenderAsync(grid);

        // 将原始渲染像素写入内存流,用于解码
        var pixelBuffer = await bitmap.GetPixelsAsync();
        using (var inputStream = new InMemoryRandomAccessStream())
        {
            var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, inputStream);
            encoder.SetPixelData(
                BitmapPixelFormat.Bgra8,
                BitmapAlphaMode.Ignore,
                (uint)bitmap.PixelWidth,
                (uint)bitmap.PixelHeight,
                DisplayInformation.GetForCurrentView().RawDpiX,
                DisplayInformation.GetForCurrentView().RawDpiY,
                pixelBuffer.ToArray());
            await encoder.FlushAsync();
            inputStream.Seek(0);

            // 解码图像并执行缩放操作
            var decoder = await BitmapDecoder.CreateAsync(inputStream);
            using (var outputStream = new InMemoryRandomAccessStream())
            {
                var scaledEncoder = await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, outputStream);
                // 设置目标尺寸为28x28
                scaledEncoder.BitmapTransform.ScaledWidth = 28;
                scaledEncoder.BitmapTransform.ScaledHeight = 28;
                // 使用高质量三次插值保证笔迹清晰
                scaledEncoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.HighQualityCubic;
                scaledEncoder.IsThumbnailGenerated = false;

                // 获取缩放后的像素数据并写入编码器
                var pixelData = await decoder.GetPixelDataAsync(
                    BitmapPixelFormat.Bgra8,
                    BitmapAlphaMode.Ignore,
                    scaledEncoder.BitmapTransform,
                    ExifOrientationMode.IgnoreExifOrientation,
                    ColorManagementMode.DoNotColorManage);

                scaledEncoder.SetPixelData(
                    BitmapPixelFormat.Bgra8,
                    BitmapAlphaMode.Ignore,
                    28,
                    28,
                    decoder.DpiX,
                    decoder.DpiY,
                    pixelData.DetachPixelData());

                await scaledEncoder.FlushAsync();
                outputStream.Seek(0);

                // 保存28x28的图像到文件
                StorageFolder pictureFolder = KnownFolders.SavedPictures;
                var file = await pictureFolder.CreateFileAsync("image.bmp", CreationCollisionOption.ReplaceExisting);
                using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    await RandomAccessStream.CopyAsync(outputStream, fileStream);
                }
            }
        }
    }

    private void clearButton_Click(object sender, RoutedEventArgs e)
    {
        // 清空InkCanvas所有笔迹
        inkCanvas.InkPresenter.StrokeContainer.Clear();
    }

    private void submitButton_Click(object sender, RoutedEventArgs e)
    {
        saveInkCanvasBitmap(); // 生成28x28分辨率图像
        // 后续神经网络处理逻辑
    }
}

关键说明

  • 缩放时采用HighQualityCubic插值模式,能最大程度保留手写笔迹的细节,避免缩放后模糊或变形;
  • 整个流程基于UWP原生的BitmapEncoder和BitmapDecoder实现,无需第三方库,性能稳定;
  • 最终保存的文件是实际像素为28x28的BMP,直接匹配神经网络784节点的输入要求。

内容的提问来源于stack exchange,提问作者Cason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:10:21