如何在 C++ 中比较两个位图屏幕截图的字节到字节

2024-01-04

在问题的最后我的最后编辑

大家好, 我必须实现一个功能来比较屏幕一部分的两个镜头,以便知道是否存在差异/变化。我写了类似下面的代码,但我无法让它工作。在代码中 COORDINATES_RECT 是一个结构体

typedef struct _COORDINATES_RECT {
int     x;
int     y;
int     sizeX;
int     sizeY;
} COORDINATES_RECT; 

输入中保存数据以了解要分析的屏幕部分,输出中返回函数发现变化的最大矩形的数据。为了更好地解释问题,我看到最后的if构造:

if(lpbitmap1[(i*bmpScreen1.bmWidth)+j] != lpbitmap2[(i*bmpScreen1.bmWidth)+j])

永远不会被处决。我不知道这是否是比较两个位图(转换为字符数组)的正确方法。我用谷歌搜索并在 msdn 中搜索但没有结果。 完整代码如下:

void testBitmapVariations(COORDINATES_RECT *c)
{
HDC hdcScreen = GetDC(NULL);
HDC hdcMemDC1 = CreateCompatibleDC(hdcScreen);
HDC hdcMemDC2 = CreateCompatibleDC(hdcScreen);
HBITMAP hBmpScreen1 = NULL;
HBITMAP hBmpScreen2 = NULL;
BITMAP bmpScreen1;
BITMAP bmpScreen2;

if(!hdcMemDC1 || !hdcMemDC2)
{
    MessageBox(NULL,L"CreateCompatibleDC failed", L"Failed", MB_OK);
    ReleaseDC(NULL, hdcMemDC1);
    ReleaseDC(NULL, hdcMemDC2);
    return;
}
hBmpScreen1 = CreateCompatibleBitmap(hdcMemDC1, c->sizeX, c->sizeY);
hBmpScreen2 = CreateCompatibleBitmap(hdcMemDC2, c->sizeX, c->sizeY);

SelectObject(hdcMemDC1,hBmpScreen1);

if(!BitBlt(hdcMemDC1, 
           0,0, 
           c->sizeX, c->sizeY, 
           hdcScreen, 
           c->x,c->y,
           SRCCOPY))
{
    MessageBox(NULL,L"BitBlt failed", L"Failed", MB_OK);
    ReleaseDC(NULL, hdcMemDC1);
    ReleaseDC(NULL, hdcMemDC2);
    return;
}

GetObject(hBmpScreen1,sizeof(BITMAP),&bmpScreen1);

BITMAPFILEHEADER   bmfHeader;    
BITMAPINFOHEADER   bi;

bi.biSize = sizeof(BITMAPINFOHEADER);    
bi.biWidth = bmpScreen1.bmWidth;    
bi.biHeight = bmpScreen1.bmHeight;  
bi.biPlanes = 1;    
bi.biBitCount = 32;    
bi.biCompression = BI_RGB;    
bi.biSizeImage = 0;  
bi.biXPelsPerMeter = 0;    
bi.biYPelsPerMeter = 0;    
bi.biClrUsed = 0;    
bi.biClrImportant = 0;

DWORD dwBmpSize = ((bmpScreen1.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpScreen1.bmHeight;

// Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that 
// call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc 
// have greater overhead than HeapAlloc.
char *lpbitmap1 = (char *)malloc(dwBmpSize);    

// Gets the "bits" from the bitmap and copies them into a buffer 
// which is pointed to by lpbitmap1.
GetDIBits(hdcScreen, hBmpScreen1, 0,
    (UINT)bmpScreen1.bmHeight,
    lpbitmap1,
    (BITMAPINFO *)&bi, DIB_RGB_COLORS);

Sleep(200);

SelectObject(hdcMemDC2,hBmpScreen2);

if(!BitBlt(hdcMemDC2, 
           0,0, 
           c->sizeX, c->sizeY, 
           hdcScreen, 
           c->x,c->y,
           SRCCOPY))
{
    MessageBox(NULL,L"BitBlt failed", L"Failed", MB_OK);
    ReleaseDC(NULL, hdcMemDC1);
    ReleaseDC(NULL, hdcMemDC2);
    return;
}

GetObject(hBmpScreen2,sizeof(BITMAP),&bmpScreen2);

char *lpbitmap2 = (char *)malloc(dwBmpSize);    

// Gets the "bits" from the bitmap and copies them into a buffer 
// which is pointed to by lpbitmap2.
GetDIBits(hdcScreen, hBmpScreen2, 0,
    (UINT)bmpScreen2.bmHeight,
    lpbitmap2,
    (BITMAPINFO *)&bi, DIB_RGB_COLORS);

int i, j, minX = bmpScreen1.bmWidth, minY = bmpScreen1.bmHeight, maxX = 0, maxY = 0;
bool changed = false;

for(i = 0; i < bmpScreen1.bmHeight; i++) 
{
    for(j = 0; j < bmpScreen1.bmWidth; j++)
    {
                    // I don't know why this if never get executed
        if(lpbitmap1[(i*bmpScreen1.bmWidth)+j] != lpbitmap2[(i*bmpScreen1.bmWidth)+j])
        {
            changed = true;

            if(i < minY)
                minY = i;
            if(i > maxY)
                maxY = i;
            if(j < minX)
                minX = j;
            if(j > maxY)
                maxY = j;
        }
    }
}
if(changed)
{
    c->x = minX;
    c->y = minY;
    c->sizeX = maxX - minX;
    c->sizeY = maxY - minY;
}
else
{
    c->sizeX = 0;
    c->sizeY = 0;
}
//Frees from the heap
free(lpbitmap1);
free(lpbitmap2);
ReleaseDC(NULL, hdcMemDC1);
ReleaseDC(NULL, hdcMemDC2); 
}

Thanks

弗朗西斯科

诗。变量声明放在它们引用的块旁边只是为了使这个问题更加清晰。

EDIT:

我像这样重写了它,它似乎有效:)感谢大家,但是任何修正都值得赞赏

void testBitmapVar(COORDINATES_RECT *c)
{
HDC     screenDC = GetDC(0),
        memDC = CreateCompatibleDC(screenDC);
HBITMAP hBm = CreateCompatibleBitmap(screenDC, c->sizeX, c->sizeY), 
        oldHBm;
BITMAP  bm;
BITMAPFILEHEADER   bmfHeader;    
BITMAPINFOHEADER   bi;
UINT    *pixels = (UINT*) malloc ((c->sizeX*c->sizeY) * sizeof(UINT));
std::ostringstream ss;
std::wstring str;
int     i, j, minX, maxX, minY, maxY;

if(!pixels)
{
    c->sizeX = 0;
    c->sizeY = 0;
    return;
}
memset(pixels, 0, (c->sizeX*c->sizeY) * sizeof(UINT));
oldHBm = (HBITMAP) SelectObject(memDC, hBm);

// copies to bitmap
BitBlt(memDC, 0, 0, c->sizeX, c->sizeY, screenDC, c->x, c->y, SRCCOPY);

Sleep(500);

BitBlt(memDC, 0, 0, c->sizeX, c->sizeY, screenDC, c->x, c->y, SRCINVERT);
GetObject(hBm, sizeof(BITMAP), &bm);

bi.biSize = sizeof(BITMAPINFOHEADER);    
bi.biWidth = bm.bmWidth;    
bi.biHeight = bm.bmHeight;  
bi.biPlanes = 1;    
bi.biBitCount = 32;    
bi.biCompression = BI_RGB;    
bi.biSizeImage = 0;  
bi.biXPelsPerMeter = 0;    
bi.biYPelsPerMeter = 0;    
bi.biClrUsed = 0;    
bi.biClrImportant = 0;

GetDIBits(memDC, hBm, 0,
    (UINT)bm.bmHeight,
    pixels,
    (BITMAPINFO *)&bi, DIB_RGB_COLORS);

for(i = 0, minY = c->sizeY, maxY = -1; i < c->sizeY; i++) 
{
    for(j = 0, minX = c->sizeX, maxX = -1; j < c->sizeX; j++)
    {
        if(pixels[(i*c->sizeX)+j])
        {
            if(i < minY)
                minY = i;
            if(i > maxY)
                maxY = i;
            if(j < minX)
                minX = j;
            if(j > maxX)
                maxX = j;
        }
    }
}
if(maxX != -1 && maxY != -1)
{
    c->x = minX;
    c->y = minY;
    c->sizeX = maxX - minX;
    c->sizeY = maxY - minY;
}
else
{
    c->sizeX = 0;
    c->sizeY = 0;
}

free(pixels);
SelectObject(memDC, oldHBm);
DeleteObject(hBm);
ReleaseDC(0, screenDC);
DeleteDC(memDC);
}

不要完全自行比较两个位图,而是考虑使用 BitBlt 使用 SRCINVERT 运算符将它们组合起来,该运算符将两者异或在一起,因此相同的部分将显示为零,所有非零区域都将是差异。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 C++ 中比较两个位图屏幕截图的字节到字节 的相关文章

  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 迭代变量并查找特定类型实例的技术

    我想迭代进程中内存中的变量 通过插件动态加载 并查找特定类型的实例 以前我可以找到特定类型 或内存中的所有类型 我可以创建类型的实例 我可以获取作为不同类型的字段包含的实例 但我无论如何都不知道只是 搜索 特定类型的实例 一种方法是使用 W
  • 以编程方式检查页面是否需要基于 web.config 设置进行身份验证

    我想知道是否有一种方法可以检查页面是否需要基于 web config 设置进行身份验证 基本上如果有这样的节点
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • C# 中的接口继承

    我试图解决我在编写应用程序时遇到的相当大的 对我来说 问题 请看这个 为了简单起见 我将尝试缩短代码 我有一个名为的根接口IRepository
  • Clang 编译器 (x86):80 位长双精度

    我正在尝试在 x86 Windows 平台上使用本机 80 位长双精度 海湾合作委员会选项 mlong double 80 https gcc gnu org onlinedocs gcc x86 Options html似乎不适用于 cl
  • 显示异常时的自定义错误消息:从客户端检测到潜在危险的 Request.Form 值

    我在我的 Web 应用程序中使用 ASP NET 的登录控件 当发生此异常时 我想在标签上显示一种有趣的错误类型System Web HttpRequestValidationException A potentially dangerou
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • IronPython:没有名为 json 的模块

    我安装了 IronPython 我的 python 文件如下所示 import sys print sys version import json 运行它的代码 var p Python CreateEngine var scope p C
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • Azure 事件中心 - 按顺序接收事件

    我使用下面的代码从 Azure Event Hub 接收事件 https learn microsoft com en us azure event hubs event hubs dotnet framework getstarted s
  • 如何挤出平面 2D 网格并赋予其深度

    我有一组共面 连接的三角形 即二维网格 现在我需要将其在 z 轴上挤出几个单位 网格由一组顶点定义 渲染器通过与三角形数组匹配来理解这些顶点 网格示例 顶点 0 0 0 10 0 0 10 10 0 0 10 0 所以这里我们有一个二维正方
  • System.Runtime.InteropServices.COMException(0x80040154):[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我在 C 项目中遇到异常 System Runtime InteropServices COMException 0x80040154 检
  • 在类的所有方法之前运行一个方法

    在 C 3 或 4 中可以做到这一点吗 也许有一些反思 class Magic RunBeforeAll public void BaseMethod runs BaseMethod before being executed public
  • 是否可以有一个 out ParameterExpression?

    我想定义一个 Lambda 表达式out范围 有可能做到吗 下面是我尝试过的 C Net 4 0 控制台应用程序的代码片段 正如您在 procedure25 中看到的 我可以使用 lambda 表达式来定义具有输出参数的委托 但是 当我想使
  • 耐用功能是否适合大量活动?

    我有一个场景 需要计算 500k 活动 都是小算盘 由于限制 我只能同时计算 30 个 想象一下下面的简单示例 FunctionName Crawl public static async Task
  • 双精度类型二维多维数组的 pinvoke 编组作为 c# 和 c++ 之间的输入和输出

    我有以下我正在尝试解决的双物质类型的 2d 多维数组的 c 和 c pinvoke 编组 我已经查看了以下热门内容以获得我目前拥有的内容使用双精度数组进行 P Invoke 在 C 和 C 之间编组数据 https stackoverflo
  • 实例化 Microsoft.Office.Interop.Excel.Application 对象时出现错误:800700c1

    实例化 Microsoft Office Interop Excel Application 以从 winforms 应用程序生成 Excel 时 出现以下错误 这之前是有效的 但突然间它停止工作了 尽管代码和 Excel 版本没有变化 我

随机推荐

  • 按 dbms 类型划分的 Liquibase 变更集

    如何对不同数据库的内容使用相同的更改集
  • MVC Razor @section 不理解脚本

    I have VS 2013 MVC 5 2 2 剃须刀3 2 2 如果您还有其他需要了解的信息 请告诉我 此问题仅发生在一个视图页面上 我有一个视图 所有 HTML 标签都正确关闭 这是你的标准观点 model MyNameSpace M
  • 使用 Volley 库获取 com.android.volley.ServerError。可能的原因有哪些?

    当我在 Volley 中提出请求时 我收到com android volley ServerError和响应代码 400 我正在做这样的事情 通用示例代码 final String param1 final String param2 et
  • Laravel 投票系统

    我正在我的 laravel school 项目中实现一个投票系统 它将是一个在线学校平台 学生可以上传项目 其他学生可以对发布的内容进行投票 不知何故 我所做的不起作用 这是到目前为止我的代码 希望有人可以帮助我 也许可以帮助我如何显示项目
  • javascript setAttribute("name",newname) 不会更改它创建的文本框的名称

    我使用这个函数在表中创建一个新行 function addRow obj var table document getElementById table2 var rowCount table rows length 1 var row t
  • CSS:删除较大文本上的行高(前导)

    如何从强制范围中删除前导 以便 lt lt 上方和下方没有额外的空间 字段行在默认的基础上占据一定的高度line height然而 对于文本大小 必填字段更高 因为字体更大 如何去掉上方和下方多余的空白 lt
  • Prometheus中将两个不同的指标分组后如何划分?

    我目前正在尝试对可用区内的 Kubernetes Pod 堆叠发出警报 我成功地使用了两种不同的指标 可以看到应用程序有多少个 pod 正在特定的可用区域上运行 但是 由于扩展 我希望警报基于百分比 因此 当某个可用区上运行特定百分比的 P
  • 通过 BeeTee 应用程序连接到其他蓝牙设备

    我需要实现一个自建蓝牙应用程序来将所有蓝牙设备连接到 iPhone 我知道 CoreBluetooth 框架不可能做到这一点 我使用私有API并将DeviceManager和BluetoothManager的头文件添加到私有框架中 并从下载
  • 在 Dockerfile 中覆盖 FROM 镜像的 ENV

    从下图可以看出 https registry hub docker com u cloudesire activemq dockerfile https registry hub docker com u cloudesire active
  • 获取 OpenGL 最大纹理尺寸

    我正在开发一个 Android 应用程序 它将广泛使用位图 并且我正在寻找一种可靠的方法来获取不同设备上 OpenGL 的最大纹理大小 我知道最小尺寸 2048x2048 但这还不够好 因为已经有分辨率更高的平板电脑 例如 2560x160
  • 如果结构具有 ReadOnlySpan 字段,如何将 ref 结构参数传递给 MethodInfo

    我有一个MethodInfo代表一个方法的对象 该方法采用ref struct作为参数 并且该结构有一个ReadOnlySpan
  • 使用 GoLang Web 服务器提供静态内容

    我正在探索 Go 的深度 并且一直在尝试编写一个简单的 Web 应用程序来理解所有内容 我正在尝试提供 React js 应用程序 下面是Go服务器的代码 我有默认路线 服务于index html工作正常 我正在努力允许将静态文件提供给该索
  • Python - 访问列表中嵌套字典中的值

    我有一个 JSON API 响应 如下所示 json data sales list date all country all units product promotions 0 downloads 1 updates 2 refunds
  • “错误:无法生成视图绑定器 java.lang.NullPointerException”的可能原因

    我正在使用 Android Studio 来处理我的 Android 项目 当构建因奇怪的堆栈跟踪而崩溃时 我遇到了一个问题 如下所示 Error Execution failed for task app compileDevDebugJ
  • DrRacket、R5RS和错误程序

    我喜欢 DrRacket IDE 但目前我正在构建一个我希望独立于它的宠物项目 这意味着我致力于仅使用 R5RS 标准程序 问题是 在 DrRacket 中有一个名为 错误 的过程 我想继续使用它 但我在标准中找不到它 我想知道是否有一种方
  • publishHtml reportFiles 参数语法是什么

    我正在尝试通过 Jenkinsfile 为 Jenkins 配置 HTML Publisher 插件来发布一些 html 文件 如下所示 publishHTML target allowMissing false alwaysLinkToL
  • 如何在 R 中创建条件虚拟对象?

    我有一个时间序列数据的数据框 其中包含每日温度观测值 我需要创建一个虚拟变量 对温度高于阈值 5C 的每一天进行计数 这本身很容易 但存在一个附加条件 仅在连续十天高于阈值后才开始计数 这是一个示例数据框 df lt data frame
  • 如何在酶中等待私人功能的承诺?

    我是 React 和任何 JavaScript 测试框架的新手 我有一个简单的组件 可以从 API 检索项目并将其显示在屏幕上 函数 getItems 是从 componentWillMount 调用的 是否可以等到 getItems 完成
  • Bitfinex 数据 API

    我正在尝试使用 bitfinex REST api 获取历史 OHLC 数据 文档如下 https bitfinex readme io v2 reference rest public candles https bitfinex rea
  • 如何在 C++ 中比较两个位图屏幕截图的字节到字节

    在问题的最后我的最后编辑 大家好 我必须实现一个功能来比较屏幕一部分的两个镜头 以便知道是否存在差异 变化 我写了类似下面的代码 但我无法让它工作 在代码中 COORDINATES RECT 是一个结构体 typedef struct CO