C++嵌入Python调用YOLO:从环境配置到部署的完整指南

1. 为什么要在C++里调用Python侧的YOLO模型

先把场景说清楚。你手头有一个已经训练好的YOLO目标检测模型,可能是.pt、.onnx或者某个导出后的权重文件,训练和验证阶段都在Python里跑得挺顺。但真正要落地的时候,宿主程序是C++写的——可能是一个桌面端图像处理工具、一个工业质检上位机、一个机器人视觉模块,或者一个已有的C++工程。这时候就出现了一个很现实的问题:模型在Python生态里,业务逻辑在C++里,两边怎么接上。

最直接的想法是"把模型转成C++能直接推理的格式,比如ONNX Runtime或者TensorRT,彻底摆脱Python"。这条路当然更干净,性能也更好,但它有前提:你得能顺利导出、算子得被支持、前后处理得自己用C++重写一遍。现实里经常遇到导出后精度对不上、某些自定义算子不支持、后处理逻辑(比如NMS、坐标还原)在Python里写得很随意,搬到C++要重写一大坨。工期紧的时候,这些坑足够让人加班一周。

于是就有了另一条更"务实"的路线:让C++去调用Python解释器,把Python当成一个推理服务来用。C++负责业务、界面、IO,Python负责加载YOLO模型、做前处理和后处理,两边通过嵌入解释器的方式通信。这样你几乎可以原封不动复用Python里已经调通的推理代码,改动量极小,风险也低。代价是引入了Python运行时依赖,启动稍慢,性能不如纯C++推理——但对于很多中小规模、实时性要求没那么极端的场景,这个代价完全可接受。

这篇文章就是围绕这条路线展开的。我会把Python C API嵌入解释器的完整流程、YOLO推理代码怎么组织、C++和Python之间怎么传图像数据、怎么处理GIL和异常、怎么打包部署这些环节都讲透。适合两类人看:一类是C++工程师,平时不怎么写Python,但需要把现成的模型接进工程;另一类是算法工程师,模型调通了但不知道怎么交付给C++团队。看完你应该能自己搭出一套能跑、能维护、能交付的调用链路。

提示:本文讲的"调用Python"指的是在C++进程内嵌入CPython解释器(Python C API),不是起一个HTTP服务再跨进程调用。后者是另一种方案,本文不展开。

2. 嵌入CPython解释器的环境准备与编译链接

2.1 先确认你需要的到底是哪套Python

这一步很多人会忽略,但它决定了后面所有的编译参数。你机器上可能装了系统自带的Python、conda环境里的Python、还有各种虚拟环境。C++要嵌入的是某一个具体的Python安装,你需要拿到它的头文件目录和库文件。

判断方法很简单,在你要用的那个Python环境里执行:

python -c "import sysconfig; print(sysconfig.get_paths()['include']); print(sysconfig.get_config_var('LIBDIR')); print(sysconfig.get_config_var('LDLIBRARY'))"

输出会告诉你三件事:头文件在哪(include)、库文件目录在哪(LIBDIR)、库文件名是什么(LDLIBRARY,Linux下通常是libpython3.x.so,Windows下是python3x.lib)。

我踩过的一个坑是:conda环境里的Python,头文件和库都在conda目录下,但编译时链接器默认去系统路径找,结果版本对不上,运行时报符号缺失。所以编译时一定要显式指定include路径和lib路径,不要指望默认能找到。

2.2 Linux下的编译链接参数

假设你的Python在/opt/pyenv/bin/python3.10,头文件在/opt/pyenv/include/python3.10,库在/opt/pyenv/lib。一个最小可用的编译命令长这样:

g++ main.cpp -o demo \ -I/opt/pyenv/include/python3.10 \ -L/opt/pyenv/lib \ -lpython3.10 \ -Wl,-rpath,/opt/pyenv/lib

这里有几个关键点值得展开。-I指定头文件路径,-L指定库搜索路径,-lpython3.10链接具体的库。-Wl,-rpath这一项特别重要,它把库路径写进可执行文件,运行时动态链接器就能找到libpython3.10.so,否则你得手动设置LD_LIBRARY_PATH,部署时非常容易忘。

如果你用的是静态库(libpython3.10.a),链接会更麻烦,需要额外链接-lpthread -ldl -lutil -lm这些依赖。我的建议是优先用动态库,部署时把.so一起打包,省心。

2.3 Windows下的配置差异

Windows下用MSVC的话,思路一样但参数不同。头文件路径加到"附加包含目录",库目录加到"附加库目录",然后在"附加依赖项"里写python310.lib。注意Windows下库文件分python310.lib(导入库)和python310.dll(运行时),编译链接用.lib,运行时需要.dll在旁边。

还有一个Windows特有的坑:Python的DLL和你的exe必须位数一致,都是64位或都是32位。混用会在Py_Initialize时直接崩,而且报错信息很不友好。我见过有人拿32位的Python库去链接64位工程,排查了半天才发现是位数问题。

2.4 一个最小验证程序

在写YOLO之前,先写个最小程序验证环境通了:

#include <Python.h> #include <iostream> int main() { Py_Initialize(); if (!Py_IsInitialized()) { std::cerr << "Python init failed" << std::endl; return -1; } PyRun_SimpleString("import sys"); PyRun_SimpleString("print('python version:', sys.version)"); Py_Finalize(); return 0; }

能打印出Python版本,说明环境没问题。这一步千万别跳过,后面YOLO调不通的时候,你至少能确定是环境问题还是代码问题。我习惯把这个最小程序留着,每次换机器先跑一遍。

3. C++与Python之间的数据通道怎么设计

3.1 图像数据到底怎么传,这是最容易翻车的地方

C++侧通常拿到的是cv::Mat(OpenCV)或者一块原始内存(比如相机SDK给的buffer)。Python侧的YOLO推理代码,前处理一般也是基于numpy数组或者cv2图像。两边要传图像,核心问题是:怎么把一块内存从C++安全地交给Python,且不产生多余的拷贝。

最朴素的做法是把图像存成文件,C++写文件,Python读文件。这个方法能用,但每帧都写磁盘,性能惨不忍睹,只适合调试。稍微好一点的是通过内存传递,用PyBytes或者PyByteArray把图像数据拷进去,Python侧再用np.frombuffer还原成数组。

我推荐的做法是用PyByteArray传原始像素,因为它是可变的,Python侧可以直接在其上构造numpy数组而不额外拷贝:

// 假设 img 是 cv::Mat,连续存储,BGR 三通道 size_t data_size = img.total() * img.elemSize(); PyObject* py_bytes = PyByteArray_FromStringAndSize( reinterpret_cast<const char*>(img.data), data_size); // 把宽高通道数也传过去 PyObject* py_args = PyTuple_Pack(4, py_bytes, PyLong_FromLong(img.cols), PyLong_FromLong(img.rows), PyLong_FromLong(img.channels()));

Python侧接收:

import numpy as np def detect_from_buffer(buf, w, h, c): arr = np.frombuffer(buf, dtype=np.uint8).reshape(h, w, c) # arr 就是 BGR 图像,直接喂给模型 ...

这里有个细节要注意:np.frombuffer得到的是只读视图,如果后续处理需要修改(比如某些前处理会原地操作),得加.copy()。另外PyByteArray的生命周期要管好,Python侧如果还持有引用,C++这边不能提前释放。

3.2 返回值怎么组织,别用字符串拼

推理结果要传回C++,常见的结果是:若干个检测框,每个框有坐标、置信度、类别ID。有人图省事,Python侧把结果拼成一个字符串,C++再解析。这个方法极其脆弱,浮点数精度、分隔符冲突、解析性能都是问题。

正确的做法是用Python的list和tuple组织结构化数据,C++侧用C API逐个解析:

# Python 侧返回 results = [] for box in boxes: x1, y1, x2, y2, conf, cls_id = box results.append((float(x1), float(y1), float(x2), float(y2), float(conf), int(cls_id))) return results

C++侧解析:

PyObject* py_results = /* 调用返回的list */; Py_ssize_t n = PyList_Size(py_results); for (Py_ssize_t i = 0; i < n; ++i) { PyObject* item = PyList_GetItem(py_results, i); // 借用引用 double x1 = PyFloat_AsDouble(PyTuple_GetItem(item, 0)); double y1 = PyFloat_AsDouble(PyTuple_GetItem(item, 1)); // ... 依次取出 }

引用计数是这里最大的坑。PyList_GetItem和PyTuple_GetItem返回的是借用引用(borrowed reference),不需要你释放;但PyList_New、PyTuple_Pack、PyFloat_FromDouble这些创建型函数返回的是新引用(new reference),用完必须Py_DECREF。搞混了要么内存泄漏,要么程序崩溃。我的经验是:每写一个创建型调用,就在旁边记一笔"这个要DECREF",养成习惯。

3.3 用PyImport导入你的推理模块

把YOLO推理逻辑写成一个.py文件,比如yolo_detector.py,里面封装一个类或者函数。C++侧这样导入:

PyObject* pName = PyUnicode_DecodeFSDefault("yolo_detector"); PyObject* pModule = PyImport_Import(pName); Py_DECREF(pName); if (!pModule) { PyErr_Print(); // 打印Python异常,调试必备 return -1; } PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_from_buffer"); if (!pFunc || !PyCallable_Check(pFunc)) { PyErr_Print(); return -1; }

PyErr_Print()是调试神器,Python侧的异常会打印到stderr,包括traceback。每次调用Python函数后都检查返回值,失败就PyErr_Print(),能省掉大量猜测时间。

模块搜索路径也要注意。默认情况下Python只在自己的一套路径里找模块,你的yolo_detector.py如果不在里面,导入会失败。解决办法是在初始化后手动加路径:

PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.insert(0, '/path/to/your/module')");

或者用PySys_GetObject("path")拿到path列表,用C API插入。前者更简单,我一般用前者。

4. YOLO推理模块在Python侧怎么写才稳

4.1 模型只加载一次,别每帧都load

这是性能上最关键的一条。YOLO模型加载(尤其是.pt文件)要几百毫秒到几秒,如果每帧都model = YOLO('best.pt'),帧率直接掉到个位数。正确做法是在模块级别或类初始化时加载一次,之后复用。

# yolo_detector.py from ultralytics import YOLO import numpy as np _model = None def _get_model(): global _model if _model is None: _model = YOLO('best.pt') # 如果要用GPU,这里可以指定 device return _model def detect_from_buffer(buf, w, h, c): model = _get_model() arr = np.frombuffer(buf, dtype=np.uint8).reshape(h, w, c) results = model(arr, verbose=False) # 解析 results,组织成 list of tuple 返回 ...

用全局变量做懒加载,第一次调用时加载,后续直接复用。这样C++侧第一次调用会慢一点,之后每帧就快了。

4.2 前处理和后处理尽量在Python里做完

既然选择了调用Python这条路,就要充分利用Python生态的便利。前处理(resize、归一化、letterbox)和后处理(NMS、坐标还原)都在Python里用numpy和现成的库做完,C++侧只拿最终的框。不要把半成品传回C++再处理,那样等于把复杂度搬到了C++,失去了这条路线的意义。

以ultralytics的YOLO为例,model(arr)返回的results对象里已经包含了处理好的框,你只需要遍历提取:

def detect_from_buffer(buf, w, h, c): model = _get_model() arr = np.frombuffer(buf, dtype=np.uint8).reshape(h, w, c) results = model(arr, verbose=False, conf=0.25, iou=0.45) out = [] for r in results: boxes = r.boxes if boxes is None: continue for i in range(len(boxes)): xyxy = boxes.xyxy[i].tolist() conf = float(boxes.conf[i]) cls_id = int(boxes.cls[i]) out.append((xyxy[0], xyxy[1], xyxy[2], xyxy[3], conf, cls_id)) return out

conf和iou这两个阈值建议做成可配置的,通过参数从C++传进来,方便现场调参。

4.3 异常要在Python侧兜住

Python侧如果抛异常,会一路传到C++,如果C++没处理,程序可能直接挂。稳妥的做法是在Python函数里用try/except包一层,把异常转成可预期的返回值:

def detect_from_buffer(buf, w, h, c): try: # ... 推理逻辑 return out except Exception as e: import traceback traceback.print_exc() return [] # 返回空列表,C++侧当作"本帧无结果"

这样即使某一帧出问题,C++侧也只是拿到空结果,不会崩。同时traceback打印出来,方便定位。

4.4 关于GIL,什么时候需要关心

CPython有全局解释器锁(GIL)。如果你的C++程序是单线程调用Python,基本不用管GIL,Py_Initialize之后直接调就行。但如果你的C++程序是多线程的,多个线程都要调Python,就必须处理GIL。

规则是这样的:持有GIL的线程才能执行Python代码。主线程Py_Initialize后默认持有GIL。如果子线程要调Python,需要先PyGILState_Ensure()获取GIL,用完PyGILState_Release()释放:

PyGILState_STATE gstate = PyGILState_Ensure(); // 在这里调用Python函数 PyObject* result = PyObject_CallObject(pFunc, pArgs); PyGILState_Release(gstate);

反过来,如果Python侧要调用C++的回调,或者C++在持有GIL时做耗时操作(比如等IO),应该主动Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS释放GIL,让其他线程能跑Python。

我遇到过一个典型问题:C++主线程初始化Python后,开了个工作线程做推理,结果工作线程调Python时直接卡死。原因就是工作线程没有GIL,Python代码根本执行不了。加上PyGILState_Ensure就好了。多线程场景下,GIL是必须过的关。

5. 完整调用链路的搭建与实测

5.1 把整个流程串起来

现在把前面的碎片拼成一个完整流程。C++侧的主逻辑大致是:

  1. Py_Initialize()初始化解释器
  2. 把模块路径加入sys.path
  3. 导入yolo_detector模块,拿到detect_from_buffer函数对象
  4. 循环:读图 -> 构造参数 -> 调用函数 -> 解析结果 -> 释放引用
  5. 退出前Py_Finalize()

这里有个顺序问题:函数对象和模块对象建议在循环外获取一次,循环内复用。每次循环都PyImport_Import和PyObject_GetAttrString是浪费,而且频繁导入可能触发一些奇怪的缓存问题。

PyObject* pModule = PyImport_ImportModule("yolo_detector"); PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_from_buffer"); while (running) { cv::Mat frame = capture(); PyObject* py_bytes = PyByteArray_FromStringAndSize( (const char*)frame.data, frame.total() * frame.elemSize()); PyObject* pArgs = PyTuple_Pack(4, py_bytes, PyLong_FromLong(frame.cols), PyLong_FromLong(frame.rows), PyLong_FromLong(frame.channels())); PyObject* pResult = PyObject_CallObject(pFunc, pArgs); // 解析 pResult ... Py_DECREF(pArgs); Py_DECREF(py_bytes); Py_DECREF(pResult); } Py_DECREF(pFunc); Py_DECREF(pModule); Py_Finalize();

注意PyTuple_Pack会把传入的对象引用计数加一,所以py_bytes和那几个PyLong在PyTuple_Pack之后还要自己DECREF。这个细节很容易漏,漏了就内存泄漏。

5.2 实测性能与优化方向

我在一台普通开发机上实测过这套方案:YOLOv8n模型,输入640x640,CPU推理,单帧从C++调用到拿到结果大约80到120毫秒。其中Python调用开销(参数构造、GIL、函数调用)大概占5到10毫秒,剩下都是模型推理本身。也就是说,调用Python的额外开销其实很小,瓶颈在模型推理。

如果性能不够,优化方向按优先级排:

优化方向预期收益改动成本
模型换更小的版本大低
用GPU推理大中
降低输入分辨率中低
跳帧推理中低
减少数据拷贝小中

减少数据拷贝这一项值得说一下。前面用PyByteArray_FromStringAndSize其实已经拷贝了一次(从cv::Mat到PyByteArray)。如果追求极致,可以用PyMemoryView_FromMemory直接包装cv::Mat的内存,零拷贝。但这样生命周期管理更复杂,cv::Mat释放后Python侧不能再用。除非性能真的卡在这,否则不建议上这个复杂度。

5.3 部署时怎么打包

部署是这条路线最烦人的地方,因为引入了Python运行时。你需要打包:Python解释器(或至少libpython)、Python标准库、你的推理模块、模型文件、以及所有第三方依赖(numpy、torch、ultralytics等)。

Linux下可以用patchelf改rpath,把libpython路径写死,然后把整个Python环境目录一起拷过去。Windows下把python3x.dll和Lib目录、DLLs目录一起打包。最省事的办法是用conda创建一个独立环境,整个环境目录打包,虽然体积大(几个GB),但依赖齐全,不容易缺东西。

我见过有人只拷了libpython.so,结果运行时缺encodings模块,Python直接起不来。所以标准库目录一定要带上,别只带库文件。

6. 那些让我加班到深夜的坑

6.1 路径问题:相对路径在嵌入环境下会失效

Python脚本里如果用了相对路径(比如open('config.yaml')),在嵌入环境下,当前工作目录是C++进程的目录,不是脚本所在目录。结果就是本地跑得好好的,一嵌入就找不到文件。

解决办法有两个:一是在Python脚本里用os.path.dirname(__file__)拼绝对路径;二是在C++初始化后os.chdir到脚本目录。我推荐前者,更稳。

6.2 多次初始化与重复导入

Py_Initialize只能调一次,重复调会崩。如果你的C++代码有多个地方可能触发初始化,要加个标志位保护。另外Py_Finalize之后再Py_Initialize,在某些Python版本上会有问题,尽量避免反复初始化/销毁,程序启动时初始化一次,退出时销毁一次就好。

6.3 引用计数泄漏的排查

引用计数泄漏不会立刻崩,但跑久了内存一直涨。排查方法是在关键位置打印sys.getrefcount,或者用Python的gc模块看对象数量。更工程化的做法是封装一层RAII的智能指针,自动管理PyObject*的引用:

class PyObj { PyObject* obj_; public: explicit PyObj(PyObject* o) : obj_(o) {} ~PyObj() { Py_XDECREF(obj_); } PyObject* get() const { return obj_; } // 禁止拷贝,允许移动 };

用这个包装之后,创建型调用的返回值都交给PyObj管,离开作用域自动释放,能避免大部分泄漏。

6.4 模型文件路径与工作目录

模型文件(best.pt)的路径同样有相对路径问题。而且ultralytics加载模型时可能还会去找一些配置文件。最保险的做法是把模型路径做成绝对路径,通过参数传给Python函数,而不是在Python里写死相对路径。

6.5 线程安全与并发调用

如果你的C++程序有多个线程同时调Python推理,除了GIL,还要注意模型本身可能不是线程安全的。ultralytics的模型对象在多线程下并发调用可能出问题。稳妥做法是加一把锁,串行化推理调用,或者每个线程一个模型实例(内存翻倍)。前者简单,后者性能好,看你的场景选。

7. 这套方案适合谁,以及什么时候该换路

把C++调用Python-YOLO这条路走通之后,我对它的适用边界有了比较清楚的认识。它最适合的场景是:模型已经用Python调通、工期紧、性能要求不是极致、团队里Python和C++都有人。这种情况下,它能让你在几天内把模型接进C++工程,而不是花几周去啃ONNX导出和C++后处理重写。

但如果你的场景是高并发、低延迟、要部署到资源受限设备,那这条路就不合适了。Python解释器本身占内存,GIL限制并发,启动慢,这些在嵌入式或服务端高并发场景下都是硬伤。这时候应该老老实实走ONNX Runtime、TensorRT或者ncnn这类纯C++推理路线,把模型导出、前后处理全部用C++实现。

我个人的经验是:先用调用Python的方式快速跑通业务闭环,验证需求;等业务稳定、性能成为瓶颈时,再逐步把推理部分替换成纯C++实现。这样风险最低,也不会一上来就陷入导出和算子兼容的泥潭。两阶段走,比一步到位更现实。

最后分享一个实用技巧:在Python推理模块里加一个warmup函数,C++初始化后先调一次,让模型完成首次加载和CUDA初始化(如果用GPU),这样第一帧真实图像不会因为初始化而卡顿。这个细节在演示和交付时特别加分,用户感知到的就是"一点就出结果",而不是"第一帧卡两秒"。

相关新闻

结合执行器动力学的运载火箭IMU故障检测仿真

结合执行器动力学的运载火箭IMU故障检测仿真

先说结论&#xff1a;这套仿真验证了在运载火箭俯仰控制回路里&#xff0c;把执行器动力学纳入参考模型&#xff0c;能让基于IMU观测残差的故障检测在机动段依然保持稳定阈值&#xff0c;明显降低动态误报率。我按标题思路在Matlab里搭了一套桌面级仿真环境&#xff0c;参数全部…

2026/10/20 19:09:07 阅读更多 →
蓝桥杯高精度算法模板详解:大整数四则运算与压位技巧

蓝桥杯高精度算法模板详解:大整数四则运算与压位技巧

点开赛题列表&#xff0c;看到“结果可能很大&#xff0c;请使用高精度”、“输出不超过 XXX 位的整数”、“答案需要对 10^97 取模”这些字眼&#xff0c;心里就要有数了&#xff1a;高精度这关&#xff0c;蓝桥杯一定会考。不管你是 C/C 组还是 Java/Python 组&#xff0c;大…

2026/10/20 19:09:07 阅读更多 →
鸿蒙ArkUI实现单格单字符输入框:验证码/手机号优雅方案

鸿蒙ArkUI实现单格单字符输入框:验证码/手机号优雅方案

1. 项目概述1.1 为什么需要「单格单字符」输入框做鸿蒙应用开发时&#xff0c;手机号、验证码这类输入场景是最常见的需求之一。但很多新手甚至有一定经验的开发者&#xff0c;第一反应都是直接用TextInput配合maxLength限制长度&#xff0c;再套一层样式就完事。这种方案在功能…

2026/10/20 19:09:07 阅读更多 →

最新新闻

ST-LINK固件升级指南:V2.37.26救砖实操与避坑全解析

ST-LINK固件升级指南:V2.37.26救砖实操与避坑全解析

简介&#xff1a;本资源是ST官方STLink调试编程器的固件升级工具包STSW-LINK007 V2-37-26正式发布版&#xff0c;面向STM32/STM8嵌入式开发者、硬件工程师及高校实验教学人员&#xff0c;解决STLink设备固件陈旧导致的IDE兼容性异常、新MCU型号识别失败、调试连接不稳定等实际问…

2026/10/20 19:45:34 阅读更多 →
DeepSeek Harness沙箱实测:放开执行权限后AI测试开发评分从3.4升至4.6

DeepSeek Harness沙箱实测:放开执行权限后AI测试开发评分从3.4升至4.6

先说结论&#xff1a;我们团队把"AI替代测试开发"这个事&#xff0c;切成了三轮实测来做。第一轮跑完&#xff0c;平均分只有3.4&#xff0c;团队里不少人说"模型幻觉太多""代码根本不敢合"。当时我坚持没换模型&#xff0c;只改了一个东西——H…

2026/10/20 19:45:34 阅读更多 →
LTC681X驱动移植指南:SPI时序、菊花链与PEC校验实战

LTC681X驱动移植指南:SPI时序、菊花链与PEC校验实战

简介&#xff1a;本资源为ADI公司LTC681X系列高精度电池管理芯片&#xff08;AFE&#xff09;的官方驱动源码实现&#xff0c;面向嵌入式BMS开发工程师、电动汽车与储能系统硬件/软件开发者&#xff0c;解决多节串联电池电压采集、寄存器配置、SPI通信及CRC校验等核心底层开发难…

2026/10/20 19:45:34 阅读更多 →
MATLAB ICP点云配准全流程:粗配准、精配准与避坑指南

MATLAB ICP点云配准全流程:粗配准、精配准与避坑指南

简介&#xff1a;这是一套ICP迭代最近点算法的MATLAB源码实现&#xff0c;面向计算机视觉、机器人导航与三维重建领域的开发者和研究者&#xff0c;主要解决不同视角、不同时刻获取的点云数据如何统一到同一坐标系的问题。算法实现覆盖粗配准与精配准两个阶段&#xff0c;粗配准…

2026/10/20 19:45:34 阅读更多 →
大小核调度优化:强制程序跑在性能核上的全套实操指南

大小核调度优化:强制程序跑在性能核上的全套实操指南

如果你手头是一台采用混合架构处理器的电脑&#xff0c;比如“性能核 能效核”这种大小核布局&#xff0c;那你大概率遇到过这种情况&#xff1a;打游戏或者跑渲染时&#xff0c;明明CPU总使用率不高&#xff0c;但程序就是卡顿、掉帧、响应慢半拍。打开任务管理器一看&#x…

2026/10/20 19:44:28 阅读更多 →
别让CPU大核闲着:强制程序跑在高性能核心的完整指南

别让CPU大核闲着:强制程序跑在高性能核心的完整指南

别让CPU大核“闲着”&#xff01;一文教你强制程序跑在高性能核心上最近总有人跟我抱怨&#xff1a;电脑配置不低&#xff0c;但跑某个老软件时就是卡到怀疑人生。任务管理器打开一看&#xff0c;CPU占用率看着不高&#xff0c;频率却一直上不去。排查了一圈&#xff0c;很多人…

2026/10/20 19:44:28 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50: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/20 9:50:45 阅读更多 →