代码之家  ›  专栏  ›  技术社区  ›  Billy Penley

扫描位图以查找特定的像素颜色,并在c中给出x、y位置++

  •  2
  • Billy Penley  · 技术社区  · 6 年前

    我只想在给定像素的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;
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Barmak Shemirani    6 年前

    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。