yolov10--C#接口

一、前言

     本章主要讲解yolov10的C#接口,主要是使用微软开发的openvinocsharp工具加载yolov10模型,并做推理。

二、yolov10模型转换

     这里为了演示,使用官方yolov10m模型(其他大小的模型同理)做演示,可从下方下载,当然也可以是自己训练好的模型

https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10m.pt

      该原始模型,需要被转换为openvinocsharp所支持的模型格式,为此需要建立一个yolov10的python环境,使用conda创建,requirements.txt 为 yolov10官方代码下的所需包

conda create -n yolov10 python=3.9
conda activate yolov10
pip install -r requirements.txt
pip install -e .

然后安装OpenVINO™环境,输入以下指令

pip install openvino==2024.1.0

在该创建好的虚拟环境,cd 至下载好的yolov10m.pt 所在目录,执行

yolo export model=yolov10m.pt format=onnx opset=11 simplify
ovc yolov10m.onnx

这样,pt文件的模型将转换为onnx文件,再换换为 openvino 所需的 bin 和 xml 文件格式

三、C#端openvinosharp相关包安装

         首先需使用VS2022构建项目,其次将openvinosharp相关包安装上

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="OpenCvSharp4" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.Extensions" Version="4.9.0.20240103" />
    <PackageReference Include="OpenCvSharp4.runtime.win" Version="4.9.0.20240103" />
    <PackageReference Include="OpenVINO.CSharp.API" Version="2024.1.0.1" />
    <PackageReference Include="OpenVINO.CSharp.API.Extensions.OpenCvSharp" Version="1.0.4" />
    <PackageReference Include="OpenVINO.runtime.win" Version="2024.1.0.1" />
  </ItemGroup>

</Project>

也就是  OpenCvSharp4、OpenCvSharp4.Extensions、OpenCvSharp4.runtime.win、OpenVINO.CSharp.API、OpenVINO.CSharp.API.Extensions.OpenCvSharp、OpenVINO.runtime.win,这6个包给装上

这部分参考自下面博客

【OpenVINO™】在C#中使用 OpenVINO™ 部署 YOLOv10 模型实现目标_yolov10 openvino-CSDN博客

四、C#加载yolo10推理代码

这样就可以创建C# winform项目,愉快地加载前面转换好的模型文件做前向推理了

// See https://aka.ms/new-console-template for more information
//Console.WriteLine("Hello, World!");

using System.Reflection;
using System.Runtime.InteropServices;
using System;
using OpenVinoSharp;
using OpenVinoSharp.Extensions.utility;
using OpenVinoSharp.Extensions;
using OpenCvSharp;
using OpenCvSharp.Dnn;
using OpenVinoSharp.preprocess;

namespace yolov10_det_opencvsharp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            string model_path = "./model_demo/yolov10m.xml";
            string image_path = "./model_demo/cat.png";
            string device = "AUTO";  //CPU GPU AUTO,可选AUTO模式

      

            // -------- Get OpenVINO runtime version --------

            OpenVinoSharp.Version version = Ov.get_openvino_version();

            Slog.INFO("---- OpenVINO INFO----");
            Slog.INFO("Description : " + version.description);
            Slog.INFO("Build number: " + version.buildNumber);

            Slog.INFO("Predict model files: " + model_path);
            Slog.INFO("Predict image  files: " + image_path);
            Slog.INFO("Inference device: " + device);
            Slog.INFO("Start yolov10 model inference.");

            //yolov10_det(model_path, image_path, device);
            yolov10_det_process(model_path, image_path , device);
        }
        static void yolov10_det(string model_path, string image_path, string device)
        {
            DateTime start = DateTime.Now;
            // -------- Step 1. Initialize OpenVINO Runtime Core --------
            Core core = new Core();
            DateTime end = DateTime.Now;
            Slog.INFO("1. Initialize OpenVINO Runtime Core success, time spend: " + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 2. Read inference model --------
            start = DateTime.Now;
            Model model = core.read_model(model_path);
            end = DateTime.Now;
            Slog.INFO("2. Read inference model success, time spend: " + (end - start).TotalMilliseconds + "ms.");
            OvExtensions.printf_model_info(model);
            // -------- Step 3. Loading a model to the device --------
            start = DateTime.Now;
            CompiledModel compiled_model = core.compile_model(model, device);
            end = DateTime.Now;
            Slog.INFO("3. Loading a model to the device success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 4. Create an infer request --------
            start = DateTime.Now;
            InferRequest infer_request = compiled_model.create_infer_request();
            end = DateTime.Now;
            Slog.INFO("4. Create an infer request success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 5. Process input images --------
            start = DateTime.Now;
            Mat image = new Mat(image_path); // Read image by opencvsharp
            int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
            Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
            Rect roi = new Rect(0, 0, image.Cols, image.Rows);
            image.CopyTo(new Mat(max_image, roi));
            float factor = (float)(max_image_length / 640.0);
            end = DateTime.Now;
            Slog.INFO("5. Process input images success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 6. Set up input data --------
            start = DateTime.Now;
            Tensor input_tensor = infer_request.get_input_tensor();
            Shape input_shape = input_tensor.get_shape();
            Mat input_mat = CvDnn.BlobFromImage(max_image, 1.0 / 255.0, new OpenCvSharp.Size(input_shape[2], input_shape[3]), 0, true, false);
            float[] input_data = new float[input_shape[1] * input_shape[2] * input_shape[3]];
            Marshal.Copy(input_mat.Ptr(0), input_data, 0, input_data.Length);
            input_tensor.set_data<float>(input_data);

            end = DateTime.Now;
            Slog.INFO("6. Set up input data success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 7. Do inference synchronously --------
            infer_request.infer();
            start = DateTime.Now;
            infer_request.infer();
            end = DateTime.Now;
            Slog.INFO("7. Do inference synchronously success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 8. Get infer result data --------
            start = DateTime.Now;
            Tensor output_tensor = infer_request.get_output_tensor();
            int output_length = (int)output_tensor.get_size();
            float[] output_data = output_tensor.get_data<float>(output_length);
            end = DateTime.Now;
            Slog.INFO("8. Get infer result data success, time spend:" + (end - start).TotalMilliseconds + "ms.");

             -------- Step 9. Process reault  --------
            start = DateTime.Now;

            List<Rect> position_boxes = new List<Rect>();
            List<int> class_ids = new List<int>();
            List<float> confidences = new List<float>();

            // Preprocessing output results
            for (int i = 0; i < output_data.Length / 6; i++)
            {
                int s = 6 * i;
                if ((float)output_data[s + 4] > 0.5)
                {
                    float cx = output_data[s + 0];
                    float cy = output_data[s + 1];
                    float dx = output_data[s + 2];
                    float dy = output_data[s + 3];
                    int x = (int)((cx) * factor);
                    int y = (int)((cy) * factor);
                    int width = (int)((dx - cx) * factor);
                    int height = (int)((dy - cy) * factor);
                    Rect box = new Rect();
                    box.X = x;
                    box.Y = y;
                    box.Width = width;
                    box.Height = height;

                    position_boxes.Add(box);
                    class_ids.Add((int)output_data[s + 5]);
                    confidences.Add((float)output_data[s + 4]);
                }
            }


            end = DateTime.Now;
            Slog.INFO("9. Process reault  success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            for (int i = 0; i < class_ids.Count; i++)
            {
                int index = i;
                Cv2.Rectangle(image, position_boxes[index], new Scalar(0, 0, 255), 2, LineTypes.Link8);
                Cv2.Rectangle(image, new OpenCvSharp.Point(position_boxes[index].TopLeft.X, position_boxes[index].TopLeft.Y + 30),
                    new OpenCvSharp.Point(position_boxes[index].BottomRight.X, position_boxes[index].TopLeft.Y), new Scalar(0, 255, 255), -1);
                Cv2.PutText(image, class_ids[index] + "-" + confidences[index].ToString("0.00"),
                    new OpenCvSharp.Point(position_boxes[index].X, position_boxes[index].Y + 25),
                    HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 0), 2);
            }
            string output_path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(image_path)),
                Path.GetFileNameWithoutExtension(image_path) + "_result.jpg");
            Cv2.ImWrite(output_path, image);
            Slog.INFO("The result save to " + output_path);
            Cv2.ImShow("Result", image);
            Cv2.WaitKey(0);
        }
        static void yolov10_det_process(string model_path, string image_path, string device)
        {
            DateTime start = DateTime.Now;
            // -------- Step 1. Initialize OpenVINO Runtime Core --------
            Core core = new Core();
            DateTime end = DateTime.Now;
            Slog.INFO("1. Initialize OpenVINO Runtime Core success, time spend: " + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 2. Read inference model --------
            start = DateTime.Now;
            Model model = core.read_model(model_path);
            end = DateTime.Now;
            Slog.INFO("2. Read inference model success, time spend: " + (end - start).TotalMilliseconds + "ms.");
            OvExtensions.printf_model_info(model);
            PrePostProcessor processor = new PrePostProcessor(model);
            Tensor input_tensor_pro = new Tensor(new OvType(ElementType.U8), new Shape(1, 640, 640, 3));   //注意这个地方要改和模型窗口一致,模型是640,这里也要640
            InputInfo input_info = processor.input(0);
            InputTensorInfo input_tensor_info = input_info.tensor();
            input_tensor_info.set_from(input_tensor_pro).set_layout(new Layout("NHWC")).set_color_format(ColorFormat.BGR);

            PreProcessSteps process_steps = input_info.preprocess();
            process_steps.convert_color(ColorFormat.RGB).resize(ResizeAlgorithm.RESIZE_LINEAR)
                .convert_element_type(new OvType(ElementType.F32)).scale(255.0f).convert_layout(new Layout("NCHW"));
            Model new_model = processor.build();
            // -------- Step 3. Loading a model to the device --------
            start = DateTime.Now;
            CompiledModel compiled_model = core.compile_model(new_model, device);
            end = DateTime.Now;
            Slog.INFO("3. Loading a model to the device success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 4. Create an infer request --------
            start = DateTime.Now;
            InferRequest infer_request = compiled_model.create_infer_request();
            end = DateTime.Now;
            Slog.INFO("4. Create an infer request success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 5. Process input images --------
            start = DateTime.Now;
            Mat image = new Mat(image_path); // Read image by opencvsharp
            int max_image_length = image.Cols > image.Rows ? image.Cols : image.Rows;
            Mat max_image = Mat.Zeros(new OpenCvSharp.Size(max_image_length, max_image_length), MatType.CV_8UC3);
            Rect roi = new Rect(0, 0, image.Cols, image.Rows);
            image.CopyTo(new Mat(max_image, roi));
            Cv2.Resize(max_image, max_image, new OpenCvSharp.Size(640, 640));   //注意这个地方要改和模型窗口一致,模型是640,这里也要640
            float factor = (float)(max_image_length / 640.0);
            end = DateTime.Now;
            Slog.INFO("5. Process input images success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 6. Set up input data --------
            start = DateTime.Now;
            Tensor input_tensor = infer_request.get_input_tensor();
            Shape input_shape = input_tensor.get_shape();
            byte[] input_data = new byte[input_shape[1] * input_shape[2] * input_shape[3]];
            //max_image.GetArray<int>(out input_data);
            Marshal.Copy(max_image.Ptr(0), input_data, 0, input_data.Length);
            IntPtr destination = input_tensor.data();
            Marshal.Copy(input_data, 0, destination, input_data.Length);

            end = DateTime.Now;
            Slog.INFO("6. Set up input data success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            // -------- Step 7. Do inference synchronously --------
            infer_request.infer();
            start = DateTime.Now;
            infer_request.infer();
  
            end = DateTime.Now;
            Slog.INFO("7. Do inference synchronously success, time spend:" + (end - start).TotalMilliseconds + "ms.");

            // -------- Step 8. Get infer result data --------
            start = DateTime.Now;
            Tensor output_tensor = infer_request.get_output_tensor();
            int output_length = (int)output_tensor.get_size();
            float[] output_data = output_tensor.get_data<float>(output_length);
            end = DateTime.Now;
            Slog.INFO("8. Get infer result data success, time spend:" + (end - start).TotalMilliseconds + "ms.");

             -------- Step 9. Process reault  --------
            start = DateTime.Now;

            List<Rect> position_boxes = new List<Rect>();
            List<int> class_ids = new List<int>();
            List<float> confidences = new List<float>();

            // Preprocessing output results
            for (int i = 0; i < output_data.Length / 6; i++)
            {
                int s = 6 * i;
                if ((float)output_data[s + 4] > 0.2)
                {
                    float cx = output_data[s + 0];
                    float cy = output_data[s + 1];
                    float dx = output_data[s + 2];
                    float dy = output_data[s + 3];
                    int x = (int)((cx) * factor);
                    int y = (int)((cy) * factor);
                    int width = (int)((dx - cx) * factor);
                    int height = (int)((dy - cy) * factor);
                    Rect box = new Rect();
                    box.X = x;
                    box.Y = y;
                    box.Width = width;
                    box.Height = height;

                    position_boxes.Add(box);
                    class_ids.Add((int)output_data[s + 5]);
                    confidences.Add((float)output_data[s + 4]);
                }
            }


            end = DateTime.Now;
            Slog.INFO("9. Process reault  success, time spend:" + (end - start).TotalMilliseconds + "ms.");
            for (int i = 0; i < class_ids.Count; i++)
            {
                int index = i;
                Cv2.Rectangle(image, position_boxes[index], new Scalar(0, 0, 255), 2, LineTypes.Link8);
                Cv2.Rectangle(image, new OpenCvSharp.Point(position_boxes[index].TopLeft.X, position_boxes[index].TopLeft.Y + 30),
                    new OpenCvSharp.Point(position_boxes[index].BottomRight.X, position_boxes[index].TopLeft.Y), new Scalar(0, 255, 255), -1);
                Cv2.PutText(image, class_ids[index] + "-" + confidences[index].ToString("0.00"),
                    new OpenCvSharp.Point(position_boxes[index].X, position_boxes[index].Y + 25),
                    HersheyFonts.HersheySimplex, 0.8, new Scalar(0, 0, 0), 2);
            }
            string output_path = Path.Combine(Path.GetDirectoryName(Path.GetFullPath(image_path)),
                Path.GetFileNameWithoutExtension(image_path) + "_result.jpg");
            Cv2.ImWrite(output_path, image);
            Slog.INFO("The result save to " + output_path);
            Cv2.ImShow("Result", image);
            Cv2.WaitKey(0);
        }
    }
}


五、输出结果

        运行代码,可以得到统计的代码加载、预处理、推理的运行时间,并且得到识别结果,类别号、置信度、以及位置

       有显卡的话,可将模型AUTO改为GPU,运行时间会更快些。。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/730422.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

iptables(5)常用扩展模块

简介 之前我们已经介绍过扩展模块的简单使用,比如使用-m tcp/udp ,-m multiport参数通过--dports,--sports可以设置连续和非连续的端口范围。那么我们如何匹配其他的一些参数呢,比如源地址范围,目的地址范围,时间范围等,这就是我们这篇文章介绍的内容。 iprange扩展模块…

Ubuntu系统下修改网卡IP地址

Ubuntu系统下修改网卡IP地址 一、Ubuntu系统介绍1.1 Ubuntu简介1.2 Ubuntu网络配置方式 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、配置网卡IP地址4.1 备份网卡配置文件4.2 查看当前IP地址4.3 修改…

0.15元1.5Mhz-1.3A同步整流BUCK降压DCDC芯片MT3410(MT3410LB)

前言 国产同步整流DCDC&#xff0c;参考价格约0.15元。 特征 高效率&#xff1a;高达 96% 1.5MHz恒定频率操作 1.3A 输出电流 无需肖特基二极管 2.3V至7V输入电压范围 输出电压低至 0.6V PFM 模式可在轻负载下实现高效率 压差操作中的100%占空比 低静态电流&#xff1a;35μ…

刘亦菲新剧玫瑰的故事

刘亦菲新剧《玫瑰的故事》&#xff1a;开放结局&#xff0c;无限遐想 当刘亦菲再次踏入荧屏&#xff0c;与导演汪俊携手打造的《玫瑰的故事》便引发了无数观众的期待与关注。这部剧不仅汇聚了众多实力派演员&#xff0c;更以其独特的剧情和精致的制作成为了近期热门的话题。《…

(项目实战)RocketMQ5.0延迟消息在聚合支付系统中的应用

1 基于业务场景掌握RocketMQ5.0 本篇文章主要结合聚合支付系统中的业务场景来落地RocketMQ中间件的应用&#xff0c;聚合支付系统主要在支付系统超时订单和商户支付结果异步通知场景中会使用到RocketMQ消息中间件。本文使用到了RocketMQ中的延迟消息知识点&#xff0c;RocketM…

JavaScript知识点大总结来了-------这一篇就足够啦!!!

JavaScript基础知识 一、对象的使用 1、创建对象 这里创建对象的方法我们采用最常用的一种&#xff1a; //第一种 <script>var Person {name: "zhangsan",age: "19",weight: "140",hight: "170",print:function(){console.…

【Android】我的手机在...自己下载...那个(浅析Intent基础运用)

【Android】我的手机在…自己下载…那个&#xff08;浅析Intent基础运用&#xff09; 在Android开发中&#xff0c;Intent&#xff08;意图&#xff09;是一个非常重要的概念。它不仅仅是用于在应用程序的各个组件之间进行通信的工具&#xff0c;也是启动新的Activity、Servic…

恭喜行云绽放,24年再度荣获国家鼓励的企业软件证书

在刚刚过去的五月份&#xff0c;行云绽放再次传来一个好消息&#xff0c;那就是2024年行云绽放再度荣获国家鼓励的企业软件证书。 什么是国家鼓励的企业软件证书&#xff1f; 国家鼓励的企业软件证书被称为“国家鼓励的软件企业证书”&#xff0c;这一证书由中国软件行业协会…

预制直埋聚氨酯保温管:卓越管道,引领未来

在管道领域中&#xff0c;预制直埋聚氨酯保温管宛如一颗璀璨明珠&#xff0c;散发着独特的光芒。 它具备卓越的保温性能&#xff0c;犹如给流体输送穿上了一层温暖的保护衣&#xff0c;有效减少热量损耗&#xff0c;实现高效的能源利用。其坚固的结构能够轻松应对各种复杂环境…

七析BI入门指南:数据资源管理

数据BI是指解决企业数据“最后一公里”&#xff0c;帮助企业全方位提高数据决策能力的数据可视化平台&#xff0c;提供平台级多租户管理&#xff0c;统一安全策略&#xff0c;精细化权限管理&#xff0c;支持与低代码平台接入集成&#xff0c;与七巧低代码平台高度融合。 数据B…

ssl证书90天过期?保姆级教程——使用acme.sh实现证书的自动续期

腾讯云相关文档相关参考-有的点不准确 前言 最近https到期了&#xff0c;想着手动更新一下https证书&#xff0c;结果发现证书现在的有效期只有90天&#xff0c;于是想找到一个自动更新证书的工具&#xff0c;发现了acme.sh&#xff0c;但是网上的文章质量参差不齐&#xff0…

Linux使用Docker部署mysql5.7

一、拉取镜像 docker pull mysql:5.7 二、查看镜像 docker images 三、创建容器 这里稍微解释下 -p参数是端口映射 -v参数是数据卷挂载 数据卷挂载是Docker中的一种功能&#xff0c;它允许将主机上的目录或文件系统与容器内的目录绑定&#xff0c;实现数据的持久化存储…

德璞资本:科技股波动解析,三巫日与日元效应下的市场走向

摘要 近期&#xff0c;美国科技股的表现令人担忧&#xff0c;标普500指数在科技股的拖累下出现下跌。亚洲股市也受到影响&#xff0c;特别是日本和韩国股市。随着期权到期日的临近&#xff0c;市场面临更大的波动风险。本文将详细分析科技股失去动能的原因、三巫日的影响及未来…

C#ListView的单元格支持添加基本及自定义任意控件

功能说明 使用ListView时&#xff0c;希望可以在单元格显示图片或其他控件&#xff0c;发现原生的ListView不支持&#xff0c;于是通过拓展&#xff0c;实现ListView可以显示任意控件的功能&#xff0c;效果如下&#xff1a; 实现方法 本来想着在单元格里面实现控件的自绘的…

消息队列kafka中间件详解:案例解析(第10天)

系列文章目录 1- 消息队列&#xff08;熟悉&#xff09;2- Kafka的基本介绍&#xff08;掌握架构&#xff0c;其他了解&#xff09;3- Kafka的相关使用&#xff08;掌握kafka常用shell命令&#xff09;4- Kafka的Python API的操作&#xff08;熟悉&#xff09; 文章目录 系列文…

拒绝吸烟,远离慢阻肺——朗格力复合营养素助力守护肺部健康

#肺科营养#朗格力#班古营养#复合营养素#肺部营养#肺部健康# 你知道吗?慢阻肺这一疾病在我国的患者数量已突破亿级大关,尤其在40岁以上的成年人中,平均每7个人中就有1位可能受其困扰。然而,很多人对慢阻肺的严重性认识不足,常常将其视为一种普通的咳嗽或喘息,忽视了它潜在的危…

ChatGPT 提示词技巧一本速通

目录 一、基本术语 二、提示词设计的基本原则 三、书写技巧 2.1 赋予角色 2.2 使用分隔符 2.2 结构化输出 2.3 指定步骤 2.4 提供示例 2.5 指定长度 2.6 使用或引用参考文本 2.7 提示模型进行自我判断 2.8 思考问题的解决过程 ​编辑 2.10 询问是否有遗漏 2.11 …

Consul 如何删除不需要的服务

一、找到需要删除的id 二、打开postman 使用put请求 http://ip:port/v1/agent/service/deregister/mc-admin-192-168-0-182-8084三、区域如果要验证输入验证

倍思突破氮化镓快充技术,为用户带来安全舒适体验

氮化镓,这个化学式为GaN的化合物,其高热稳定性和化学稳定性使其在多种极端环境中都能保持优良的性能,从而为其在电子器件领域的应用奠定了坚实的基础。 2018年前后开始,氮化镓快充充电器进入国内市场。作为第三代半导体材料的代表,氮化镓具有宽禁带的特性,其禁带宽度远大于传统…

芋道源码 yudao-cloud 、Boot 文档,开发指南 看全部,破解[芋道快速开发平台 Boot + Cloud]

1、文档全部保存本地部署查看&#xff0c;真香 文档已抓取最新版本&#xff0c;2024.06.21。【唯一遗憾&#xff0c;表结构到2024.04月&#xff0c;已被限制放到知识星球】会员中心&#xff0c;支付中心&#xff0c;CRM&#xff0c;ERP&#xff0c;商城&#xff0c;公众号运行…