【问题标题】:Get Pixel color fastest way?获取像素颜色最快的方法?
【发布时间】:2012-05-17 22:36:42
【问题描述】:

我正在尝试为 Windows 应用程序制作自动点击器。它运作良好,但速度非常慢! 我目前正在使用“getPixel”方法,每次调用它都会重新加载一个数组。

这是我当前的代码:

hdc = GetDC(HWND_DESKTOP);
bx = GetSystemMetrics(SM_CXSCREEN);
by = GetSystemMetrics(SM_CYSCREEN);
start_bx = (bx/2) - (MAX_WIDTH/2);
start_by = (by/2) - (MAX_HEIGHT/2);
end_bx = (bx/2) + (MAX_WIDTH/2);
end_by = (by/2) + (MAX_HEIGHT/2);

for(y=start_by; y<end_by; y+=10)
{   
    for(x=start_bx; x<end_bx; x+=10)
    {
        pixel = GetPixel(*hdc, x, y);
        if(pixel==RGB(255, 0, 0))
        {
            SetCursorPos(x,y);
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            Sleep(50);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            Sleep(25);
        }
    }
}

所以基本上,它只是扫描屏幕上的像素范围,如果检测到红色按钮,就会启动鼠标事件。

我知道还有其他方法可以获取像素颜色,例如 bitblt。但是我已经进行了一些研究,但我不明白我应该怎么做才能扫描颜色阵列。我需要能够快速扫描屏幕的东西才能抓住按钮。

你能帮帮我吗?

谢谢。

【问题讨论】:

  • 什么时候调用你的代码?在空闲时间?当用户移动鼠标时?有多种方法可以检测红色按钮,例如使用 FindWindow()。
  • 顺便说一句,我的代码处于无限循环中。但我想使用一个颜色捕捉器,而一个偏移的。所以,当我开始我的代码时,它只是进入循环并检查红色按钮。
  • 如果这段代码处于无限循环中,那么问题就不是GetPixel。事实上,您的应用不让其他应用拥有任何 CPU 时间。
  • 顺便说一句,我所有的东西都在一个线程中。正如我所说,它适用于 getPixel。我只是在寻找更好的方法来做到这一点
  • 效果不好——你说它很慢。如果没有分析数据,我给出了它慢的最好理由。

标签: c++ bitblt getpixel


【解决方案1】:

我找到了一种明显比 GetPixel 更快的完美方法:

HDC hdc, hdcTemp;
RECT rect;
BYTE* bitPointer;
int x, y;
int red, green, blue, alpha;

while(true)
{
    hdc = GetDC(HWND_DESKTOP);
    GetWindowRect(hWND_Desktop, &rect);
            int MAX_WIDTH = rect.right;
        int MAX_HEIGHT = rect.bottom;

    hdcTemp = CreateCompatibleDC(hdc);
    BITMAPINFO bitmap;
    bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
    bitmap.bmiHeader.biWidth = MAX_WIDTH;
    bitmap.bmiHeader.biHeight = MAX_HEIGHT;
    bitmap.bmiHeader.biPlanes = 1;
    bitmap.bmiHeader.biBitCount = 32;
    bitmap.bmiHeader.biCompression = BI_RGB;
    bitmap.bmiHeader.biSizeImage = MAX_WIDTH * 4 * MAX_HEIGHT;
    bitmap.bmiHeader.biClrUsed = 0;
    bitmap.bmiHeader.biClrImportant = 0;
    HBITMAP hBitmap2 = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
    SelectObject(hdcTemp, hBitmap2);
    BitBlt(hdcTemp, 0, 0, MAX_WIDTH, MAX_HEIGHT, hdc, 0, 0, SRCCOPY);

    for (int i=0; i<(MAX_WIDTH * 4 * MAX_HEIGHT); i+=4)
    {
        red = (int)bitPointer[i];
        green = (int)bitPointer[i+1];
        blue = (int)bitPointer[i+2];
        alpha = (int)bitPointer[i+3];

        x = i / (4 * MAX_HEIGHT);
        y = i / (4 * MAX_WIDTH);

        if (red == 255 && green == 0 && blue == 0)
        {
            SetCursorPos(x,y);
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
            Sleep(50);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
            Sleep(25);
        }
    }
}

我希望这可以帮助其他人。

【讨论】:

  • 这是在检查每个像素吗?我不明白你的 x 和 y 作业。
  • XY 是正在审查的像素的位置。它们是无用的,除非你想对这个像素做一个动作。如果它的颜色是全红色,它会将鼠标设置到该像素并单击鼠标左键。
  • 干得好,但有些东西我不明白。为什么要考虑分配给像素 Alpha 分量的字节?因为是截图,所以alpha的值永远是255,对吧?那么,将 biBitCount 参数设为 24 不是更好吗?
  • 你完全正确。 Aplha 部分没用。
  • GetWindowRect 与 HWND_DESKTOP 句柄返回 FALSE。需要添加 hWND_Desktop = GetDesktopWindow()?或使用 GetSystemMetrics() 代替..
【解决方案2】:

简单的答案是,如果这是您坚持使用的方法,那么就没有太多需要优化的地方了。正如其他人在 cmets 中指出的那样,您可能应该使用不同的方法来定位要单击的区域。例如,看看使用 FindWindow。

如果你不想改变你的方法,那么至少在每次完整的屏幕扫描后让你的线程休眠一段时间。

【讨论】:

  • 您好,您能告诉我更多有关 Findwindow 的信息吗?我是这样使用它的:mhwnd = FindWindow(NULL, "Application Window Name"); hdc = GetDC(mhwnd); 接下来是什么?
  • 您要单击的按钮可能有自己的窗口句柄。尝试使用诸如 Spy++ 之类的窗口检查器程序来查找您想要单击的对象的窗口句柄,您可能可以通过一些巧妙的代码找到该特定项目。
猜你喜欢
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 2020-04-27
相关资源
最近更新 更多