对 BITMAPINFO (HBITMAP) 中像素数据的原始/直接访问

2024-01-01

我试图弄清楚如何从屏幕访问原始像素信息。到目前为止,我一直将屏幕捕获到 HBITMAP,填充 BITMAPINFO,然后创建此 BITMAPINFO 变量的指针以直接从内存读取。 我知道必须从文件中“删除”标头,因此我将指针直接前进到位图数据(将 sizeof(MyBMInfo2->bmiHeader) 添加到我的指针偏移量)。我还知道该位图是反转/自上而下的,第一个像素位于原始数据的末尾。我需要弄清楚如何从图像中给定的 X 和 Y 中提取 R G 和 B 字节,而这正是我无法做到的。 所以我问先生,一盏灯、一个片段或任何提示可以帮助我从 gdi32 重新创建 Bitmap.GetPixel(x,y) 的肮脏尝试(太慢了,我需要一个更好的)。

A snippet到目前为止我的源代码:

...
HDC hCaptureDC  = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done 
DeleteDC(hCaptureDC);

BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

// Get the MyBMInfo structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
    printf("error\n");
}

BITMAPINFO* MyBMInfo2 = &MyBMInfo;
BYTE* bitmapBits=(BYTE*)MyBMInfo2+sizeof(MyBMInfo2->bmiHeader);
//So... how do I acess X and Y RGB bytes now? xD
...

顺便说一下......还有其他更直接的方法可以在不引发内存保护错误的情况下执行此操作吗?或者...另一种更快的方式? 谢谢。

--Edit--

使用Barmak的代码我已经弄清楚如何根据当前光标位置访问X和Y rgb,下面是源代码:

#include <windows.h>

int main()
{
    HWND hwnd = GetDesktopWindow();
    RECT rc;
    GetClientRect(hwnd, &rc);
    int width = rc.right;
    int height = rc.bottom;
    if (width < 1 || height < 1)
    {
        OutputDebugStringA("error\n");
        return 0;
    }

    HDC hdc = GetDC(hwnd);

    HDC hCaptureDC = CreateCompatibleDC(hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
    HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
    BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
    SelectObject(hCaptureDC, hOld);

    BITMAPINFO MyBMInfo = { 0 };
    MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

    BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
    bmpInfoHeader.biWidth = width;
    bmpInfoHeader.biHeight = height;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = 32;

    DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
    BYTE *bits = malloc(size);

    if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
    {
        OutputDebugStringA("success\n");
        //you can use bits here

        //access bits from upper-left to lower-right corner
        POINT p;
        GetCursorPos(&p);
        int x = p.x;
        int y = p.y;

        int col = x;
        int row = height - y - 1;
        int index = (row * width + col) * 4;

        BYTE b = bits[index + 0];
        BYTE g = bits[index + 1];
        BYTE r = bits[index + 2];

        printf("r:%i g:%i b:%i \n",r,g,b);


    }
    else
    {
        OutputDebugStringA("error\n");
    }

    free(bits);

    DeleteDC(hCaptureDC);
    DeleteObject(hBitmap);
    ReleaseDC(hwnd, hdc);

    return 0;
}

非常感谢谢米拉尼先生。对于谁对我的答案投了反对票,请考虑撤回它? :) 和平。


GetDibBits需要一个缓冲区来接收位。您必须分配缓冲区,然后在不再需要时将其删除。

#include <windows.h>

int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPTSTR, int)
{
    HWND hwnd = GetDesktopWindow();
    RECT rc;
    GetClientRect(hwnd, &rc);
    int width = rc.right;
    int height = rc.bottom;
    if (width < 1 || height < 1)
    {
        OutputDebugStringA("error\n");
        return 0;
    }

    HDC hdc = GetDC(hwnd);

    HDC hCaptureDC = CreateCompatibleDC(hdc);
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, width, height);
    HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
    BitBlt(hCaptureDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY | CAPTUREBLT);
    SelectObject(hCaptureDC, hOld);

    BITMAPINFO MyBMInfo = { 0 };
    MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);

    BITMAPINFOHEADER bmpInfoHeader = { sizeof(BITMAPINFOHEADER) };
    bmpInfoHeader.biWidth = width;
    bmpInfoHeader.biHeight = height;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biBitCount = 32;

    DWORD size = ((width * bmpInfoHeader.biBitCount + 31) / 32) * 4 * height;
    BYTE *bits = malloc(size);

    if (GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS))
    {
        OutputDebugStringA("success\n");
        //you can use bits here

        //access bits from lower-left to upper-right corner
        for (int row = 0; row < height; row++)
        {
            for (int col = 0; col < width; col++)
            {
                //for 32 bit image only:
                int index = (row * width + col) * 4;

                BYTE blue  = bits[index + 0];
                BYTE green = bits[index + 1];
                BYTE red   = bits[index + 2];
            }
        }

        //access bits from upper-left to lower-right corner
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                int col = x;
                int row = height - y - 1;
                int index = (row * width + col) * 4;

                BYTE b = bits[index + 0];
                BYTE g = bits[index + 1];
                BYTE r = bits[index + 2];
            }
        }

    }
    else
    {
        OutputDebugStringA("error\n");
    }

    free(bits);

    DeleteDC(hCaptureDC);
    DeleteObject(hBitmap);
    ReleaseDC(hwnd, hdc);

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

对 BITMAPINFO (HBITMAP) 中像素数据的原始/直接访问 的相关文章

  • 如何在多线程C++ 17程序中交换两个指针?

    我有两个指针 pA 和 pB 它们指向两个大的哈希映射对象 当pB指向的哈希图完全更新后 我想交换pB和pA 在C 17中 如何快速且线程安全地交换它们 原子 我是 c 17 的新手 2个指针的原子无等待交换可以通过以下方式实现 inclu
  • 代码 GetAsyncKeyState(VK_SHIFT) & 0x8000 中的这些数字是什么?它们是必不可少的吗?

    我试图在按下按键的简单动作中找到这些数字及其含义的任何逻辑解释 GetAsyncKeyState VK SHIFT 0x8000 可以使用哪些其他值来代替0x8000它们与按键有什么关系 GetAsyncKeyState 根据文档返回 如果
  • 为什么pow函数比简单运算慢?

    从我的一个朋友那里 我听说 pow 函数比简单地将底数乘以它的指数的等价函数要慢 例如 据他介绍 include
  • 如何判断计算机是否已重新启动?

    我曾经使用过一个命令行 SMTP 邮件程序 作为试用版的限制 它允许您在每个 Windows 会话中最多接收 10 封电子邮件 如果您重新启动计算机 您可能还会收到 10 个以上 我认为这种共享软件破坏非常巧妙 我想在我的应用程序中复制它
  • 为什么在 WebApi 上下文中在 using 块中使用 HttpClient 是错误的?

    那么 问题是为什么在 using 块中使用 HttpClient 是错误的 但在 WebApi 上下文中呢 我一直在读这篇文章不要阻止异步代码 https blog stephencleary com 2012 07 dont block
  • C# 数据表更新多行

    我如何使用数据表进行多次更新 我找到了这个更新 1 行 http support microsoft com kb 307587 my code public void ExportCSV string SQLSyntax string L
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 类型约束

    我有以下类层次结构 class Header IEnumerable
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 在视口中查找 WPF 控件

    Updated 这可能是一个简单或复杂的问题 但在 wpf 中 我有一个列表框 我用一个填充数据模板从列表中 有没有办法找出特定的数据模板项位于视口中 即我已滚动到其位置并且可以查看 目前我连接到了 listbox ScrollChange
  • 在 NaN 情况下 to_string() 可以返回什么

    我使用 VS 2012 遇到了非常令人恼火的行为 有时我的浮点数是 NaN auto dbgHelp std to string myFloat dbgHelp最终包含5008角色 你不能发明这个东西 其中大部分为0 最终结果是 0 INF
  • 如何在 C 中安全地声明 16 位字符串文字?

    我知道已经有一个标准方法 前缀为L wchar t test literal L Test 问题是wchar t不保证是16位 但是对于我的项目 我需要16位wchar t 我还想避免通过的要求 fshort wchar 那么 C 不是 C
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • C++ 中的双精度型数字

    尽管内部表示有 17 位 但 IEE754 64 位 浮点应该正确表示 15 位有效数字 有没有办法强制第 16 位和第 17 位为零 Ref http msdn microsoft com en us library system dou
  • 将签名位图转换为签名字符串(很奇怪的一个)

    基本上我需要将位图图像转换为字符串 但这不是常见的 困境在于该字符串由两部分组成 1 积分 2 线路 我需要将图像转换为由 分隔的两个部分 我得到的一个例子是 221A 221A270A270A25032503200720071716171
  • OpenGL:仅获取模板缓冲区而没有深度缓冲区?

    我想获取一个模板缓冲区 但如果可能的话 不要承受附加深度缓冲区的开销 因为我不会使用它 我发现的大多数资源表明 虽然模板缓冲区是可选的 例如 排除它以利于获得更高的深度缓冲区精度 但我还没有看到任何请求并成功获取仅 8 位模板缓冲区的代码
  • 堆栈是向上增长还是向下增长?

    我在 C 中有这段代码 int q 10 int s 5 int a 3 printf Address of a d n int a printf Address of a 1 d n int a 1 printf Address of a
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • OpenCV SIFT 描述符关键点半径

    我正在深入研究OpenCV的SIFT描述符提取的实现 https github com Itseez opencv blob master modules nonfree src sift cpp 我发现了一些令人费解的代码来获取兴趣点邻域

随机推荐

  • D3.js 中的树形图 x 和 y 属性从何而来?

    这是 JavaScript 代码 d3 json city json function error root var nodes cluster nodes root var links cluster links nodes consol
  • UITableView 单元格上的 Peek 和 Pop 因 UISearchController 而失败

    Peek and Pop 正在与UISearchController 但是 一旦您开始使用以下命令搜索表 Peek 和 Pop 就会停止工作updateSearchResults I ve extended Apple s Table Se
  • 从“local hackage”安装软件包(通过 cabal)

    是否有可能让阴谋集团 下载特定的包源 包括所有依赖包源 在稍后阶段 当不再依赖互联网连接时 通过 cabal 从本地下载的文件中自动按正确的顺序安装这些软件包 以便构建所需的软件包 我知道你可以使用cabal unpack查看特定包的源代码
  • IBM Worklight 6.1 开发者版下载链接

    我正在尝试从市场或谷歌下载 IBM Worklight 6 1 但我看不到任何相同的结果 任何人都可以分享 IBM WL 6 1 的链接以及如何将修复包升级到 6 1 0 1 我也在寻找开发者版本 由于 6 2 已发布 我只能看到 6 2
  • Altair 结合多个数据集

    我最近才知道Vega Vega Lite and Altair并将其视为最佳 Python 绘图工具的真正竞争者 我目前正在努力解决的问题是将两个数据帧中的信息绘制到共享一个或两个轴的同一个图表中 我尝试过类似的事情 plot1 alt C
  • 如何使用正则表达式匹配不在两个特殊字符之间的内容?

    我有一个像这样的字符串 a b c a b a b b a a 我如何匹配每一个a不是由以下分隔的字符串的一部分 我想匹配这里粗体的所有内容 a bc a乙 乙 乙a a 我想替换这些匹配项 或者通过用空字符串替换它们来删除它们 因此删除匹
  • 如何在 Spring-Web 中使用 RestTemplate 解析 gzip 编码响应

    我修改后使用 RESTful Web 服务 https spring io guides gs consuming rest 调用示例通过id获取用户 https api stackexchange com docs users by id
  • 如何使用 cv2.createButton 在 OpenCV 3.1 中制作按钮?

    我正在尝试向图像处理脚本添加一个按钮 以保存二进制阈值的高 HSV 值和低 HSV 值 根据OpenCV 3 0文档here http docs opencv org 3 0 beta modules highgui doc qt new
  • 如何将 jquery.Validate 与 jquery.multiselect 下拉菜单一起使用?

    所以情况是这样的 尝试使用添加下拉框jquery multiselect http www erichynds com jquery jquery ui multiselect widget 当前使用的表单上的插件jquery 验证 htt
  • 按需发布时的最佳(您认为)GIT 工作流程(在大多数情况下一次 1-2 个票证)

    我是一个 Git 新手 我正在寻求你的建议 在我工作的公司中 我们有一个 工作流程 其中我们的项目有一个 Git 存储库 有 2 个分支 master and prod 所有开发人员都致力于master分支 如果票证完成 从开发人员的角度来
  • Python Tkinter 输入小部件不接受输入

    我在 Tkinter 条目小部件方面遇到了一个非常奇怪的问题 当我尝试向其中输入内容时 他们不接受我的输入 在重新启动电脑并重新安装 Python 之后 我弄清楚了为什么会发生这种情况 在root mainloop 在代码中 代码看起来像这
  • 拆分 SAS 数据集

    我有一个 SAS 数据集 如下所示 id dept 1 A 2 A 3 A 4 A 5 A 6 A 7 A 8 A 9 B 10 B 11 B 12 B 13 B 每个观察代表一个人 我想将数据集分成 团队 数据集 每个数据集最多可以有 3
  • 为什么我不能从 long 中导出?

    我的函数返回一些长值 其中包含低 32 位和高 32 位中的两个值 我认为处理返回值的最佳方法 是从 long 派生我的自定义类型并提供 类型扩展器 例如 GetLowerValue GetHigherValue 问题是 NET 不允许从
  • XGBOOST:sample_Weights 与scale_pos_weight

    我有一个高度不平衡的数据集 想知道在哪里考虑权重 因此我试图理解之间的区别scale pos weight论证中XGBClassifier和sample weight的参数fit方法 如果可以同时使用这两种方法或者如何选择其中一种方法 我们
  • 增加ggplot2中axis.title和axis.text之间的间距(版本> = 0.9.0)

    我目前正在使用 github 上的最新版本的 ggplot2 在 0 8 9 版本中 我可以执行以下操作来增加 axis title 和 axis text 之间的空间 Before ggplot diamonds aes clarity
  • 如何在使用 asm 库进行检测的方法中查找空的局部变量

    在为其不同方法检测类时为了使方法在文本文件中执行写入操作 我首先将字符串存储在显式定义的局部变量 3160 中 如何选择这些变量以防止与已有变量发生冲突 就像这段代码一样 代码每次进入任何方法时都会将类名写入文本文件 为了做到这一点 必须使
  • 如何将 tfjs-node 与从源代码构建的 libtensorflow 结合使用

    我看到可以使用libtensorflow如自述文件中所述 是从源代码构建的https github com tensorflow tfjs node optional build libtensorflow from tensorflow
  • C/C++ 中负数返回 false 吗?

    在 C C 中将整数评估为布尔值时 负数是真还是假 无论编译器如何 它们总是正确 错误吗 所有非零值将被转换为true 和零值false 当负数非零时 它们会被转换为true 引用 C 11 标准 强调我的 4 12 布尔转换 conv b
  • 制作锁子甲背景主题

    我想制作一个像这样的锁子甲 我尝试过使用线性渐变 但似乎不起作用 background linear gradient 0c0c0c 222222 important 我希望输出与 imgur 中显示的图像类似 线性渐变有用吗 你可以这样做
  • 对 BITMAPINFO (HBITMAP) 中像素数据的原始/直接访问

    我试图弄清楚如何从屏幕访问原始像素信息 到目前为止 我一直将屏幕捕获到 HBITMAP 填充 BITMAPINFO 然后创建此 BITMAPINFO 变量的指针以直接从内存读取 我知道必须从文件中 删除 标头 因此我将指针直接前进到位图数据