Получить цвет пикселя быстрее всего?

Я пытаюсь сделать автокликер для приложения 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. Но я провел некоторые исследования, и я не понимаю, как я должен это делать, чтобы сканировать цветовой массив. Мне нужно что-то, что очень быстро сканирует экран, чтобы поймать кнопку.

Не могли бы вы мне помочь?

Спасибо.


person Manitoba    schedule 09.05.2012    source источник
comment
Когда вызывается ваш код? в простое? когда пользователь двигает мышь? Существуют разные способы обнаружения красной кнопки, например, с помощью FindWindow().   -  person Adriano Repetti    schedule 09.05.2012
comment
Кстати, мой код находится в бесконечном цикле. Но я хочу использовать ловушку цвета, а офсетную. Итак, когда я запускаю свой код, он просто входит в цикл и проверяет красную кнопку.   -  person Manitoba    schedule 09.05.2012
comment
Если этот код находится в бесконечном цикле, проблема не в GetPixel. Это тот факт, что ваше приложение не позволяет другим приложениям использовать процессорное время.   -  person tenfour    schedule 09.05.2012
comment
Кстати, все мои вещи находятся в теме. Как я уже сказал, это хорошо работает с getPixel. я просто ищу лучший способ сделать это   -  person Manitoba    schedule 09.05.2012
comment
Это не работает - вы сказали, что это медленно. Без профилирования данных я назвал лучшую причину, по которой это медленно.   -  person tenfour    schedule 09.05.2012


Ответы (2)


Я нашел идеальный способ, который явно быстрее, чем у 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);
        }
    }
}

Я надеюсь, что это может помочь кому-то еще.

person Manitoba    schedule 09.05.2012
comment
это проверка каждого пикселя? Я не понимаю ваших заданий x и y. - person user1397417; 27.02.2014
comment
X и Y — расположение просматриваемого пикселя. Они бесполезны, если только вы не хотите выполнить действие с этим пикселем. Если его цвет полностью красный, он установит мышь на этот пиксель и сделает щелчок левой кнопкой мыши. - person Manitoba; 27.02.2014
comment
Хорошая работа, но я чего-то не понимаю. Зачем учитывать байт, присвоенный альфа-составляющей пикселя? Поскольку это скриншот, значение альфы всегда будет 255, верно? Итак, не лучше ли сделать параметр biBitCount равным 24? - person Delgan; 19.04.2014
comment
Вы совершенно правы. Часть Aplha бесполезна. - person Manitoba; 19.04.2014
comment
GetWindowRect с дескриптором HWND_DESKTOP возвращает FALSE. нужно добавить hWND_Desktop = GetDesktopWindow()? или вместо этого используйте GetSystemMetrics() .. - person xakepp35; 24.06.2017
comment
Почему вам нужно умножать biSizeImage на 4? - person Scdev; 07.09.2019
comment
Красный и синий нужно поменять местами: синий = (int)bitPointer[i];зеленый = (int)bitPointer[i + 1];красный = (int)bitPointer[i + 2]; - person Gary Davies; 09.10.2019
comment
К сожалению, это все еще медленно для моей цели. Я хочу настроить мышь точно в то же время, когда пиксель получает определенный цвет. Но мой контекст — это когда кто-то рисует на экране. Если пользователь рисует рукой очень быстро, метод запускает событие только после того, как пользователь уже прошел этот пиксель. Мне нужно отключить мышь именно в тот момент, когда пиксель окрашивается, чтобы пользователь не мог рисовать следующие пиксели. Я думаю, что нет никакого способа достичь этого. - person Eduardo M; 11.02.2020

Простой ответ заключается в том, что если вы настаиваете на использовании этого метода, то оптимизировать особо нечего. Как отмечали другие в комментариях, вам, вероятно, следует использовать другой метод для определения области для щелчка. Взгляните, например, на использование FindWindow.

Если вы не хотите менять свой метод, то, по крайней мере, немного отложите поток после каждого полного сканирования экрана.

person korona    schedule 09.05.2012
comment
Привет, Не могли бы вы рассказать мне больше о Findwindow? Я использую это так: mhwnd = FindWindow(NULL, "Application Window Name"); hdc = GetDC(mhwnd); Что дальше? - person Manitoba; 09.05.2012
comment
Кнопка, которую вы хотите нажать, вероятно, имеет собственный дескриптор окна. Попробуйте использовать программу оконного инспектора, такую ​​как Spy++, чтобы найти дескриптор окна объекта, который вы хотите щелкнуть, и вы, вероятно, сможете найти этот конкретный элемент с помощью какого-нибудь умного кода. - person korona; 09.05.2012