如何在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
相关产品推荐
相关产品推荐

