1

Тема: ImageSearh через функцию, не через GoSub. Пишу для POE.

Здравствуйте не подскажите почему этот код всегда выдает False?
Почему-то в виде самопальной функции поиск выдает всегда 0.

+ открыть спойлер
;++++++++++++++++++++++++++++Функции++++++++++++++++++++++++++++++
{
	pic_found(searchAreaX, searchAreaY, searchAreaX2, searchAreaY2, pic_name) ;поиск картинок
	{
		global
		ImageSearch, picX, picY, %searchAreaX%, %searchAreaY%, %searchAreaX2%, %searchAreaY2%, %A_ScriptDir%\%pic_name%.png
		Return, picX picY
	}
}
sc3B:: ;F1
CLEAR_INVENRATY: ;Перекладываем все сферы свитки и точку в с][рон...
pic_found(0, 0, 1920, 1080, Inventary_detected)
;ImageSearch, picX, picY, 0, 0, 1920, 1080, %A_ScriptDir%\Inventary_detected.png
If !ErrorLevel
{
		ToolTip, Инвентарь открыт!
		Sleep, 500
		ToolTip
	}
	else
	{
		ToolTip, Инвентарь закрыт!
		Sleep, 500
		ToolTip
	}
Return

Но вот так всё работает исправно, и поиск находит картинку.
Внимание строка закомментирована.

+ открыть спойлер
;++++++++++++++++++++++++++++Функции++++++++++++++++++++++++++++++
{
	pic_found(searchAreaX, searchAreaY, searchAreaX2, searchAreaY2, pic_name) ;поиск картинок
	{
		global
		ImageSearch, picX, picY, %searchAreaX%, %searchAreaY%, %searchAreaX2%, %searchAreaY2%, %A_ScriptDir%\%pic_name%.png
		Return, picX picY
	}
}
sc3B:: ;F1
CLEAR_INVENRATY: ;Перекладываем все сферы свитки и точку в с][рон...
;pic_found(0, 0, 1920, 1080, Inventary_detected)
ImageSearch, picX, picY, 0, 0, 1920, 1080, %A_ScriptDir%\Inventary_detected.png
If !ErrorLevel
{
		ToolTip, Инвентарь открыт!
		Sleep, 500
		ToolTip
	}
	else
	{
		ToolTip, Инвентарь закрыт!
		Sleep, 500
		ToolTip
	}
Return

Скорее вопрос в том как правильно разместить ErrorLeval что бы он выходил в глобал(?)
Просто первый раз творю тут через функции

2 (изменено: romzes96, 2018-12-25 11:21:31)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Всем спасибо!
Нашел в чём была проблем. pic_name надо было взять в "". А именно Inventary_detected.

То есть так не правильно:
pic_found(0, 0, 1920, 1080, Inventary_detected)
А так правильно:
pic_found(0, 0, A_ScreenWidth, A_ScreenHeight, "Inventary_detected")

3

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Появился другой вопрос.
Есть ли на AHK OpenCV или его аналог?
Хотелось бы производить поиск по изображению, но не по 100% сходству. Это возможно?

4

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

На оф.форуме есть тема FindText(), поиск идет по форме одноцветной(+/-) части изображения.
Вызывать функции библиотек OpenCV из ahk можно с помощью DllCall().

5

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

stealzy Спасибо с этим обязательно ознакомлюсь. Но пока что всё получается с точным сравнение с картинкой.
Не мог ли бы помочь с новым вопросом? А именно:

Я пишу скрипт для POE (Path Of Exile). Хочу написать точнее. Скрипт просто должен перекладывать всю валюту из инвентаря в тайник.
В процессе создания скрипта возникла проблема с моим пониманием ImageSearch.

Сам скрипт:

+ открыть спойлер
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
SetBatchLines, -1
CoordMode, Pixel, Window
#If WinActive("ahk_class POEWindowClass")
;++++++++++++++++++++++++++++Переменные++++++++++++++++++++++++++++
{
	ivent_boxX:= A_ScreenWidth//1.51181102362 ;1270
	ivent_boxY:= A_ScreenHeight//1.84300341297 ;586
	ivent_boxX2:= A_ScreenWidth//1.00840336134 ;1904
	ivent_boxY2:= A_ScreenHeight//1.2676056338 ;852
	Item_list = Item_1,Item_2,Item_3
}
;++++++++++++++++++++++++++++Функции++++++++++++++++++++++++++++++
{
	pic_found(searchAreaX, searchAreaY, searchAreaX2, searchAreaY2, pic_name) ;поиск картинок
	{
		global
		ImageSearch, picX, picY, %searchAreaX%, %searchAreaY%, %searchAreaX2%, %searchAreaY2%, %A_ScriptDir%\%pic_name%.png
		;MsgBox, %searchAreaX% %searchAreaY% %searchAreaX2% %searchAreaY2% %A_ScriptDir%\%pic_name%.png
		Return, picX picY
	}
	move_item()
	{
		Send, {Ctrl Down}
		Send, {LButton}
		Send, {Ctrl Up}
	}
	item_found(searchAreaX, searchAreaY, searchAreaX2, searchAreaY2, pic_name)
	{
		global
		ImageSearch, itemX, itemY, %searchAreaX%, %searchAreaY%, %searchAreaX2%, %searchAreaY2%, %A_ScriptDir%\Item\%pic_name%.png
		Return, itemX itemY
	}
}
;++++++++++++++++++++++++++++Бинды++++++++++++++++++++++++++++++++
*~RButton::
{
	Send, {sc11}
	Send, {sc12}
	Send, {sc2}
	Send, {sc3}
	Send, {sc4}
	Send, {sc5}
	Send, {sc6}
	GetKeyState, state, RButton, P
	if state = D
		KeyWait, RButton, Up
}
Return

*~PrintScreen::
Sleep, 1000
MouseClickDrag, Left, %ivent_boxX%, %ivent_boxY%, %ivent_boxX2%, %ivent_boxY2% , 0 ; Передвижение мыши
Return

F4::
ExitApp
Return


sc3B:: ;F1
CLEAR_INVENRATY: ;Перекладываем все сферы свитки и точку в с][рон...
pic_found(0, 0, A_ScreenWidth, A_ScreenHeight, "Inventary_detected")
If !ErrorLevel
{	
	while(A_Index < 26)
	{
		item_found(ivent_boxX, ivent_boxY, ivent_boxX2, ivent_boxY2, "Image_"A_Index)
		If !ErrorLevel
		{
			MouseMove, %itemX%, %itemY%
			move_item()
		}
		else
		{
			
		}
	}
}
else
{
	ToolTip, Инвентарь закрыт!
	Sleep, 500
	ToolTip
}
Return

Скрипт перекладывает 26 видов валют которые определены маленькими картинками.
Вот так выглядит инвентарь:
http://prntscr.com/lzrkyg
Вот так я взял 'индификатор' каждой валюты, и это рабочий вариант:
http://prntscr.com/lzrn4w

Сделал 26 маленьких картинок которые затем идут в ImageSearch и ищутся ТОЛЬКО в зоне инвентаря.
Но столкнулся с проблемой. ImageSearch/скрипт всё делает правильно только в том случае если валюта в инвентаре лежит в том же порядке как на первом скриншоте. А по идее он должен брать их и в обратном порядке, и не зависимо от места нахождения в инвентаре. Но в порядке валютной иерархии то есть от полезной к бесполезной.

6 (изменено: romzes96, 2018-12-26 22:55:20)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Вот как-то сообразил некий bitmap на костылях. 2x2 пикселя. Лучше всего составить 4x4. Но таким методом это не правильно.
Кто-нибудь может помочь с данной функцией? А то в данном варианте очень много "регрессии" кода. Буду очень признателен за помощь. Будет некий bitmap.

Функция:

+ открыть спойлер
get_bitmap(searchAreaX, searchAreaY, searchAreaX2, searchAreaY2, color1p, color2p, color3p, color4p, variation)
	{
		global
		;MsgBox, %searchAreaX% %searchAreaY% %searchAreaX2% %searchAreaY2% %color1p% %color2p% %color3p% %color4p% %variation%
		PixelSearch, bit1X, bit1Y, %searchAreaX%, %searchAreaY%, %searchAreaX2%, %searchAreaY2%, %color1p%, %variation%, Fast RGB ;Ищем 1 цвет. 
		If !ErrorLevel
		{
			result1 = 1 ;Если нашли ищем цвет правее от первого.
			bit1X++
			PixelSearch, bit2X, bit2Y, %bit1X%, %bit1Y%, %searchAreaX2%, %searchAreaY2%, %color2p%, %variation%, Fast RGB
			If !ErrorLevel
			{
				result2 = 1 ;Если нашли ищем цвет ниже второго.
				bit1Y++
				PixelSearch, bit3X, bit3Y, %bit1X%, %bit1Y%, %searchAreaX2%, %searchAreaY2%, %color3p%, %variation%, Fast RGB
				If !ErrorLevel
				{
					result3 = 1 ;Если нашли ищем цвет ниже второго.
					bit1X--
					PixelSearch, bit4X, bit4Y, %bit1X%, %bit1Y%, %searchAreaX2%, %searchAreaY2%, %color4p%, %variation%, Fast RGB
					If !ErrorLevel
					{
						result4 = 1 ;Если нашли 4 пиксель то финиш.
						Return, bit1X bit1Y
					}
					else
					{
						ToolTip, BitMap Работает не правильно. Не нашел 4 пиксель.
						Sleep, 500
						ToolTip
					}
				}
				else
				{
					ToolTip, BitMap Работает не правильно. Не нашел 3 пиксель.
					Sleep, 500
					ToolTip
				}
			}
			else
			{
				ToolTip, BitMap Работает не правильно. Не нашел 2 пиксель.
				Sleep, 500
				ToolTip
			}
		}
		else
		{
			ToolTip, BitMap Работает не правильно. Не нашел 1 пиксель.
			Sleep, 500
			ToolTip
		}
		If (result1 == result2 == result3 == result4)
		{
			Return, bit1X bit1Y
		}
	}

Есть еще мысля сделать так что бы можно было выбрать мышкой область и если область превышает 4x4 то в центре этой области мы получаем 16 соседних цветов. И пишем их в файл. А то так очень не удобно. 2x2 не удобно в ручную цвета выбирать. А 4x4 вообще невообразимо нудно и долго. Хм или даже проще. Тыкаем в центральный пиксель и от него получаем массив пикселей 4x4. Но массив в AHK для меня тема тяжелая, поэтому просто получаем 4x4 от выбранного/центрального пикселя. За это возьмусь завтра наверно. Сейчас хотел бы как-то привести код в порядок оптимизировать его для того что бы можно было ввести не 4 цвета, а 16. Если кто знает пишите буду рад!

P.s. Конечно можно и так костылить, но будет очень громоздко.

7 (изменено: romzes96, 2018-12-26 23:30:41)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Вот по такому принципу. Хм кажется не плохо.
Как на скриншоте.
Опечатка на скрине

Post's attachments

Screenshot_31.png 31.71 kb, file has never been downloaded. 

You don't have the permssions to download the attachments of this post.

8 (изменено: romzes96, 2018-12-27 09:02:53)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Ну вот еще 1 костыль под вечер... Мда. Стыдно, но потом переделаю.

Функция которая сграбит 16 цветов. Начиная с левого верха.

Код:

+ открыть спойлер
MgetFbitmap()
	{
		global
		MouseGetPos, mX, mY
		mX--
		mY--
		start_point = mX
		PixelGetColor, color1p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color2p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color3p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color4p, %mX%, %mY%, RGB
		mY++
		mX = start_point
		PixelGetColor, color5p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color6p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color7p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color8p, %mX%, %mY%, RGB
		mY++
		mX = start_point
		PixelGetColor, color9p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color10p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color11p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color12p, %mX%, %mY%, RGB
		mY++
		mX = start_point
		PixelGetColor, color13p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color14p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color15p, %mX%, %mY%, RGB
		mX++
		PixelGetColor, color16p, %mX%, %mY%, RGB
		Return, color1p color2p color3p color4p color5p color6p color7p color8p color9p color10p color11p color12p color13p color14p color15p color16p
	}

9 (изменено: stealzy, 2018-12-27 02:59:43)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Нюанс в производительности: встроенная команда PixelSearch будет искать долго и не годится. А дело в том, что под капотом она состоит из двух операций - взятия буфера экрана (что занимает существенное время в десятки мс), и только затем взятия пикселя оттуда (практически мгновенно).
Правильно будет взять буфер только первый один раз а потом доставать из него любые отдельные пиксели. Для этого используются готовые функции.
Тема эта поднималась на форуме множество раз и я многим уже отвечал подробно, уверен при желании вы все найдете.
Ну и FindText() хорош по скорости. Применял оба подхода для одной игры.
Но до создания вариативной ImageSearch я не дошел .
Если почитать справку, то в ImageSearch уже есть параметр вариации, указывается так:
ImageSearch, FoundX, FoundY, 40,40, 300, 300, *14 C:\My Images\test.bmp
14 - число вариативности, от 0 до 255. По умолчанию 0.

10

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

stealzy, Спасибо большое понял как пользоваться FindText(). Это прекрасно!

11

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

romzes96 пишет:

Есть ли на AHK OpenCV или его аналог?

На ahk нету, зато есть на ближайшем аналоге - AutoIt.
Если есть желание можете попробовать перенести и поделиться.
https://www.autoitscript.com/forum/topi … nt-1280955
https://www.autoitscript.com/forum/topi … ch-feature

12 (изменено: Malcev, 2018-12-30 18:26:58)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Вроде перенёс этот пример на автохотки.
https://www.autoitscript.com/forum/topi … nt-1280955

;start dll opencv
h1 := DllCall("LoadLibrary", "Str", "opencv_core2413.dll", "Ptr")
h2 := DllCall("LoadLibrary", "Str", "opencv_highgui2413.dll", "Ptr")
h3 := DllCall("LoadLibrary", "Str", "opencv_imgproc2413.dll", "Ptr")

file1 := "1.jpg"
file2 := "2.jpg"
window := "gui"

;// load IPL type image both images must have same number of bits and color channels!
pimg := DllCall("opencv_highgui2413.dll\cvLoadImage", "AStr", file1, "int", CV_LOAD_IMAGE_COLOR := 1, "Cdecl Int")
ptemp := DllCall("opencv_highgui2413.dll\cvLoadImage", "AStr", file2, "int", CV_LOAD_IMAGE_COLOR := 1, "Cdecl Int")

;// Create some windows to show the input
;// and output images in.
;//
DllCall("opencv_highgui2413.dll\cvNamedWindow", "AStr", window, "int", CV_WINDOW_AUTOSIZE := 0x00000001, "Cdecl Int")

;// show our input image
;//
DllCall("opencv_highgui2413.dll\cvShowImage", "AStr", window, "ptr", pimg, "Cdecl")

;// Determine images height and width to create results matrix
WidthHeight := DllCall("opencv_core2413.dll\cvGetSize", "ptr", pimg, "Cdecl int64")
width := 0xFFFFFFFF & WidthHeight
height := WidthHeight >> 32
WidthHeight := DllCall("opencv_core2413.dll\cvGetSize", "ptr", ptemp, "Cdecl int64")
width2 := 0xFFFFFFFF & WidthHeight
height2 := WidthHeight >> 32
rw :=  width - width2 + 1
rh :=  height - height2 + 1

;// Create Opencv matrix object 32 bit floating
presult := DllCall("opencv_core2413.dll\cvCreateMat", "int", rh, "int", rw, "int", CV_32FC1 := 5, "Cdecl ptr")

;// Template matching
DllCall("opencv_imgproc2413.dll\cvMatchTemplate", "ptr", pimg, "ptr", ptemp, "ptr", presult, "int", CV_TM_CCOEFF_NORMED := 5, "Cdecl")
DllCall("opencv_core2413.dll\cvNormalize", "ptr", presult, "ptr", presult, "Double", 0, "Double", CV_C := 1, "int", CV_MINMAX := 32, "ptr", 0, "Cdecl")
DllCall("opencv_imgproc2413.dll\cvThreshold", "ptr", presult, "ptr", presult, "Double", thresh := 0.9, "Double", maxval := 1, "int", CV_THRESH_BINARY := 0, "Cdecl double")

;//locate matches
;
;// Create minmax variables to pass to opencv
VarSetCapacity(pmaxloc, 8, 0)
VarSetCapacity(pminloc, 8, 0)
VarSetCapacity(pmaxval, 8, 0)
VarSetCapacity(pminval, 8, 0)

;// create mask to find multiple matches
pmask := DllCall("opencv_core2413.dll\cvCreateImage", "int", rw, "int", rh, "int", IPL_DEPTH_8U := 8, "int", channels := 1, "Cdecl ptr")
DllCall("opencv_core2413.dll\cvSet", "ptr", pmask, "double", 1, "double", 1, "double", 1, "double", 1, "ptr", 0, "Cdecl")

;// Find location of maximum
DllCall("opencv_core2413.dll\cvMinMaxLoc", "ptr", presult, "ptr", &pminval, "ptr", &pmaxval, "ptr", &pminloc, "ptr", &pmaxloc, "ptr", pmask, "Cdecl")

loop
{
   ;// Mask it to find others if exists and draw red rectangle on input image
   DllCall("opencv_core2413.dll\cvRectangle", "ptr", pmask, "int", NumGet(pmaxloc, 0, "int")-5, "int", NumGet(pmaxloc, 4, "int")-5, "int", NumGet(pmaxloc, 0, "int")+ width2, "int", NumGet(pmaxloc, 4, "int")+height2, "double", 0, "double", 0, "double", 0, "double", 0, "int", -1, "int", 8, "int", 0, "Cdecl")
   DllCall("opencv_core2413.dll\cvRectangle", "ptr", pimg, "int", NumGet(pmaxloc, 0, "int")-5, "int", NumGet(pmaxloc, 4, "int")-5, "int", NumGet(pmaxloc, 0, "int")+ width2+10, "int", NumGet(pmaxloc, 4, "int")+height2+10, "double", 0, "double", 0, "double", 255, "double", 0, "int", 2, "int", 8, "int", 0, "Cdecl")

   ;// Update input image
   DllCall("opencv_highgui2413.dll\cvShowImage", "AStr", window, "ptr", pimg, "Cdecl")

   ;// Find location of maximum
   DllCall("opencv_core2413.dll\cvMinMaxLoc", "ptr", presult, "ptr", &pminval, "ptr", &pmaxval, "ptr", &pminloc, "ptr", &pmaxloc, "ptr", pmask, "Cdecl")
   if (NumGet(pmaxval, 0, "double") < 0.99)
      break
   sleep 1000
}
msgbox done
DllCall("opencv_core2413.dll\cvReleaseImage", "ptr*", pmask, "Cdecl")
DllCall("opencv_core2413.dll\cvReleaseMat", "ptr*", presult, "Cdecl")
DllCall("opencv_core2413.dll\cvReleaseImage", "ptr*", ptemp, "Cdecl")
DllCall("opencv_core2413.dll\cvReleaseImage", "ptr*", pimg, "Cdecl")
DllCall("opencv_highgui2413.dll\cvDestroyAllWindows", "Cdecl")

13 (изменено: pixel75, 2021-01-11 15:54:31)

Re: ImageSearh через функцию, не через GoSub. Пишу для POE.

Malcev   Прошу пардона, не почтите за примитивную лесть и попытку манипуляции, примите моё глубочайшее уважение и искренние восхищения недостижимостью Вашего интеллекта! Меня интересует вопрос того, как, основываясь на приведенном примере,  вычленить найденные координаты Уолли на вокзале и кликнуть на его местоположение? Признаюсь, реализация принципов нейронной сети на языке АНК - это достойно необычайного уважения. Ах, если бы кто то более умный и тщеславный научил бы тому, как из вышеизложенного организовать функцию, в которую передавались бы имена базового и искомого файлов изображений, область координат поиска и процент совпадения, исходя из которого, функция выдавала бы правду или ложь.