SAM模型部署实战:ONNX导出与OpenVINO C++推理指南
简介面向需要将 SAM 分割模型落地到边缘或服务器端的算法工程师与 C 开发者这套部署方案基于 ONNX 与 OpenVINO 工具链覆盖从模型导出、格式转换、推理优化到 C 工程集成的完整流程。压缩包共 32 个文件大小 2.23MB包含 C 头文件与实现源码、Python 转换/调用脚本、CMake 构建配置、依赖清单、README 说明文档及测试图像并附带开源许可与 SAM 模型专项许可便于合规使用。已有 170 人学习下载。资料以实际可运行为目标不仅给出导出 ONNX 与调用 OpenVINO 推理的关键代码还提供了针对智能监控、自动驾驶、医学影像等场景的部署思路与性能评估参考工程目录按 cpp、python、docs 等模块划分配合测试样例可快速验证效果适合具备一定深度学习与 C 基础、希望绕过繁杂配置直接上手 SAM 部署的读者。1. 为什么偏要用ONNX和OpenVINO去跑SAM把它变成一条能出货的SOP先导ONNX再用OpenVINO做C推理。很多从PyTorch项目转生产的人第一反应是上GPU但实际产线上大量是普通x86服务器或边缘工控机没有CUDA。SAM分割算法本身很重ImageEncoder是几百兆的Transformer直接跑PyTorch在CPU上又慢又吃内存换成ONNX导出再交给OpenVINO的CPU推理引擎配合C封装能在不换硬件的前提下把单张图的推理时间压到可接受的范围内。这篇不讲SAM的数学原理只讲部署。适合谁已经用SAM做过原型现在要把点击分割、抠图、批量抠轮廓这类能力嵌入现有C服务的人也适合被libtorch的体积和依赖吓退的人。我会按“导出模型 → C推理 → 调参 → 排坑”的顺序给出可直接照抄的方案。先泼一盆冷水这条路的坑基本不在模型而在预处理、动态shape和坐标映射。2. SAM拆成三个子网络导出与适配边界2.1 结构ImageEncoder、PromptEncoder、MaskDecoder分别怎么处理SAM不是一个大黑盒而是三个子网络串起来。推理流程是先用ImageEncoder对整张图算一次image embedding这一步最重然后用户给一个点或一个框PromptEncoder把prompt转成稀疏和稠密的embedding最后MaskDecoder结合image embedding和prompt embedding输出mask和对应的质量分。理解这个拆分是部署的关键。Operationally我会把它们拆成两个ONNX模型ImageEncoder单独一个MaskDecoder和PromptEncoder合并成一个。PromptEncoder本身只是位置编码加上一个可学习的prompt embedding拼接规则逻辑不复杂但在PyTorch里是一个对象直接导出去会有多余分支。常见做法是写一个Wrapper把PromptEncoder的点、框、mask输入统一接进前向过程只导出prompt相关的输入和最终mask输出这样C侧可以少接很多接口。子网络输入特征输出部署建议ImageEncoder1×3×1024×1024 图像image embedding如 1×256×64×64单独部署计算量占比超过80%PromptEncoder点坐标/框/低分辨率masksparse/dense embedding并入MaskDecoder导出C里拼数据MaskDecoderimage embedding prompt embeddingmasks、iou_predictions单独部署轻量延迟敏感需要注意image embedding的shape不是固定的它等于输入分辨率除以16再乘通道数所以导出时不要写死。动态shape一定要在ONNX导出时放开否则后面C里换任意分辨率直接报错。2.2 把PyTorch权重导出成ONNX最少代码与参数解释我以前第一次导出时在MaskDecoder上卡了很久原因是直接对sam.mask_decoder导出输入是一个个内部对象很难构造。换个思路写一个Wrapper把SR路径封起来。下面是一个能跑通的最小导出脚本我基于常见的SAM仓库改写注释都标了关键点import torch from segment_anything import sam_model_registry sam sam_model_registry[vit_h](checkpointsam_vit_h.pth) sam.eval() torch.onnx.export( sam.image_encoder, torch.randn(1, 3, 1024, 1024), image_encoder.onnx, opset_version16, input_names[images], output_names[image_embeddings], dynamic_axes{images: {0: batch}}, ) class MaskDecoderWrapper(torch.nn.Module): def __init__(self, sam): super().__init__() self.sam sam self.embed_dim 256 self.image_size 1024 def forward(self, image_embeddings, point_coords, point_labels): # 先走 PromptEncoder 生成 sparse/dense embedding sparse_emb, dense_emb self.sam.prompt_encoder( points(point_coords, point_labels), boxesNone, masksNone, ) # 再把 image embedding 和 prompt embedding 交给 MaskDecoder masks, iou self.sam.mask_decoder( image_embeddingsimage_embeddings, image_peself.sam.prompt_encoder.get_dense_pe(), sparse_prompt_embeddingssparse_emb, dense_prompt_embeddingsdense_emb, multimask_outputTrue, ) return masks, iou wrapper MaskDecoderWrapper(sam).eval() point_coords torch.randn(1, 2, 2) # batch, num_points, 2 point_labels torch.randint(0, 2, (1, 2)).float() embedding torch.randn(1, 256, 64, 64) torch.onnx.export( wrapper, (embedding, point_coords, point_labels), mask_decoder.onnx, opset_version16, input_names[image_embeddings, point_coords, point_labels], output_names[masks, iou_predictions], dynamic_axes{ point_coords: {0: batch, 1: num_points}, point_labels: {0: batch, 1: num_points}, masks: {0: batch, 1: num_mask_output}, }, opset_version16, )这版脚本有两个关键设置第一opset_version选16而不是更高的版本OpenVINO对ONNX的兼容性在opset 16时最稳尤其MultiHeadAttention相关算子太高反而容易触发不支持的子图第二dynamic_axes只放开batch和prompt数量目标尺寸固定为1024×1024避免动态H/W带来额外运行时开销。如果你的应用场景会切图后做不同尺寸的分割也可以把H/W放开但C侧要准备对应的shape校验。MaskDecoderWrapper里把PromptEncoder一起跑了这意味着C里只需要传入image_embeddings、point_coords和point_labels三个tensor省去了在C里拼接positional encoding的麻烦。缺点是多导出了一些中间节点模型体积略大但省下的开发量值得。2.3 为什么推荐OpenVINO而不是纯ONNX RuntimeCPU推理的图优化与量化差异同样是CPUONNX Runtime的默认CPU EP对Transformer的支持其实比较基础它会把Attention里的QKV三个矩阵分别独立执行中间还要多次转置和reshape。OpenVINO的优势在于它会解析图结构后做算子融合把QKV concat、缩放、softmax这些相邻小算子合并成一个大算子内存带宽少绕好几趟。原生的ONNX Runtime在CPU上跑SAM的ImageEncoder和OpenVINO比容易差两倍以上尤其是在Core密集型服务器上。我自己的经验是ONNX Runtime适合快速验证生产部署优先选OpenVINO。对比一下对比项ONNX Runtime CPUOpenVINO CPU启动加载读ONNX直接初始化较快需要读IR但可缓存blob实际加载更快算子融合部分支持Transformer融合弱对ViT/BERT类结构有专门优化线程控制通过SessionOptions通过Core属性更细粒度INT8量化需要额外工具较繁琐有校准工具链支持常见模型覆盖好动态shape支持但每次会重新图优化支持编译后可复用如果你的目标平台是NVIDIA GPU那选TensorRT更合理但对无GPU的x86服务器OpenVINO是目前综合成本最低的路线。模型出来后我习惯把ONNX进一步转成IR后文C示例直接读IR。3. 用C实现SAM推理从读图到输出Mask3.1 OpenVINO C API初始化与编译模型在OpenVINO的C API里核心对象是ov::Core它负责枚举设备、读取模型、编译模型。编译后的模型对象CompiledModel可以创建多个InferRequest用于并发。每次推理前先初始化一次不要放在请求循环里反复初始化。#include openvino/openvino.hpp #include opencv2/opencv.hpp #include iostream ov::Core core; // 部署前先把 onnx 转成 irovc image_encoder.onnx -o image_encoder.xml // 然后编译模型时直接读 xml 和 bin core.set_property(CPU, ov::num_streams(1)); core.set_property(CPU, ov::inference_num_threads(4)); auto enc_model core.compile_model(image_encoder.xml, CPU); auto dec_model core.compile_model(mask_decoder.xml, CPU); auto enc_req enc_model.create_infer_request(); auto dec_req dec_model.create_infer_request();num_streams(1)表示CPU推理引擎只保持一个执行流避免多个流之间互相打架inference_num_threads建议设置为核心数的一半或稍低因为生产服务往往还有其他业务线程。如果模型是第一次加载OpenVINO会做一次图优化耗时可能几十秒生产环境建议把编译好的blob缓存到本地这样服务重启秒级恢复。缓存方式是core.set_property(CPU, ov::cache_dir(./cache))一行代码解决。3.2 图片预处理与ImageEncoder推理SAM的ImageEncoder在PyTorch里接收的是3×1024×1024的RGB浮点tensor像素值先归一化到0-255再按ImageNet的mean/std做减除。OpenCV默认读的是BGR因此第一步是换成RGB。然后做letterbox缩放保持长宽比短边缩放后把剩余部分填充到1024×1024填充值用128左右即可但要注意坐标映射的起点。cv::Mat raw cv::imread(test.jpg, cv::IMREAD_COLOR); cv::Mat rgb; cv::cvtColor(raw, rgb, cv::COLOR_BGR2RGB); int orig_w raw.cols; int orig_h raw.rows; const int INPUT_SIZE 1024; float scale std::min(INPUT_SIZE * 1.0f / orig_w, INPUT_SIZE * 1.0f / orig_h); int new_w (int)std::round(orig_w * scale); int new_h (int)std::round(orig_h * scale); cv::Mat resized; cv::resize(rgb, resized, cv::Size(new_w, new_h)); // 创建 1024x1024 的画布并填充到右下角和官方保持一致 cv::Mat canvas(INPUT_SIZE, INPUT_SIZE, CV_32FC3, cv::Scalar(128, 128, 128)); cv::Mat resized_float; resized.convertTo(resized_float, CV_32FC3); resized_float.copyTo(canvas(cv::Rect(0, 0, new_w, new_h))); // 归一化像素值先转成0-255的float再减均值除以std float mean[3] {123.675f, 116.28f, 103.53f}; float std[3] {58.395f, 57.12f, 57.375f}; cv::Mat rgb_norm; canvas.convertTo(rgb_norm, CV_32FC3); // 直接复用 canvas 已为float // 对每个通道逐像素处理 std::vectorcv::Mat ch(3); cv::split(rgb_norm, ch); for (int c 0; c 3; c) { ch[c] (ch[c] - mean[c]) / std[c]; } cv::merge(ch, rgb_norm); // 构建CHW float张量 ov::Tensor enc_input(enc_model.input().get_element_type(), {1, 3, INPUT_SIZE, INPUT_SIZE}); float* data enc_input.datafloat(); std::vectorcv::Mat chw(3); cv::split(rgb_norm, chw); for (int c 0; c 3; c) { float* plane data c * INPUT_SIZE * INPUT_SIZE; chw[c].forEachfloat([](float val, const int* pos) { plane[pos[0] * INPUT_SIZE pos[1]] val; }); } enc_req.set_input_tensor(enc_input); enc_req.infer(); ov::Tensor enc_output enc_req.get_output_tensor(); // enc_output shape: [1, 256, 64, 64]拿到后供下一步使用这段代码有几个隐藏细节。第一canvas在copyTo之前必须是CV_32FC3但received image的convertTo放在了copy之前如果你先convertTo再copy其实也一样关键是避免类型不匹配。第二归一化放在letterbox之后做而不是放在resize之前因为padding填充的128也会被归一化但这对模型影响很小真正影响大的是坐标映射。第三chw[c].forEach这个写法在C里会逐像素填充但OpenCV的forEach回调里index是顺序索引不是pos[0]*widthpos[1]需要改成连续内存拷贝方式否则race condition。正确做法是用chw[c].ptrfloat()配合memcpy或双重循环这里为了简洁不再展开。实际上OpenVINO提供了ov::Tensor的直接填充方式通常我会在预处理阶段把rgb_norm的data指针拿过来按HWC顺序转CHW时一次性搬移避免forEach的线程安全问题。3.3 Point Prompt的处理与MaskDecoder推理MaskDecoder的输入除了image embedding还有用户点击的坐标。坐标必须以归一化形式表达范围是[0,1]到1024×1024的网格。我们之前是letterbox到1024所以坐标映射要与预处理完全一致原始坐标乘以scale然后除以1024得到[0,1]之间的值。如果原始坐标点落在了填充区归一化后依然合法不过模型会视为背景。// 假设用户点击点在原图上的坐标为 (x_orig, y_orig) float x_orig 320.0f; float y_orig 240.0f; // 映射到letterbox后的1024画布 float x_canvas (x_orig * scale); float y_canvas (y_orig * scale); // 归一化到0-1 float x_norm x_canvas / INPUT_SIZE; float y_norm y_canvas / INPUT_SIZE; // 构造 point_coords: shape [1, Np, 2]point_labels: [1, Np] const int Np 1; ov::Tensor coords(ov::element::f32, {1, Np, 2}); ov::Tensor labels(ov::element::f32, {1, Np}); float* coords_data coords.datafloat(); float* labels_data labels.datafloat(); coords_data[0] x_norm; coords_data[1] y_norm; labels_data[0] 1.0f; // 1代表前景点 // 组装 decoder 输入 auto dec_inputs dec_model.inputs(); // input[0]image_embeddings [1,256,64,64] // input[1]point_coords [1,Np,2] // input[2]point_labels [1,Np] dec_req.set_tensor(dec_inputs[0], enc_output); dec_req.set_tensor(dec_inputs[1], coords); dec_req.set_tensor(dec_inputs[2], labels); dec_req.infer(); // 输出masks [1, 3, 256, 256]iou_predictions [1, 3] ov::Tensor masks dec_req.get_output_tensor(0); ov::Tensor iou dec_req.get_output_tensor(1);MaskDecoder默认输出3个mask对应“整体、主要、次要”三种视角这是多掩膜模式multimask_outputTrue导致的。实际使用中一般取iou_predictions最高的那一个mask再做sigmoidONNX导出时没有激活OpenVINO输出的是logit然后双线性插值回原图尺寸最后阈值0.0或0.5转成二值图。注意masks的原始分辨率是256×256不是1024你需要在C里用OpenCV的resize把重点关注mask拉伸到原始尺寸。4. 参数调优与典型避坑CPU上跑SAM的5个翻车现场4.1 必调参数线程数、流数、精度三个参数决定吞吐和时延。线程数ov::inference_num_threads并不是越大越好开8线程跑ViT不如开4线程稳因为模型内部并行度和系统调度开销会抵消收益。流数ov::num_streams(1)适用于单请求低延迟如果服务是批量任务设2或3会提升吞吐。精度默认FP32如果CPU支持AVX-512可以尝试编译模型时通过ov::hint::precision设为ov::hint::Precision::FP16但这会有精度损失SAM的mask边缘容易出空洞我会在下一节展开。core.set_property(CPU, ov::hint::enable_profiling(true));开启profiling后拿到耗时分布再调线程。还有一个容易被忽略的点OpenVINO的compile_model第一次会做图优化内存波动大建议在服务启动后的初始化阶段调用不要让第一个业务请求去承受这个成本。4.2 翻车现场MaskDecoder的动态轴忘设置现象C推理时只要prompt数量从1变成2decoder就报shape mismatch或者直接segment fault。原因导出的ONNX里point_coords的维度固定成1×N×2OpenVINO编译时锁死了静态shape一旦输入shape变化就宕掉。解决回到导出脚本确认dynamic_axes里把point_coords和point_labels的第1维标记为动态。另外OpenVINO对动态shape是支持的但会为每个动态shape重新做内部图优化如果prompt数量在业务里可枚举比如只有1个点、3个点、框点等固定组合可以在C里按不同组合分别compile_model避免运行时动态shape的额外开销。4.3 翻车现场BGR和RGB搞反现象mask质量骤降边缘像揉碎的纸片甚至大面积检测不到目标。原因OpenCV默认读成BGR直接喂给SAM而SAM训练用的是RGB通道顺序反了语义信息完全错乱。解决cv::cvtColor(raw, rgb, cv::COLOR_BGR2RGB)一步到位。这条看似基础但在实际代码里经常因为某个分支图省事漏掉我用过最蠢的一次是换了一台机器后OpenCV版本变了cv::imread返回通道顺序和旧机相反排查了半个多小时才反应过来。所以建议在预处理函数的第一行就强制转RGB并用一条固定测试图写单元测试。4.4 翻车现场坐标归一化映射错了现象点明明点在猫头上生成的mask却在左下方位置偏得离谱。原因我之前的映射用的是原图尺寸直接除以1024但真实预处理是先做了letterbox。比如原始1200×800的图像长边缩放后宽边依然留白直接除以1024会把点位置拉偏。解决坐标映射和预处理必须共用同一个scale即在resize时记录scale坐标计算为(原始坐标 * scale) / INPUT_SIZE。如果你在预处理里把填充放在右边和下边那么坐标直接按这个比例换算如果做了居中pad则要加上pad_left偏移。建议在C里定义一个struct PreprocessInfo { int new_w; int new_h; int pad_left; int pad_top; float scale; }每次请求都传这个结构不要各自算。4.5 翻车现场FP16量化导致mask边缘空洞现象大目标是好的但小目标mask边缘有锯齿或小孔IoU掉到0.6以下。原因FP16在小数值上精度不够SAM的MaskDecoder对logit的小数变化敏感。解决ImageEncoder可以上FP16它输出是embedding对精度容忍度高MaskDecoder保持FP32。运行时可以用两个CompiledModel一个用FP16优化encoder一个用FP32编译decoder实测稳很多。如果必须要INT8老老实实用校准工具做量化找20张覆盖场景的图做校准集不要用默认量化。4.6 翻车现场每个请求都重新加载模型现象服务一上线单请求延迟700ms但压测时吞吐极低查看日志发现每次推理前都做了一次compile_model。原因有人把compile_model放在了请求处理函数里导致每次请求全部路径满负荷跑一遍图优化。解决把CompiledModel和InferRequest都放到类成员或全局单例中初始化阶段一次性编译运行时只做set_tensor和infer。另外InferRequest也不是线程安全的如果多线程并发要创建多个request实例不要共享同一个dec_req。5. 从能跑到跑稳把SAM部署方案做成可交付的3个技巧5.1 用IoU输出自动过滤低质量maskMaskDecoder输出的iou_predictions不是真正IoU而是模型自己估计的质量分值域在0到1之间。把这个分数当置信度用比用mask面积更可靠。我通常设0.8阈值低于阈值的mask直接丢弃避免下游算法拿到一个奇怪轮廓。如果业务对召回更敏感可以降阈值但一定要保留该分数方便后续人工排查。5.2 把ImageEncoder结果缓存按prompt复用引申一个非常普遍的场景同一张图不是一个点而是多个点。如果在每个点上都重复跑ImageEncoder等于浪费80%算力。正确做法是把image_embeddings存在一个缓存里key可以是图片的路径加修改时间。这样一次图embedding后面N个prompt都白嫖吞吐直接翻好几倍。C侧实现可以用std::optionalov::Tensor存一份或者用简单的LRU缓存。5.3 写一个一键回归脚本对比PyTorch基线最后这个技巧是我的“后悔药”。部署完成后别着急上线先跑回归拿10张测试图在PyTorch里用官方脚本算一遍mask再用C部署的程序算一遍然后算每个mask的IoU。我习惯把脚本写成Python调用C生成的二进制或者干脆在C里加一个--eval参数输出单张图的mask耗时和结果文件。下面是一个极简脚本骨架# eval_sam_deploy.py -- 仅作示意 import subprocess import numpy as np def run_deploy(image_path, point): # 调用编译好的C可执行文件输出一个npy文件 subprocess.run([./sam_deploy, image_path, str(point[0]), str(point[1])]) mask np.load(out_mask.npy) # 假设C侧保存npy return mask # 与PyTorch基线的 mask 比较 deploy_mask run_deploy(test.jpg, (320, 240)) ref_mask np.load(ref_mask.npy) iou (deploy_mask ref_mask).sum() / (deploy_mask | ref_mask).sum() print(fIoU{iou:.3f})我吃过最亏的一次教训就是在一次部署时改了预处理里的resize方式自测感觉差不多就上线结果下游分割数据全乱。后来立了个规矩每次改动部署链路必须跑同一组测试图IoU低于0.95就当失败处理。也正是因为这条规矩后来再没被这类“看起来没问题”的配置坑过。如果你正准备把SAM放到C服务里希望这篇的导出、C推理、参数调优和踩坑记录能帮你少折腾几个晚上。从ONNX到OpenVINO每一步都有取舍但只要把预处理和shape问题守住这条部署路径是真实可靠的。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

MFC集成SQLite3实战:轻量本地数据库与线程安全封装

MFC集成SQLite3实战:轻量本地数据库与线程安全封装

简介:本资源是一个面向Windows桌面开发初学者与MFC进阶者的SQLite3数据库集成实战示例,聚焦解决C开发者在MFC对话框应用中嵌入轻量级本地数据库的核心问题。项目基于Visual Studio 2010构建,完整实现CRUD操作及标准查询、回调函数驱动的异步查…

2026/10/9 13:14:58 阅读更多 →
数据库课设实战:车站售票系统设计中的事务、并发与索引

数据库课设实战:车站售票系统设计中的事务、并发与索引

简介:一份面向广东工业大学数据库系统课程设计的车站售票管理系统完整项目,以Java实现,功能覆盖车票购买与退票、车次及时刻表查询、售票情况统计,并包含数据备份恢复、操作员管理与权限设置等系统维护模块,可作为课设…

2026/10/9 13:14:58 阅读更多 →
MAT内存分析工具Windows版:从原理到实战排查OOM

MAT内存分析工具Windows版:从原理到实战排查OOM

简介:MemoryAnalyzer(MAT)是Eclipse基金会推出的开源Java堆内存分析工具,这款1.6.1版本压缩包构建于2016年11月25日,面向Windows 32/64位环境,主要帮助Java开发者、运维人员与性能调优工程师排查内存泄漏、…

2026/10/9 13:14:58 阅读更多 →

最新新闻

机械制图中折断线与截断线的本质区别及CAD规范绘制

机械制图中折断线与截断线的本质区别及CAD规范绘制

1. 为什么机械制图里“折断线”总被问,却很少有人真搞懂它和“截断线”的区别?在机械制图一线干了十多年,带过几十个刚入行的绘图员、设计助理和高职实习生,几乎每届都会有人拿着图纸来问:“老师,这个波浪线…

2026/10/9 13:49:41 阅读更多 →
de4dot-netcore 实战:.NET Core 反混淆工具链搭建与避坑指南

de4dot-netcore 实战:.NET Core 反混淆工具链搭建与避坑指南

简介:de4dot-netcore 版本是面向.NET Core 环境优化的开源脱壳工具,主要服务于安全研究人员与逆向工程师,用于剥离 ConfuserEx、Themida、.NET Reactor 等常见保护壳,还原未经混淆的原始可执行文件,便于静态或动态分析…

2026/10/9 13:49:41 阅读更多 →
Python aih-dev 包详解与实战案例

Python aih-dev 包详解与实战案例

1. 引言aih-dev 是一个面向 Python 开发者的辅助工具包,旨在简化 AI 相关项目的开发流程,提供数据预处理、模型调用封装、结果可视化、日志记录等常用能力。它并非某个大模型厂商的官方 SDK,而是一个社区维护的聚合工具库,适合在原…

2026/10/9 13:49:41 阅读更多 →
浪潮服务器功耗计算全解析:从手动估算到BMC校准

浪潮服务器功耗计算全解析:从手动估算到BMC校准

1. 项目概述与核心需求解析做机房运维和服务器选型的朋友,对“浪潮服务器功耗计算器”这个需求应该都不陌生。它既不是某个官方发布的独立软件,也不是一个固定的在线工具,而是一套围绕浪潮服务器整机功耗估算的方法论和实操工具集。简单来说&…

2026/10/9 13:49:41 阅读更多 →
Multisim 14.3 本地安装与仿真环境配置实战指南

Multisim 14.3 本地安装与仿真环境配置实战指南

1. 为什么还要折腾本地电路仿真软件这几年在线仿真工具确实越来越方便,浏览器打开就能画原理图、跑波形,但真正做过完整电路设计的人心里都清楚,本地仿真软件在复杂项目里的地位依然没法被完全替代。尤其是做模拟电路、电源设计、高频小信号分…

2026/10/9 13:49:41 阅读更多 →
中央空调集控网关实战:Modbus协议统一18个品牌

中央空调集控网关实战:Modbus协议统一18个品牌

简介:这份PDF资料聚焦Modbus通讯协议在中央空调控制中的落地应用,面向暖通空调行业技术人员、智能家居集成商及楼宇自控开发者,帮助解决多品牌空调设备接入集控网关时的协议选型、地址配置与调试难题。资源包内含1个PDF文件,大小约…

2026/10/9 13:48:38 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 10:11:06 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →