Что нового

Перевод функции поиска всех координат одного цвета в DLL

iamOmg

Новичок
Сообщения
97
Репутация
2
Версия AutoIt: v3.3.14.0

Описание:
На форуме есть отличный скрипт для поиска всех координат нужного цвета, работает безотказно но вот со скоростью проблемы. На ноутбуке с двухъядерным core i5 прямоугольник с разрешением 1500x500 прогоняет за 2 секунды, если искать цвет с оттенком то время работы будет уже 4 секунды и выше. Это слишком много, учитывая что у многих до сих пор ещё dual core`ы стоят.

Единственным выходом в такой ситуации, как подсказали люди на форуме, может быть только перевод функции в dll или машинный код. Прошу помощи у знающих пользователей форума.

Примечания:
Скрипт поиска
Код:
#include <WinAPIGdi.au3>

$iT = TimerInit()
$aPixels = _PixelGetArray(100, 100, 10, 10, 0x000000, 10)
ConsoleWrite(TimerDiff($iT) & @LF)

#include <Array.au3>
_ArrayDisplay($aPixels)

Func _PixelGetArray($i_X, $i_Y, $i_Width, $i_Height, $i_Color, $i_Shade = 0, $h_Wnd = 0, $f_FirstOnly = False)
  Local $i_Size = $i_Width * $i_Height, $a_Pixels[$i_Size + 1][2] = [[0]], $h_DC, $h_MemDC, $h_Bitmap, $t_Bits, $i_Index
  $h_DC = _WinAPI_GetDC($h_Wnd)
  $h_MemDC = _WinAPI_CreateCompatibleDC($h_DC)
  $h_Bitmap = _WinAPI_CreateCompatibleBitmap($h_DC, $i_Width, $i_Height)
  _WinAPI_SelectObject($h_MemDC, $h_Bitmap)
  _WinAPI_BitBlt($h_MemDC, 0, 0, $i_Width, $i_Height, $h_DC, $i_X, $i_Y, 0x00CC0020) ; $SRCCOPY
  _WinAPI_DeleteDC($h_MemDC)
  _WinAPI_ReleaseDC($h_Wnd, $h_DC)
  $t_Bits = DllStructCreate('dword[' & $i_Size & ']')
  _WinAPI_GetBitmapBits($h_Bitmap, 4 * $i_Size, DllStructGetPtr($t_Bits))
  _WinAPI_DeleteObject($h_Bitmap)
  If $i_Shade Then
    Local $a_RGB[3] = [BitAND(BitShift($i_Color, 16), 0xFF), BitAND(BitShift($i_Color, 8), 0xFF), BitAND($i_Color, 0xFF)]
    For $i = 0 To $i_Height - 1
      For $j = 0 To $i_Width - 1
        $i_Index += 1
        Local $i_Clr = BitAND(DllStructGetData($t_Bits, 1, $i_Index), 0x00FFFFFF)
        Switch BitAND(BitShift($i_Clr, 16), 0xFF)
          Case $a_RGB[0] - $i_Shade To $a_RGB[0] + $i_Shade
            Switch BitAND(BitShift($i_Clr, 8), 0xFF)
              Case $a_RGB[1] - $i_Shade To $a_RGB[1] + $i_Shade
                Switch BitAND($i_Clr, 0xFF)
                  Case $a_RGB[2] - $i_Shade To $a_RGB[2] + $i_Shade
                    $a_Pixels[0][0] += 1
                    $a_Pixels[$a_Pixels[0][0]][0] = $j + $i_X
                    $a_Pixels[$a_Pixels[0][0]][1] = $i + $i_Y
                    If $f_FirstOnly Then ExitLoop 2
                EndSwitch
            EndSwitch
        EndSwitch
      Next
    Next
  Else
    For $i = 0 To $i_Height - 1
      For $j = 0 To $i_Width - 1
        $i_Index += 1
        If BitAND(DllStructGetData($t_Bits, 1, $i_Index), 0x00FFFFFF) = $i_Color Then
          $a_Pixels[0][0] += 1
          $a_Pixels[$a_Pixels[0][0]][0] = $j + $i_X
          $a_Pixels[$a_Pixels[0][0]][1] = $i + $i_Y
          If $f_FirstOnly Then ExitLoop 2
        EndIf
      Next
    Next
  EndIf
  ReDim $a_Pixels[$a_Pixels[0][0] + 1][2]
  Return $a_Pixels
EndFunc   ;==>_PixelGetArray
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
iamOmg
Вот dll, правда, особо не проверял

Делает скриншот окна целиком
Из dll получает 2 структуры с x и y координатами, потом сводит их в массив
(разбираться со структурами в autoit не хочется)


Можно и многопоточность добавить, будет быстрее
 

Вложения

  • GetColor2.zip
    55.2 КБ · Просмотры: 27
Автор
iamOmg

iamOmg

Новичок
Сообщения
97
Репутация
2
Вау, работает очень быстро, мгновенно практически, только походу есть какой-то сдвиг в восприятии цветов. Находит совсем не то, оригинальный цвет для поиска не находит совсем. Для теста с помощью AWinfo цвет получал, использовал в скрипте, но скрипт не находил вообще ничего.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
iamOmg

Попробуй поменять
Код:
$ret = DllCall($dll, 'int:cdecl', 'PixelGetArray_DLL', 'hwnd', $hwnd, 'int', Dec($color), 'int', $shade, 'ptr', $pDataX, 'ptr', $pDataY)

на
Код:
$ret = DllCall($dll, 'int:cdecl', 'PixelGetArray_DLL', 'hwnd', $hwnd, 'int', $color, 'int', $shade, 'ptr', $pDataX, 'ptr', $pDataY)
 
Автор
iamOmg

iamOmg

Новичок
Сообщения
97
Репутация
2
Заработало, правда координаты почему-то смещаются на пикселей 5-10 направо вниз.
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
iamOmg [?]
Заработало, правда координаты почему-то смещаются на пикселей 5-10 направо вниз.
Какя система? Если Win 7, может это от аэро
Если делаю скрин этого окна, а потом в paint смотрю - координаты пикселей совпадают
 
Автор
iamOmg

iamOmg

Новичок
Сообщения
97
Репутация
2
windows 8.1, даже масштабирование отключено



Добавлено:
Сообщение автоматически объединено:

Не сразу смекнул что координаты относительно окна выдаются, так что всё работает. Большое спасибо вам :thumbs_up:
Код:
Opt("MouseCoordMode", 0)
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
iamOmg
перевод функции в dll
FindPixel - поиск пикселей Версия 1.3 из ответа #10

Код:
$t = TimerInit()
$arr = _PixelSearchArray(100, 100, 1000, 1000, 0x101010, 10)
ConsoleWrite(TimerDiff($t) & @CRLF)

#include <Array.au3>
_ArrayDisplay($arr)

Func _PixelSearchArray($iX, $iY, $iWidth, $iHeight, $iColor, $iShade = 0, $iStep = 1, $hWnd = 0)
  Local $aRes, $tPix, $iCoord, $hDll = DllOpen("FindPixel.dll")
  If $hDll = -1 Then Return SetError(1, 0, 0)
  If Not $hWnd Then
    DllCall($hDll, "int", "ScreenToBuff", "int", 0, "int", 0, "int", @DesktopWidth, "int", @DesktopHeight, "int", 0)
  Else
    Local $aPos = WinGetPos($hWnd)
    If Not IsArray($aPos) Then Return SetError(2, 0, 0)
    DllCall($hDll, "int", "ScreenToBuff", "int", 0, "int", 0, "int", $aPos[2], "int", $aPos[3], "int", $hWnd)
  EndIf
  If @error Then Return SetError(3, 0, 0)
  DllCall($hDll, "int", "SetSearchMode", "int", 1)
  If @error Then Return SetError(4, 0, 0)
  $iColor = BitOR(BitAND($iColor, 0x00FF00), BitShift(BitAND($iColor, 0x0000FF), -16), BitShift(BitAND($iColor, 0xFF0000), 16))
  $aRes = DllCall($hDll, "int", "FindPixel_Buff_ToArr", "int", $iX, "int", $iY, "int", $iWidth, "int", $iHeight, "int", $iColor, "int", $iShade, "int", $iStep)
  If @error Or $aRes[0] = -1 Then Return SetError(5, 0, 0)
  If $aRes[0] = -2 Then
    Local $aPixels[1][2] = [[0]]
    Return $aPixels
  Else
    Local $aPixels[$aRes[0] + 1][2] = [[$aRes[0]]]
    $tPix = DllStructCreate("dword[" & $aRes[0] & "]")
    DllCall($hDll, "int", "GetPixelArr", "ptr", DllStructGetPtr($tPix), "int", $aRes[0])
    If @error Then Return SetError(6, 0, 0)
    For $i = 1 To $aRes[0]
      $iCoord = DllStructGetData($tPix, 1, $i)
      $aPixels[$i][0] = BitAND($iCoord, 0xFFFF)
      $aPixels[$i][1] = BitAND(BitShift($iCoord, 16), 0xFFFF)
    Next
  EndIf
  DllClose($hDll)
  Return $aPixels
EndFunc
 
Автор
iamOmg

iamOmg

Новичок
Сообщения
97
Репутация
2
Благодарю, этот вариант работает так же идеально. Dll рулит, что сказать, скорость работы скрипта 60 миллисекунд. Интересно, а можно таким же макаром поиск картинки сделать, как в ImageSearch - http://autoit-script.ru/index.php?topic=175.0 ? Это вообще бы бомба была :blum:ilot:
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
363
iamOmg
Можно
В этой теме http://autoit-script.ru/index.php?topic=20405.0
я уже обещал, если будет время
 

_serfer_78_

Новичок
Сообщения
16
Репутация
0
WSWR сказал(а):
iamOmg
Вот dll, правда, особо не проверял

Делает скриншот окна целиком
Из dll получает 2 структуры с x и y координатами, потом сводит их в массив
(разбираться со структурами в autoit не хочется)


Можно и многопоточность добавить, будет быстрее

А как же из нее получить X,Y если координаты она отдает в одной ячейке массива просто разделенные пробелом?
Мне пока видится что то типо StringSplit -ом в архив выдергивать...
Поскажите кто в курсе как это пограмотнее организовать?
В целом библиотека понравилась, удобная..
 

NickSpirit

Знающий
Сообщения
44
Репутация
5
По поводу ImageSearch - вот было бы действительно шикарно сделать сию функцию в DLL...

Другой вопрос - где тут можно скачать BmpSearch.au3?
 

_serfer_78_

Новичок
Сообщения
16
Репутация
0
Alofa сказал(а):
_serfer_78_ сказал(а):
... В целом библиотека понравилась, удобная..
_serfer_78_, в этой теме InnI аж почти 2 года назад дал ссылку. Почитайте последний пост той темы - вам еще больше понравится.

СПС улыбнуло)) Я уже не плохого бота на FindPixel намутил, и FastFind уже давно юзаю естественно FindPixel на мой взгляд более функционален и скорость приличная, но хотелось бы по подробнее узнать именно о GetColor2 , что за зверь такой и с чем его едят :smile:
 
Верх