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

如何在Blazor中编写文件上传与图像分类并展示结果的代码

Blazor 文件上传与图像分类实现(适配.NET 7/8)

针对旧视频版本不符的问题,以下是基于官方原生组件+当前主流框架版本的实现方案,覆盖Blazor Server和WebAssembly两种场景,直接整合文件上传、图像预览、分类推理与结果展示全流程。


一、核心UI组件(通用)

使用Blazor原生InputFile组件(.NET 5+标准内置,替代旧视频中的第三方/自定义上传组件),实现文件选择、预览与分类触发逻辑:

@page "/image-classifier"
@inject IImageClassifierService ClassifierService

<h3>图像上传与分类</h3>

<div class="upload-area">
    <InputFile OnChange="HandleFileSelected" accept="image/*" multiple="false" />
</div>

@if (selectedImage != null)
{
    <div class="image-preview">
        <img src="@imageDataUrl" alt="上传预览" style="max-width: 400px; max-height: 400px;" />
        <p>文件名: @selectedImage.Name</p>
        <p>文件大小: @(selectedImage.Size / 1024) KB</p>
    </div>

    @if (classificationResult != null)
    {
        <div class="result-card">
            <h4>分类结果(Top 5):</h4>
            <ul>
                @foreach (var item in classificationResult)
                {
                    <li>@item.Label: @(item.Score * 100):0.##%</li>
                }
            </ul>
        </div>
    }
    else if (isProcessing)
    {
        <p>正在分析图像...</p>
    }
}

@code {
    private IBrowserFile? selectedImage;
    private string? imageDataUrl;
    private List<ClassificationResult>? classificationResult;
    private bool isProcessing;

    private async Task HandleFileSelected(InputFileChangeEventArgs e)
    {
        selectedImage = e.File;
        isProcessing = true;
        classificationResult = null;

        // 生成预览图(限制10MB以内文件)
        var imageStream = selectedImage.OpenReadStream(maxAllowedSize: 10 * 1024 * 1024);
        var imageBytes = await imageStream.ReadAllAsync();
        imageDataUrl = $"data:{selectedImage.ContentType};base64,{Convert.ToBase64String(imageBytes)}";

        // 调用分类服务
        classificationResult = await ClassifierService.ClassifyImageAsync(imageBytes);
        isProcessing = false;
    }

    // 统一分类结果模型
    public class ClassificationResult
    {
        public string Label { get; set; } = string.Empty;
        public float Score { get; set; }
    }
}

二、图像分类服务实现

根据Blazor部署类型选择对应方案:

1. Blazor Server(用ML.NET)

直接使用ML.NET加载预训练图像分类模型,适合服务器端推理:

服务代码

public interface IImageClassifierService
{
    Task<List<ClassificationResult>> ClassifyImageAsync(byte[] imageBytes);
}

public class MLNetImageClassifierService : IImageClassifierService
{
    private readonly PredictionEngine<ImageInput, ImagePrediction> _predictionEngine;

    public MLNetImageClassifierService()
    {
        // 加载预训练模型(需提前将模型文件放入项目Models目录)
        var mlContext = new MLContext();
        var model = mlContext.Model.Load("Models/ImageClassificationModel.zip", out _);
        _predictionEngine = mlContext.Model.CreatePredictionEngine<ImageInput, ImagePrediction>(model);
    }

    public async Task<List<ClassificationResult>> ClassifyImageAsync(byte[] imageBytes)
    {
        // 图像预处理:裁剪为模型要求的224x224尺寸
        using var stream = new MemoryStream(imageBytes);
        var image = Image.Load(stream);
        image.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(224, 224), Mode = ResizeMode.Crop }));

        // 执行推理
        var input = new ImageInput { Image = image };
        var prediction = _predictionEngine.Predict(input);

        // 整理排序结果
        var results = prediction.Score
            .Select((score, index) => new ClassificationResult
            {
                Label = prediction.Label[index],
                Score = score
            })
            .OrderByDescending(x => x.Score)
            .Take(5)
            .ToList();

        return await Task.FromResult(results);
    }

    // ML.NET输入输出模型
    public class ImageInput
    {
        [ImageType(224, 224)]
        public Bitmap Image { get; set; } = null!;
    }

    public class ImagePrediction
    {
        [ColumnName("Score")]
        public float[] Score { get; set; } = null!;

        [ColumnName("Label")]
        public string[] Label { get; set; } = null!;
    }
}

服务注册(Program.cs)

builder.Services.AddScoped<IImageClassifierService, MLNetImageClassifierService>();

2. Blazor WebAssembly(用ONNX Runtime)

由于WASM不支持System.Drawing,使用ONNX Runtime Web加载轻量型预训练模型(如MobileNetV2):

安装依赖

通过NuGet安装:Microsoft.ML.OnnxRuntime.WebAssembly

服务代码

public class OnnxImageClassifierService : IImageClassifierService
{
    private readonly InferenceSession _session;
    private readonly List<string> _labels;

    public OnnxImageClassifierService()
    {
        // 加载ONNX模型与标签文件(需放入wwwroot/models目录)
        var modelBytes = await File.ReadAllBytesAsync("wwwroot/models/mobilenetv2.onnx");
        _session = new InferenceSession(modelBytes);
        _labels = (await File.ReadAllLinesAsync("wwwroot/models/imagenet-labels.txt")).ToList();
    }

    public async Task<List<ClassificationResult>> ClassifyImageAsync(byte[] imageBytes)
    {
        // 图像预处理:归一化、转换为ONNX要求的张量格式
        using var stream = new MemoryStream(imageBytes);
        var image = await Image.LoadAsync(stream);
        image.Mutate(x => x.Resize(new ResizeOptions { Size = new Size(224, 224), Mode = ResizeMode.Crop }));

        var tensor = new DenseTensor<float>(new[] { 1, 3, 224, 224 });
        for (int y = 0; y < 224; y++)
        {
            for (int x = 0; x < 224; x++)
            {
                var pixel = image[x, y];
                tensor[0, 0, y, x] = (pixel.R / 255f - 0.485f) / 0.229f;
                tensor[0, 1, y, x] = (pixel.G / 255f - 0.456f) / 0.224f;
                tensor[0, 2, y, x] = (pixel.B / 255f - 0.406f) / 0.225f;
            }
        }

        // 执行推理
        var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("input", tensor) };
        using var results = await _session.RunAsync(inputs);
        var outputTensor = results.First().AsTensor<float>();

        // 整理结果
        var classificationResults = outputTensor
            .Select((score, index) => new ClassificationResult
            {
                Label = _labels[index],
                Score = score
            })
            .OrderByDescending(x => x.Score)
            .Take(5)
            .ToList();

        return classificationResults;
    }
}

服务注册(Program.cs)

builder.Services.AddScoped<IImageClassifierService, OnnxImageClassifierService>();

三、版本适配注意事项

  • 旧视频中可能使用的InputFileComponent已被官方原生InputFile替代(.NET 5+内置,无需额外包)
  • Blazor Server可直接使用ML.NET,WASM需用ONNX Runtime(避免System.Drawing依赖问题)
  • 模型/标签文件需放在对应目录:Server端放Models,WASM端必须放wwwroot/models

四、可选样式优化

添加CSS提升界面体验:

.upload-area {
    padding: 20px;
    border: 2px dashed #ccc;
    border-radius: 8px;
    text-align: center;
    margin-bottom: 20px;
    cursor: pointer;
}

.image-preview {
    margin: 20px 0;
}

.result-card {
    padding: 15px;
    background-color: #f5f5f5;
    border-radius: 8px;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 12:25:28