欢迎光临
我们一直在努力

踩坑30+后,我把C#上位机AI视觉系统跑在了Windows/Linux工控机上(统一架构+生产级落地)

在这里插入图片描述

一、为什么要做跨平台AI视觉上位机?

在工业自动化项目里,AI视觉检测早已从“锦上添花”变成了产线标配。但过去两年我在十几个项目里反复遇到同一个死局:

  • 客户产线既有Windows工控机(兼容老PLC、Halcon授权),又有Linux/国产工控机(降本、信创要求),两套代码维护成本直接翻倍;
  • 传统方案用C#做上位机UI,Python跑YOLO推理,Socket传结果,延迟高、进程易崩、现场运维要同时维护两个运行时;
  • 换平台就要重写UI、重适配串口/CAN、重调推理环境,一个项目移植周期动辄半个月,现场调试全是坑。

今年我们把整套方案重构了一遍:基于.NET 8 + Avalonia + ONNX Runtime,实现了一套C#代码,同时部署Windows、Linux、国产工控机,AI视觉推理完全原生实现,零Python依赖,代码复用率超过92%。目前已经在3条汽车零部件检测产线、2条3C外观检测产线稳定运行超过6个月。

本文把完整的架构设计、核心实现、部署流程和踩坑清单全部整理出来,所有代码和配置都经过生产环境验证。

二、整体架构:五层分层,一次编译多端运行

整个系统采用分层解耦设计,核心原则是业务逻辑与平台实现完全隔离,所有平台差异都收敛在最底层的抽象层中。

graph TD
A[应用层:AI视觉上位机UI] –> B[业务逻辑层:检测流程/数据管理/报警逻辑]
B –> C[核心能力层]
C –> C1[AI推理引擎:ONNX Runtime]
C –> C2[图像处理:OpenCVSharp]
C –> C3[设备通信:串口/CAN/OPC UA/Modbus]
C –> C4[数据存储:SQLite/日志]
C –> D[跨平台抽象层]
D –> D1[UI渲染抽象:Avalonia]
D –> D2[硬件接口抽象:平台适配]
D –> D3[系统API抽象:文件/进程/权限]
D –> E[硬件与OS层]
E –> E1[Windows 工控机 x64/ARM64]
E –> E2[Linux 工控机 x64/ARM64]
E –> E3[国产系统:统信/银河麒麟]

架构设计的三个核心决策

  • UI层统一用Avalonia,放弃WPF/WinForms
    WPF只能跑Windows,MAUI更偏向消费端移动设备,工业场景的触控屏、无桌面嵌入式环境、长时运行稳定性都不如Avalonia。它支持X11/Wayland/DRM直出,能直接跑在无桌面的Linux工控机上,XAML语法和WPF高度接近,原有WPF代码迁移成本很低。
  • AI推理统一ONNX Runtime,彻底去掉Python
    不管是Windows还是Linux,CPU还是GPU,都用同一套ONNX模型、同一套C#推理代码。ONNX Runtime官方提供了x64/ARM64的原生库,支持CUDA、OpenVINO、TensorRT等加速方案,性能比Python调用ONNX高5%-10%,没有GIL锁,多并发场景优势更明显。
  • 所有硬件接口做抽象,平台差异下沉到底层
    串口、CAN、数字IO、相机SDK都定义统一接口,通过依赖注入根据运行平台注入不同实现。业务层完全感知不到平台差异,新增平台只需要加一个实现类,不需要修改业务代码。
  • 三、核心模块的生产级实现

    3.1 跨平台UI层:从WPF到Avalonia的工业级适配

    Avalonia的跨平台能力很强,但工业场景有很多细节需要单独处理,直接用默认配置大概率会在现场翻车。

    (1)UI与业务完全分离

    采用MVVM架构,ViewModel层完全不引用任何平台相关的API,所有平台操作都通过接口注入。这样不仅方便单元测试,而且UI崩溃不会影响底层的检测流程和设备通信。

    // 平台接口抽象,业务层只依赖这个
    public interface IPlatformService
    {
    string GetSerialPortMapping(string logicalPort);
    string GetAppDataPath();
    void SetBootAutoStart(bool enable);
    }

    // Windows 实现
    public class WindowsPlatformService : IPlatformService { … }

    // Linux 实现
    public class LinuxPlatformService : IPlatformService { … }

    (2)嵌入式Linux无桌面部署

    很多Linux工控机没有安装桌面环境,Avalonia支持直接通过DRM/KMS渲染,不需要X11/Wayland。发布时只需要在入口处调用StartLinuxDrm,就能直接输出到工业触摸屏。

    // Program.cs 跨平台入口
    public static int Main(string[] args)
    {
    if (OperatingSystem.IsLinux() && !args.Contains("–windowed"))
    {
    // 无桌面DRM模式,直接渲染到屏幕
    return BuildAvaloniaApp()
    .StartLinuxDrm(args, DRMOutputOptions.Default);
    }
    return BuildAvaloniaApp()
    .StartWithClassicDesktopLifetime(args);
    }

    (3)工业触摸屏适配

    工业现场操作员戴劳保手套操作,默认的按钮点击区域太小,必须统一扩大点击热区;同时要关闭系统级的触摸手势,避免误操作。

    <!– 工业按钮样式,扩大点击区域 –>
    <Style TargetType="Button" x:Key="IndustrialButton">
    <Setter Property="Padding" Value="24,16"/>
    <Setter Property="MinHeight" Value="56"/>
    <Setter Property="MinWidth" Value="120"/>
    <Setter Property="FontSize" Value="18"/>
    </Style>

    3.2 AI推理引擎:C#原生实现,跨平台性能一致

    这是整套方案的核心。我们彻底抛弃了“C#调Python”的中转方案,所有推理逻辑都用C#原生实现,Windows和Linux使用完全相同的模型文件和推理代码。

    (1)推理引擎选型与配置

    我们选用Microsoft.ML.OnnxRuntime托管包,它是官方维护的C#绑定,性能和兼容性最好。会话配置根据平台自动选择最优执行提供器。

    public class YoloInferenceService : IDisposable
    {
    private readonly InferenceSession _session;
    private readonly string _modelPath;

    public YoloInferenceService(string modelPath, bool useGpu = false)
    {
    _modelPath = modelPath;
    var sessionOptions = new SessionOptions
    {
    ExecutionMode = ExecutionMode.Parallel,
    GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED,
    MemoryPattern = true
    };

    // 平台自动选择加速方案
    if (useGpu && OperatingSystem.IsWindows())
    {
    sessionOptions.AppendExecutionProvider_CUDA(0);
    }
    else if (useGpu && OperatingSystem.IsLinux())
    {
    // Linux下优先OpenVINO,兼容Intel工控机
    sessionOptions.AppendExecutionProvider_OpenVINO("CPU");
    }
    else
    {
    sessionOptions.AppendExecutionProvider_CPU();
    }

    _session = new InferenceSession(modelPath, sessionOptions);
    }
    }

    (2)模型量化与跨平台一致性

    工控机大多是CPU推理,必须对ONNX模型做INT8量化。量化后模型体积减小75%,推理速度提升1.5-2倍,精度损失控制在1%以内,完全满足工业检测要求。

    关键注意点:

    • 模型导出时固定opset版本为12-17,不要盲目用最新版,避免Linux下算子不支持;
    • 量化校准集必须使用现场采集的真实产线图片,不要用公开数据集;
    • 统一使用RGB通道输入,OpenCV读取的BGR图像必须显式转换,否则检测结果坐标和类别全错。
    (3)零拷贝内存优化

    高频推理场景下,频繁创建销毁张量会产生大量内存碎片。我们使用OrtValue复用输入输出缓冲区,结合.NET的Memory<byte>实现零拷贝,长时间运行内存占用稳定。

    实测在i5-12400工控机上,YOLOv12n INT8模型单帧推理耗时28ms,帧率稳定30+,内存峰值150MB以内,连续运行72小时无内存泄漏。

    3.3 设备通信层:跨平台硬件接口抽象

    工业上位机离不开串口、CAN、PLC通信,这也是跨平台移植最容易踩坑的地方。Windows的端口名是COM3,Linux下是/dev/ttyUSB0,如果硬编码到代码里,换平台直接崩溃。

    (1)串口通信统一封装

    public interface ISerialPortService
    {
    bool Open(string logicalPort, int baudRate);
    void Send(byte[] data);
    event Action<byte[]> DataReceived;
    }

    public class CrossPlatformSerialPort : ISerialPortService
    {
    public bool Open(string logicalPort, int baudRate)
    {
    // 平台自动映射端口名
    string physicalPort = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
    ? logicalPort
    : $"/dev/tty{logicalPort.ToUpper().Replace("COM", "USB")}";

    // 权限检查:Linux下需要dialout组权限
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
    {
    if (!File.Exists(physicalPort))
    throw new IOException($"串口设备不存在:{physicalPort}");
    }

    var serialPort = new SerialPort(physicalPort, baudRate);
    serialPort.Open();
    return true;
    }
    }

    (2)CAN与OPC UA的跨平台支持
    • CAN总线:Windows用周立功CAN卡,Linux用SocketCAN,统一封装为ICanService接口,业务层只发收报文;
    • OPC UA:使用OPC Foundation官方跨平台库,Windows和Linux完全通用,不需要任何平台适配;
    • Modbus TCP/RTU:基于NModbus封装,跨平台无差异。

    3.4 图像采集与处理

    工业相机SDK大多同时提供Windows和Linux版本,我们把相机采集封装为统一的ICameraService,支持海康、大恒、Basler等主流相机。

    图像处理统一使用OpenCVSharp4,它的跨平台支持非常成熟,Windows下用OpenCV的dll,Linux下安装libopencv-dev即可。需要注意:

    • Linux下不要用System.Drawing.Common,微软已经停止跨平台支持,工业场景会有各种GDI+依赖问题;
    • 图像格式统一用Mat,不要频繁转换为Bitmap,避免内存拷贝;
    • 相机采集到的图像直接写入ONNX输入缓冲区,实现采集-推理零拷贝。

    四、跨平台部署与运维指南

    4.1 发布配置

    采用.NET自包含发布模式,目标机器不需要安装.NET运行时,拷贝过去就能运行。

    # Windows x64 发布
    dotnet publish -c Release -r win-x64 –self-contained true -p:PublishSingleFile=true

    # Linux x64 发布
    dotnet publish -c Release -r linux-x64 –self-contained true -p:PublishSingleFile=true

    # Linux ARM64 发布(飞腾/瑞芯微工控机)
    dotnet publish -c Release -r linux-arm64 –self-contained true

    4.2 Linux工控机部署步骤

  • 把发布包拷贝到/opt/vision-inspector/目录;
  • 给可执行文件加执行权限:chmod +x VisionInspector;
  • 串口权限:把当前用户加入dialout组,避免每次用sudo;
  • 配置systemd服务,实现开机自启和崩溃自动重启;
  • 无桌面环境下直接运行,DRM模式需要root权限或者video组权限。
  • 4.3 容器化部署(可选)

    对于多设备批量部署,可以打包成Docker镜像,Linux工控机直接拉取运行。Windows容器也支持,但工业现场用得不多。

    FROM mcr.microsoft.com/dotnet/runtime:8.0-jammy
    WORKDIR /app
    COPY publish/ .
    RUN apt-get update && apt-get install -y libopencv-dev libc6-dev
    ENTRYPOINT ["./VisionInspector"]

    五、生产环境踩坑30+,这10个最致命

    跨平台的坑90%都出在平台差异的细节上,很多问题在开发环境不会出现,到了现场才集中爆发。这里列出出现频率最高、影响最大的10个。

    坑点现象根因解决方案
    串口找不到设备 Linux下启动报“端口不存在” Windows是COMx,Linux是/dev/ttyUSBx,硬编码端口名 按平台动态映射端口,提供端口扫描和手动选择界面
    程序启动闪退 Linux工控机双击没反应,日志报GDI+错误 使用了System.Drawing.Common,Linux缺少libgdiplus 全部替换为OpenCVSharp,移除所有System.Drawing引用
    推理结果全错 检测框位置偏移、类别识别错误 OpenCV读取BGR,模型输入RGB,通道顺序反了 推理前显式转换通道,统一预处理逻辑
    无桌面环境无法运行 Linux工控机没装桌面,UI启动失败 默认使用X11渲染,没有X Server 启用Avalonia DRM模式,直接渲染到帧缓冲
    触摸屏点击偏移 屏幕旋转后触摸坐标错位 DRM模式下触摸坐标没有跟随屏幕旋转 配置DrmOutputOptions.Orientation,Avalonia会自动转换触摸坐标
    模型加载失败 Linux下报“算子不支持” ONNX模型opset版本过高,Linux原生库不支持 导出模型固定opset=12,避免使用自定义算子
    长时间运行内存泄漏 运行几小时后内存持续上涨 频繁创建InferenceSession和Mat对象 全局单例会话,复用张量缓冲区,及时释放非托管资源
    老工控机启动崩溃 报“非法指令”错误 新版ONNX Runtime需要AVX2指令集,老CPU不支持 降级到ONNX Runtime 1.15版本,该版本兼容SSE指令集
    CAN通信失败 Linux下CAN卡无法通信 Windows用厂商SDK,Linux需要SocketCAN 统一封装ICanService,Linux下使用SocketCAN实现
    中文显示乱码 Linux下界面中文变成方块 系统缺少中文字体 打包时嵌入思源黑体,Avalonia指定自定义字体

    六、性能实测:Windows vs Linux

    我们在同配置硬件(i5-12400、16G内存、集显)上分别测试了Windows 10 IoT和Ubuntu 22.04的推理性能,模型为YOLOv12n INT8,输入640×640。

    指标Windows 10 IoTUbuntu 22.04差异
    单帧推理耗时 28.1ms 29.3ms +4.3%
    平均帧率 35.6 FPS 34.1 FPS -4.2%
    内存峰值 148 MB 156 MB +5.4%
    程序启动耗时 1.2s 1.5s +25%
    72小时内存增长 +8MB +11MB 均在正常范围

    可以看到,Linux下的推理性能和Windows基本持平,差距在5%以内,完全满足工业现场的实时性要求。如果搭配Intel OpenVINO加速,Linux下的CPU推理性能还能再提升20%-30%。

    七、总结与后续扩展

    这套统一架构最大的价值不是“能跑”,而是把跨平台的复杂度全部收敛到底层,业务开发人员完全不需要关心平台差异。新增一个检测工位,只需要写一次业务逻辑,就能同时部署到Windows和Linux工控机上,项目交付周期缩短了60%。

    后续我们还在做两个方向的优化:

  • 模型热更新:支持产线不停机更新AI模型,不需要重启上位机;
  • 边缘集群调度:多台工控机统一管理模型、配置和检测数据;
  • 国产化深度适配:针对飞腾、鲲鹏、龙芯平台做指令集优化。
  • 如果你的项目也面临Windows/Linux多平台部署、AI视觉集成、老系统改造的问题,这套架构可以直接参考落地。

    赞(0)
    未经允许不得转载:171主机测评 » 踩坑30+后,我把C#上位机AI视觉系统跑在了Windows/Linux工控机上(统一架构+生产级落地)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址