使用 OpenCvSharp 作为图像处理库、OpenVINO 作为推理后端时,需要安装以下核心包:
DeploySharp 基础库及扩展库:
JYPPX.DeploySharpJYPPX.DeploySharp.OpenCvSharp
Runtime 库:
OpenCvSharp4.runtime.win OpenVINO.runtime.win
推理代码如下所示,可直接复制运行:
using OpenCvSharp; // 引入 OpenCvSharp,用于图像的读取、显示和矩阵操作using DeploySharp.Model; // 引入模型定义和配置类using DeploySharp.Data; // 引入数据处理相关的类using DeploySharp.Engine; // 引入推理引擎核心接口和枚举using DeploySharp; // 引入 DeploySharp 主库和可视化工具namespace DeploySharp.OpenCvSharp.Demo{ /// <summary>
/// YOLO26 目标检测演示 (基于OpenVINO + OpenCvSharp)
/// </summary>
public class Yolov26DetDemo
{ public static void Run()
{ // ==========================================
// 1. 路径配置
// ==========================================
// 模型下载提示:模型和测试图片可以前往QQ群(945057948)下载
// 注意:此处加载的是标准的 .onnx 模型文件,而不是 TensorRT 的 .engine 文件。
// ONNX 模型具有良好的跨平台特性。
string modelPath nbemc.cn= @"E:\Model\yolov28\yolo26s.onnx";
// 设置待检测的图片路径
string imagePath = @"E:\Data\image\bus.jpg"; // ==========================================
// 2. 模型配置
// ==========================================
// 创建 YOLO26Det 的配置对象,传入模型路径
Yolov26DetConfig config = new Yolov26DetConfig(modelPath);
// ==========================================
// 3. 类别字典定义 (COCO 80类)
// ==========================================
// 定义 COCO 数据集的 80 个类别名称
// 这些名称将用于在结果可视化时标注检测到的物体
List<string> d www.yfiso9000.com= new List<string> { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear", "hair drier", "toothbrush" }; // 构建<索引, 类别名>字典
Dictionary<int, string> CategoryDict = new Dictionary<int, string>(); for (int i = 0; i < d.Count; i++)
{
CategoryDict[i] = d[i];
}
// 将类别字典赋值给配置对象
config.CategoryDict = CategoryDict; // ==========================================
// 4. 模型初始化
// ==========================================
// 实例化模型,传入配置。
// 此时 DeploySharp 会根据配置加载 ONNX 模型,并初始化 DirectML 会话。
Yolov26DetModel model = new Yolov26DetModel(config);
// 使用 OpenCvSharp 读取图片到 Mat 对象中
// Mat 是 OpenCV 中用于存储图像数据的核心矩阵结构
Mat img = Cv2.ImRead(imagePath); // ==========================================
// 5. 模型推理 (预热与测试)
// ==========================================
// 执行多次推理。
// 第一次推理通常包含模型加载、内存分配等初始化开销,耗时较长。
Result[] result = model.Predict(img);
// 后续推理用于测试稳定的推理速度。
result = model.Predict(img);
result =yfiso9000.com model.Predict(img);
result = model.Predict(img);
// 打印性能分析记录。
// 这将输出推理过程中各阶段(如预处理、推理执行、后处理)的耗时统计。
model.ModelInferenceProfiler.PrintAllRecords();
// 初始化列表,用于存储处理后的图像(本例主要用于演示)
List<Mat> resultsMat = new List<Mat>(); // ==========================================
// 6. 结果可视化与显示
// ==========================================
// 调用可视化工具,将检测框(矩形框)和类别标签绘制在原图上。
// VisualizeOptions(1.0f) 可能指定了缩放比例或字体大小等参数。
var resultImg = Visualize.DrawDetResult(result, img, new VisualizeOptions(1.0f));
// 将绘制好的图像加入列表
resultsMat.Add(resultImg);
// 使用 OpenCV 的窗口显示结果图像。
// "image" 是窗口的标题。
Cv2.ImShow("image", resultImg);
// 等待按键输入。
// 参数 0 表示无限期等待,直到用户按下键盘任意键。
// 这是为了防止控制台程序执行完毕后窗口立即闪退。
上述代码与 3.2 节的代码结构基本相似。使用 OpenVINO 作为推理后端时,通常无需额外设置,因为 DeploySharp 默认支持 OpenVINO。
若设备配备英特尔的集成显卡、独立显卡或 NPU,可通过以下代码指定推理设备以获得更好的性能:
config.SetTargetInferenceBackend(InferenceBackend.OpenVINO); config.SetTargetDeviceType(DeviceType.GPU0); // 设置设备为集显// 或config.SetTargetDeviceType(DeviceType.GPU1); // 设置推理设备为独立显卡
using DeploySharp.Model; // 引入模型配置相关的类 using DeploySharp.Data; // 引入数据结果定义相关的类 using DeploySharp.Engine; // 引入推理引擎核心接口 using DeploySharp; // 引入 DeploySharp 主库及可视化工具 namespace DeploySharp.OpenCvSharp.Demo { m.yfiso9000.com /// <summary> /// YOLO26Seg 实例分割演示类 /// 本示例展示如何加载 TensorRT 引擎文件,对图像进行实例分割推理,并将掩码绘制在原图上。 /// </summary> public class Yolov26SegDemo { public static void Run() { // ========================================== // 1. 路径配置 // ========================================== // 模型下载提示:模型和测试图片可以前往QQ群(945057948)下载 // 设置 TensorRT 引擎文件路径。 // 注意:这里使用的是 .engine 文件,它是针对特定 GPU 和 TensorRT 版本编译的。 // 文件名中的 '-seg' 表示这是一个带有分割头的实例分割模型。 string modelPath m.Lyyqhb.cn= @"D:\Program Files\TensorRT-10.13.0.35-cu11\bin\yolo26s-seg.engine" ; // 设置待推理的图片路径 string wap.yfiso9000.com imagePath = @"E:\Data\image\bus.jpg" ; // ========================================== // 2. 模型配置与初始化 // ========================================== // 创建 YOLO26Seg (实例分割) 的配置对象,传入模型路径 Yolov26SegConfig config = new Yolov26SegConfig(modelPath); // [关键设置] 指定推理后端为 TensorRT。 // 利用 TensorRT 可以在 NVIDIA GPU 上获得极高的推理速度。 config.SetTargetInferenceBackend(InferenceBackend.TensorRT); // 实例化模型。 // 此时会加载引擎文件,初始化 GPU 显存上下文。 Yolov26SegModel model wap.jntmjq.cn= new Yolov26SegModel(config); // ========================================== // 3. 图像加载 // ========================================== // 使用 OpenCvSharp 读取图片。 // img 是一个 Mat 对象,包含了图像的像素数据。 Mat img = Cv2.ImRead(imagePath); // ========================================== // 4. 模型推理 (预热与性能测试) // ========================================== // 执行第一次推理。 // 运行通常包含模型加载、显存分配等开销,耗时较长。 var result = model.Predict(img); // 执行后续多次推理。 // 这是为了排除初始化开销,测试模型在稳定状态下的推理速度。 result = model.Predict(img); result wap.Lyyqhb.cn= model.Predict(img); result =jinditec.com model.Predict(img); // 打印推理性能分析记录。 // 这将输出预处理、推理计算、后处理(包括掩码生成)各阶段的耗时。 model.ModelInferenceProfiler.PrintAllRecords(); // ========================================== // 5. 结果可视化 // ========================================== // 调用可视化工具,绘制分割结果。 // 注意这里使用的是 DrawSegResult (绘制分割结果),而不是 DrawDetResult (绘制检测框)。 // 该函数会将检测到的物体框、类别标签以及彩色的半透明掩码绘制在原图上。 var resultImg www.jinditec.com= Visualize.DrawSegResult(result, img, new VisualizeOptions( 1.0f )); // 使用 OpenCV 窗口显示渲染后的结果图像。 Cv2.ImShow( "image" , resultImg);
2. 支持i.MXRT118x 3. 支持NOR Flash一般读写擦操作 4. 支持UART&USB blhost协议与MCU ROM通信 5. 支持bootloader程序加头(slot0,1 app start, Magic)与下载 6. 支持application程序加头(Len, CRC32, Version, Magic)与下载
Tiny OTA 固件:
1. 支持i.MXRT117x 2. 支持i.MXRT118x 4. 支持主核示例程序(对于双核MCU而言) 4. BL: 仅支持FlexSPI1 XIP application程序管理 (永远从slot 0位置启动) 5. BL: 支持CRC32-MPEG2校验以判断application完整性 6. BL: 复用软件reliable update流程(来自于Kinetis Bootloader) 7. BL: 5秒超时内通过UART&USB blhost与上位机通信,否则跳转进application执行
固件地址 https://github.com/JayHeng/imxrt-tiny-ota-fw/archive/refs/tags/v1.0.zip IDE版本:IAR EWARM v9.70.1
使用 IAR 打开 \imxrt-tiny-ota-fw\targets\imxrt1180\apps\tota_app\cm33 工程(基于SDK hello world XIP 工程),切换到 flex_nor_debug target(工程选项里已经设置了 XIP_BOOT_HEADER_ENABLE=0,即生成的 binary 就是裸的 ARM 程序),当前在其链接文件里设定 ARM 程序起始地址在 FlexSPI1 Flash 的 0x28080000 处,编译生成 tota_app_cm33.bin(bin 起始地址就是 0x28080000),用户可根据需要修改 tota_app 工程链接文件里的 app_image_offset 值。
define symbol m_flash_start = 0x28000000; define symbol app_image_offset = 0x00080000; define symbol m_text_start m.jinditec.com = m_flash_start + app_image_offset;

有了 tota_app_cm33.bin 之后,后续再通过 MCU-TinyOtaUtility 工具加上 OTA 头(包含 Length、CRC32、Version、Magic)并将其烧写到 Flash Slot0 或者 Slot1 位置(注意 Slot 0 对应偏移应与 app_image_offset 一致),OTA 信息位置复用了 ARM Vector Table 里保留的如下几个 Vector。

使用 IAR 打开 \imxrt-tiny-ota-fw\targets\imxrt1180\apps\tota_sbl\cm33 工程(基于SDK flashloader 工程,但是对工程做了一些改动,增加了 ROM boot header,链接文件也从 RAM target 改成了标准 XIP target,此外还使能了黑科技,即利用 IDE 特性将除了 init_data_bss 代码之外的 RO 段全部搬移到 RAM 执行,这样方便运行后续因 application 搬移需要的 Flash 擦写操作),当前在其链接文件里设定 ARM 程序起始地址在 FlexSPI1 Flash 的 0x2800B000 处,编译生成 tota_sbl_cm33.bin(注意 bin 起始地址是 0x28000400,因为包含 fcb 等启动头),一般来说我们无需修改 tota_sbl 工程链接文件。
define symbol m_flash_start = 0x28000000; define symbol app_image_offset = 0x0000B000; define symbol m_text_start = m_flash_start + app_image_offset; define symbol m_fcb_offset = 0x400; define symbol m_fcb_start = m_flash_start + m_fcb_offset; define symbol m_interrupts_ram_start wap.jinditec.com = 0x304A0000;
因为 RT1180 独特的 TRDC 权限管理,在 tota_sbl 工程配套的 container 里的 image_entry.size 长度需要覆盖从 Flash 起始地址一直覆盖到 Slot 0 全部空间,否则会影响 ROM 跳转至 tota_sbl 以及 tota_sbl 跳转到 tota_app 执行。这一点后续可改进为在 tota_sbl 里设置 TRDC 权限来解决 tota_app 跳转权限问题,这样可以减小 container 里的 image_entry.size 长度(仅需覆盖 tota_sbl 空间即可)。

有了 tota_sbl_cm33.bin 之后,后续再通过 MCU-TinyOtaUtility 工具加上 OTA 头(包含 slot0,1 app start, Magic)并将其烧写到 Flash 起始位置(从 fcb 位置开始),OTA 信息位置依然复用了 ARM Vector Table 里保留的如下几个 Vector。这里的 app load addr 参数功能暂时还未实现,后续可用于拓展支持灵活的 application 加载地址配置。

当 Flash Slot 0,1 处分别有了可用的 application,为了调试方便,我们也可以直接手动修改 tota_sbl 工程的 startup 文件里的如下参数值,这样可以直接在线下载调试 tota_sbl 工程,无需通过上位机工具来添加 OTA 头以及烧写。

当 SBL 里 OTA 头 Magic 校验通过,且 slot 0,1 地址有效时,SBL 会执行 Reliable Update 流程。
1. 如果 slot 0,1 程序均无效(无 Magic 或者 CRC 校验失败),直接进入 ISP 模式等待上位机下载 2. 如果 slot 0 程序有效,slot 1 程序无效,5s 超时后跳转至 slot 0 程序执行 3. 如果 slot 0 程序无效,slot 1 程序有效,将 slot 1 程序拷贝至 slot 0 位置,5s 超时后跳转至 slot 0 程序执行 4. 如果 slot 0,1 程序均有效,判断两者的程序版本: - 如果 slot 0 版本不低于 slot 1 版本,5s 超时后跳转至 slot 0 程序执行
Agent绝非单一语言模型的增强版,LLM仅相当于其 “认知中枢”,真正支撑其完整功能的是一套协同运作的多模块架构,成熟可落地的Agent系统至少包含几大核心模块,各模块如同精密团队中的不同角色,各司其职又紧密配合。
加锁时,我们以业务标识作为 key(比如库存锁用 “lock:stock:1001”,1001 为商品 ID),以随机字符串作为 value(后续释放锁时需验证该 value,避免误删他人持有的锁),同时设置过期时间,防止服务宕机导致锁无法释放而引发死锁。
早期 Redis 版本中,加锁需分两步执行(SETNX + EXPIRE),但这两步并非原子操作,存在并发漏洞(比如执行完 SETNX 后服务宕机,EXPIRE 未执行,锁有效)。在 Redis 2.6.12 及以上版本,支持 SET 命令多参数合并,可一次性完成加锁、设值、设过期时间,保证原子性:
// 加锁核心命令(Redis CLI)SET lock:stock:1001 random-value NX PX 30000// 说明:// NX:仅当 key 不存在时才设置,保证互斥性// PX:设置过期时间(毫秒),这里设为 30 秒,避免死锁// random-value:随机字符串,需保证全局唯一,用于释放锁时身份校验
在 Java 中(以 Spring Data Redis 为例),加锁代码如下:
public boolean lock(String key, String value, long expireMs) { Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, expireMs, TimeUnit.MILLISECONDS); return Boolean.TRUE.equals(result);
}
释放锁时,不能直接执行 DEL 命令删除 key,否则会出现“误删锁”问题——比如服务 A 持有锁后因业务耗时过长,锁已过期自动释放,此时服务 B 成功加锁,若服务 A 执行完业务后直接 DEL 锁,会误删掉服务 B 持有的锁。
因此,释放锁需分三步:1. 读取锁的 value;2. 验证 value 是否与自身持有一致;3. 一致则删除 key 释放锁。这三步需保证原子性,否则仍存在并发漏洞(比如验证完 value 后,锁刚好过期,服务 B 加锁,此时服务 A 执行 DEL 仍会误删锁),需通过 Redis Lua 脚本实现:
-- 释放锁 Lua 脚本(保证原子性)if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])else
return 0end jntmjq.cn
Java 中调用 Lua 脚本释放锁的代码:
public boolean unlock(String key, String value) { String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
DefaultRedisScript<Long> redisScript www.jntmjq.cn= new DefaultRedisScript<>(script, Long.class); Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), value); return 1L.equals(result);
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048957/viewspace-3109156/ ,如需转载,请注明出处,否则将追究法律责任。