MFC实战:枚举Windows进程并显示窗口标题与内存占用
最近整理Windows桌面开发的笔记正好写到“MFC读取程序信息并显示”这一节。这可能也是很多初学MFC的人会遇到的题目做一个界面把当前系统里的进程、窗口之类的信息读出来显示到列表里。说实话MFC这套东西放到现在看着是有点“老”但你要是想快速写一个系统维护小工具、进程查看器、窗口管理器它依然是Windows平台上很顺手的选择毕竟封装好的控件和API调用比纯Win32 SDK开发省事不少。这期内容适合两类人一类是刚学完MFC对话框程序、想找个综合练手项目的人另一类是想自己做点实用工具、但不想去啃C#或Electron的C开发者。从零开始建工程、写代码、排错一套走完你对Windows进程模型、窗口管理、消息机制的理解会明显上一个大台阶。我尽量把这个过程的思路、代码和坑都写清楚。1. 项目整体思路与设计拆解1.1 到底要读取什么“程序信息”先明确一下这里说的“程序信息”是什么。这个题目非常宽泛可以读进程列表、窗口标题、CPU占用、内存占用、模块列表甚至可以读文件版本信息。如果一开始就什么都想做项目会迅速失控。我的建议是第一版只做四件事枚举系统当前正在运行的进程拿到每个进程的PID和进程名。对每个进程尝试找到它的主窗口读取窗口标题。读取进程占用的内存大小。把以上信息用列表形式展示出来支持刷新。这个范围刚好能把MFC的列表控件、定时器、按钮事件、Windows API的进程快照和窗口枚举都串起来又不至于太复杂。后续再想扩展比如双击查看模块信息、右键结束进程、实时监控CPU占用都是在这个骨架上加肉的事。1.2 为什么选MFC而不是直接写Win32或转用其他框架很多人会问现在做Windows界面直接用Win32 SDK写不是更底层、更“专业”吗或者干脆用Qt、C#/.NET不是更快吗我的真实感受是MFC作为Win32 API的C封装最大的价值在于把消息循环、窗口注册、控件创建这些繁琐的样板代码收进类框架里。你不需要手工写几百行窗口过程函数就能得到一个带对话框界面、能响应按钮点击的Windows程序。而Win32裸写对于练习底层原理很好但做“读取并显示程序信息”这种偏应用层的小工具效率确实低一些。至于Qt和C#它们当然很强大。但如果你所在的项目组、或者你手头的代码库就是MFC维护的老工程那掌握MFC依然是一项实打实的技能。实际上很多工业控制软件、内部运维工具至今都是MFC写的舍得花一周把这个流程打通后面能在很多存量项目上派上用场。1.3 功能模块划分我把整个项目拆成三个模块数据获取模块调用Windows API遍历进程、窗口读取内存占用结果临时存放在内存中。界面展示模块使用MFC的CListCtrl控件以报表模式展示数据带列头。交互刷新模块点击“刷新”按钮或者启用定时器重新读取数据并更新列表。这样分的好处是测试的时候可以先在控制台或调试输出里验证数据是否读对了再决定怎么往界面上填。不然数据和界面混在一起出问题很难判断是API调用失败还是控件使用有误。2. 核心API与原理解析2.1 进程快照CreateToolhelp32Snapshot与Process32First/Next枚举进程最常用的方式不是遍历Windows内部的内核结构而是调用Toolhelp API生成一份“进程快照”。其实就是一个特定时刻系统中进程列表的副本。HANDLE hSnapshot CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot INVALID_HANDLE_VALUE) { // 快照创建失败 return; } PROCESSENTRY32 pe; pe.dwSize sizeof(PROCESSENTRY32); if (Process32First(hSnapshot, pe)) { do { // pe.th32ProcessID 是进程PID // pe.szExeFile 是进程可执行文件名 // pe.th32ParentProcessID 是父进程PID } while (Process32Next(hSnapshot, pe)); } CloseHandle(hSnapshot);这里有两个非常容易踩的坑。第一个坑是PROCESSENTRY32结构体中的dwSize字段必须手动初始化否则Process32First直接返回FALSE。原因很简单系统需要靠这个字段确认你使用的结构体版本和缓冲区大小。很多新手第一次写忘了赋sizeof(PROCESSENTRY32)然后怎么查都查不出原因。第二个坑是CreateToolhelp32Snapshot的返回值。它失败时返回的是INVALID_HANDLE_VALUE也就是(HANDLE)-1不是NULL。我用NULL判断过结果程序在后面的Process32First里直接崩了。凡是返回句柄的API失败值到底是NULL还是INVALID_HANDLE_VALUE一定要先查文档确认。2.2 窗口枚举EnumWindows回调函数进程ID拿到之后第二步是找到某个进程对应的“主窗口”。这就要用到EnumWindows。BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { // lParam 里传入的是进程PID DWORD targetPid (DWORD)lParam; DWORD windowPid 0; GetWindowThreadProcessId(hwnd, windowPid); if (windowPid targetPid IsWindowVisible(hwnd)) { TCHAR szTitle[MAX_PATH] {0}; int len GetWindowText(hwnd, szTitle, MAX_PATH); if (len 0) { // 找到了可见且有标题的窗口记录下来 } } return TRUE; // 继续枚举 }EnumWindows会枚举桌面上所有顶层窗口并对每个窗口调用你提供的回调函数。回调返回TRUE继续枚举返回FALSE则提前停止。需要注意一个进程可能有很多可见窗口也可能一个都没有。常见的策略是枚举到第一个可见且有标题的窗口就停止或者收集所有符合条件的窗口再从中选一个。在进程管理器里通常每个进程只显示一个主窗口所以找到第一个就停止完全够用。还有一个细节GetWindowText读取的是窗口的标题栏文字。如果目标是其他进程的窗口系统会跨进程发送消息来获取文字这会导致一定的性能开销。在一次性全量枚举时没问题但如果做成定时器每秒刷新就要考虑只读取当前选中进程的窗口标题避免卡顿。2.3 内存占用GetProcessMemoryInfo内存占用需要先打开进程句柄再用GetProcessMemoryInfo查询。HANDLE hProcess OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess) { PROCESS_MEMORY_COUNTERS pmc; ZeroMemory(pmc, sizeof(pmc)); if (GetProcessMemoryInfo(hProcess, pmc, sizeof(pmc))) { // pmc.WorkingSetSize 是物理内存占用单位字节 } CloseHandle(hProcess); }PROCESS_MEMORY_COUNTERS结构体里字段不少WorkingSetSize表示当前驻留物理内存大小PagefileUsage表示虚拟内存占用。通常展示前者即可把字节数除以1024再除以1024转成MB。但是这里有个很现实的权限问题某些系统进程比如会话管理相关的进程普通权限下调用OpenProcess会返回NULL。这是正常现象不是代码写错了。在界面显示时这种情况就直接展示“N/A”或者权限不足别让程序因为一句获取失败就中断整个刷新流程。2.4 这三个API怎么配合起来用先调用CreateToolhelp32Snapshot拿到全局进程列表这是第一层循环。在循环里对每一个PID调用EnumWindows去找主窗口标题这是第二层枚举。同时对同一个PID调用OpenProcess加GetProcessMemoryInfo获取内存。这个流程看起来逻辑清晰但性能上有一点要注意进程可能上百个每个进程都要枚举一次全局窗口列表这是O(N*M)的复杂度N是进程数M是窗口数。实测在普通电脑上一次全量刷新大约几十到一百毫秒可接受。但如果你追求更优可以先枚举所有窗口把窗口和PID的映射关系存到一个哈希表里之后再遍历进程时直接查表。这样一次窗口枚举搞定所有进程。我推荐第一版先把功能跑通用简单的双重遍历。等功能稳定了再优化数据结构也更容易验证优化前后的结果是否一致。3. 实操过程与核心代码实现3.1 创建MFC对话框工程我用的是VS环境新建项目时选择“MFC应用程序”在向导里选“基于对话框”即可。工程名可以叫ProcInfoViewer这个看个人习惯。创建完会自动生成一个对话框资源上面默认有一个确定按钮和一个取消按钮。打开资源视图找到IDD对话框先删掉默认按钮然后从工具箱拖进来一个List Control控件用于展示进程信息。设置它的View属性为Report并勾选需要边框。一个Button控件作为刷新按钮。一个Static Text控件显示状态信息比如“共N个进程”。给列表控件添加成员变量。在类向导里选中列表控件关联一个CListCtrl类型的变量我习惯命名为m_listProc。然后重写对话框的OnInitDialog在初始化时加载列头BOOL CProcInfoViewerDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置列表控件扩展样式整行选中、网格线 m_listProc.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); // 添加列 m_listProc.InsertColumn(0, _T(PID), LVCFMT_LEFT, 80); m_listProc.InsertColumn(1, _T(进程名), LVCFMT_LEFT, 200); m_listProc.InsertColumn(2, _T(窗口标题), LVCFMT_LEFT, 250); m_listProc.InsertColumn(3, _T(内存占用(MB)), LVCFMT_RIGHT, 120); // 初始化时刷新一次 RefreshProcessList(); return TRUE; }列宽我是按实际显示效果调的PID列80像素足够进程名留200窗口标题有时候很长给250比较合适。这些数值没有标准答案取决于你的界面整体宽度。3.2 核心代码刷新进程列表“刷新”按钮的点击事件里调用RefreshProcessList函数。下面是这个函数的完整实现我把数据获取和界面填充写在一起方便第一版理解。void CProcInfoViewerDlg::RefreshProcessList() { // 清空旧数据 m_listProc.DeleteAllItems(); // 1. 创建进程快照 HANDLE hSnapshot CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot INVALID_HANDLE_VALUE) { AfxMessageBox(_T(创建进程快照失败)); return; } PROCESSENTRY32 pe; pe.dwSize sizeof(PROCESSENTRY32); int nIndex 0; BOOL bRet Process32First(hSnapshot, pe); while (bRet) { DWORD pid pe.th32ProcessID; CString strName pe.szExeFile; // 2. 根据PID查找主窗口标题 CString strWindowTitle GetWindowTitleByPid(pid); // 3. 获取进程内存占用 CString strMemory GetProcessMemoryByPid(pid); // 4. 插入到列表 m_listProc.InsertItem(nIndex, _T()); m_listProc.SetItemText(nIndex, 0, FormatPid(pid)); m_listProc.SetItemText(nIndex, 1, strName); m_listProc.SetItemText(nIndex, 2, strWindowTitle); m_listProc.SetItemText(nIndex, 3, strMemory); nIndex; bRet Process32Next(hSnapshot, pe); } CloseHandle(hSnapshot); // 状态栏显示进程数量 CString strStatus; strStatus.Format(_T(共 %d 个进程), nIndex); SetDlgItemText(IDC_STATIC_STATUS, strStatus); }FormatPid就是一个把DWORD转成CString的小工具没什么特别的。3.3 窗口标题查询函数前面回调里用EnumWindows这里封装一个辅助函数GetWindowTitleByPid。struct WindowSearchParam { DWORD pid; CString title; }; BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { WindowSearchParam* pParam (WindowSearchParam*)lParam; DWORD windowPid 0; GetWindowThreadProcessId(hwnd, windowPid); if (windowPid pParam-pid) { TCHAR szTitle[MAX_PATH] {0}; int len GetWindowText(hwnd, szTitle, MAX_PATH); if (len 0 IsWindowVisible(hwnd)) { pParam-title szTitle; return FALSE; // 找到第一个符合条件的窗口就结束枚举 } } return TRUE; } CString CProcInfoViewerDlg::GetWindowTitleByPid(DWORD pid) { WindowSearchParam param; param.pid pid; param.title _T(); EnumWindows(EnumWindowsProc, (LPARAM)param); return param.title; }这里我用了一个小结构体把参数传给回调函数因为回调函数是全局函数不能直接访问对话框类的成员变量。传参的方式就是把需要的结果放在结构体里通过LPARAM传入。判断窗口时我同时检查了IsWindowVisible和标题是否非空。有窗口但没标题的进程在进程管理器里通常显示为空这里也统一显示为空字符串。3.4 内存查询函数CString CProcInfoViewerDlg::GetProcessMemoryByPid(DWORD pid) { CString strResult _T(N/A); HANDLE hProcess OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess) { PROCESS_MEMORY_COUNTERS pmc; ZeroMemory(pmc, sizeof(pmc)); if (GetProcessMemoryInfo(hProcess, pmc, sizeof(pmc))) { double mb (double)pmc.WorkingSetSize / (1024.0 * 1024.0); strResult.Format(_T(%.1f), mb); } CloseHandle(hProcess); } return strResult; }WorkingSetSize是进程当前实际占用物理内存的字节数包括共享内存中属于该进程的部分所以和任务管理器里的“内存(活动工作集)”基本对应。要注意的是它不包含页文件里的虚拟内存部分这会在某些高内存压力的场景下产生几MB到几十MB的差异这是正常现象。3.5 菜单资源里加一个不依赖按钮的刷新方式除了按钮我还习惯加一个右键菜单来触发刷新因为列表控件右键弹出“刷新”是很常见的交互。这个不是必须但值得做。在资源视图里新建一个菜单ID为IDR_MENU_PROC上面放一个“刷新”菜单项ID设置为IDC_REFRESH和按钮使用同一个命令ID。在OnInitDialog里设置列表控件的右键菜单// 在 OnInitDialog 中添加 m_listProc.SetParent(this); // 重写 PreTranslateMessage 或者使用控件的右键通知更简单的做法是给列表控件添加NM_RCLICK通知然后加载菜单显示。这个细节不影响核心功能不加也行。4. 常见问题与排查技巧实录4.1 列表为空Process32First返回FALSE第一步先检查dwSize有没有初始化。这是遇到最多的新手问题代码里没有给pe.dwSize赋值导致系统无法判断结构体大小直接返回FALSE。PROCESSENTRY32 pe; pe.dwSize sizeof(PROCESSENTRY32); // 这一行不能省另外检查快照句柄是否创建成功CreateToolhelp32Snapshot失败时要看返回的是不是INVALID_HANDLE_VALUE而不是NULL。4.2 窗口标题全是乱码这个大概率是字符集问题。MFC工程默认使用Unicode字符集TCHAR在编译后是wchar_tGetWindowText取出的也是Unicode字符串正常情况下应该直接显示中文。如果你在项目属性里把“字符集”设置成“使用多字节字符集”那么TCHAR是char而GetWindowText内部是宽字符这时就要做转换。我的建议是直接用Unicode编译少很多编码问题。老代码迁移到新工程时容易遇到这个坑新工程直接默认Unicode就好。还有一个隐蔽的问题如果你用CString接收窗口标题然后在SetItemText时传strTitle在Unicode下毫无问题。但有些人图省事用char数组接收然后强制转给CString就会得到一堆乱码。遇到这种情况别急着怀疑系统API先在调试器里看GetWindowText返回的原始缓冲区是不是正确的。4.3 刷新时界面卡顿一次全量刷新虽然在性能上可接受但如果在按钮点击事件里反复调用并且进程数特别多一秒内多次刷新还是可能让界面出现可见的迟滞感。最简单的解决方法是不要在UI线程频繁做全量刷新。可以给刷新按钮加一个“屏蔽重入”的逻辑if (m_bRefreshing) { return; } m_bRefreshing TRUE; RefreshProcessList(); m_bRefreshing FALSE;这样即使快读双击刷新按钮也不会出现两次刷新同时执行导致列表闪烁的问题。真正的性能瓶颈主要在窗口标题获取上EnumWindows加GetWindowText组合在进程数上百时会花掉几十毫秒。如果以后想升级成实时监控考虑先用一次EnumWindows把所有窗口信息存在按进程PID分组的容器里再遍历进程查表速度可以提升一个量级。4.4 某些进程内存显示“N/A”这跟权限有关。OpenProcess失败通常有两种情况进程是系统级进程当前用户权限不够。目标进程属于其他会话比如管理员权限运行的程序。处理办法就是容忍失败显示“N/A”或者“权限不足”不要弹出错误框打断用户。如果确实需要读取所有进程信息可以考虑给程序添加管理员权限的清单文件requireAdministrator但这会带来UAC弹窗提醒小工具是否需要这样做要权衡一下。4.5 进程名很长导致列宽不够列宽设置可以支持用户手动拖动LVS_EX_FULLROWSELECT扩展样式不会影响列拖拽。但初始化时还是建议给进程名留足够宽度因为像svchost.exe这种不算长但一些软件进程名往往很占空间。我习惯在OnInitDialog里设置列宽后再设置CListCtrl的sethovercursor之类的扩展样式保证用户体验。这些细节做不做看心情但列宽这种直接决定第一观感的东西最好一次性调好。5. 后续功能扩展的几个方向这版程序跑通之后其实已经有了一个很实用的“进程查看器”雏形。你可以继续加功能每加一个都涉及新的知识点结束进程双击列表项或者右键菜单加“结束进程”内部调用OpenProcess(PROCESS_TERMINATE)加TerminateProcess。这里要注意结束的是别人的程序要有二次确认机制。进程详细内存增加PagefileUsage、QuotaPeakNonPagedPoolUsage字段的显示做一个内存详情对话框。模块列表枚举指定进程加载的DLL模块用CreateToolhelp32Snapshot加TH32CS_SNAPMODULE参数能看到进程依赖哪些链库。排序功能CListCtrl本身不内置排序需要处理LVN_COLUMNCLICK消息用CListCtrl::SortItems自定义比较函数。这又是一个很好的练习点。定时自动刷新用SetTimer加WM_TIMER消息每5秒自动刷新一次列表。注意刷新完恢复选中状态不然用户正在看某个进程列表一闪选中行丢了体验很差。我个人做这个练习时的体会是这个题目最大的价值不在于你最终实现了多少功能而在于你把“进程”和“窗口”这两个Windows系统中非常核心的概念串起来了。以前只知道进程是个黑盒子做完之后自然就理解了进程ID、主窗口、句柄、权限这些词在实际代码里是什么样的关系。后面再学线程、消息循环就有了一层具象的认知基础。最后分享一个很小的技巧调试这类读取系统信息的程序时别只盯着代码看把任务管理器打开放在旁边对比。你一刷新列表任务管理器里的进程列表也在跳两边对照着看如果出现某个进程你这里没有、或者内存差异巨大排查方向就清晰很多。真实系统数据本身就是最好的调试参照物。

相关新闻

金山毒霸卸载后仍弹窗?彻底清理残留的完整指南

金山毒霸卸载后仍弹窗?彻底清理残留的完整指南

说个有点反直觉的现象:很多人以为把金山毒霸从“应用列表”里卸载了,弹窗就会彻底消失。结果重启完电脑,右下角照旧弹“今日热点”,甚至卸载当天就开始弹。我这些年处理过不少类似情况,文件夹删不掉、服务还在跑、计划…

2026/10/18 12:00:14 阅读更多 →
jackalope:基于Python的GFF3基因注释可视化工具实战指南

jackalope:基于Python的GFF3基因注释可视化工具实战指南

简介:Jackalope 是一款面向生物信息学分析人员的 GFF3 基因注释数据可视化工具,适合需要将 ENSEMBL 基因结构转化为直观图表的科研人员与开发者使用。它同时提供 Perl 与 Python 两套脚本:前者可依据 ENSEMBL ID 直接抓取对应 GFF3 文件&…

2026/10/18 12:00:14 阅读更多 →
103976英文单词翻译库:SQL、CSV、Excel三种格式与实战应用

103976英文单词翻译库:SQL、CSV、Excel三种格式与实战应用

简介:一份包含103976个英文单词的翻译库,同时提供SQL、CSV、Excel三种格式,面向英语学习者、翻译工作者及软件开发者。库表内置英文单词、中文翻译、词性及多种词义,执行SQL语句即可生成表,支持SQL Server、MySQL等主流…

2026/10/18 12:00:14 阅读更多 →

最新新闻

hostapd-2.10源码解析:从编译到二次开发实战指南

hostapd-2.10源码解析:从编译到二次开发实战指南

简介:hostapd-2.10源码包面向Linux无线开发与嵌入式网络工程师,用于在Linux系统上以软件方式创建和管理WiFi热点,替代硬件AP实现主机模式接入点。包内共655个文件,以363个C源文件和235个头文件为核心,覆盖nl80211驱动、…

2026/10/18 15:50:15 阅读更多 →
LISREL验证性因素分析完整指南:从模型识别到拟合判读

LISREL验证性因素分析完整指南:从模型识别到拟合判读

简介:一份面向社会科学、心理学及教育学研究者与学生的LISREL软件验证性因素分析教学PPT,系统讲解结构方程模型中验证性因素分析的核心逻辑与实操要点。资源从“准确Vs简洁”的数据处理两难切入,说明如何输入相关矩阵、设定理论模型、输出再生…

2026/10/18 15:50:15 阅读更多 →
通义千问Qwen3本地部署实战:MoE架构、硬件选型与性能调优

通义千问Qwen3本地部署实战:MoE架构、硬件选型与性能调优

前几天有个朋友来问我,说他拿到一台旧工作站,想跑一个新出的开源模型,问我到底值不值得折腾。我第一反应是问他:你要跑的模型是哪个?他回答说在想跑通义千问 Qwen3 系列。我说那就很值得,Qwen3 这一代把 Mo…

2026/10/18 15:50:15 阅读更多 →
AI原生应用人机共创成功案例:用TaoToken统一Key打通多模型协作链路

AI原生应用人机共创成功案例:用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/18 15:50:15 阅读更多 →
翁恺C语言习题集刷题指南:环境搭建、题型拆解与避坑要点

翁恺C语言习题集刷题指南:环境搭建、题型拆解与避坑要点

简介:浙江大学翁恺教授C语言课程习题与源码合集,专门面向C语言初学者、备考计算机等级考试或自学编程的读者,覆盖从基础语法到典型算法的多层次练习。资源共4个文件,包含txt题解文档、Python辅助脚本、inscode在线交互文件和html页…

2026/10/18 15:50:15 阅读更多 →
红色党建风工作总结PPT模板:从空白页到成稿的工程化流程

红色党建风工作总结PPT模板:从空白页到成稿的工程化流程

简介:这是一套面向党政部门的工作总结PPT模板,整体采用红色党建风格,视觉庄重且富有感染力,适合年终总结、阶段汇报、主题教育展示等场合。模板内置完整汇报逻辑,共分为工作目标与背景、工作成果与亮点、挑战与解决方案…

2026/10/18 15:49:14 阅读更多 →

日新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 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/18 0:55:02 阅读更多 →
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/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →