VC++扫雷源码实战:Win32 API与GDI桌面开发入门

简介:这份VC++扫雷游戏源程序面向具备C++基础、希望深入Windows桌面开发与游戏逻辑实现的开发者。项目基于Visual C++与MFC构建,完整呈现经典扫雷的算法设计与交互界面,涵盖雷区初始化、点击判断、标记雷、邻接格子雷数计算等核心逻辑,并借助对话框与控件实现鼠标点击、右键菜单等事件驱动交互,是理解二维数组遍历、递归展开与内存管理的实战范例。资源包共54个文件,约1.95MB,包含8个h头文件、6个cpp源文件、7个bmp位图、3个wav音效、1个ico图标及rc资源脚本,另有sbr、obj、pdb等编译调试中间文件,便于直接编译运行与断点调试。目前已有94人学习下载。通过研读源码,读者可掌握MFC界面搭建、事件绑定、错误处理与调试技巧,适合作为课程设计、C++进阶练习或游戏开发入门的参考素材。

1. 扫雷不只是小游戏:一份 VC++ 源码能让你摸清 Windows 桌面开发的骨架

很多人第一次接触 Windows 桌面开发,都是从扫雷这类小游戏开始的。这份 VC++ 游戏源程序扫雷,就是一套完整的 Win32 窗口程序,用 C++ 写成,编译出来就是一个能直接玩的扫雷。它适合两类人:一类是刚学完 C++ 语法、想找个能跑起来的项目练手的新手;另一类是想回头补 Win32 API、GDI 绘图和消息循环的老手。别看扫雷规则简单,它把窗口注册、消息泵、鼠标事件、定时器、资源脚本这些桌面开发的基本功全串了一遍。你把这套源码跑通、改几个参数,比看十篇 GDI 教程都管用。下面我按“能干什么 → 怎么跑 → 怎么改”的顺序,把这份源码拆开讲。

2. 工程结构与技术选型:Win32 API + GDI 的经典组合

2.1 为什么是 VC++ 而不是 MFC 或 Qt

这份源码用的是原生 Win32 API,没有依赖 MFC 框架,也没有 Qt 那套信号槽。好处是编译出来的 exe 体积极小,通常几十 KB,而且不需要额外运行库。坏处是所有窗口控件都要自己画,按钮、数字、笑脸全是 GDI 绘制出来的。对于想理解 Windows 消息机制的人来说,这反而是优点——没有框架帮你藏东西,WndProc里每个WM_消息都得自己处理。

常见做法是:用 Visual Studio 新建一个“Windows 桌面应用程序”空项目,然后把源码里的.cpp、.h、.rc文件加进去。如果你用的是较新版本的 VS,注意把字符集改成“使用多字节字符集”,因为老式 Win32 代码里大量用了char和sprintf,改成 Unicode 会报一堆错。

2.2 目录里都有什么

一份典型的扫雷源码包,解压后大概长这样:

MineSweeper/ ├── MineSweeper.sln // VS 解决方案文件 ├── MineSweeper/ │ ├── main.cpp // WinMain 入口,窗口注册与消息循环 │ ├── GameCore.cpp // 雷区生成、翻开、标记、胜负判定 │ ├── GameCore.h │ ├── Render.cpp // GDI 绘制格子、数字、笑脸 │ ├── Render.h │ ├── resource.h // 资源 ID 定义 │ ├── MineSweeper.rc // 菜单、图标、对话框资源 │ └── res/ // 图标、位图等

核心逻辑集中在GameCore.cpp,界面绘制在Render.cpp,入口和消息分发在main.cpp。这种拆分方式虽然简单,但已经具备了“逻辑与渲染分离”的雏形,改起来不会牵一发动全身。

2.3 关键数据结构

雷区通常用一个二维数组表示,每个格子用一个结构体或整型编码:

// GameCore.h struct Cell { bool isMine; // 是否是雷 bool isRevealed; // 是否已翻开 bool isFlagged; // 是否插旗 int adjacentMines; // 周围雷数,0-8 }; class GameCore { public: void Init(int rows, int cols, int mineCount); // 初始化雷区 void Reveal(int r, int c); // 翻开格子 void ToggleFlag(int r, int c); // 插旗/取消 bool IsWin() const; // 胜利判定 bool IsLose() const; // 失败判定 const Cell& GetCell(int r, int c) const; private: std::vector<std::vector<Cell>> grid; int rows, cols, mines; bool gameOver; void PlaceMines(int safeR, int safeC); // 首次点击不踩雷 void FloodFill(int r, int c); // 空白区域扩散 };

PlaceMines接收首次点击坐标,保证第一下不会炸,这是扫雷的标配逻辑。FloodFill用递归或队列实现,翻开一个空白格后自动展开周围区域。参数rows、cols、mineCount决定了难度,初级 9×9 10 雷,中级 16×16 40 雷,高级 16×30 99 雷,这些都可以在初始化时改。

3. 核心模块拆解:从消息循环到 GDI 绘制

3.1 WinMain 与消息泵

Windows 程序的生命线是消息循环。WinMain里先注册窗口类,再创建窗口,然后进入GetMessage/TranslateMessage/DispatchMessage的循环:

// main.cpp int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) { WNDCLASS wc = {0}; wc.lpfnWndProc = WndProc; // 窗口过程函数 wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); wc.lpszClassName = L"MineSweeperWnd"; RegisterClass(&wc); HWND hwnd = CreateWindow(wc.lpszClassName, L"扫雷", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, 400, 400, NULL, NULL, hInstance, NULL); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; }

WndProc是消息处理中心,鼠标点击、定时器、重绘都从这里进来。WM_LBUTTONDOWN处理左键翻开,WM_RBUTTONDOWN处理右键插旗,WM_TIMER更新计时器,WM_PAINT触发 GDI 绘制。每个消息的lParam里打包了鼠标坐标,用LOWORD和HIWORD取 x、y,再除以格子边长就能算出点的是哪一格。

3.2 雷区生成与首次点击保护

雷区生成不能一上来就随机撒雷,否则第一下就可能炸。正确做法是等玩家第一次点击后,再在非点击区域随机布雷:

void GameCore::PlaceMines(int safeR, int safeC) { std::vector<std::pair<int,int>> candidates; for (int r = 0; r < rows; ++r) for (int c = 0; c < cols; ++c) if (r != safeR || c != safeC) // 排除首次点击格 candidates.push_back({r, c}); std::random_device rd; std::mt19937 gen(rd()); std::shuffle(candidates.begin(), candidates.end(), gen); for (int i = 0; i < mines && i < (int)candidates.size(); ++i) { auto [r, c] = candidates[i]; grid[r][c].isMine = true; } // 计算每个格子周围的雷数 for (int r = 0; r < rows; ++r) for (int c = 0; c < cols; ++c) grid[r][c].adjacentMines = CountAdjacentMines(r, c); }

std::shuffle比rand()更均匀,避免某些格子雷密度异常。CountAdjacentMines遍历周围 8 个方向,边界检查不能少,否则数组越界直接崩。如果你想把“首次点击保护”扩展成“首次点击周围 8 格也安全”,只需在排除条件里多排除一圈即可。

3.3 GDI 绘制:把格子画到窗口上

WM_PAINT里用BeginPaint/EndPaint配对,中间用Rectangle、TextOut、DrawText画格子:

// Render.cpp void Render::DrawBoard(HDC hdc, const GameCore& game) { int cellSize = 24; for (int r = 0; r < game.GetRows(); ++r) { for (int c = 0; c < game.GetCols(); ++c) { int x = c * cellSize; int y = r * cellSize; const Cell& cell = game.GetCell(r, c); // 画格子边框 Rectangle(hdc, x, y, x + cellSize, y + cellSize); if (cell.isRevealed) { if (cell.isMine) { // 画雷 Ellipse(hdc, x + 4, y + 4, x + cellSize - 4, y + cellSize - 4); } else if (cell.adjacentMines > 0) { // 画数字,不同数字用不同颜色 SetTextColor(hdc, GetNumberColor(cell.adjacentMines)); char buf[2] = { (char)('0' + cell.adjacentMines), 0 }; TextOutA(hdc, x + 7, y + 4, buf, 1); } } else if (cell.isFlagged) { // 画旗子 // ... } } } }

cellSize决定格子大小,改这个值就能缩放整个界面。GetNumberColor返回 1 到 8 对应的颜色,经典扫雷里 1 是蓝色、2 是绿色、3 是红色,这些都可以按自己喜好调。注意TextOutA用的是多字节字符集,如果你项目设成了 Unicode,要改成TextOutW并传宽字符。

3.4 递归展开与胜负判定

翻开空白格时,如果周围没有雷,要自动展开相邻区域。递归实现简单,但雷区大时可能栈溢出,稳妥做法是用队列:

void GameCore::FloodFill(int r, int c) { std::queue<std::pair<int,int>> q; q.push({r, c}); while (!q.empty()) { auto [cr, cc] = q.front(); q.pop(); if (cr < 0 || cr >= rows || cc < 0 || cc >= cols) continue; Cell& cell = grid[cr][cc]; if (cell.isRevealed || cell.isFlagged) continue; cell.isRevealed = true; if (cell.adjacentMines == 0 && !cell.isMine) { for (int dr = -1; dr <= 1; ++dr) for (int dc = -1; dc <= 1; ++dc) if (dr != 0 || dc != 0) q.push({cr + dr, cc + dc}); } } }

胜利判定是:所有非雷格子都被翻开。失败判定是:翻开了任意一个雷。这两个条件在每次Reveal后检查一次,更新gameOver标志,然后触发重绘。

4. 编译运行与调试:从源码到可玩 exe

4.1 用 Visual Studio 跑起来

打开.sln文件,确认平台工具集和 Windows SDK 版本匹配。如果提示找不到windows.h,说明没装“使用 C++ 的桌面开发”工作负载。编译前检查三点:字符集设为多字节、C++ 语言标准至少 C++11、链接器子系统是WINDOWS。按 F5 运行,应该能看到一个窗口,左键点格子,右键插旗,点中雷就弹提示。

4.2 常见编译错误与处理

  • error C2440: “初始化”: 无法从“const char [x]”转换为“LPCWSTR”:字符集设成了 Unicode,改成多字节即可。
  • error LNK2019: 无法解析的外部符号:通常是.rc文件没加进项目,或者资源 ID 对不上。
  • 窗口一闪而过:WinMain里消息循环写错,检查GetMessage返回值判断。

4.3 调试技巧

在WndProc里对WM_LBUTTONDOWN下断点,看lParam解出来的坐标对不对。如果点击没反应,先确认窗口过程有没有正确返回DefWindowProc。GDI 绘制出问题,用OutputDebugString打印格子状态,或者临时把cellSize调大,肉眼观察绘制区域。

5. 避坑与常见问题:那些年我踩过的雷

5.1 首次点击就炸

现象:刚开局点第一下就踩雷。原因:雷区在初始化时就已经随机布好,没有排除首次点击格。解决:把布雷推迟到第一次左键点击后,用PlaceMines(safeR, safeC)排除点击格。

5.2 递归展开导致栈溢出

现象:点开一大片空白区域时程序崩溃。原因:FloodFill用递归实现,雷区大时递归深度超过栈限制。解决:改成队列或栈的迭代写法,如上文FloodFill所示。

5.3 右键插旗后左键还能翻开

现象:插了旗的格子左键点击仍然会翻开。原因:Reveal里没有检查isFlagged。解决:在Reveal开头加if (cell.isFlagged) return;,插旗的格子不允许翻开。

5.4 计时器不更新或更新过快

现象:计时器数字不动,或者一秒跳好几下。原因:SetTimer的时间间隔单位是毫秒,设成 1000 才是 1 秒;另外WM_TIMER里要累加计数并重绘。解决:确认SetTimer(hwnd, 1, 1000, NULL),在WM_TIMER里seconds++后InvalidateRect。

5.5 窗口重绘闪烁

现象:调整窗口大小或频繁重绘时界面闪烁。原因:每次WM_PAINT直接画到屏幕 DC。解决:用双缓冲——先画到内存 DC,再BitBlt到屏幕 DC。这是 GDI 绘图的老毛病,加上双缓冲后闪烁基本消失。

6. 二次开发与改造思路:把扫雷改成你自己的项目

这份源码最大的价值不是扫雷本身,而是它提供了一个可运行的 Win32 骨架。你可以在这个骨架上换皮、换逻辑、加功能。下面说几个我实际改过的方向。

改难度和界面尺寸:在GameCore::Init里把rows、cols、mineCount改成变量,从菜单或对话框读取。Render::DrawBoard里的cellSize改成根据窗口宽度动态计算,就能实现自适应缩放。注意改完要重新计算窗口客户区大小,用AdjustWindowRect把边框和标题栏算进去。

加双缓冲:在WM_PAINT里创建兼容 DC 和位图,所有绘制先画到内存位图,最后一次性BitBlt到窗口。代码大概长这样:

case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); HDC memDC = CreateCompatibleDC(hdc); HBITMAP memBmp = CreateCompatibleBitmap(hdc, clientW, clientH); HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, memBmp); // 所有绘制操作改用 memDC Render::DrawBoard(memDC, game); BitBlt(hdc, 0, 0, clientW, clientH, memDC, 0, 0, SRCCOPY); SelectObject(memDC, oldBmp); DeleteObject(memBmp); DeleteDC(memDC); EndPaint(hwnd, &ps); break; }

clientW和clientH从GetClientRect获取。双缓冲加上后,窗口拖动和重绘都不会闪。

加音效和动画:用PlaySound播放 wav 文件,在翻开、插旗、爆炸时触发。动画可以用定时器逐帧重绘,比如爆炸时让雷闪几下。注意音效文件要放进res/并在.rc里注册。

改造成其他棋类游戏:扫雷的格子模型和点击逻辑,稍加改动就能变成翻转棋、数独或推箱子。核心是把Cell结构体换成你需要的状态字段,Reveal换成你的操作函数,Render换成你的绘制逻辑。消息循环和窗口框架完全不用动。

验证改造是否成功:每次改完,先跑一遍完整对局——开局、翻开、插旗、胜利、失败,五个状态都走一遍。再故意点边界格子,看有没有数组越界。最后用_CrtSetDbgFlag开内存泄漏检测,确认没有 GDI 对象泄漏。GDI 对象泄漏是 Win32 程序的血泪坑,CreateCompatibleDC、CreateCompatibleBitmap用完必须DeleteObject和DeleteDC,否则跑久了句柄数爆掉,界面直接卡死。

从那以后我每次改 GDI 代码,都强制走一遍“创建-使用-删除”的配对检查,宁可多写两行清理代码,也不留句柄泄漏的后悔药。希望这份拆解能帮到你,拿到源码后先跑通,再挑一个模块动手改,比干看强得多。

本文还有配套的精品资源,点击获取

相关新闻

Win11本地部署DeepSeek-R1:Ollama实操与避坑指南

Win11本地部署DeepSeek-R1:Ollama实操与避坑指南

简介&#xff1a;面向 Windows 11 用户与 AI 应用爱好者的 DeepSeek-R1 本地部署指南&#xff0c;围绕 Ollama 工具详细介绍在个人电脑上运行大模型所需的软硬件准备、环境搭建与调用方法&#xff0c;不仅降低使用门槛&#xff0c;还能帮助读者摆脱云端依赖&#xff0c;兼顾数据…

2026/10/20 12:10:04 阅读更多 →
自监督学习如何让AI Agent从原始数据中学会本领

自监督学习如何让AI Agent从原始数据中学会本领

训练一个Agent&#xff0c;最憋屈的事是什么&#xff1f;我觉得是人手跟不上。数据标注的进度永远比模型迭代慢半步&#xff1a;你想让机器人在仓库里学会识别货架缝隙&#xff0c;得先让标注员一帧一帧框出来&#xff1b;想让对话Agent学会判断用户情绪&#xff0c;得先雇人给…

2026/10/20 12:10:04 阅读更多 →
AI生成内容如何降低AI疑似度?嘎嘎降AI使用指南与避坑全攻略

AI生成内容如何降低AI疑似度?嘎嘎降AI使用指南与避坑全攻略

最近两个月&#xff0c;找我聊“AI写出来的东西发不出去”的人明显变多了。无论是做自媒体、写公众号、搞电商文案&#xff0c;还是在读学生写课程报告&#xff0c;很多人的操作路径都是一样的&#xff1a;先让AI把初稿拉出来&#xff0c;自己再改改就发&#xff0c;结果拿到第…

2026/10/20 12:10:04 阅读更多 →

最新新闻

AI生成内容红线全解析:从审核技术到创作者避坑指南

AI生成内容红线全解析:从审核技术到创作者避坑指南

1. 从AI魔改到AIGC微短剧&#xff0c;为什么2026年的"红线"问题绕不过去过去这一两年&#xff0c;AI生成视频的进化速度着实让人心惊。去年大家还在用"AI魔改"恶搞老电影片段&#xff0c;把台词换成离谱的台词、表情换成夸张的表情&#xff1b;到了今年&am…

2026/10/20 13:03:57 阅读更多 →
​地球物理大地测量学计算系列之二十三过指定点重力等位面构造

​地球物理大地测量学计算系列之二十三过指定点重力等位面构造

1、过指定点重力等位面构造 利用高阶地球重力场位系数模型&#xff0c;计算过指定点(经度&#xff0c;纬度&#xff0c;大地高)重力等位面相对于指定点的大地高差和重力差格网。利用局部重力场数据&#xff0c;能进一步精化过指定点重力等位面的大地高差和重力差格网。 [功能]…

2026/10/20 13:03:57 阅读更多 →
STM32F407 挂载 Si5324 时钟芯片配置程序全流程与避坑指南

STM32F407 挂载 Si5324 时钟芯片配置程序全流程与避坑指南

简介&#xff1a;这份资源面向嵌入式开发与时钟系统设计人员&#xff0c;提供基于STM32F407平台配置Si5324时钟发生器的完整程序方案。Si5324作为可编程多输出频率合成器&#xff0c;支持LVPECL、HCSL、LVDS、LVCMOS等多种输出格式&#xff0c;常用于通信、数据中心与测试设备。…

2026/10/20 13:03:57 阅读更多 →
国产AI芯片软件生态破局:从CUDA垄断到联合深度适配

国产AI芯片软件生态破局:从CUDA垄断到联合深度适配

上个月我们做国产算力选型评审&#xff0c;小组拿到一块新出的国产AI加速卡&#xff0c;硬件规格表相当漂亮——算力、显存、互连带宽都不弱于我们正在用的国际GPU。可真正把流行的开源大模型跑起来时&#xff0c;第一晚就栽在算子兼容性上报错。那一刻我突然意识到&#xff1a…

2026/10/20 13:03:57 阅读更多 →
STM32F407驱动Si5324时钟芯片:I2C配置程序与调试避坑指南

STM32F407驱动Si5324时钟芯片:I2C配置程序与调试避坑指南

简介&#xff1a;这份资源面向嵌入式开发与时钟系统设计人员&#xff0c;提供基于STM32F407平台配置Si5324时钟发生器的完整程序方案。Si5324作为高精度、低相位噪声的可编程频率合成器&#xff0c;广泛用于通信、数据中心与测试设备&#xff0c;资源围绕其寄存器配置、分频系数…

2026/10/20 13:03:57 阅读更多 →
context-mode:一种运行时上下文驱动的行为策略设计范式

context-mode:一种运行时上下文驱动的行为策略设计范式

1. “context-mode”不是新功能&#xff0c;而是开发者正在集体重构的底层认知最近在多个技术社区和开源项目讨论区里&#xff0c;“context-mode”这个词高频出现&#xff0c;但翻遍主流文档、API手册甚至GitHub仓库的README&#xff0c;几乎找不到它的官方定义。它既不是某个…

2026/10/20 13:02:56 阅读更多 →

日新闻

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 阅读更多 →