Что нового

FindPixel - поиск пикселей

Автор
P

Prog

Продвинутый
Сообщения
537
Репутация
65
Yura [?]
Вы уверенны, что: Color - Задает цвет для поиска, должен быть в формате RGB? Я создал в пейнте черный рисунок с 1 пикселем цвета 0xB5E61D. Цвет смотрю в ControlViewer в формате RGB. Нужный пиксель по нужным координатам FindPixel() нашел. Но когда я задал $Сolor = 0x1DE6B5, то есть в BGR.
https://ru.wikipedia.org/wiki/RGB
COLORREF — стандартный тип для представления цветов в Win32. Используется для определения цвета в RGB виде. Размер — 4 байта. При определении какого-либо RGB цвета, значение переменной типа COLORREF можно представить в шестнадцатеричном виде так:

0x00bbggrr

rr, gg, bb — значение интенсивности соответственно красной, зелёной и синей составляющих цвета. Максимальное их значение — 0xFF.
Обратите внимание что в шестнадцатеричной записи байты располагаются как BGR, но на самом деле это RGB, потому что в шестнадцатеричной записи, младший байт находится справа, а старший слева, из-за этого кажется что запись BGR, но в памяти цвет располагается в последовательности RGB.

В PureBasic вы для доступа к загруженному изображению используете "#Image" (The number by which to identify the loaded image. #PB_Any can be specified to autogenerate this number. ) Я правильно понимаю, что если во все функции добавить еще один параметр- число, которое будет передаваться в #Image, то можно будет использовать буфер под номером=это число, то есть можно было бы использовать несколько буферов? (например для отслеживания динамических изменений на экране).
Да. Возможно создать практически неограниченное число картинок (сколько памяти хватит).

ImageLoadHandle(hBmp) есть, обратная функция- получение hBmp из буфера, если это возможно, то тоже было бы отлично.
Нужно добавить в DLL такую функцию.
Код:
ProcedureDLL ImageGetHandle()
  Protected Result = 0
  
  If IsImage(#Image)
    Result = ImageID(#Image)
  EndIf
  
  ProcedureReturn Result
EndProcedure
 

Yura

Знающий
Сообщения
36
Репутация
7
При определении какого-либо RGB цвета, значение переменной типа COLORREF можно представить в шестнадцатеричном виде так:

0x00bbggrr
:shok: :blink:
http://www.rgbtohex.net/You entered R: 0, G: 0, B: 255 which converts to the following in Hex code: #0000FF
в rgb - 0хrrggbb. ИлиControlViewer, AutoitInfo и еще несколько сайтов в которых я переводил цвета нагло нас обманывают :smile:

За ImageID(#Image) спасибо, я тоже уже на нее наткнулся в поиске :smile:
 
Автор
P

Prog

Продвинутый
Сообщения
537
Репутация
65
Не нужно путать представление цвета в винде и в веб ЯП.
В винде последовательность байт RGB.
R это младший байт, а B старший байт.

В HEX представлении слева располагается старший байт, а справа младший байт.
 

Yura

Знающий
Сообщения
36
Репутация
7
Я вас понял, msdn почитал, но поймите и вы: пользователь вашей либы будет смотреть на COLORREF или будет смотреть на AutoitInfo или другой цветоопредилятор подобный и оттуда брать цвет для поиска? А там не в COLORREF.
Я не программист пока что, учу сейчас Джаву, чтоб работать в этом направлении. Но я программировал микрухи на ассемблере и С, по верхам писал еще на многих языках, с математикой всегда дружил и пол года как защитил кандидатскую. Я разбираюсь, потому что мне это интересно и я намерен развиваться в этом направлении. Но большинству пользователей по..., они не будут разбираться, попробуют, не работает и плюнут.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Prog сказал(а):
R это младший байт, а B старший байт.
Если говорить про GDI, где цвета задаются в BGR, то в памяти это будет располагаться так:

R G B A

В GDI+ все цвета задаются в ARGB.
 

Yura

Знающий
Сообщения
36
Репутация
7
Prog сказал(а):
Внес измерения в библиотеку.

Проверил опять с Shade=0 при запуске поиска пикселя в цикле 1000 раз. Скорость возросла буквально чуть-чуть, около 0.5 мс. Так как в внутри 2х циклов при Shade=0 выполняется только это
Код:
Color = Point(x, y)
              
              If Shade=0
                If P_Color = Color
                  SetData()
                EndIf
              Else
то скорее всего функция Point самая времязатратная.

Интересная особенность: в вашей функции поиска ярко выражена зависимость времени поиска от расположения искомого пикселя, это понятно, перебор по строкам и столбцам. В FastFind время поиска всегда почти одинаковое. Если искомый пиксель будет в точке с координами (0,10) например, то ваш поиск будет намного быстрее, если в средине картинки или тем более в конце- в разы медленней. В FastFind- все время около 2 мс у меня, куда бы точку не перемещал. Когда будет время, я поищу исходник FastFind, посмотрю. Такое впечатление, что там не попиксельный перебор, а другой подход. Или есть какая-то подготовительная процедура по обработке битмапа, которая занимает около 2 мс, и потом почти мгновенный поиск пикселя.

Сейчас я напишу , что нашел по вопросу о поисках пикселей в PureBasic, если я там не так что-то понял, прошу тапками не бросать. Я посмотрел по англоязычных форумах по пурику и там были вопросы о повышении производительности сканирования области, поиска пикселей и т.п. Вы используете рисование 2д. Может есть другой способ. Не совсем поиск пикселей, но возможно эта тема так-то поможет (сомневаюсь, но вдруг) http://www.purebasic.fr/english/viewtopic.php?t=27740. Только скажите, вам это интересно или вы уже сделали как сделали, 2 или 10 мс не важно, и не будете ничего менять?
 
Автор
P

Prog

Продвинутый
Сообщения
537
Репутация
65
Та тема была создана давно. В те времена действительно функция Point работала медленно, но начиная с версии 4.50, ее значительно ускорили.
 

Yura

Знающий
Сообщения
36
Репутация
7
Prog сказал(а):
Та тема была создана давно. В те времена действительно функция Point работала медленно, но начиная с версии 4.50, ее значительно ускорили.
Отлично, что ее ускорили. Один вопрос тогда. Что лучше:
1) Сделать скриншот, а потом потратить еще несколько мс чтоб через GetDIBits() выдернуть цвета пикселей в строку или массив. Или даже через рисование и Point в циклах, что вангую будет дольше в несколько раз. Потом искать обычным перебором в циклах в этой строке и выигрывать время на каждом поиске.
2) Сделать как есть у вас сейчас: при каждом поиске каждый цвет пикселя перегонять в DIB через Point (эта команда ведь это делает?).


FFNearestPixel() => X = 1330, Y = 517, Time = 1.9394303123768; Snapshot_time: 8.70994497860369
FindPixel() => X = 1330, Y = 517, Time = 10.5035193190783; Snapshot_time: 6.87397916245433

Это то, что есть сейчас: вы делаете скриншот на 2 мс быстрее, чем в FastFind, а потом НА КАЖДОМ поиске теряете время. Почему? А я посмотрел исходники FastFind. Ее автор не против, чтоб кто хочет в ней копался, поэтому выкладываю ссылку https://github.com/FastFrench/FastFind/tree/master/FastFindDLL. Смотрим в SnapShots.cpp. После BitBlt(sdc, 0, ...) идет строка GtSnapShotData[NoSnapShot].SnapShotPixels = getbits(...). Метод getbits прописан в ImageProcessing.cpp и какая неожиданность! через GetDIBits() делает уже сами поняли что. Поиски пикселей прописаны в PixelPcocessing.cpp и аналогом вашей процедуры Search_Pixel есть int WINAPI GenericColorSearch(...), которая используется во всех поисках пикселей. Ищет цвета пикселей из screen_pixel. (LPCOLORREF screen_pixel = GtSnapShotData[NoSnapShot].SnapShotPixels;) То есть из того, что получили в getbits()- строки, в которую подряд записаны цвета, на каждый цвет по 4 байта- 1 байт пустой и по байту на r, g, b.
Теперь о том, почему, как я писал раньше, время поиска в FastFind одинаковое независимо от расположения пикселя на экране. Просто потому, что всегда проверяются все пиксели, автор не сделал выход из циклов поиска пикселей, когда найден первый пиксель искомого цвета. Но он ищет не просто первый пиксель, а пиксель ближайший к заданной точке, поэтому при нахождении пикселя нужного цвета считает расстояние и сравнивает с предыдущим лучшим результатом. X = 1330, Y = 517 в своем примере я выбрал именно поэтому- точка в правом нижнем углу моей области поиска, чтоб оба алгоритма прошлись по всей картинке и можно было адекватно сравнить их быстроту.
Желаю вам заморочиться на этом и ускорить свой поиск в несколько раз. Если решитесь - еще раз посмотрите на ссылку, которую дал в предыдущем ответе.


Теперь о FindPixel_Buff и ей подобным. Когда x=0, y=0, Width=0, Height=0, чтоб автоматично поиск шел по всей картинке в буфере. Как вы в WinSize() сделали для окон.

Функция FindPixel() ИМХО лишняя, делает скриншот и потом ищет - не нужно этого, путает больше, чем пользы. Есть 2 отдельные функции- скриншот и поиск, для этого дела и не надо больше.

Search_Pixel() у вас "If Shade<>0", надо "If Shade>0". Когда Shade<0 сделать Shade=0 или Shade=abs(Shade). И желательно проверку от дурака добавить, чтоб значение Shade было в границах 0-255.

Эта длл будет работать на XP? на x64?
Какая у вас версия PureBasic? У меня 5.0, компилятор ругается на перенос строк, приходится лепить их в 1 строку. И длл получаются чуть меньшего размера, чем у вас.
 

Yura

Знающий
Сообщения
36
Репутация
7
1) Написал обертки ко всем функциям, кроме ImageLoadMem - считаю ненужной при наличии ImageLoadHandle, и FindPixel- тоже считаю ненужной.
Добавил ImageLoadHandle, которую автор не внес в библиотеку версии 1.4.
Поиск по умолчанию теперь тот, что автор назвал с отсечкой по Х, а по факту есть обычный поиск в области. Такое изменение на мой взгляд (и как читал ниже не только на мой) полностью логичное.

2) Написал справку в .chm, где все разжевано и есть пример использования функций. Справка включает внесенные мной изменения.

Справка вложением не влазит, закинул в файловый архив: UDF, справку, демо файл, dll и исходник кода в PureBasic. В dll уже внесены описанные выше мелкие изменения. Называется в файловом архиве "FindPixel (Автор dll - Prog)", думаю Prog будет не в обиде:smile:

У меня не было возможности протестировать справку и тестовый пример на других компьютерах. Если что-то не так там- пишите. Если вместо содержания страниц пишет "Переход на веб-страницу отменен" или "Действие отменено" - зайдите в свойства файла и нажмите "Разблокировать".

Думаю, что теперь эта либа может получить более массовое применение - больше не надо при вызове каждой функции кучу времени тратить на ее написание и разбор параметров. Но, на мой взгляд, там можно еще очень много чего добавить и улучшить. Если автор не будет ее дальше развивать, то не исключаю вероятности, что этим займусь я:smile:

Ссылка на скачивание:
https://autoit-script.ru/index.php?action=downloads;sa=downfile&id=523
 

IgorFIN

Новичок
Сообщения
6
Репутация
1
Ссылка не рабочая, можно еще раз залить
 
Верх