【问题标题】:Scan BitMap for Specific pixel color, and give x, y location in c++扫描位图以获取特定像素颜色,并在 c++ 中给出 x、y 位置
【发布时间】:2018-09-07 15:15:00
【问题描述】:

我只是想根据给定像素的 RGB 值扫描内存中的位图以查找特定颜色,如果找到,请给我该像素的 x、y 线。我这里有代码将给定窗口的位图存储在内存中,并且工作正常。但是当我尝试检索红色值为 60 的像素所在的位置时,我得到了各种时髦的值。 这是我当前的代码:

bool findColor(int x, int y, int w, int h, LPCSTR fname) {
HWND window = FindWindow(0, ("windownamehere"));
HDC hdcSource = GetDC(window);
HDC hdcMemory = CreateCompatibleDC(hdcSource);
int capX = GetDeviceCaps(hdcSource, HORZRES);
int capY = GetDeviceCaps(hdcSource, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hdcSource, w, h);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);
BitBlt(hdcMemory, 0, 0, w, h, hdcSource, x, y, SRCCOPY);
SelectObject(hdcMemory, hBitmapOld);
//Added
HDC hdc = GetDC(0);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
GetDIBits(hdcMemory, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS);
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
MyBMInfo.bmiHeader.biCompression = BI_RGB;
GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS);
BYTE red, blue, green;
char* pCurrPixel = (char*)lpPixels;
for (y = 0; y < h; y++)
{
    for (x = 0; x < w; x++)
    {
        red = pCurrPixel[0];
        green = pCurrPixel[1];
        blue = pCurrPixel[2];
        if ((red == 134))
            std::cout << x << ", " << y;
        pCurrPixel += 4;
    }
}
SelectObject(hdcMemory, hBitmapOld);
DeleteObject(hBitmap);
DeleteDC(hdcSource);
DeleteDC(hdcMemory);
return false;
}

【问题讨论】:

标签: c++ colors bitmap pixel


【解决方案1】:

hBitmap = (HBITMAP)SelectObject(hdcMemory, hBitmapOld);

这会覆盖hBitmap,你不希望这样。您应该将该行更改为:

SelectObject(hdcMemory, hBitmapOld);

那么你可以使用GetDIBits

此外,您已经将位图复制到内存 dc。您可以使用GetPixel 获取颜色。无需拨打GetDIBits

HBITMAP hBitmapOld = (HBITMAP)SelectObject(hdcMemory, hBitmap);
COLORREF color = GetPixel(hdcMemory, x, y);
BYTE red = GetRValue(color);
BYTE green = GetGValue(color);
BYTE blue = GetBValue(color);
...
SelectObject(hdcMemory, hBitmapOld);
DeleteObject(hBitmap);
DeleteDC(hdcMemory);
RleaseDC(0, hdcSource);

完成后还请致电DeleteObject(hBitmap)

使用GetDIBits:32 位位图格式是 BGRA 而不是 RGBA,因此第一个字节是蓝色,而不是红色。在将位视为 32 位位图之前,您应该专门请求 32 位位图或检查位计数。

#include <iostream>
#include <vector>
#include <Windows.h>

int main()
{
    HWND target = FindWindow("Notepad", 0);
    if(!target)
    {
        printf("error, no window\n");
        return 0;
    }

    RECT rc;
    GetWindowRect(target, &rc);
    int x = rc.left;
    int y = rc.top;
    int w = rc.right - rc.left;
    int h = rc.bottom - rc.top;

    int screen_w = GetSystemMetrics(SM_CXFULLSCREEN);
    int screen_h = GetSystemMetrics(SM_CYFULLSCREEN);

    HDC hdc = GetDC(HWND_DESKTOP);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, screen_w, screen_h);
    HDC memdc = CreateCompatibleDC(hdc);
    HGDIOBJ oldbmp = SelectObject(memdc, hbitmap);
    BitBlt(memdc, 0, 0, w, h, hdc, x, y, CAPTUREBLT | SRCCOPY);
    SelectObject(memdc, oldbmp);

    BITMAPINFOHEADER infohdr = { sizeof(infohdr), w, h, 1, 32 };
    int size = w * h * 4;
    std::vector<BYTE> bits(size);
    int res = GetDIBits(hdc, hbitmap, 0, h, &bits[0], 
            (BITMAPINFO*)&infohdr, DIB_RGB_COLORS);
    if(res != h)
    {
        std::cout << "error\n";
        return 0;
    }

    BYTE *ptr = bits.data();
    //for(y = 0; y < h; y++)
    for(y = h - 1; y >= 0; y--) //bitmaps bits start from bottom, not top
    {
        for(x = 0; x < w; x++)
        {
            BYTE blu = ptr[0];
            BYTE grn = ptr[1];
            BYTE red = ptr[2];
            ptr += 4;
        }
    }

    SelectObject(memdc, oldbmp);
    DeleteObject(hbitmap);
    ReleaseDC(HWND_DESKTOP, hdc);
    DeleteDC(memdc);

    return 0;
}

请注意,如果用户未使用默认 DPI 设置,则该过程应支持 DPI。

【讨论】:

  • 我想我应该补充一下,我试图避免 getPixel() 因为我正在扫描大量像素,这会非常慢。我试图从位缓冲区中提取 RGB 数据,比较它们,如果为真,则返回该像素的 x y 线。
  • 如果您应用我建议的更改,GetDIBits 将起作用。在继续之前,您必须检查位图的位数。要比较不同的位图,它们的位数必须相同。
  • 我已经对我的原始帖子进行了编辑。我仍然得到疯狂的价值观。这让我很难理解。
  • 您以错误的方式阅读这些位。此外,您没有错误检查,也没有按照我的建议正确清理资源 - 请参阅编辑。
  • 太棒了,这对我帮助很大,并且代码正在运行。现在的最后一步是弄清楚如何将 Y 轴倒置,考虑到位图似乎是自下而上构建的。
猜你喜欢
  • 2011-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-06
相关资源
最近更新 更多