c++ - 位图到 mat/2d 数组

标签 c++ opencv bitmap

我的目标是有一个程序可以捕获游戏的屏幕,然后从代码中读取图片。

我真的是 win api 的新手 + 从未使用过位图,所以我很难过,我是一个完全的菜鸟。

我必须截屏的代码是(在堆栈溢出时找到的):

    HDC hScreenDC = GetDC(NULL);
// and a device context to put it in
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

int width = GetDeviceCaps(hScreenDC, HORZRES);
int height = GetDeviceCaps(hScreenDC, VERTRES);

// maybe worth checking these are positive values
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);

// get a new bitmap
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);

// clean up
DeleteDC(hMemoryDC);
DeleteDC(hScreenDC);

我的想法是将“hBitmap”转换为 mat/2d 数组。 我在互联网上搜索并找到了下一个解决方案:

  1. 将图像加载到 HBITMAP 句柄中。

  2. 从 HBITMAP 获取 BITMAP 对象。

  3. 创建一个 DWORD 数组以从 BITMAP 加载 bmBits。

  4. 将DWORD数组保存成RGB结构矩阵。

第 1 步已经完成,我有变量“hBitmap”。

对于第 2 步,我添加了下一个代码:

//Get BITMAP object from HBITMAP
BITMAP bitmap;
GetObject(hBitmap, sizeof(BITMAP), &bitmap);

在删除 dc 之前。

我不知道如何进行第 3 步和第 4 步。 如果有人向我展示我会很高兴,因为我没有设法找到有关该主题的任何简单指南。 如果有其他更好的解决方案,我也很乐意听到。

编辑:试图将其保存为带有“Barmak Shemirani”答案的 .ppm,但它只显示了 4 个大方 block ?

注意:i +=4,我知道它的 rgba 而不是 rgb,但是 a 总是 255 代码:

using namespace std;
int main()
{
    cout << "Hello World!\n";
    HDC hScreenDC = GetDC(NULL);
    // and a device context to put it in
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

int width = GetDeviceCaps(hScreenDC, HORZRES);
int height = GetDeviceCaps(hScreenDC, VERTRES);

// maybe worth checking these are positive values
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);

// get a new bitmap
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);


WORD bpp = 32; //32-bit bitmap
cout << "width=" << width << endl;
cout << "height=" << height << endl;
DWORD size = ((width * bpp + 31) / 32) * 4 * height;
BITMAPINFOHEADER bi = { sizeof(bi) };
bi.biWidth = width;
bi.biHeight = height;
bi.biPlanes = 1;
bi.biBitCount = bpp;

unsigned char* bits = new unsigned char[size];
int result = GetDIBits(hScreenDC, hBitmap, 0, height, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);

ofstream img(".ppm");
img << "P3" << endl;
img << 1536 << " " << 864 << endl;
img << "255" << endl;
for (int i = 0; i <= 864; i++) {
    for (int j = 0; j < 1536; j+=4) {
        int r = bits[i];
        int g = bits[i + 1];
        int b = bits[i + 2];
        img << r << " " << g << " " << b << endl;
    }
}

cout << "finished" << endl;

delete[]bits;

// clean up
    SelectObject(hMemoryDC, hOldBitmap);//now we can destroy hMemoryDC & hBitmap
    DeleteObject(hBitmap);
    DeleteDC(hMemoryDC);
    ReleaseDC(0, hScreenDC);

最佳答案

GetObject(hBitmap...)将填写 bm.bmBits仅限 DIB 成员。但是这里我们没有DIB。使用 GetDIBits反而。下面的示例将像素读入 bits对于 32 位位图。

WORD bpp = 32; //32-bit bitmap
DWORD size = ((width * bpp + 31) / 32) * 4 * height;
BITMAPINFOHEADER bi = { sizeof(bi) };
bi.biWidth = width;
bi.biHeight = height;
bi.biPlanes = 1;
bi.biBitCount = bpp;

unsigned char* bits = new unsigned char[size];
int result = GetDIBits(hdc, hBitmap, 0, height, bits, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
...
delete[]bits;

此外,您的代码还需要 ReleaseDC(0, hScreenDC)用于清理,而不是 DeleteDC(hScreenDC) ,因为 DC 被 GetDC 收购了.

//cleanup:
SelectObject(hMemoryDC, hOldBitmap);//now we can destroy hMemoryDC & hBitmap
DeleteObject(hBitmap);
DeleteDC(hMemoryDC);
ReleaseDC(0, hScreenDC);

以 ppm/非二进制形式保存:

ofstream img("filename.ppm");
img << "P3\n";
img << width << " " << height << "\n";
img << "255\n";
for(int y = height - 1; y >= 0; y--) 
{
    for(int x = 0; x < width; x ++)
    {
        int i = (y * width + x) * 4;
        int r = bits[i + 2];
        int g = bits[i + 1];
        int b = bits[i + 0];
        img << r << " " << g << " " << b << " ";
    }
    img << "\n";
}

关于c++ - 位图到 mat/2d 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51993412/

相关文章:

c++ - 使用 QT 和 MinGW32 在 Windows 上检查内存泄漏

c++ - OpenCV:将 std::vector 传递给需要 OutputArray 的函数时,vec 包含垃圾

python - 如何在OpenCV中从图像中提取条纹区域?

database - 位图索引有何帮助?

c++ - Windows 平台最快的 C++ 链接器是什么?

c++ - 如何在现有 Windows 应用程序中获得 ATL 支持

c++ - 无法在 Eclipse Neon 中使用 openmp 编译指示编译 C++

opencv - 如何用opencv改变饱和度值?

android - 如何在 SQLite (Android) 中存储可绘制/位图

java - Android Java Bitmap.getByteCount() 显示的大小比实际大小大