Busca de imagens

Artigos, manuais, conselhos e dicas sobre programação em AutoHotkey

Moderator: Gio

User avatar
Gio
Posts: 1057
Joined: 30 Sep 2013, 10:54
Location: Brazil

Busca de imagens

30 Nov 2019, 11:31

Bom dia :)

Vi que vários usuários têm interesse neste tema, e decidi fazer este tutorial explicando em pormenores como fazer.

O AutoHotkey possui algumas funcionalidades para efetuar busca de imagens, como os comandos ImageSearch e PixelSearch. Essa ferramentas podem ser bastante úteis no campo da automação, pois alguns controles, programas e até mesmo jogos não oferecem suporte para automação via códigos. Por este motivo, se desejarmos implementar automação nestes casos, seremos forçados a usar a própria interface visual que o usuário opera para simular uma operação automatizada no programa.


Vamos aprender a fazer? :thumbup:


Índice de conteúdos deste tutorial:
1. O que é busca de imagens
2. ImageSearch, um comando mais prático
3. PixelSearch, um comando mais poderoso
3.1 As cores em uma imagem
3.2 Sistemas binário e hexadecimal de números
3.3 Sistemas hexadecimal de cores
3.4 Esquema RGB de cores
3.5 Esquema BGR de cores
3.6. O Comando PixelSearch
3.7. Conclusão


1. O que é busca de imagens


Imagine que você quer automatizar um programa. Para o correto funcionamento do programa, o usuário precisa apertar um botão. Quando ele clica no botão, o programa faz algo útil e essa operação que você quer automatizar.

Mas após tentar efetuar o clique no botão através dos comandos control (controlclick, controlfocus, controlsend, etc), você percebe que o eles não vão funcionar porque o botão em questão não foi implementado da forma usual das DLLs do Windows: ele é apenas uma imagem na tela e o programa apenas usa um clique naquelas coordenadas para acionar a rotina.

Para piorar, imagine que o botão nem sempre está no mesmo lugar, pois o script deverá funcionar em todo e qualquer computador, e a tela pode estar maximizada, minimizada, puxada para o lado, em outro monitor, etc, etc, etc... Assim não adianta tentar escrever as coordenadas direto no script (ou seja, sem hardcode).

Então como você faria para encontrar as coordenadas certas e clicar nesse "botão"?

Uma maneira relativamente simples de fazê-lo é atraves dos comandos de busca de imagens (ImageSearch e PixelSearch).

Vamos aprender a utilizá-los? :thumbup:



2. ImageSearch, um comando mais prático

O comando ImageSearch é um comandos relativamente simples que faz o seguinte: através de um arquivo de imagem que você possua no seu computador, ele vai buscar a mesma imagem na tela do computador, e se encontrar, vai avisar através da variável embutida ErrorLevel, além de colocar as coordenadas onde a imagem foi localizada em duas variáveis: uma com a posição horizontal em pixels da esquerda para a direita da tela (Coordenada X) e a outra com a posição vertical em pixels da parte de cima para baixo da tela (Coordenada Y). Essas são as mesmas coordenadas que outros comandos (como o MouseClick e o MouseMove) utilizam.

Com essas informações podemos então definir duas coisas: SE a imagem foi localizada na tela, e ONDE ela está na tela. Naturalmente, isto é tudo que precisamos para efetuar uma ação tal como clicar naquela imagem através do comando MouseClick, por exemplo.

Então o que vamos fazer para implementar essa rotina? É bem simples, e vamos fazer passo a passo!

:arrow: Imagine que queira clicar no botão "Fórum" localizado na página inicial do AutoHotkey (https://www.autohotkey.com/).

1. Primeiro, nós vamos tirar um print da tela da página do AutoHotkey

forum.png
forum.png (449.01 KiB) Viewed 5351 times

2. Depois, nós vamos abrir a imagem do print no paint, e recortar a imagem do botão. Dai, é só colar essa imagem sozinha em uma nova tela do paint (diminua bastante o tamanho da imagem de fundo antes de colar para que a imagem final não fique com bordas brancas).

botao isolado.png
botao isolado.png (28.95 KiB) Viewed 5351 times

3. Depois, salvamos a imagem isolada do botao em um arquivo chamado "botao_a_apertar.png" dentro da pasta do nosso script.

imagem na pasta.png
imagem na pasta.png (42.53 KiB) Viewed 5351 times

4. Por fim, rodamos o código abaixo, abrimos novamente a página do AutoHotkey e apertamos o F2 para ativar a rotina.

Code: Select all

F2::
CoordMode, Pixel, Screen ; Primeiro configuramos as coordenadas XY para serem relativas à tela inteira (e não somente à janela ativa).
ImageSearch, PosX, PosY, 0, 0, %A_ScreenWidth%, %A_ScreenHeight%, %A_ScriptDir%/botao_a_apertar.png ; Depois efetuamos o comando.
If (ErrorLevel = 0) ; Se depois de rodar o comando não houverem erros, então a imagem foi corretamente localizada !
{
	X_Um_Pouco_Mais_A_Esquerda := PosX + 20 ; Como o comando retorna a posição superior-esquerda da imagem, vamos clicar um pouco mais à esquerda (pois alguns botões tem bordas que não são clicáveis)
	Y_Um_Pouco_Mais_Abaixo := PosY + 20 ; Como o comanod retorna a posição superior-esquerda da imagem, vamos clicar um pouco mais abaixo (novamente: isto é para evitar bordas!)
	MouseMove, %X_Um_Pouco_Mais_A_Esquerda%, %Y_Um_Pouco_Mais_Abaixo% ; Movemos o mouse para a posição calculada.
}
else ; Mas se deupos de rodar o comando houverem erros...
{
	msgbox, 0x10, Erro, Não foi possível localizar a imagem ! ; informamos ao usuário
}
Return
Se tudo der certo, o script vai mover o mouse para o botão "fórum" sempre que apertarmos F2 na página do AutoHotkey. Experimente mover o mouse em várias direções e depois clicar o F2.

:arrow: O script está localizando a posição do botão através do comando ImageSearch e depois movendo o mouse para a posição localizada (com 10 pixels a mais para evitar bordas). Se quiséssemos, poderíamos também configurar um clique nas coordenadas desejadas, mas acredito que isso você já saiba fazer.

:arrow: DICA: note que apesar de estarmos usando a imagem do botão inteira no exemplo, podemos recortar apenas um pedaço do botão para usar como imagem a ser buscada no comando. Essa estratégia pode melhorar as chances de uma imagem ser localizada (caso a imagem esteja parcialmente escondida, por exemplo).

:arrow: O comando ImageSearch possui ainda algumas outras opções que podem ajudar na hora de localizar uma imagem. Uma delas é aceitar uma variação nas tonalidades da imagem que você determina o grau. Assim, se os pixels da imagem forem um pouco mais escuros ou um pouco mais claros, ou se a cor variar um pouquinho, ainda será possível encontrar a imagem. A variação pode ser indicada no parâmetro de caminho do arquivo, escrevedo asterisco seguido do grau de variação desejado antes de escrever o caminho do arquivo (separado por um espaço simples). Exemplo: *10 c:/imagens/exemplo.png. Outra opção que pode ser bastante útil é determinar uma cor para servir como background. Dessa forma, se torna possível utilizar uma imagem que contenha fundo branco para localizar a imagem ainda que o fundo mude para verde (basta determinar que o branco será uma cor "transparente"). Nesse caso, você pode escrever um asterisco, seguido da palavra "Trans" e depois seguido da cor escolhida antes do caminho do arquivo. (Exemplos: *TransWhite c:/imagens/exemplo.png ou *Trans0x9DAF99 c:/imagens/exemplo.png (Falaremos de códigos de cores no item seguinte deste tutorial).

3. PixelSearch, um comando mais poderoso

Conforme vimos na parte 2 deste tutorial, podemos utilizar o comando ImageSearch para buscar facilmente imagens na tela quando elas estiverem inteiramente visíveis (ou parcialmente desde que usemos um pedaço que estiver visível) e desde que elas não tenham muita variação (apenas um pouco na tonalidade).

Mas o que fazer quando a imagem em questão pode variar de alguma forma?

Imagine que você está tentar encontrar a posição de um boneco dentro de um jogo. A imagem do boneco está sempre visível na tela, mas ocorre que como se trata de uma animação, ela nem sempre será a mesma. Estudando um pouco o funcionamento de uma animação, percebemos que ela é feita basicamente de duas formas: ou colocando várias imagens pré-prontas (os sprites 2D) ou gerando na hora as várias imagens 2D a partir de objeto 3D (através da renderização), e depois passando em qualquer caso as imagens uma a uma sequencialmente e rapidamente (para criar o efeito da animação). Em ambos os casos, as imagens de fato variam e fazem isso rapidamente. Assim o comando ImageSearch se tornará inútil para localizar o boneco, pois não há como garantir a sincronia entre as chamadas ao comando e a imagem em exibição naquele exato instante (ainda que chamassemos o comando uma vez para cada sprite, a velocidade de mudança é tal que é mais provável que em nenhum caso coincidiria - pois o comando não é processado tão rápidamente assim).

Neste caso, como faremos então para criar um script que encontre uma imagem dentro de uma animção?

:arrow: Simples! Vamos usar o comando PixelSearch, que encontra apenas 1 pixel de determinada cor na tela.

Parece estranho que isso possa resolver o nosso problema? Saiba que a possibilidade de buscar um único pixel é muito mais flexível do que buscar uma imagem inteira, e que ela permite que coloquemos mais inteligência em nossas rotinas.

Para saber como isso funciona, vamos primeiro entender a fundo tudo o que está envolvido em uma cor quando falamos de computadores e programação.

Vamos lá? :thumbup:

3.1 As cores em uma imagem

Os monitores de hoje em dia são capazes de gerar imagens com milhões de cores diferentes. Isso ocorre porque cada pixel da tela é iluminado em vários graus por cada uma das três cores básicas: vermelho, verde e azul.

Essas três cores formam a base do sistema aditivo de cores, e isso significa que a partir delas, podemos formar quaisquer outras cores adicionando cada cor primária em um determinado grau. Quer um exemplo? Se você iluminar um pixel com um vermelho bem forte e o mesmo pixel também com um azul bem forte (e se além disso você mantiver o verde dele bem fraco) você terá como resultado uma cor violeta forte. Assim, perceba que qualquer uma das milhões de cores possível em um monitor é basicamente um resultado da força de iluminação variável entre as três cores básicas (incluindo até mesmo o preto e o branco, pois o primeiro é ausência de luminosidade nos 3 canais e o outro é luminosidade máxima nos 3 canais).

No computador, podemos então formar qualquer cor indicando os valores de iluminação de cada cor dentro do mesmo pixel: quanto de iluminação no canal vermelho, quando no canal verde e quanto no canal azul... Isso é feito normalmente utilizando um código de cores.

A maioria dos códigos de cores se comporta da seguinte forma: Dois dígitos hexadecimais para o canal vermelho, seguido de dois para o canal verde e dois para o canal azul. O valor dos dígitos é numérico e quanto maior o valor em cada canal, mais forte e mais clara será aquela cor (do inverso, quanto menor o valor de um canal, mais fraca ou escura será aquela cor). Trata-se do esquema aditivo de cores, pois o monitor EMITE luz.

3.2 Sistemas binário e hexadecimal de números

Estamos acostumados a contar os números de forma decimal (base 10). Por isso, cada casa decimal tem 10 possibilidades de números. Desta feita, só precisamos de 10 símbolos, repetidos se preciso, para representar qualquer número que quisermos. Eles são: 1, 2, 3, 4, 5, 6, 7, 8, 9 e 0.

Esse sistema é o mais difundido e o mais usado no dia-a-dia, mas você sabia que é possível escrever qualquer número usando uma quantidade diferente de símbolos?

No computador, por exemplo, usa-se o sistema binário em alguns casos, que é composto apenas de 0 e 1. Nesse caso, o número 3 seria representado como 11. você saberia dizer o porquê?

Simples: A primeira casa (a da direita) é a das unidades, então o valor 1 lá significa 1... Mas a segunda casa tem um significado especial: ela significa um número a mais que uma casa da primeira cheia. Pense no sistema decimal: o algarismo 1 no número 10 significa que enxemos a casa das unidades (9) e depois adicionamos mais 1... Então da mesma forma ocorre no sistema binário: enxemos a casa das unidades (1) e depois adicionamos mais 1. Então temos que a segunda casa respresenta na verdade o valor 2, pois no sistema binário a casa enche no 1. Portanto, respondendo à pergunta do por que 11 em binário seria 3: se temos 1 na segunda casa e ainda temos 1 na casa de unidades... temos 3. O número 3 é então a mesma coisa que 11 em binário. Se ainda estiver confuso, lembre-se de quando aprendeu sobre as casas, e como o 9 se transforma em 10 adicionando um número à esquerda e depois voltando ao 0. Você também pode olhar a tabela abaixo.
NUMEROS EM BINARIO.png
NUMEROS EM BINARIO.png (8.73 KiB) Viewed 5036 times
Simples não?

:arrow: O sistema de números em decimal se tornou o mais usado no dia-a-dia porque com ele é possível representar números grandes com bem menos dígitos do que usando o sistema binário e também porque nesse caso só é preciso memorizar 10 símbolos (então, até uma criança pode aprender eles em um tempo razoável). Mas agora que aprendemos que existe o sistema binário além do decimal... Poderiam existir outros sistemas também? É claro que sim: Sempre que valer a pena, podemos inventar outros sistemas. E tem um sistema que também vai valer bastante a pena quando estivermos tratando de programação: o sistema hexadecimal (base 16).

Esse sistema possui 16 símbolos, e como vamos precisar de 6 símbolos a mais que o decimal, vamos facilitar nossa vida usando as 6 primeiras letras do alfabeto (de A até F, pois dessa forma quase ninguém vai precisar aprender novos símbolos).

NUMEROS EM HEXADECIMAL.png
NUMEROS EM HEXADECIMAL.png (15.6 KiB) Viewed 5036 times

:arrow: Veja o que ocorreu quando excedemos o 9: o número 10 em decimal equivale ao número A em hexadecimal! Assim, nós não precisamos de mais do que uma casa para representar qualquer número entre 0 e 15.

:arrow: Quando chegamos ao número 16, aí sim criamos uma nova casa e adiconamos 1 a ela... por isso, 10 em hexadecimal equivale a 16 em decimal.

Entendeu como funciona? :beer:

:arrow: Os números em hexadecimal não são tão intuitivos... Isso ocorre porque passamos nossa vida inteira usando apenas o sistema decimal. Assim, temos plena ciência da grandeza de um número quando ele é representado em decimal, mas em hexadecimal não é tão simples: será que C8 em hexadecimal é maior que 200 em decimal?

Pense um pouco e depois veja abaixo a resposta.
Spoiler

:arrow: Apesar de não ser tão intuitivo usar a base hexadecimal, a calculadora do windows permite que você calcule e converta entre decimais e hexadecimais facilmente: basta ir em exibir -> programador e selecionar Hex ou Dec.

Mas se esse sistema não é intuitivo, pra quê usá-lo? :crazy:

Simples: Em programação o byte (8 bits) é muito importante, pois ele é o menor valor endereçavel na memória. Além disso, uma única instrução do processador processa ao mesmo tempo um certo múltiplos de bytes (32 ou 64 bits, que daria 4 ou 8 bytes). Assim, acessar e trabalhar com bits individuais é na verdade mais custoso em termos de processamento do que acessar e trabalhar com bytes inteiros. É aí que entra o sistema hexadecimal: com ele, podemos representar qualquer valor possível de um byte com apenas 2 dígitos.

Um byte tem 256 possibilidades de valores, e isso vai do 00 ao FF em hexadecimal. Portanto, ao usar o sistema decimal, não poderíamos garantir que o usuário inseriu um valor de byte válido apenas pela quantidade de casas decimais: 251 seria válido, mas 258 não seria, enquanto que 178 seria, mas 312 não seria... Precisaríamos de um algoritmo :crazy:

Com o sistema hexadecimal fica mais fácil: qualquer valor hexadecimal de dois dígitos válido é um valor válido para um byte.

:arrow: O autohotkey é capaz de trabalhar com números no sistema hexadecimal. Para indicar um número neste sistema, basta precedê-lo do prefixo "0x". Assim, o script abaixo é perfeitamente válido. Execute-o para ver o número que é exibido.

Code: Select all

ABC := 0xC8 + 0xC8
msgbox %ABC%

:arrow: Se você executou o código acima, viu que o AutoHotkey entendeu o valor informado, mas converteu-o automaticamente para decimal. Assim, C8 + C8 resultou em 400 (o que está certo, pois C8 é igual a 200). 200 + 200 = 400. Mas isso não é tudo: o AutoHotkey também pode ser configurado para exibir números em hexadecimal. Isto é feito usando-se o comando SetFormat.

Code: Select all

Setformat, Integer, h
ABC := 0xC8 + 0xC8
msgbox %ABC%
:arrow: No código acima, a msgbox exibiu o número 0x190. Se você fizer a conta, verá que 190 em hexadecimal equivale a 400 no sistema decimal (use a calculadora do windows na configuração exibir -> programador, escreva 400 com Dec selecionado e depois mude a seleção para Hex. Você verá o valor se transformar de 400 para 190 e vice-versa conforme alterna entre decimal e hexadecimal).

Mas lembre-se: não é necessário trocar o formato de exibição dos números para trabalhar com os códigos hexadecimais. Basta escrevê-los com o prefixo "0x" em qualquer lugar onde puder escrever números ou em qualquer parâmetro que espere uma string numérica ou simplesmente hexadecimal.

3.3 Sistemas hexadecimal de cores


Conforme dito anteriormente, o sistema hexadecimal é muito útil na programação por causa do byte. No caso das cores, a maioria dos monitores hoje em dia é capaz de representar um pouco mais que 16 milhões de cores. Você sabe o porque?

256 * 256 * 256 = 16.777.216

É isso mesmo: um byte de possibilidades para cada canal de cor. Assim, o nível de verde em uma cor pode variar de 0 a 256, bem como o nível de vermelho e também o de azul. Dessa forma, toda instrução de iluminação de pixel toma exatamente 3 bytes (24 bits) e a informação para iluminar aquele pixel estará contida em exatamente 3 endereços na memória. Tudo casa perfeito em termos de armazenamento, processamento e exibição na máquina: nada fica quebrado.

Dessa forma, quando queremos representar uma cor, como faremos?

3.4 Esquema RGB de cores

ATENÇÃO !! O comando PixelSearch utiliza por padrão o esquema BGR de cores (e não o RGB), mas você pode mudar isso escrevendo RGB no parâmetro de opções do comando.

O esquema RGB de cores é o mais utilizado na programação, e nada mais é do que: primeiro vermelho (Red), depois verde (Green), depois azul (Blue). Assim, podemos dizer que uma cor RGB 9F00C8 significa:

Vermelho 9F (ou 159 até um valor máximo de 255 possibilidades) - Vermelho intermediário.
Verde 00 (ou 0 até um valor máximo de 255 possibilidade) - Verde zerado.
Azul C8 (ou 200 até um valor máximo de 255 possibilidade) - Azul forte.

O resultado:

COR 9F00C8.png
COR 9F00C8.png (40.66 KiB) Viewed 5034 times

:arrow: Você pode visualizar qualquer cor no google pesquisando por color e depois o código hexadecimal de 3 canais dela. Exemplo: color 9F00C8.

:arrow: DICA: Você pode encontrar o código RGB de uma cor qualquer que esteja sendo exibida na sua tela usando o WindowSpy, uma ferramenta embutida na instalação do AutoHotkey e que pode ser acessada clicanco com o botão direito do mouse no ícone de H verde que aparece na parte inferior-direita da tela sempre que você executa qualquer script (basta executar qualquer script que não termine imediatamente, como os que têm msgbox ou hotkeys, e você poderá buscar o ícone na bandeja do windows - clique na seta para exibir ícones ocultos da bandeja se precisar).
WindowSpy.png
WindowSpy.png (57.1 KiB) Viewed 5007 times

3.5 Esquema BGR de cores

Se você entendeu o esquema RGB, entender o BGR é bem simples: os canais só mudaram de posição. Assim, a nossa mesma cor 9F00C8 em RGB ficaria assim em BGR: C8009F.

:arrow: Se você não utilizar a opção RGB no parâmetro de opções do PixelSearch, terá de escrever o código da cor em BGR. Utilize a informação acima para entender como transformar de RGB para BGR se precisar (ou use a opção RGB).


3.6. O Comando PixelSearch

Agora que sabemos tudo o que está envolvido nas cores que o nosso monitor exibe, vamos falar sobre o comando PixelSearch, que como dito antes, é mais flexível que o comando ImageSearch. Com ele, poderemos elaborar rotinas muito poderosas de busca de imagens e de busca de elementos visuais na tela do computador.

O comando PixelSearch basicamente busca um único pixel da cor que você quiser na tela. Além disso, ele é capaz de buscar uma variação da cor indicada em um montante que você controla (por exemplo, procurar um pixel vermelho com valor R G B igual a 9A 00 00 e com uma variação de até 10 tons no comando fará com que um pixel R G B 9D 05 08 seja identificado pelo comando. Isso ocorre porque todos os canais variaram menos de 10 tons cada). Com essa funcionalidade, se a cor de vermelho a ser buscada for um pouco mais escuro ou um pouquinho mais claro do que estiver de fato na tela, ou se for um pouquinho mais alaranjado ou mais violeta, o comando ainda assim poderá encontrar o pixel e retornar a coordenada para você.

O poder desse comando está em encontrar imagens que podem variar de muitas formas, mantendo apenas alguns pontos em comum. Assim, quando você estiver buscando uma imagem que pode estar redimensionada na tela ou quando você estiver buscando encontrar um objeto animado, esse comando poderá ser bem mais útil que o ImageSearch.

Para ilustrar, imagine que estamos buscando um boneco de um menino em uma animação na tela. Comecemos estudando um pouco a animação em questão, de modo que possamos identificar o que varia de fato e o que se mantém parecido. Para fazer isso, vamos isolar os sprites do menino:


Image


:arrow: Perceba que enquanto a animação vai rodando na tela, a imagem do menino trocará varias vezes por segundo na tela (o que é esperado em uma animação). Por causa disso, o comando ImageSearch provavelmente falharia na detecção e localização da imagem do menino. Isso vai ocorrer porque o ImageSearch buscaria apenas uma imagem e é muito improvável que exatamente aquela imagem esteja na tela no exato momento em que o comando rodar.

Mas antes que pensemos ser impossível elaborar um programa para encontrar o menino na tela, vamos considerar a possibilidade de procurarmos apenas alguns pixels de determinadas cores ao invés de imagens inteiras. Perceba no nosso exemplo do menino, que as cores do menino na verdade permanecem semelhantes em todos os sprites. Isso é algo muito comum em qualquer animação: Se estamos falando de um personagem que usa um casaco azul-claro, todo e qualquer sprite dele terá pelo menos um bocado de pixeis azul-claro (ainda que a tonalidade varie um pouco). Vamos usar isso a nosso favor! :beer:

:arrow: O comando PixelSearch poderá encontrar o menino sem muita dificuldade pelo fato de que a média da cor do seu casaco (e de alguns outros elementos da vestimenta) não muda muito e isso ocorre mesmo que a forma dele na imagem mude.

Assim, vamos observar os sprites e perceber como as cores das partes do menino visíveis são muito semelhantes em todos os sprites possíveis: o chapéu sempre é vermelho, o casaco sempre é azul, a face sempre é bege... Tem muita informação boa para isolar o menino aqui!

Dessa forma, ao buscar uma única cor com uma variação que permita-a ser encontrada em qualquer um dos sprites do menino, temos uma grande chance de encontrar a localização do menino. Basta buscar um pixel no azul da cor do casaco, com uma margem de variação tal que a cor correponda a pelo menos 1 pixel de todas as imagens do casaco.

É assim que vamos encontrar o menino pelas cores do seu casaco :superhappy:

:arrow: Exemplo de rotina PixelSearch (role a página do tópico até a imagem dos bonecos acima ficar visível próximo à parte superior-esquerda da tela do computador e rode o código abaixo. O código vai mover o mouse até o chapéu de um dos bonecos a cada 10 segundos [a imagem dos bonecos precisar estar visível !]):

Code: Select all

#Persistent
SetTimer, EXEMPLO_DE_ROTINA_10_SEGUNDOS, 10000 ; Executa a rotina de busca a cada 10 segundos...
Return

EXEMPLO_DE_ROTINA_10_SEGUNDOS:
CoordMode, Pixel, Screen ; Ajusta para que a coordenada informada ao PixelSearch seja relativa à tela inteira do computador.
PixelSearch, PosX, PosY, 0, 0, 1000, 1000, 0xF62A2F, 10, Fast RGB ; Busca um pixel vermelho com tonalidade hexadecimal vermelho F6 (154 em decimal), verde 2A, azul 2F. Variação até 10 tons. Área de busca 1000x1000 a partir do canto superior-esquerdo da tela.
if (ErrorLevel = 0) ; Se ErrorLevel continuar 0 depois do comando, o comando encontrou um pixel na cor das especificações.
{
	Funcao_Exemplo(PosX, PosY) ; Chama a função Funcao_Exemplo passando para ela os valores de PosX e PosY como sendo os parâmetros Posicao_X e Posicao_Y.
}
Else
{
	msgbox, 0x10, Erro, Pixel do chapéu não encontrado ! `n Deixe a imagem dos bonecos visível na tela e tente novamente.
}
Return

Funcao_Exemplo(Posicao_X, Posicao_Y)
{
	CoordMode, Mouse, Screen ; Ajusta para que a coordenada informada ao MouseMove seja relativa à tela inteira do computador.
	MouseMove, %Posicao_X%, %Posicao_Y% ; Move o mouse para a posição encontrada.
	Msgbox, 0, Aviso, Pixel do chapéu encontrado nas posições X: %Posicao_X% e Y: %Posicao_Y% ; Informa as posições encontradas.
}
Return


:arrow: EXPLICAÇÃO DA ROTINA ACIMA:

A rotina acima basicamente faz o seguinte:
  • 1. Utiliza o comando CoordMode, Pixel, Screen para fazer com que o comando PixelSearch considere todas as coordenadas como relativas à tela do computador (e não à janela ativa, como é o seu padrão).
  • 2. Chamamos o comando PixelSearch passando os seguintes parâmetros:
  • 2.1. PosX: Esta é a variável que receberá a coordenada X (horizontal, da esquerda para a direita, de 0 até a resolução horizontal máxima da tela) onde o pixel da cor buscada for encontrado.
  • 2.2. PosY: Esta é a variável que receberá a coordenada Y (vertical, de cima para baixo, de 0 até a resolução vertical máxima da tela) onde o pixel da cor buscada for encontrado.
  • 2.3. 0: Este primeiro zero significa que vamos buscar o pixel a partir do início da tela (posição horizontal 0, ou seja, no canto esquerdo da tela).
  • 2.4. 0: Este primeiro zero significa que vamos buscar o pixel a partir do início da tela (posição vertical 0, ou seja, no canto superior da tela). Este parâmetro juntamente com o parâmetro acima indica que a posição inicial da busca será o primeiro pixel do canto superior-esquerdo da tela.
  • 2.5. 1000: este número determinada a posição horizontal máxima da busca: vamos buscar o pixel somente nos 1000 primeiros pixeis horizontais de cada linha.
  • 2.6. 1000: este número determinada a posição vertical máxima da busca: vamos buscar o pixel somente nos 1000 primeiros pixeis verticais de cada linha. Este parâmetro juntamente com o parâmetro acima indica nossa área de busca, que será um quadrado de 1000 pixels de lado e altura, iniciado no canto superior-direito da tela. DICA: Você pode utilizar as variáveis embutidas A_ScreenWidth e A_ScreenHeight nestes dois parâmetros para buscar o pixel na tela inteira sem precisar se preocupar com qual a resolução máxima atual da tela.
  • 2.7. 0xF62A2F: é o código da cor que vamos buscar. Como usaremos a opção RGB no parâmetro de opções, temos a seguinte composição: Vermelho F6, Verde 2A, Azul 2F.
  • 2.8. 10: esta é a variação máxima que toleraremos em cada canal de cor. Isso significa, por exemplo, que até 10 tons a mais em qualquer canal (inclusive nos 3) é tolerável e será considerado como uma cor igual à que estamos buscando (ou seja, se indicamos vermelho F6, uma cor com vermelho FC também servirá - desde que os outros canais correspondam dentro da tolerância também).
  • 2.9 . Fast RGB: este é o parâmetro de opções, onde optamos por usar o método rápido de busca e indicamos que nosso código de cor está em RGB.
  • 3. Após rodar o comando, verificamos na variável ErrorLevel se o comando encontrou um pixel na cor daquelas características.
  • 3.1. Se foi encontrado um pixel adequado, chamamos a função Funcao_Exemplo() passando as variáveis que receberam as coordenadas do pixel. Essa função moverá o mouse para lá e avisará o usuário com um MsgBox. OBS: Veja que usamos o comando CoordMode, Mouse, Screen dentro da função para garantir que o MouseMove também interpretará as coordenadas como sendo relativas à tela do computador.
  • 3.2 Se não foi encontrado nenhum pixel adequado às nossas especificações, simplesmente avisaremos o usuário com uma MsgBox.
    Fim da rotina

:arrow: Mas e se houver outro objeto na mesma animação que tenha aquela cor?

Suponha que você esteja buscando o menino pelo seu casaco azul e viu que existe uma flor no cenário que possui cores azuis próximas às do casaco. Isso pode gerar um problema, afinal, o comando pode determinar a posição da flor como se fosse a do menino. O que fazer? :think:

Simples!: analise bem o cenário da animação ANTES de determinar o que vai servir para encontrar o boneco. Além do casaco, você pode procurar tons de vermelho do chapéu ou tons de bege correspondentes à face, e se preciso for, você pode também pesquisar todos os 3 tons em sequência, de modo a determinar a posição do boneco pela proximidade em pelo 2 coordenadas (É quase impossível que você não seja capaz de elaborar uma rotina que encontre uma máscara de pixels que corresponda em cores e distâncias apenas ao boneco, pois lembre que estamos falando de objetos diferentes: uma flor difere em várias formas de um boneco).

3.7. Conclusão

Neste tutorial adquirimos muitos conhecimentos importantes para elaborar rotinas de busca de imagens na tela do computador. Se você o estudou bem, deve estar com uma visão bem mais abrangente de como são exibidas as imagens em uma tela de computador e de como você pode usar esse conhecimento para criar rotinas inteligentes de busca de imagens na tela.

Para fazer uma rotina com ImageSearch ou PixelSearch, basta seguir este passo-a-passo:
  • 1. Estude a tela ou o cenário onde a imagem-alvo está localizada. Opte entre o ImageSearch ou o PixelSearch conforme o grau de variação da imagem-alvo na tela (uma imagem estática pode ser buscada com ImageSearch, mas uma animação seria melhor buscada com o PixelSearch).
  • 2. Se o ImageSearch for suficiente, basta tirar um print da imagem, recortar parte dela e usar no comando. Se precisar do PixelSearch, continue os passos a seguir.
  • 3. Verifique qual (ou quais) cores existem na imagem-alvo e que não existem no resto da tela ou cenário (procure cores únicas que possam identificar a imagem-alvo e que não variem tanto quando a imagem for de animação).
  • 4. Descubra o código hexadecimal RGB daquelas cores usando o WindowSpy (ou através de um printscreen colado em um editor de imagens que mostre o código dos pixels).
  • 5. Implemente a rotina usando PixelSearch, colocando o código RGB da cor escolhida, a área de busca da tela e a variação aceitável de tonalidades da imagem (o PixelSearch trabalha com BGR por padrão, mas você pode forçar o uso do RGB escrevendo RGB no parâmetro de opções. Se quiser usar BGR, basta trocar os dois primeiros caracteres com os dois últimos - Exemplo: 0x010203 em RGB ficaria 0x030201 em BGR).
  • 6. Teste a rotina várias vezes para garantir que o objeto-alvo está de fato sendo localizado com confiabilidade. Se necessário, ajuste a variação de tonalidade ou escolha outra cor mais confiável.
Se ainda tiver alguma dúvida sobre o tema, ou se quiser compartilhar alguma informação útil e que não tenha sido tratada no tutorial, sinta-se livre para postar abaixo ou cirar um tópico no nosso fórum Ajuda e Suporte Geral. Um forte abraço e vamos em frente com o nosso aprendizado :thumbup:
User avatar
Gio
Posts: 1057
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: Busca de imagens

02 Jan 2020, 20:03

Terminei a versão inicial deste tutorial. Agora temos uma sessão sobre PixelSearch, conforme prometido :thumbup:

Também alterei o nome do tutorial e as referências para busca de imagens (para não confundir com tópicos mais avançados, como reconhecimento facial, OCR e automação de carros). Estes tópicos mais avançados deixaremos para tratar em uma outra ocasião (o ImageSearch e o PixelSearch já devem servir para 99% dos casos :beer: ).
marlontomazi
Posts: 4
Joined: 09 Jul 2020, 07:15

Re: Busca de imagens

09 Jul 2020, 07:20

Parabens pelo tutorial!!! Muito bem explicado, eu que sou leigo sobre o assunto consegui entender perfeitamente!!! Muito obrigado por dedicar seu tempo com esse tutorial, com certeza ajudou muitas pessoas.

Eu to tentando fazer um script pra mim pra usar , minha duvida é a seguinte, tem como eu utilizar por exemplo duas ações? Se estiver com a vida na metade, usar cura.... se aparecer um status de envenenado, usar magia pra curar veneno... tem como fazer isso com o pixel search tudo no mesmo script?
User avatar
Gio
Posts: 1057
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: Busca de imagens

09 Jul 2020, 08:31

Bom dia Marlontomazi.

Tem sim. O comando PixelSearch atualiza a variável ErrorLevel, então quando você executa o comando, você pode imediatamente depois utilizar uma condicional (expressão if) para determinar o que fazer caso o primeiro pixel tenha sido encontrado, e logo depois dessa condicional (ou seja, depois do bloco dela) você já poderia colocar o segundo PìxelSearch seguido da segunda condicional, e isso verificaria a segunda possibilidade.

:arrow: Atualizando o exemplo do tutorial, uma pesquisa por 2 pixels diferentes em sequencia na imagem dos bonecos ficaria assim:

Code: Select all

#Persistent
SetTimer, EXEMPLO_DE_ROTINA_10_SEGUNDOS, 10000 ; Executa a rotina de busca a cada 10 segundos...
Return

EXEMPLO_DE_ROTINA_10_SEGUNDOS:
CoordMode, Pixel, Screen ; Ajusta para que a coordenada informada ao PixelSearch seja relativa à tela inteira do computador.
PixelSearch, PosX, PosY, 0, 0, 1000, 1000, 0xF62A2F, 10, Fast RGB ; Busca um pixel vermelho com tonalidade hexadecimal vermelho F6 (154 em decimal), verde 2A, azul 2F. Variação até 10 tons. Área de busca 1000x1000 a partir do canto superior-esquerdo da tela.
if (ErrorLevel = 0) ; Se ErrorLevel continuar 0 depois do comando, o comando encontrou um pixel na cor das especificações.
{
	Funcao_Exemplo(PosX, PosY) ; Chama a função Funcao_Exemplo passando para ela os valores de PosX e PosY como sendo os parâmetros Posicao_X e Posicao_Y.
	msgbox, 0, Aviso, o primeiro pixel (vermelho) foi encontrado. Em seguida, buscaremos o segundo (azul).
	Sleep 2000
}
Else
{
	msgbox, 0x10, Erro, Pixel do chapéu não encontrado ! `n Deixe a imagem dos bonecos visível na tela e tente novamente.
}
CoordMode, Pixel, Screen ; Ajusta para que a coordenada informada ao PixelSearch seja relativa à tela inteira do computador.
PixelSearch, PosX, PosY, 0, 0, 1000, 1000, 0x3687E3, 5, Fast RGB ; Busca um pixel AZUL (do casaco do boneco).
if (ErrorLevel = 0) ; Se ErrorLevel continuar 0 depois do comando, o comando encontrou um pixel na cor das especificações.
{
	Funcao_Exemplo(PosX, PosY) ; Chama a função Funcao_Exemplo passando para ela os valores de PosX e PosY como sendo os parâmetros Posicao_X e Posicao_Y.
	msgbox, 0, Aviso, o segundo pixel (azul) também foi encontrado.
	Sleep 2000
}
Else
{
	msgbox, 0x10, Erro, Pixel do casaco não encontrado ! `n Deixe a imagem dos bonecos visível na tela e tente novamente.
}
Return

Funcao_Exemplo(Posicao_X, Posicao_Y)
{
	CoordMode, Mouse, Screen ; Ajusta para que a coordenada informada ao MouseMove seja relativa à tela inteira do computador.
	MouseMove, %Posicao_X%, %Posicao_Y% ; Move o mouse para a posição encontrada.
	Msgbox, 0, Aviso, Pixel encontrado nas posições X: %Posicao_X% e Y: %Posicao_Y% ; Informa as posições encontradas.
}
Return
:arrow: No código acima, as ações exclusivas relativas respectivamente ao pixel vermelho e ao pixel azul seriam colocadas no bloco onde estão respectivamente as mensagens o primeiro pixel (vermelho) foi encontrado. Em seguida, buscaremos o segundo (azul).
e
o segundo pixel (azul) também foi encontrado.
marlontomazi
Posts: 4
Joined: 09 Jul 2020, 07:15

Re: Busca de imagens

09 Jul 2020, 09:02

Entendi, eu to com um pouco de dificuldade pra adaptar pro meu caso. Mais sua explicação foi ótima!! Vou dar uma pesquisada pra tentar adaptar pra apertar teclas ao inves de mover o cursor do mouse sabe? Se baixar a vida, apertar F1, se baixar a mana apertar F2 e assim por diante
Manoel_Agostinho
Posts: 2
Joined: 13 Jul 2020, 18:53

Re: Busca de imagens

13 Jul 2020, 19:04

Olá!

Excelente tutorial! Obrigado pelo auxílio e disponibilidade!

Quanto ao tema tenho uma dúvida. Estou criando um script e a imagem possui os mesmos conjuntos de pixels, só que as cores variam.

Gostaria de saber se há como converter a imagem para a escala de cinza antes de procurá-la? Ou se dá para fazer com que o script procure a “silhueta” da imagem.

Ex: uma imagem contém uma palavra cujos pixels variam de cor. Uma hora a imagem está colorida, em outra hora está em escala de cinza. Como existem outras palavras cujas cores também se reproduzem na tela, o comando pixelsearch se torna inviável. O ideal seria buscar em uma tonalidade padrão.

Alguma ideia?
Attachments
53475E58-9B17-4D6F-874B-E0C50AF6BFFE.jpeg
Imagem mostrando a diferença de tonalidades. Gostaria que o script padronizasse a pesquisa e tivesse como alvo a imagem em escala de cinza e não multicolorida.
53475E58-9B17-4D6F-874B-E0C50AF6BFFE.jpeg (1.05 MiB) Viewed 1768 times
User avatar
Gio
Posts: 1057
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: Busca de imagens

13 Jul 2020, 19:43

Boa noite Manoel_Agostinho.

Vejo que você está tentando reconhecer textos em imagens. Normalmente, esse tipo de tarefa não é executada com PixelSearch ou ImageSearch, pois neste caso em especial seria muito complexo criar um algoritmo que funcionasse a contento usando estas ferramentas. Mesmo assim, existem outras ferramentas de programação lhe que podem ajudar neste sentido, todas elas envolvidas no assunto de OCR (Optical Character Recognition, em inglês, ou Reconhecimento Ótico de Caracteres, em português).

Os algoritmos de OCR normalmente são implementados através de inteligência artificial, o que pode envolver redes neurais ou outras ferramentas de machine learning. É um pouco complexo e trabalhoso criar um algoritmo desses, mas você pode buscar funções e bibliotecas (inclusive DLLs) prontas para aplicar diretamente no seu código.

Busque por OCR nos nossos fórums e você encontrará tópicos como este, que trazem implementações em AutoHotkey fáceis de adaptar no seu projeto em AutoHotkey para ferramentas de OCR (com dependências): https://www.autohotkey.com/boards/viewtopic.php?f=6&t=36047

Mas caso tenha interesse em criar um algoritmo de OCR você mesmo, saiba também pode fazer isso (embora que como dito antes, é algo consideravelmente trabalhoso e um pouco avançado). Escrevi um tutorial básico sobre Redes Neurais Artificiais em AutoHotkey em 2018 nos fórums em inglês (você pode acesá-lo aqui).
Manoel_Agostinho
Posts: 2
Joined: 13 Jul 2020, 18:53

Re: Busca de imagens

20 Jul 2020, 15:19

Inicialmente agradeço muito pelas sugestões! Vou aproveitar para estudar a questão de implementação de IA também!

No caso descrito consegui o que eu queria usando o recurso que você ensinou para o pixelsearch. Assim, coloquei a variação de tons ensinada no PixelSearch no ImageSearch (funcionou!). Deixo aqui o registro pois pode ser a dúvida de alguém também.

Mais uma vez, muito obrigado pela ajuda! 😊👍🏽
josueh
Posts: 11
Joined: 08 Feb 2020, 06:07
GitHub: Josueh

Re: Busca de imagens

10 Aug 2020, 06:49

Ótimo tutorial Gio!

Return to “Tutoriais”

Who is online

Users browsing this forum: No registered users and 1 guest