Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2

GetPixel() работает нереально медленно на Windows 7

17.02.2011, 10:48. Показов 25120. Ответов 67
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Написал программу (бот для онлайн игры), вся его работа заключается в получении цвета пикселя в нужных координатах и совершения тех или иных деййствий в зависимости от полученного цвета. Стояла ХР, все работало прекрасно, но вот решил попробовать семерку и столкнулся с необъяснимой вещью - бот нереально тупит. Например в самом начале он ищет окно игры в браузере (всмысле его координаты) а потом в этом окне находит нужную кнопку по ее цвету:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void find_button(POINT& but,HDC dc){
    HWND desktop=GetDesktopWindow();
    RECT rect;
    GetWindowRect(desktop,&rect);//получаем разрешение экрана
    const COLORREF buttonc=(10142681&0x00FCFCFC);//цвет кнопки, слегка загрубленный, на всякий случай
    but.x=rect.right-30;
    but.y=rect.bottom/2-100;
    while((GetPixel(dc,but.x,but.y)&0x00FCFCFC)==0x00FCFCFC)
        but.x--;//находим окно игры
    but.x-=112;
    bool f=false;
    while(!f){//находим кнопку
        clf=((GetPixel(dc,but.x,but.y))&0x00FCFCFC);
        for(int i=1;i<=10;i++){
            if(clf!=buttonc)
                break;
            else if(i==10)//если 10 пикселей подряд одного цвета, то похоже это кнопка
                f=true;
 
        }
        but.y++;
    }
    SetCursorPos(but.x,but.y+20);
    but.y+=23;
}
слегка быдлокод, т.к. писал "лишь бы работало" )) Но не об этом речь. В общем на ХР все эти действия происходят мнгновенно (для человеческого глаза), а на семерке на это уходит 5-6 секунд. По-моему нереальное время. Пробовал в диспетчере задач менять приоритет процесса - непомогло. Далее вся работа бота сводится к считываню цветов в определенных местах и реагированию на произошедшие события (цвет изменился - значит что-то случилось)), но естественно с такими темпами ни чего не работает. Вот сижу и думаю - почему на Win7 так медленно работают обычные API ?

Добавлено через 9 минут
поечему я решил что тормозит именно GetPixel()? - потому, что больше тут тормозить не чему)
1
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
17.02.2011, 10:48
Ответы с готовыми решениями:

Несколько GetPixel с экрана - код работает слишком медленно
Собственно в данный момент я использую этот код. int GetPixel(int X, int Y) { Bitmap bmp = new Bitmap(1, 1,...

Ноутбук начал нереально медленно работать (Acer aspire 5750g)
Поставил на ноутбук windows 10.Ставил через USB-флешку, активировал через kms.Все вроде было отлично.Поставил драйвера Nvidia,поиграл в...

Медленно работает Windows 7
Почему при включении плеера,текстового редактора и инета винда начинает тормозить. Windows 7 AMD 6000+ 2x 3ГГц DDR2 - 2x2048MB GeForce...

67
59 / 59 / 2
Регистрация: 22.01.2011
Сообщений: 187
20.02.2011, 18:32
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Kastaneda Посмотреть сообщение
На этот цикл потребовалось где 6-7 сек
действительно очень долго, в чем причина даже ума не приложу.
вопрос, по какой причине таким оброзом ищиш окно игры?
не проще ли FindWinowEx.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.02.2011, 19:26  [ТС]
Цитата Сообщение от bobrovskii Посмотреть сообщение
не проще ли FindWinowEx.
Браузерная игра написанная на flash. Мне нужно определить край окна, а от него уже дальше ищу кнопки в окне, тоже по цвету пикслелей. Т.к. у них нет своих handle'ов.

Добавлено через 56 секунд
Но меня уже не столько мой бот интересует, сколько время, затраченное на GetPixel() в Windows7.
0
59 / 59 / 2
Регистрация: 22.01.2011
Сообщений: 187
20.02.2011, 20:09
Kastaneda, попробуй с CreateCompatibleDC, CreateCompatibleBitmap как предложил turboq, тоже вариант. может что получится.
П.С. ЛС Event`s.
1
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.02.2011, 20:55  [ТС]

Не по теме:

bobrovskii, с сигналами все понятно, удобная вещь)



Добавлено через 39 минут
Может глупый вопрос, но все же: может GetPixel() тормозить из-за некорректного драйвера для видеокарты?
0
59 / 59 / 2
Регистрация: 22.01.2011
Сообщений: 187
20.02.2011, 21:01
Kastaneda, в таком случае большинство приложений используйших эту функцию имели бы такойже глюк. тут что то в твоем коде. если время будет скину в ЛС вариант с CreateCompatibleBitmap может поможет.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.02.2011, 21:06  [ТС]
Цитата Сообщение от bobrovskii Посмотреть сообщение
в таком случае большинство приложений используйших эту функцию имели бы такойже глюк
Ну да, логично, не подумал.

Цитата Сообщение от bobrovskii Посмотреть сообщение
если время будет скину в ЛС вариант с CreateCompatibleBitmap может поможет
Не уверен, что это то, что мне нужно. Мне в дальнейшем нужно в life режиме работать с пикселями (мнгновенно реагировать на изменение цвета определенного пикселя), а с CreateCompatibleBitmap, на сколько я понял, такого не получится. Хотя я не так много про CreateCompatibleBitmap почитал.
0
59 / 59 / 2
Регистрация: 22.01.2011
Сообщений: 187
20.02.2011, 21:13
Kastaneda, Скорость практически таже, кода больше)
в любом случае ничего не теряеш.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
20.02.2011, 21:16  [ТС]
Цитата Сообщение от bobrovskii Посмотреть сообщение
Kastaneda, Скорость практически таже, кода больше)
Значит я не правильно понял цель применения CreateCompatibleBitmap, тогда можно попробовать)
0
4 / 4 / 5
Регистрация: 16.04.2010
Сообщений: 10
22.02.2011, 17:56
Используйте GetDIBits.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
24.02.2011, 12:07  [ТС]
В общем написал свою ф-цию MyGetPixel(), выкладываю код, на случай если когда-нибудь кто-нибудь столкнется с похожей проблемой и воспользуется поиском по форуму:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
COLORREF MyGetPixel(HWND hGame,int x,int y){//на входе хэндл нужного окна и координаты x,y
    COLORREF pixel;
    BITMAPINFO BMI={0};
    HDC hGDC=GetDC(hGame);
    int Bitp=GetDeviceCaps(hGDC, BITSPIXEL);
    HDC hTmpDC=CreateCompatibleDC(hGDC);
    HBITMAP hTmpBmp=CreateCompatibleBitmap(hGDC,1,1);
    SelectObject(hTmpDC,hTmpBmp);
    BitBlt(hTmpDC,0,0,1,1,hGDC,x,y,SRCCOPY);
    BMI.bmiHeader.biSize = sizeof(BMI.bmiHeader);
        BMI.bmiHeader.biWidth = 1;
        BMI.bmiHeader.biHeight = 1;
        BMI.bmiHeader.biPlanes = 1;
        BMI.bmiHeader.biBitCount = Bitp;
        BMI.bmiHeader.biCompression = BI_RGB;
    BMI.bmiHeader.biSizeImage=Bitp/8;
    BMI.bmiHeader.biClrUsed = 0;
    BMI.bmiHeader.biClrImportant = 0;
    int TMP=GetDIBits(hTmpDC,hTmpBmp,0,1,&pixel,&BMI, DIB_RGB_COLORS);
    pixel&=0xFFFFFF;
    ReleaseDC(hGame,hGDC);
    return pixel;
}
Все работает очень быстро))

Не по теме:

Сегодня установил на семерку SP1, там стандартный GetPixel() прекрасно работает, вот же блиннн...

2
59 / 59 / 2
Регистрация: 22.01.2011
Сообщений: 187
24.02.2011, 12:16
Kastaneda, код хороший), ReleaseDC присутствует а DeleteDC забыл.
1
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
24.02.2011, 13:41  [ТС]
Ну я так подумал, что поскольку HDC hTmpDC локальная переменная, то нет смысла вызывать DeleteDC() для нее, все равно при выходе из MyGetPixel() она уничтожется. Или все таки нужно?

Добавлено через 7 минут
Да, наверное все таки нужно, хендл удаляется, а устройство в памяти все равно наверно висит.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
24.02.2011, 16:02
Цитата Сообщение от Kastaneda Посмотреть сообщение
хендл удаляется, а устройство в памяти все равно наверно висит
Удаляется не хэндл, а локальная переменная, содержащая значение хэндла. Точно так же, если ты вызовешь malloc и результат запишешь в локальную переменную, то после завершения процедуры память не освободится
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
24.02.2011, 17:39  [ТС]

Не по теме:

Цитата Сообщение от Evg Посмотреть сообщение
Удаляется не хэндл, а локальная переменная, содержащая значение хэндла.
Ну да, я это и подразумевал)



Добавлено через 43 минуты
Цитата Сообщение от Kastaneda Посмотреть сообщение
Сегодня установил на семерку SP1, там стандартный GetPixel() прекрасно работает, вот же блиннн...
Это я погарячился) В общем ситуация такая - если получать пиксель используя хэдл рабочего стола (или контекст ус-ва, связанный с раб. столом в случае с GetPixel()), то тупит и моя ф-ция и стандартная, если использовать например хэндл браузера, то обе ф-ции работают быстро. Вот такая вот магия...
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
24.02.2011, 17:46
Цитата Сообщение от Kastaneda Посмотреть сообщение
Это я погарячился) В общем ситуация такая - если получать пиксель используя хэдл рабочего стола (или контекст ус-ва, связанный с раб. столом в случае с GetPixel()), то тупит и моя ф-ция и стандартная, если использовать например хэндл браузера, то обе ф-ции работают быстро. Вот такая вот магия...
По-моему это +1 к догадке из поста #6. Попробуй всё-таки работать и читать сразу весь экран в промежуточную память за одно обращение к устройству, а дальнейшую работу с точками уже выполнять над этой памятью (без обращения к устройству на каждую точку)
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
24.02.2011, 18:35  [ТС]
Цитата Сообщение от Evg Посмотреть сообщение
По-моему это +1 к догадке из поста #6.
Да, по-моему так и есть.
Цитата Сообщение от Evg Посмотреть сообщение
читать сразу весь экран в промежуточную память за одно обращение к устройству, а дальнейшую работу с точками уже выполнять над этой памятью (без обращения к устройству на каждую точку)
Для меня не вариант, на сколько я понял в памяти сохранится "мнгновенный снимок" экрана, т.е. через секунду снимок в памяти не будет соответствовать реальному состоянию экрана, а мне нужно реагировать на события в реальном времени. Поэтому я каждый раз создаю битмап в памяти размером 1 пиксель, и копирую в него пиксель, находящийся в нужных мне координатах на экране.

Evg, а почему ты отсюда:

Цитата Сообщение от Kastaneda Посмотреть сообщение
В общем ситуация такая - если получать пиксель используя хэдл рабочего стола (или контекст ус-ва, связанный с раб. столом в случае с GetPixel()), то тупит и моя ф-ция и стандартная, если использовать например хэндл браузера, то обе ф-ции работают быстро.
сделал такие выводы:

Цитата Сообщение от Evg Посмотреть сообщение
По-моему это +1 к догадке из поста #6.
?
Я вот связи не вижу. Браузер развернут на весь экран (т.е. он не на много меньше всего рабочего стола), но при этом работать с браузером в разы (наверное в сотни, а то и в тысячи раз) быстрее, чем со столом. Вообще не понимаю почему так, тем более я только с одной точкой в своей ф-ции работаю.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
24.02.2011, 20:09
Цитата Сообщение от Kastaneda Посмотреть сообщение
т.е. через секунду снимок в памяти не будет соответствовать реальному состоянию экрана
За эту секунду ты можешь несколько тысяч раз обработать снимок всего экрана. Причём самая тяжёлая по времени операция - это перегнать снимок экрана в буффер. Когда ты достаёшь одну точку, то этот процесс по времени несильно отличается.

Если на пальцах, то ситуация примерно такая (цифры взяты от балды, чисто чтобы показать соотношение). Миллион тактов уходит на то, чтобы сделать снимок экрана, тысячу тактов уходит на то, чтобы снимок обработать. Практически тот же миллион тактов уходит на то, чтобы сделать снимок одной точки. И один такт на то, чтобы точку обработать. Т.е. при непосредственном обращении к устройству нет разницы, делать снимок всего экрана или снимок одной точки. При снимке одной точки всё равно делается снимок всего экрана, только ты этого не видишь.

Когда ты работаешь с одним окном, то при повторном вызове снимок всего жкрана уже не делается, а используется закэшированный. А потому на обработку тысячи раз одной точки у тебя уходит миллион тактов плюс тысячу раз по одной точке (т.е. столько же, как если бы ты делал снимок всего экрана и обрабатывал тысячу точек). Когда работаешь с целым рабочим столом, то кэширование по каким-то причинам не делается и на обработку тысячу раз одной точки у тебя получается тысяча снимков экрана (от чего так всё и тормозит).

Чем принципиально лучше вариант с получением снимка всего экрана. По скорости работы он принципиально не должен отличаться от варианта, когда за раз достаётся одна точка. Только при этом управление процессом находится в гораздо более полной мере в твоих руках, чем руках системы. Другими словами, ты перестаёшь зависеть от капризов работы GetPixel (которую, кстати говоря, не очень-то и рекомендуют к использованию): тут она работает так, там работает сяк, с таким хэндлом работает быстро, с таким медленно. Вместо кода, живучесть которого выясняется методом тыка и массового тестирования, ты получаешь код, которые независимо ни от чего и ни от кого работает везде одинаково быстро.

Естественно, всё это в предположении, что догадка верна

Цитата Сообщение от Kastaneda Посмотреть сообщение
вот связи не вижу
Как я уже говорил - кэширование. За окно (хоть оно во весь экран, хоть не во весь) отвечает только один процесс. За рабочий стол - туева хуча процессов, включая системные и те, что отображены в tray. Возможно, что там для подтстраховки нет кэширования, возможно - что действительно что-то там меняется.
0
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
24.02.2011, 20:40  [ТС]
Цитата Сообщение от Evg Посмотреть сообщение
За эту секунду ты можешь несколько тысяч раз обработать снимок всего экрана.
Либо я не понимаю, что ты хочешь до меня донести, либо ты не понимаешь, что мне нужно) Мне нужно каждую долю секунды получать новый снимок экрана, это важно.

Когда ты работаешь с одним окном, то при повторном вызове снимок всего жкрана уже не делается, а используется закэшированный.
Но ведь в таком случае, я бы не смог отследить изминения цвета в определенной точке, но у меня получается), значит снимок экрана делается каждый раз. Моя ф-ция MyGetPixel() вызывается в непрерывном цикле в отдельном потоке и при изменении цвета определенного пикселя шлет сигнал в параллельный поток. Если бы при этом использовался кэшированный снимок экрана, то я бы не смог реализовать то, что я хочу.


Цитата Сообщение от Evg Посмотреть сообщение
Как я уже говорил - кэширование. За окно (хоть оно во весь экран, хоть не во весь) отвечает только один процесс. За рабочий стол - туева хуча процессов, включая системные и те, что отображены в tray. Возможно, что там для подтстраховки нет кэширования, возможно - что действительно что-то там меняется.
Это похоже на правду, но тогда (если все таки снимок действительно хэшируется) я не понимаю, как можно отловить изменение цвета в захешированном снимке?
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21285 / 8310 / 637
Регистрация: 30.03.2009
Сообщений: 22,671
Записей в блоге: 30
24.02.2011, 21:25
Впервые за время пользования фатально накрылся Chrome. И, естественно, в тот момент, когда было написано много текста

Вкратце вот что написал.

Кэшируется изображение, естественным образом, только тогда, когда оно не меняется. Система "знает" о том, когда картинка поменялась, а потому в нужный момент кэш инвалидирует, делает новый снимок экрана и кэширует его.

Моя идея сводилась к тому, что с небольшими интервалами (например, 50 или 100 раз в секунду), ты делаешь снимок экрана, а дальше весь анализ делаешь на снимке. В процессе анализа (я смотрю на код из первого поста) у тебя много раз вызывается GetPixel, а в новом варианте вместо этого у тебя будет просто чтение значения из буффера памяти
1
 Аватар для Kastaneda
5232 / 3206 / 362
Регистрация: 12.12.2009
Сообщений: 8,143
Записей в блоге: 2
25.02.2011, 04:13  [ТС]
Цитата Сообщение от Evg Посмотреть сообщение
Кэшируется изображение, естественным образом, только тогда, когда оно не меняется. Система "знает" о том, когда картинка поменялась, а потому в нужный момент кэш инвалидирует, делает новый снимок экрана и кэширует его.
А, ну теперь дошло)))
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
25.02.2011, 04:13

Windows XP медленно работает
Помогите пожалуйста, ситуация следующая...Винда начала глючить, комп не хотел выключаться и я переустановил ее с форматированием. Теперь...

USB работает медленно (Windows 7)
Операционная система: Windows 7 Ultimate x64 (original, RTL, не сборка). Motherboard: ASUS P5QL-CM Драйвера после установки Windows...

Windows XP работает слишком медленно
Добрый день. Есть дома второй компьютер, на нём батя вся в шашки играет) Я не чайник, с 15 лет ставил ХP сам и чем только не...

Медленно работает Аксесс 97 под Windows 7
База работает под Акс97. Кратко алгоритм таков. Открывается связанная таблица как рекордсет. Организуется цикл по записям в ВБА. ...

После переустановки Windows 7 медленно работает система
Здравствуйте! Так случилось что мне доводится часто переустанавливать Windows на ноутбуках разных производителей. И я заметил одну не...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

Новые блоги и статьи
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru