Автор Тема: FindPixel - поиск пикселей  (Прочитано 13920 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
FindPixel - поиск пикселей
« Создано: Апрель 19, 2015, 15:34:47 »
Небольшая библиотека для быстрого поиска пикселей. Описание функций в архиве.
Пример.
Код: AutoIt [Выделить]
#include <WinAPIGdi.au3>

$dll=DllOpen("FindPixel.dll")
$t=TimerInit()

; FindPixel(x, y, Width, Height, Color, Shade, Steps, hWnd)
$Ret=DllCall($dll, "int", "FindPixel", "int",  0, "int",  0, "int",  1000, "int",  700, "int", _WinAPI_RGB(255, 0, 0), "int", 0, "int", 1, "int", 0)

ConsoleWrite("time "&TimerDiff($t)&" ms" & @CRLF)
$Ret=$Ret[0]
if $Ret>=0 then
   ConsoleWrite("Pixel found: X=" & BitAND($Ret, 0xFFFF) & "    Y="& BitAND(BitShift($Ret, 16), 0xFFFF) & @CRLF)
Else
  if $Ret=-1 Then
     ConsoleWrite("Error!" & @CRLF)
  elseif $Ret=-2 Then
     ConsoleWrite("Pixel not found" & @CRLF)
  endif
endif
DllClose($dll)

Правда функция _WinAPI_RGB работает не так как ожидается. Она кодирует не в формате RGB, а формате BGR. Учитывайте это.


Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Русское сообщество AutoIt

FindPixel - поиск пикселей
« Отправлен: Апрель 19, 2015, 15:34:47 »

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 3156
  • Репутация: 832
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #1, Отправлен: Апрель 19, 2015, 17:00:32 »
Первый же тест быстродействия не обнаружил различий в скорости 1858.17576760174
1848.00372551522
(нажмите для показа/скрытия)
Чем вы мотивируете пользователей к использованию вашей dll?

Не понял, как работать с буфером? Вероятно, в функцию нужно передать указатель на буфер с картинкой? Примерчик бы...

А почему нет функции получения цвета пикселя сразу с экрана, без работы с буфером?

И самое главное. Нужна функция, аналогичная FindPixel(), но возвращающая двумерный массив координат найденных цветов. Если эта функция по скорости будет сопоставима с PixelSearch() - вот это будет мотивация.

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #2, Отправлен: Апрель 19, 2015, 17:14:57 »
InnI  [?]
Цитировать
Не понял, как работать с буфером? Вероятно, в функцию нужно передать указатель на буфер с картинкой? Примерчик бы...
Буфер это просто картинка, сохраненная в памяти. Поместить картинку в буфер можно одной из следующих функций:FindPixel()
ScreenToBuff()
ImageLoadMem()
ImageLoad()
Поскольку картинка уже загружена, то поиск по ней будет проходить намного быстрее, ведь отсутствует необходимость ее постоянно подгружать. И если на картинке нужно найти несколько пикселей, скорость окажется выше чем у AutoIt-функции PixelSearch.


Цитировать
Нужна функция, аналогичная FindPixel(), но возвращающая двумерный массив координат найденных цветов.
Это возможно, но функция вернет не массив в формате AutoIt, а указатель на начало двумерного массива.

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 3156
  • Репутация: 832
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #3, Отправлен: Апрель 19, 2015, 17:56:05 »
Prog
С буфером разобрался. Получается, у вас один буфер на всю dll, а-ля буфер обмена Windows - текущие данные затирают предыдущие.

Цитировать
функция вернет не массив в формате AutoIt
В чём проблема? Создайте простенькую UDF, работающую с вашей dll. Иначе круг её пользователей будет сильно ограничен.

Русское сообщество AutoIt

Re: FindPixel - поиск пикселей
« Ответ #3 Отправлен: Апрель 19, 2015, 17:56:05 »

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #4, Отправлен: Апрель 19, 2015, 18:13:29 »
InnI  [?]
Цитировать
Получается, у вас один буфер на всю dll, а-ля буфер обмена Windows - текущие данные затирают предыдущие.
Да. Для моих задач этого было достаточно.

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 3156
  • Репутация: 832
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #5, Отправлен: Апрель 19, 2015, 18:51:40 »
dll работает с перекрытыми и "задвинутыми" окнами. Это плюс.

Color - Задает цвет для поиска, должен быть в формате RGB.А мои опыты показывают, что формат должен быть BGR. Непривычно.

И ещё. В описаниях функций, где присутствует hWnd, указано, что координаты относительно окна. На самом деле - относительно рабочей области окна (без заголовка и меню).

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #6, Отправлен: Июль 26, 2015, 23:53:38 »
InnI  [?]
Цитировать
Нужна функция, аналогичная FindPixel(), но возвращающая двумерный массив координат найденных цветов.
Добавил функции FindPixel_Buff_ToArr() и GetPixelArr().
Пример поиска в файле.
Код: AutoIt [Выделить]
#include <WinAPIGdi.au3>

$dll=DllOpen("FindPixel.dll")
$t=TimerInit()

; ImageLoad(FileName)
$Ret=DllCall($dll, "int", "ImageLoad", "str",  "Image.bmp")

if $Ret[0]=0 Then
  ConsoleWrite("Image not found" & @CRLF)
else
  ; FindPixel_Buff_ToArr(x, y, Width, Height, Color, Shade, Steps)
  $Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int",  0, "int",  0, "int",  90, "int",  90, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

  ConsoleWrite("time "&TimerDiff($t)&" ms" & @CRLF)
  $Count=$Ret[0]
  ConsoleWrite("Count pixel "&$Count & @CRLF)
  if $Count>0 then

     $Arr = DllStructCreate("dword[" & $Count & "]")

     ; GetPixelArr(*Buff, Count)
     $Ret=DllCall($dll, "int", "GetPixelArr", "ptr",  DllStructGetPtr($Arr), "Int", $Count)
     For $i=1 to $Ret[0]
       $Pos = DllStructGetData($Arr, 1, $i)
       ConsoleWrite("Pixel found: X=" & BitAND($Pos, 0xFFFF) & "    Y="& BitAND(BitShift($Pos, 16), 0xFFFF) & @CRLF)
     Next

  endif
endif
DllClose($dll)



Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 3156
  • Репутация: 832
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #7, Отправлен: Июль 27, 2015, 02:12:08 »
Prog
Цитировать
Пример поиска в файле
Изменил на
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int",  20, "int",  60, "int",  40, "int",  40, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

Результат: -1. Тогда сделал так
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int",  20, "int",  60, "int",  80, "int",  100, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

Результат: 2.
Получается, что параметры не "Width, Height", а "Right, Bottom".

Следующий поиск для вашего примера
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int",  15, "int",  10, "int",  45, "int",  90, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

находит пиксель в координатах 10:18, хотя данная координата не входит в область поиска.

Русское сообщество AutoIt

Re: FindPixel - поиск пикселей
« Ответ #7 Отправлен: Июль 27, 2015, 02:12:08 »

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #8, Отправлен: Июль 27, 2015, 20:28:13 »
InnI  [?]
Цитировать
Получается, что параметры не "Width, Height", а "Right, Bottom".
Изначально задумывалось именно как Width и Height, но по факту действительно работает как Right и Bottom. Исправил.


Цитировать
находит пиксель в координатах 10:18, хотя данная координата не входит в область поиска.
Входит, т. к. ищет слева на право и сверху вниз. При переходе на новую строку, начинает искать с нулевой позиции X.
Это было сделано для того чтобы была возможность найти все пиксели требуемого цвета.
Код: AutoIt [Выделить]
#include <WinAPIGdi.au3>

Const $FP_SM_Def = 0  ; Метод поиска по умолчанию - построчно слева на право и сверху вниз.
Const $FP_SM_Clip = 1 ; Метод поиска с отсечением пикселей по координате X.

$dll=DllOpen("FindPixel.dll")

; ImageLoad(FileName)
$Ret=DllCall($dll, "int", "ImageLoad", "str",  "Image.bmp")

if $Ret[0]=0 Then
  ConsoleWrite("Image not found" & @CRLF)
else

  ; SetSearchMode(Mode)
  DllCall($dll, "int", "SetSearchMode", "int", $FP_SM_Def)

 $Ret = 0

 Do
   ; FindPixel_Buff(x, y, Width, Height, Color, Shade, Steps)
   $Ret=DllCall($dll, "int", "FindPixel_Buff", "int",  BitAND($Ret, 0xFFFF), "int",   BitAND(BitShift($Ret, 16), 0xFFFF), "int",  100, "int",  100, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

   $Ret=$Ret[0]

   if $Ret>0 then
    ConsoleWrite("Pixel found: X=" & BitAND($Ret, 0xFFFF) & "    Y="& BitAND(BitShift($Ret, 16), 0xFFFF) & @CRLF)
    $Ret+=1
   endif

  until $Ret<0

endif
DllClose($dll)


Но можно с помощью функции SetSearchMode изменить логику поиска.
Код: AutoIt [Выделить]
#include <WinAPIGdi.au3>

Const $FP_SM_Def = 0  ; Метод поиска по умолчанию - построчно слева на право и сверху вниз.
Const $FP_SM_Clip = 1 ; Метод поиска с отсечением пикселей по координате X.

$dll=DllOpen("FindPixel.dll")
$t=TimerInit()

; ImageLoad(FileName)
$Ret=DllCall($dll, "int", "ImageLoad", "str",  "Image.bmp")

if $Ret[0]=0 Then
  ConsoleWrite("Image not found" & @CRLF)
else

; SetSearchMode(Mode)
DllCall($dll, "int", "SetSearchMode", "int", $FP_SM_Clip)

; FindPixel_Buff_ToArr(x, y, Width, Height, Color, Shade, Steps)
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int",  15, "int",  10, "int",  45, "int",  90, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)

  ConsoleWrite("time "&TimerDiff($t)&" ms" & @CRLF)
  $Count=$Ret[0]
  ConsoleWrite("Count pixel "&$Count & @CRLF)
  if $Count>0 then

     $Arr = DllStructCreate("dword[" & $Count & "]")

     ; GetPixelArr(*Buff, Count)
     $Ret=DllCall($dll, "int", "GetPixelArr", "ptr",  DllStructGetPtr($Arr), "Int", $Count)
     For $i=1 to $Ret[0]
       $Pos = DllStructGetData($Arr, 1, $i)
       ConsoleWrite("Pixel found: X=" & BitAND($Pos, 0xFFFF) & "    Y="& BitAND(BitShift($Pos, 16), 0xFFFF) & @CRLF)
     Next

  endif
endif
DllClose($dll)



Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Оффлайн InnI [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 3156
  • Репутация: 832
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #9, Отправлен: Июль 28, 2015, 00:31:00 »
Prog
Цитировать
При переходе на новую строку, начинает искать с нулевой позиции X.
Логика, мягко говоря, странная. Сначала задаём область поиска, затем эту область игнорируем. Лучше бы вы сделали поиск "с отсечением" по умолчанию.

Следующий вызов приводит к аварийному завершению работы AutoIt
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int", 0, "int", 0, "int", 0, "int", 0, "int", _WinAPI_RGB(0, 0, 255), "int", 0, "int", 1)


Теперь ищем серый цвет в вашем примере
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int", 0, "int", 0, "int", 1, "int", 1, "int", _WinAPI_RGB(200, 200, 200), "int", 0, "int", 1)

и находим два пикселя, вместо одного. При поиске
Код: AutoIt [Выделить]
$Ret=DllCall($dll, "int", "FindPixel_Buff_ToArr", "int", 0, "int", 0, "int", 2, "int", 2, "int", _WinAPI_RGB(200, 200, 200), "int", 0, "int", 1)

находим семь пикселей вместо четырёх. При поиске 3х3 будет найдено 13 пикселей. Поиск в области 1х0 находит два пикселя, а поиск в области 0х1 крашит AutoIt.

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #10, Отправлен: Июль 28, 2015, 12:42:40 »
InnI  [?]
Цитировать
Логика, мягко говоря, странная.
Такой метод позволяет найти все пиксели требуемого цвета без использования FindPixel_Buff_ToArr. Пример выше.

Все остальные ошибки исправил.


Внимание: Для просмотра прикреплённых файлов необходимо Войти или Зарегистрироваться

Оффлайн iamOmg [?]

  • Новичок
  • *
  • Сообщений: 97
  • Репутация: 2
    • Награды
Re: FindPixel - поиск пикселей
« Ответ #11, Отправлен: Август 10, 2015, 19:34:00 »
Библиотека отличная, было бы классно если бы ещё поиск по картинке добавить.
"Чтобы сделать яблочный пирог с нуля, вам придется для начала создать вселенную"

Оффлайн Prog [?]

  • Новичок
  • *
  • Сообщений: 214

  • Автор темы
  • Репутация: 15
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Re: FindPixel - поиск пикселей
« Ответ #12, Отправлен: Август 10, 2015, 20:43:21 »
Есть библиотека BmpSearch, чем она не подошла? Скоростью работы или функционалом?
Практика показывает что вариантов поиска может быть много (например поиск с процентным совпадением, или отклонением цветов, многопоточный поиск и т. д.) и реализация их всех потребует много времени. Проще сделать библиотеку с требуемым функционалом по индивидуальному заказу.
« Последнее редактирование: Август 10, 2015, 20:49:58 от Prog »

Оффлайн Yura [?]

  • Новичок
  • *
  • Сообщений: 36
  • Репутация: 7
    • Награды
  • Версия AutoIt: 3.3.14.0
Re: FindPixel - поиск пикселей
« Ответ #13, Отправлен: Декабрь 06, 2015, 21:39:00 »
Есть у меня Bitmap в памяти, который я получил через загрузку картинки средствами WinAPI или после скриншота или еще как-то, надо загрузить в буфер через ImageLoadMem(Mem, Size). Описание: Функция загружает в буфер BMP картинку из памяти. Если выполнено успешно, вернет не 0. Может я туплю, но мне такое описание мало о чем говорит. Нужно описание каждого параметра- что это такое, и если нет обертки в виде функции вызова dll, то надо тип параметров еще. Я вот час убил гадая подбирая и все равно толку 0.
Например, я получил $hBitmap из картинки через _WinAPI_LoadImage. Mem- это может быть $hBitmap? Что за Size? Тот, что через _WinAPI_GetBitmapDimension получается или ширина картинки умноженная на высоту или размер памяти, которую она занимает? :stars:
 Вот набросок функции-обертки, подправьте параметры, пожалуйста.
Код: AutoIt [Выделить]
$hBMP = _WinAPI_LoadImage(0, 'image.bmp', $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE); загрузка image.bmp (в папке скрипта)
;Как теперь положить в буфер $hBMP?
$tSIZE = _WinAPI_GetBitmapDimension($hBMP)
$hBMP_Size = DllStructGetData($tSIZE, 'X') * DllStructGetData($tSIZE, 'Y'); длинна*высоту BMP

$Ret = _ImageLoadFromMemory($hBMP, $hBMP_Size)
If @error Then
    ConsoleWrite("An error occurred."&@CR)
Else
    ConsoleWrite($Ret&@CR)
EndIf

;-------------------------------------------------------------
Func _ImageLoadFromMemory($hBMP, $Size) ;обертка для вызова длл
    $Result = DllCall('FindPixel.dll', 'int', 'ImageLoadMem', 'handle', $hBMP, 'int', $Size)
    If @error Then Return SetError(1)

    Return $Result[0]
EndFunc

« Последнее редактирование: Декабрь 06, 2015, 23:05:47 от Yura »

Оффлайн Yashied [?]

  • AutoIt MVP
  • Глобальный модератор
  • *
  • Сообщений: 5349
  • Репутация: 2687
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.x.x
Re: FindPixel - поиск пикселей
« Ответ #14, Отправлен: Декабрь 06, 2015, 22:40:49 »
Mem - это адрес на буфер с данными битмапа (пикселами), а не хэндл на битмап.

Код: AutoIt [Выделить]
$hDIB = _WinAPI_CopyBitmap($hBitmap)
$tDIB = DllStructCreate($tagDIBSECTION)
_WinAPI_GetObject($hDIB, DllStructGetSize($tDIB), DllStructGetPtr($tDIB))
_WinAPI_DeleteObject($hDIB)
; $tDIB.bmBits - это то, что нужно


_WinAPI_CopyBitmap() необходима, если указанный битмап DDB, иначе $tDIB.bmBits будет содержать 0.

Size - размер буфера в байтах. Подозреваю, что данная DLL работает только с 32-битными битмапами, поэтому

Код: AutoIt [Выделить]
$Size = $tDIB.bmWidth * $tDIB.bmHeight * 4



Думай, прежде чем говорить.

Русское сообщество AutoIt

Re: FindPixel - поиск пикселей
« Ответ #14 Отправлен: Декабрь 06, 2015, 22:40:49 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
12 Ответов
6315 Просмотров
Последний ответ Январь 04, 2012, 13:40:17
от Guezt Gutsy
5 Ответов
2951 Просмотров
Последний ответ Апрель 29, 2011, 08:55:23
от zoxer1
0 Ответов
1566 Просмотров
Последний ответ Август 18, 2011, 05:32:12
от running-frag
2 Ответов
2184 Просмотров
Последний ответ Ноябрь 25, 2011, 15:20:51
от running-frag
0 Ответов
1623 Просмотров
Последний ответ Апрель 22, 2012, 15:28:50
от madmasles
31 Ответов
9629 Просмотров
Последний ответ Октябрь 15, 2013, 14:08:50
от madmasles
7 Ответов
1462 Просмотров
Последний ответ Июнь 09, 2014, 00:57:19
от gloss
16 Ответов
2792 Просмотров
Последний ответ Октябрь 21, 2014, 11:31:48
от CrazyKing
5 Ответов
964 Просмотров
Последний ответ Февраль 08, 2015, 19:04:44
от Ksaan
2 Ответов
944 Просмотров
Последний ответ Март 30, 2015, 19:49:44
от S_K