Aller au contenu

Reconnaissance visuelle

C’est le moteur d’OculiX. Vous lui montrez une petite image, il vous indique où elle se trouve à l’écran. Cliquer, taper, attendre — tout part de là.

Screen

Un moniteur physique. Screen(0) est l’écran principal, Screen(1), Screen(2), etc. couvrent les écrans suivants. Hérite de Region.

Region

Une zone rectangulaire dans laquelle on cherche. find, click et type opèrent dessus. Un Screen est une Region qui couvre tout l’écran.

Pattern

Une image, plus deux réglages : son seuil similar() et son targetOffset().

Match

Une recherche qui a réussi. C’est une Region, à laquelle s’ajoutent un score et le Pattern qui l’a produite.

Location

Un point (x, y). Rien de plus.

Partout où OculiX attend une image, vous pouvez passer un Pattern à la place — et inversement.

Toute opération visuelle se ramène à l’un de ces cinq appels. Chacun accepte un chemin ("button.png"), un Pattern, ou une autre Region.

find(image) — localiser une fois, planter si rien

Section intitulée « find(image) — localiser une fois, planter si rien »

Cherche l’image dans la region, renvoie un Match à la première occurrence trouvée. Lève FindFailed si rien n’est trouvé. À utiliser quand l’image doit être là.

btn = find("save.png")
btn.click()

exists(image) — localiser une fois, renvoyer None si rien

Section intitulée « exists(image) — localiser une fois, renvoyer None si rien »

Même chose que find(), mais retourne None à la place de lever une exception. Parfait pour les branchements conditionnels.

if exists("error_dialog.png"):
click("ok_button.png")
else:
click("submit.png")

wait(image, secs) — attendre qu’une image apparaisse

Section intitulée « wait(image, secs) — attendre qu’une image apparaisse »

Boucle jusqu’à ce que l’image apparaisse, ou jusqu’à expiration du délai. Indispensable pour synchroniser un script avec une UI qui met du temps à charger.

# Lance l'export, attend que la fenêtre de sauvegarde s'ouvre (max 10 s)
click("export.png")
wait("save_dialog.png", 10)
type("filename_field.png", "rapport.csv")

waitVanish(image, secs) — attendre qu’une image disparaisse

Section intitulée « waitVanish(image, secs) — attendre qu’une image disparaisse »

Symétrique de wait(). Indispensable pour attendre la fin d’un chargement, d’une animation, d’un toast de confirmation. Souvent la primitive qui change tout sur une UI moderne.

# Soumet le formulaire, attend que le spinner disparaisse, puis continue
click("submit.png")
waitVanish("loading_spinner.png", 30)
click("next_step.png")

Renvoie un itérateur sur tous les Match, triés par similarité décroissante. À utiliser dès qu’il y a plusieurs cibles identiques à traiter.

# Coche toutes les cases visibles d'un formulaire
for cb in findAll("checkbox_unchecked.png"):
cb.click()
from sikuli import *
s = Screen(0) # moniteur principal
# Patiente jusqu'à 10 s pour que l'application s'ouvre
app = s.wait("main_window.png", 10)
# On limite la recherche au volet de droite — plus rapide, moins ambigu
right_pane = app.right(app.getW() // 2)
save = right_pane.find("save_button.png")
save.highlight(1.5) # visualise le match 1,5 s avant de cliquer
save.click()

Par défaut, OculiX exige 70 % de similarité. Vous pouvez l’ajuster pour un appel ou pour tout le script :

click(Pattern("button.png").similar(0.85)) # juste cet appel
Settings.MinSimilarity = 0.65 # le script entier

Un seuil haut est plus strict, un seuil bas plus permissif. L’antialiasing, la transparence, un changement de thème ou le hinting des polices abaissent tous le score. Plutôt que de recapturer l’image à chaque variation, abaissez le seuil.

Cliquer ailleurs qu’au centre — le target offset

Section intitulée « Cliquer ailleurs qu’au centre — le target offset »

Un clic OculiX tombe au centre du match. Si ce n’est pas ce que vous voulez, le targetOffset décale le point de clic :

# Clique 30 pixels à droite et 5 pixels sous le centre de l'icône
icon = Pattern("icon.png").targetOffset(30, 5)
click(icon)

C’est la méthode habituelle pour cliquer sur un libellé situé à côté d’une icône reconnaissable.

r = Screen(0)
r.left(200) # bande de 200 px à gauche
r.right(200) # bande de 200 px à droite
r.above(100) # bande de 100 px au-dessus
r.below(100) # bande de 100 px en-dessous
r.inside() # la region elle-même
r.nearby(50) # élargit de 50 px tout autour
r.grow(50, 100) # élargit en largeur et hauteur séparément
r.morphTo(otherRegion)

Associées à find(), ces opérations rendent un script beaucoup plus stable :

# Ne cherche que dans la boîte de dialogue
dialog = wait("save_dialog_title.png", 5)
dialog.click("save_button.png")

Les ancres — fixer une zone par rapport à un repère

Section intitulée « Les ancres — fixer une zone par rapport à un repère »
header = find("header_logo.png")
search_box = header.right(800).below(0)
search_box.click()
search_box.type("oculix")

Quand la mise en page bouge mais que la position relative reste stable, les ancres permettent au script de continuer à fonctionner sans repasser sur chaque image.

for m in findAll("checkbox_unchecked.png"):
m.click()

Vous récupérez un itérateur de Match, trié par similarité décroissante.

match = find("save_button.png")
match.highlight(2)
match.highlight(2, "green")

Quand un script clique au mauvais endroit, c’est l’outil de diagnostic le plus rapide : highlight() montre exactement ce qu’OculiX a trouvé. La moitié des questions « pourquoi a-t-il cliqué là ? » disparaissent en quelques secondes après un coup de highlight.

Dans l’IDE, Run → Run Slow Motion ajoute une mise en évidence brève avant chaque action. Pratique pour démontrer un script à un non-technicien ou enregistrer une vidéo.

Settings.MinSimilarity = 0.7 # seuil minimum par défaut
Settings.AlwaysResize = 1.0 # mise à l'échelle des captures avant matching
Settings.MoveMouseDelay = 0.3 # durée du déplacement du curseur (secondes)
Settings.WaitScanRate = 3 # scans par seconde pendant wait()
Settings.AutoWaitTimeout = 3.0 # attente implicite avant chaque action

Quatre réflexes pour les scripts qui doivent tenir la charge

Section intitulée « Quatre réflexes pour les scripts qui doivent tenir la charge »

Plus le pattern est petit, plus le matching est rapide

Capturez serré autour de la cible. OpenCV a moins de pixels à comparer.

Limitez la zone de recherche

Une Region ciblée est toujours préférable à un balayage complet de l’écran.

Gardez les Match

Quand la mise en page ne bouge pas, target.click() est gratuit là où un nouveau find() coûte du CPU.

exists() au lieu de try/except

find() lève FindFailed si rien n’est trouvé. exists() renvoie None à la place — plus pratique pour brancher proprement, sans cascade d’exceptions à attraper.

ErreurCause habituelle
FindFailedL’image n’est pas visible, elle est masquée, ou le seuil est trop strict
ImageMissingLe chemin est faux, ou l’image manque dans le bundle .sikuli
org.opencv.core…Apertix mal résolu — voir Installation