VS2008下GDAL读取与显示TIFF影像的完整实现指南

简介:一份面向GIS开发者的VS2008 C++工程,基于GDAL库读取并显示TIFF遥感影像,覆盖从数据集打开、波段读取、像素显示到资源释放的完整流程。工程源码与调试文件齐全,共45个文件、压缩包14.31MB,包含7个.h头文件与5个.cpp源文件,以及.sln/.vcproj工程配置、可直接运行的.exe、.pdb/.ilk调试符号,还有.rc/.ico/.bmp等界面资源;编译中间文件.obj/.pch/.idb也保留在内,方便对照Visual C++的构建过程,并附有说明文档便于快速上手。学习时可重点关注GDALDriverManager获取驱动器、GDALDataset打开数据集、GDALRasterBand读取波段、ReadRaster获取像素等典型API调用,工程已预先配置好头文件路径与链接库,避开常见的GDAL环境搭建坑,同时给出了x86/x64平台配置的注意事项。目前已有800人学习,适合C++入门者快速上手GDAL,也适合GIS开发者作为影像显示模块的参考实现。后续可按需扩展裁剪、重采样、颜色校正,甚至接入PROJ.4实现坐标转换,扩展性强。

1. VS2008里的GDAL工程能干什么:老代码最需要的影像读取链路

如果你接手过一套 VS2008 时代的 GIS 老代码,大概率遇到过这种场景:界面框架都齐全,菜单能点,窗口能拉,但一打开.tif文件,画面上什么都没有——要么黑屏,要么只有左下角几个坐标数字在跳。这个工程解决的就是这件事:让它用 C++ 和 GDAL 库把 TIFF 影像真正读出来、显示在窗口里。

它不做什么图像增强、不搞深度学习、不接数据库,就是老项目里最刚需的一条链路:GDAL 打开文件 → 读栅格波段 → 做灰度映射 → 用 GDI 画到窗口。适合两类人:一类是接手历史项目、正被“VS2008 + GDAL + TIFF”组合折磨的维护者;另一类是教学或 Demo 阶段,想用最小代码量理解 GDAL 数据模型的学生和开发者。下面这套流程,我在模拟项目X里完整跑通过,从配置到出图,每一步都能照抄。

2. 环境准备:把 VS2008 和 GDAL 接上头

2.1 GDAL 版本选择与编译器对应关系

VS2008 对应的是 VC9 编译器,这套环境很老,但不是随便拿一个新版 GDAL 就能编译的。GDAL 从 1.8 开始大幅度调整构建脚本,到 2.x 时代基本放弃了对 VS2008 的官方支持。常见做法是选 GDAL 1.7 的编译产物,或者找一份用 VC9 编译好的 1.6/1.7 静态库。我自己习惯用 1.7,头文件是gdal_priv.h,导入库是gdal_i.lib,这两个名字在后续代码里会一直用到。

如果你的机器上只有新版 GDAL 源码,也可以自己编译。但编译的时候记得确认工具集选的是 v90,不是 v100 或更高。这里有一个关键点:VC9 编译器对 C++ 标准的支持还停留在 C++03 层面,新版本 GDAL 源码里用了不少新特性,硬编会报一堆语法错误。老库配老编译器,这是这条链路里最稳妥的组合。

# 以 GDAL 1.7 源码为例,用 VS2008 命令行工具进入源码目录 # 先运行 vcvars32.bat 设置环境,再执行 nmake /f makefile.vc # 如果直接使用编译好的库,跳过这一步 nmake /f makefile.vc

这段命令的含义:nmake 是微软的构建工具,/f makefile.vc指定使用 GDAL 自带的 VC 构建脚本。编译产物包括gdal.dll、gdal_i.lib(导入库)和gdal_priv.h等头文件。如果不走自编译路线,直接用现成库文件也可以,但必须确认导入库是 32 位。VS2008 默认工程是 Win32 平台,如果你把一个 64 位库塞进来,链接期直接报 LNK1112 模块计算机类型冲突,这个坑后面避坑章节细说。

2.2 工程属性配置:包含目录、库目录、预处理器与字符集

配置顺序有讲究,老项目里最容易遗漏的是预处理器定义和字符集。VS2008 创建工程时有个坑:默认字符集选了 Unicode,而 GDAL 1.x 的 C 接口清一色是const char*。如果你的工程是 Unicode,调用GDALOpen("D:/test.tif", GA_ReadOnly)时会报“无法从const wchar_t*转换为const char*”。常见做法是工程属性里把字符集改成“使用多字节字符集”,否则你得每个字符串都套一层CT2A转换,代码丑不说,还容易漏。

接着配三个路径:

项目属性 -> C/C++ -> 常规 -> 附加包含目录:D:/gdal_1_7/include 项目属性 -> 链接器 -> 常规 -> 附加库目录:D:/gdal_1_7/lib 项目属性 -> 链接器 -> 输入 -> 附加依赖项:gdal_i.lib 项目属性 -> C/C++ -> 预处理器 -> 预处理器定义:WIN32_LEAN_AND_MEAN;_USE_MATH_DEFINES

WIN32_LEAN_AND_MEAN不是 GDAL 必需的,但 VS2008 的 Windows SDK 头文件和 GDAL 的cpl_port.h在一起编译时,偶尔会冒出一堆C4005宏重定义警告。加上这个宏能让windows.h少引入一些用不到的组件,冲突面变小。_USE_MATH_DEFINES则是为了保证<cmath>里M_PI等常量可见,GDAL 的地理坐标转换代码会用到。这两个宏属于“加上了多半没事,不加可能玄学报错”的类型。

2.3 最小验证工程:先证明库是通的再写功能

配完属性之后不要急着写业务代码,先做一个最小用例把 GDAL 拉起。新建一个 Win32 控制台项目,贴下面这段代码编译运行。如果这个跑通了,后面所有问题都只会在业务逻辑层。

#include "gdal_priv.h" #include "cpl_conv.h" #include <cstdio> int main() { GDALAllRegister(); // 注册所有栅格驱动,必须先调用 const char* pszFile = "D:/test.tif"; GDALDataset* pDataset = (GDALDataset*)GDALOpen(pszFile, GA_ReadOnly); if (!pDataset) { printf("打开失败: %s\n", CPLGetLastErrorMsg()); return -1; } printf("影像大小: %d x %d, 波段数: %d\n", pDataset->GetRasterXSize(), pDataset->GetRasterYSize(), pDataset->GetRasterCount()); GDALClose(pDataset); return 0; }

第一行GDALAllRegister()经常被漏掉。它的作用是初始化 GDAL 内部所有驱动插件,包括 GeoTIFF、JPEG、PNG 等格式支持。如果不调用,GDALOpen会返回空指针,因为 GDAL 不知道该用哪个驱动去解析.tif后缀的文件。这一步做得隐蔽,翻车率极高。

GDALOpen的第二个参数GA_ReadOnly表示只读打开,这样 GDAL 不会在影像目录下创建.lock文件,也不会因为权限问题导致打开失败。返回类型在 1.7 里直接赋给GDALDataset*。后续的GetRasterXSize()返回影像列数,GetRasterYSize()返回行数,GetRasterCount()返回波段数。开两个不同尺寸的 TIFF 对比输出,可以顺手验证库确实在干活。

3. 核心模块拆解:一个 TIFF 从打开到显示的完整链路

3.1 读取栅格数据:GDALDataset 与 RasterIO 的配合

工程跑通D:/test.tif只算完成 10%,真正的重头戏是读像素。GDAL 的数据模型分成三层:数据集(Dataset)→ 栅格波段(RasterBand)→ 像素块(Block)。每个 TIFF 文件是一个数据集,数据集里可以包含多个波段,每个波段代表一个图层的数据。比如一个 RGB 影像就是三个波段叠加。读取时先用GetRasterBand(1)拿到第一个波段,再调RasterIO把数据拷到内存缓冲区。

#include "gdal_priv.h" #include "cpl_conv.h" #include <cstdio> #define WIDTH 1024 #define HEIGHT 768 int LoadTiff(const char* pszFile, unsigned char* pBuffer, int& nWidth, int& nHeight) { GDALAllRegister(); GDALDataset* pDataset = (GDALDataset*)GDALOpen(pszFile, GA_ReadOnly); if (!pDataset) return -1; nWidth = (int)pDataset->GetRasterXSize(); nHeight = (int)pDataset->GetRasterYSize(); GDALRasterBand* pBand = pDataset->GetRasterBand(1); // 只读第一个波段 if (nWidth > WIDTH) nWidth = WIDTH; if (nHeight > HEIGHT) nHeight = HEIGHT; CPLErr err = pBand->RasterIO(GF_Read, 0, 0, nWidth, nHeight, // 源区域:从左上角开始读 pBuffer, nWidth, nHeight, // 目标缓冲区:按窗口大小填 GDT_Byte, // 缓冲区的数据类型 0, 0); // 像素间隔和行间隔,0 表示紧凑排列 GDALClose(pDataset); return (err == CE_None) ? 0 : -1; }

RasterIO是 GDAL 里最容易用错但功能最强的函数。它的完整签名比上面这段多几个参数,但核心逻辑是:从源影像里截取一块矩形区域,缩放或原样写入一块内存缓冲区。上面代码里,源区域是(0, 0, nWidth, nHeight),也就是从影像左上角开始,取和窗口一样大的区域。目标区参数同样是(pBuffer, nWidth, nHeight),意思是不缩放,原样把像素拷进缓冲区。

这里有个隐含逻辑:如果影像本身是 5000×4000,窗口是 1024×768,那这块代码只读左上角那 1024×768 的小区域。如果想要全图缩小显示,可以把目标缓冲区的高度和宽度改小,让RasterIO自动重采样。这个特性在后面的二次开发里非常有用。

3.2 灰度映射:16位影像直接显示为什么会黑屏

很多 TIFF 影像并不是 8 位灰度,而是 16 位无符号整型,像素范围能到 0~65535。如果你把这堆 16 位数据直接塞给 GDI 的 8 位显示接口,结果就是:亮度值超过 255 的部分全部裁剪成白,低于 255 的部分偏暗,整体画面接近黑色。这是“打开影像一片黑”最常见的原因,跟 GDAL 读取失败是两码事。

另外还有一个细节:RasterIO的缓冲区类型必须声明成GDT_UInt16,跟影像的实际位深吻合。如果你声明成GDT_Byte,GDAL 内部会做截断转换,16 位值的高字节被扔掉,低字节留下,亮度信息大量丢失,同样会得到一张偏黑的图。

// 读取原始 UInt16 数据 GUInt16* pRawData = new GUInt16[nWidth * nHeight]; pBand->RasterIO(GF_Read, 0, 0, nWidth, nHeight, pRawData, nWidth, nHeight, GDT_UInt16, 0, 0); // 计算最小最大值,用于线性拉伸 GUInt16 nMin = 65535, nMax = 0; for (int i = 0; i < nWidth * nHeight; i++) { if (pRawData[i] < nMin) nMin = pRawData[i]; if (pRawData[i] > nMax) nMax = pRawData[i]; } // 线性拉伸到 8 位,避免黑屏 unsigned char* pDisplayData = new unsigned char[nWidth * nHeight]; double dRange = (double)(nMax - nMin); if (dRange < 1.0) dRange = 1.0; for (int i = 0; i < nWidth * nHeight; i++) { pDisplayData[i] = (unsigned char)((pRawData[i] - nMin) * 255.0 / dRange); }

这段代码的意义:先扫一遍原始数据,找出实际的最大最小值。然后按线性公式把每个像素从[nMin, nMax]映射到[0, 255]。这样不管原始影像的直方图偏暗还是偏亮,显示效果都能铺满整个灰度范围。如果影像数据里有异常大的离群值,比如单个像素到了 60000,其他像素都在 1000~2000 之间,这个简单线性拉伸会被离群值带偏,整体画面仍然偏暗。改进方案是去掉最高和最低 1% 的极值再计算映射范围,这个属于后续优化,初次能正常出图更重要。

3.3 GDI 显示:SetDIBitsToDevice 绘制 DIB 位图

数据读出来以后,最后一步是把它画到窗口上。VS2008 时代没有 WPF,更没有 GPU 加速,唯一靠谱的做法是使用 GDI 的SetDIBitsToDevice。这个函数把一个 DIB(设备无关位图)直接绘制到窗口 DC 上。需要注意的是,DIB 的扫描行顺序是自底向上还是自顶向下,由BITMAPINFOHEADER.biHeight的正负决定。

BITMAPINFO bmi; memset(&bmi, 0, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = nWidth; bmi.bmiHeader.biHeight = -nHeight; // 负值表示自顶向下,方便和 RasterIO 的行序对应 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 8; // 8 位灰度图 bmi.bmiHeader.biCompression = BI_RGB; // 初始化灰度调色板 for (int i = 0; i < 256; i++) { bmi.bmiColors[i].rgbBlue = (unsigned char)i; bmi.bmiColors[i].rgbGreen = (unsigned char)i; bmi.bmiColors[i].rgbRed = (unsigned char)i; bmi.bmiColors[i].rgbReserved = 0; } // 绘制到窗口 SetDIBitsToDevice(hDC, 0, 0, nWidth, nHeight, // 目标窗口位置和大小 0, 0, // 源 DIB 起始坐标 0, nHeight, // 起始扫描行和总行数 pDisplayData, &bmi, DIB_RGB_COLORS);

核心逻辑全在参数里。biHeight取负值对应自顶向下的数据排列,我们读出来第一行是影像顶部,用负值则画面朝向正确(GDI DIB 画自顶向上排列数据时图片会上下颠倒)。biBitCount = 8配合bmiColors调色板定义了灰度映射。SetDIBitsToDevice的第二个参数 0 是需要传入逻辑坐标的单位,如果窗口 DC 的映射方式默认是MM_TEXT,那这个 0 就是像素坐标。最后一个DIB_RGB_COLORS告诉 GDI 调色板在bmiColors里,而不是在独立的逻辑调色板里。

整个显示链路的性能瓶颈不在 GDI 绘制,而在RasterIO的数据拷贝。如果影像尺寸特别大,一次性读全图进内存容易失败。常见做法是先压缩到窗口分辨率再读,或者用RasterIO里原生的降采样参数。愿意深入的话,GDAL 的 OverView 金字塔也能加速这种操作,但 VS2008 老项目里一般用不到,先能出图,再谈优化。

3.4 完整流程梳理:从文件路径到屏幕像素

为了方便理解这几段代码之间的关系,我把整个调用链列成一张表。这张表也能作为你写代码时的调试地图。

步骤关键操作对应数据常见失败点
1GDALAllRegister全局驱动表漏调导致打不开文件
2GDALOpen(path, GA_ReadOnly)GDALDataset路径不存在或格式不支持
3GetRasterBand(band)GDALRasterBand波段序号越界
4RasterIO(GF_Read, ...)像素缓冲区数据类型与位深不匹配
5灰度数据拉伸8位灰度缓冲区未拉伸导致黑屏
6SetDIBitsToDevice窗口DC位图高度正负搞反导致图像颠倒

第 4 步和第 5 步之间有一个容易忽略的中间环节:如果影像本身是 8 位灰度,其实不用做拉伸,直接把数据塞给SetDIBitsToDevice就能显示;如果是 16 位或多波段,才需要先转换。写通用显示模块时,我一般会先判断GetRasterDataType()的返回值,再决定走哪条处理路径。另外多波段影像通常只显示第 1 波段,或者按 R、G、B 三个波段分别读出来合成真彩色图,这个在后面的三次开发里展开。

GDAL 的老版本 API 里还有一个经典坑:GDALRasterBand*的RasterIO在读取过程中,如果缓冲区内存不足,可能会返回CE_Failure,但不会抛出异常。所以判断err == CE_None是必须的,别依赖返回值以外的任何东西。

4. 避坑清单:这条路上最常见的四类翻车现场

4.1 打开影像地址返回空指针:驱动注册被跳过

现象:GDALOpen返回 nullptr,CPLGetLastErrorMsg()输出"GDALOpen() failed"之类的信息,但文件路径确认存在。

原因:最常见的是GDALAllRegister()没有调用,或者调用放在了GDALOpen之后。GDAL 的驱动机制是懒加载,不注册驱动,它不知道该用什么插件解析文件格式。还有一个可能性是文件路径含中文,而工程字符集是 Unicode,路径字符串在底层被转成 ANSI 时乱码。

解决:第一行必须写GDALAllRegister()。路径如果含中文,先把工程字符集改成多字节。老项目里还有一种情况是路径用了CFileDialog,拿到的宽字符串直接转指针传给 GDAL,必挂。统一走CT2A转换或用绝对路径调试。

4.2 链接期 LNK2019:库版本、平台和配置全对不上

现象:编译通过,链接报错,形如LNK2019: unresolved external symbol _GDALAllRegister。

原因:第一种,你链接的是gdal.lib但 GDAL 1.7 提供的实际导入库叫gdal_i.lib,两者符号表不一致。第二种,你的工程是 Debug 配置,链接的库是 Release 编译的;或是反过来。VS2008 老 GDAL 库经常只有 Release 版,因为在 CRT 层面 Debug 和 Release 的符号修饰不同。第三种,工程是 x64 平台,库是 x86 的。

解决:统一到一组。附加依赖项只写gdal_i.lib,如果要在 Debug 下调试,就用/NODEFAULTLIB:msvcprt这类开关尝试绕过,但更靠谱的是直接所有项目都跑 Release。检查平台下拉框,确认是 Win32。这套组合本身很老,别硬给自己加戏上 x64。

4.3 16位影像画面全黑:位深没匹配导致数据被截断

现象:窗口显示一片黑,但打开同一张影像的 8 位版本却正常;用GetRasterDataType()查询返回GDT_UInt16。

原因:像素值范围是 0~65535,显示函数只能用 8 位颜色,GDI 的biBitCount设成 8 位后直接接收了未转换的原始数据,高位被截断,剩下的低位噪声让画面变黑。有些人还会犯另一个错:RasterIO的GDT_Byte跟GDT_UInt16混用,GDAL 没法替你保底。

解决:先ComputeRasterMinMax或自己扫描一遍,求出真实最小最大值,再线性拉伸到 8 位。不要用new unsigned char[nWidth*nHeight]直接接GDT_UInt16的数据缓冲区,那样类型不匹配,读到的是字节序排列错乱的值。

4.4 图像上下颠倒:DIB 行序与影像行序不一致

现象:显示出的影像是镜像翻转的,山区地形看着像倒立。

原因:GDAL 读出来的数据第一行是影像顶部,而 Windows 标准 DIB 自底向上排列位图数据。BITMAPINFOHEADER.biHeight为正时,GDI 按自底向上解析,把顶部数据当成了最后一行。

解决:创建BITMAPINFO时把biHeight设为负值。代码里更新bmi.bmiHeader.biHeight = -nHeight;一行就能转过来。这个坑 100% 会出现一次,记住它的名字叫“负高度”。

5. 二次开发扩展:从“显示一幅图”到“处理交互式影像”

这个工程最值得改造的地方,是把“显示”和“读取”解耦。现在LoadTiff和 GDI 绘制全挤在一起,如果要在同一窗口切换多幅影像,代码会越来越乱。我习惯先抽一个CTiffViewer类,内部维护GDALDataset*指针和显示参数,外部只提供LoadFile、ZoomTo、GetBitmap几个接口。

class CTiffViewer { public: int LoadFile(const char* pszPath); int GetDisplayData(unsigned char* pOut, int nOutW, int nOutH); void Close(); private: GDALDataset* m_pDataset; GDALRasterBand* m_pBand; int m_nWidth, m_nHeight, m_nBandCount; GDALDataType m_eDataType; };

改造的核心点是GetDisplayData里加一个目标尺寸参数。原来固定以原始分辨率读取,改成把期望显示宽高传进去,利用RasterIO的缩放能力直接重采样。这样从 100% 缩放到 25% 只是一组参数的事,不用手动开金字塔。如果将来要做放大镜效果,也能把这个函数作为数据源,在局部区域多读一块数据。

我自己的血泪经验是:改这个类的第一版时,想省事把拉伸逻辑直接写在LoadFile里,结果 8 位和 16 位影像的兼容性变成一团乱麻。后来改成每次显示前动态判断位深,数据流内部先转成一个统一格式,界面层永远只处理 8 位灰度或 24 位真彩色,才彻底消停。从那以后,我接手任何老影像工程,第一次跑通后必做的操作是:拿三张不同位深的 TIFF(8 位、16 位、含坐标信息的地理 TIFF)挨个走一遍,确认所有路径都输出到窗口上再动手加新功能——希望帮到你。

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

相关新闻

多智能体协同算法在智能电网分布式调度中的应用与代码实现

多智能体协同算法在智能电网分布式调度中的应用与代码实现

做电力系统调度优化的人&#xff0c;这两年应该都明显感觉到一件事&#xff1a;传统集中式调度那套玩法&#xff0c;越来越难伺候了。分布式光伏、风电、储能这些资源一批批往电网里塞&#xff0c;调度对象从几十个变成几百上千个&#xff0c;中央控制器就算算力再猛&#xff0…

2026/10/20 5:50:18 阅读更多 →
从0到2万Star:AI编程教程的开源增长与踩坑实录

从0到2万Star:AI编程教程的开源增长与踩坑实录

我前两天刷着代码托管平台仓库里的Star数字&#xff0c;看着它从三位数一点点爬过两万&#xff0c;同一周手机里收到某国产AI助手的官方推荐通知&#xff0c;说我的AI编程教程被收录进他们的学习资源。那一刻确实有点恍惚。这份教程从立项到被人主动推荐&#xff0c;中间隔了两…

2026/10/20 5:50:18 阅读更多 →
Qwen 底座 + 外企背书:Clef-Flash 大火,中文开源模型出海迎来新范本

Qwen 底座 + 外企背书:Clef-Flash 大火,中文开源模型出海迎来新范本

Qwen 底座 外企背书&#xff1a;Clef-Flash 大火&#xff0c;中文开源模型出海迎来新范本 【免费下载链接】clef-flash 项目地址: https://ai.gitcode.com/hf_mirrors/Cloudflare/clef-flash 2026 年 10 月初&#xff0c;Cloudflare 在一周内先后抛出两颗"炸弹&q…

2026/10/20 5:50:18 阅读更多 →

最新新闻

HTTP POST表单提交全解析:Content-Type、编码格式与实战避坑指南

HTTP POST表单提交全解析:Content-Type、编码格式与实战避坑指南

1. 从一个被忽略的细节说起&#xff1a;为什么表单提交远不止填个action很多人第一次接触Web开发&#xff0c;接触到的第一个"能跑起来"的功能&#xff0c;大概率就是一个HTML表单。写一个<form>标签&#xff0c;配上action和method"post"&#xff0…

2026/10/20 6:25:32 阅读更多 →
自动驾驶多模态数据生成:统一传感器输出的关键技术与实践

自动驾驶多模态数据生成:统一传感器输出的关键技术与实践

自动驾驶算法做到后面&#xff0c;真正卡脖子的往往不是模型结构&#xff0c;而是数据。尤其当你同时要喂摄像头、激光雷达、毫米波雷达这几个完全不同的传感器时&#xff0c;数据稀缺和模态不一致会被放大成一个系统工程问题。OmniGen 这个名字听起来很高端&#xff0c;去掉包…

2026/10/20 6:25:32 阅读更多 →
三层网络架构冗余配置实战:VRRP、浮动路由与链路聚合详解

三层网络架构冗余配置实战:VRRP、浮动路由与链路聚合详解

前阵子搭了一套三层结构的网络实验环境&#xff0c;核心两台、汇聚两台、接入一台&#xff0c;实验目标很明确&#xff1a;把三层架构里的各路冗余手段都配上&#xff0c;然后人为制造故障&#xff0c;看流量到底能不能自己绕过去。做完最大的感受是——冗余两个字说起来容易&a…

2026/10/20 6:25:32 阅读更多 →
最新论文追踪指南:平台选择、检索技巧与自动订阅全攻略

最新论文追踪指南:平台选择、检索技巧与自动订阅全攻略

想第一时间看到领域里刚出炉的论文&#xff0c;最怕的不是搜不到&#xff0c;而是根本不知道该去哪个平台搜、用什么关键词、按什么排序。组会汇报前临时抱佛脚、开题时需要确认自己做的方向有没有人抢先发表、审稿时想查一查某篇预印本到底有没有正式见刊——这些场景我都经历…

2026/10/20 6:25:32 阅读更多 →
Web服务器Nginx与集群架构——Java开源litemall小商城项目应用实践

Web服务器Nginx与集群架构——Java开源litemall小商城项目应用实践

/* 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 6:25:32 阅读更多 →
AI大模型自动化测试实战:全流程智能测试设计与落地

AI大模型自动化测试实战:全流程智能测试设计与落地

我在一线做测试自动化和质量保障已经快十年&#xff0c;说实话&#xff0c;前八年大部分时间都花在写脚本、调框架、跟环境和用例维护作斗争上。最近这两年&#xff0c;AI大模型自动化这个方向确实改变了我的工作节奏。之前接手某个跨平台系统&#xff0c;每个版本回归要花上两…

2026/10/20 6:24:32 阅读更多 →

日新闻

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/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →