You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用memcmp进行BMP图像匹配的问题及GetDIBits对齐疑问

24位BMP图像匹配失败问题解决(GetDIBits字节对齐影响)

核心原因

GetDIBits会严格遵循BMP的行字节对齐规则添加填充字节:24位BMP要求每行像素数据的总字节数必须是4的倍数,不足时会在每行末尾补0(padding)。小尺寸图的宽度可能刚好让宽度*3是4的倍数(比如宽度为4,4*3=12),此时无padding,memcmp整块对比有效;但大尺寸图宽度不满足时,padding的存在会导致memcmp对比到无关的填充字节,匹配失败。

关键计算式

计算每行实际占用的字节数(含padding):

int stride = ((width * 3) + 3) & ~3;

其中width是图像的像素宽度,stride就是GetDIBits返回的每行数据长度。

解决方案:逐行对比有效像素区域

不能直接用memcmp对比整块内存,需要跳过每行末尾的padding,只对比有效像素部分:

  1. 先计算原图和裁剪图的行步长(stride)及每行有效像素字节数:
// 原图参数
int screenshotWidth = ...;   // 截图宽度(像素)
int screenshotHeight = ...;  // 截图高度(像素)
int screenshotStride = ((screenshotWidth * 3) + 3) & ~3;
int screenshotPixelBytes = screenshotWidth * 3;

// 裁剪图参数
int croppedWidth = ...;      // 裁剪图宽度(像素)
int croppedHeight = ...;     // 裁剪图高度(像素)
int croppedStride = ((croppedWidth * 3) + 3) & ~3;
int croppedPixelBytes = croppedWidth * 3;
  1. 逐行逐区域匹配(注意BMP从左下角存储的坐标转换):
// 遍历所有可能的匹配起始位置(x为水平偏移,y为垂直偏移,从图像顶部开始计数)
for (int y = 0; y <= screenshotHeight - croppedHeight; y++) {
    for (int x = 0; x <= screenshotWidth - croppedWidth; x++) {
        int isMatch = 1;
        // 逐行对比裁剪图与原图对应区域
        for (int row = 0; row < croppedHeight; row++) {
            // BMP存储从左下角开始,需反转行坐标
            int srcRowIdx = screenshotHeight - 1 - y - row;
            int cropRowIdx = croppedHeight - 1 - row;
            
            // 定位到当前行的有效像素起始地址
            unsigned char* srcPixelStart = screenshotArray + srcRowIdx * screenshotStride + x * 3;
            unsigned char* cropPixelStart = croppedArray + cropRowIdx * croppedStride;
            
            // 仅对比有效像素部分,跳过padding
            if (memcmp(srcPixelStart, cropPixelStart, croppedPixelBytes) != 0) {
                isMatch = 0;
                break;
            }
        }
        if (isMatch) {
            // 找到匹配,返回坐标(x为水平起始点,y为垂直起始点,从图像顶部算起)
            printf("匹配成功:(%d, %d)\n", x, y);
            return;
        }
    }
}
// 未找到匹配
printf("未找到匹配区域\n");

注意点

  • BMP的像素存储顺序是左下角到右上角,所以在计算内存行索引时需要反转y轴,确保坐标对应图像的实际显示位置。
  • 若追求匹配效率,可先对比裁剪图的首行/特征行,快速排除不可能的位置,减少不必要的memcmp调用。

内容的提问来源于stack exchange,提问作者Eric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 22:55:16