Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

GUI Automation - locate image

by Anonymous Monk
on Mar 08, 2004 at 20:42 UTC ( [id://334919]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Goal: How to quickly locate/find a graphic on the screen... using Win32::GuiTest to load data into Jinitiator application on Windows 2000 desktop. Challenge: determine when data is accepted, or error occurred. ie: grab the error box and compare with known image(s).. Grabbing the screen is easy, (alt-PrintScreen), grab clipboard image... PerlMagick can access it fast as a blob image. scanning the whole image ( 1024 x 768 ) for a match in Perl can take more than 30 seconds... Graphical searching appears to not be an available function in PerMagick nor GD module... Any ideas for a speedup using Perl ?

Replies are listed 'Best First'.
Re: GUI Automation - locate image
by Corion (Patriarch) on Mar 08, 2004 at 21:14 UTC

    Depending on how your target application displays its windows, you can possibly dig down through it to get at the real text and caption of the window instead of needing to capture screens.

    Take a look at the included minispy.pl program and especially the FindWindow() routine - you will need a bit of knowledge about GDI or generally windowing APIs though, to make sense of the data returned by it.

    Otherwise, if you have to stay on the graphic route, consider using PDL - I think PodMaster has a PPM package for Win32.

Re: GUI Automation - locate image
by paulbort (Hermit) on Mar 09, 2004 at 03:56 UTC
    I can give a little bit more information to add to what Corion has already said. This will be much faster if you chase it through the windowing system. The downside is that the app will be less portable, but I infer from your question that you're in Windows regardless of where you want to be.

    So on to the meat. First, every window on the screen (and some not) in Windows has a Window Handle. This is a long int that you can use to have a conversation with the OS about a window. Given a window's handle, you can access all of the content of the window, including the title, any text fields, and any buttons. (This is a handy way to send a 'click' message to a button, and it's like the user clicked it.)

    Once the Perl app has the process ID, it can wander the list of windows for that process, start asking for handles, and examining window titles. (Titles are good for error messages, because they're usually consistent even when the error message itself varies.)

    Some things that might help:

    The people at http://sysinternals.com/ write really useful Windows utilities. "Handle" and "Process Explorer" might help here.

    Microsoft publishes all of their APIs on the web, you just have to dig to find them. Start with http://msdn.windows.com, and choose library. The API calls that will get you started are FindWindow (Find a top-level window) FindWindowEx (find a child window) and GetWindowText.

    This will not result in pretty or interesting code, but it will be so much faster than a graphics approach.

    I'd post a sample, but all of my hacking on this was done a few years ago, for a former employer, in Visual Basic. :(

    --
    Spring: Forces, Coiled Again!

      I'm at work now, where I use Win32::GUITest to automate a stubborn application, and here is a modified version of the spy-- program that I used to look at the current selection in a listbox. The stubborn program displays its status by filling a listbox with all possible status values and then selecting the active status...

      # $Id: guitest-spy.html,v 1.1 2001/09/19 23:31:36 erngui Exp $ # # MS has a very nice tool (Spy++). # This is Spy-- # use Win32::GuiTest qw/FindWindowLike GetWindowText GetClassName IsWind +owEnabled GetWindowID GetChildDepth GetDesktopWindow GetComboContents GetListContents Ge +tListText SendKeys /; use Win32::API; for (FindWindowLike(0,qr/^Explorer -/)) { SendKeys("%ao"); print "Looking for dialog\n"; my @dialog = FindWindowLike($_,qr/Optionen/,""); print "Looking for listbox\n"; my @listbox = FindWindowLike($dialog[0],"","",752); while (1) { print "Getting current selection\n"; my $i = SendMessage($listbox[0], LB_GETCURRSEL,0,0 ); print $i; print "Getting current selection text\n"; my $t = GetListText($listbox[0],$i); print $t,"\n"; sleep 1; }; }
        Corion, ++ and thanks for the example! We're hoping to start writing some GUI test automation here, could I steal^H^H^H^H^H copy that code for our internal use? It would sure be nice to be able to develop in-house what CA wanted $20K+ for, and that code will save me at least a few hours.

        --
        Spring: Forces, Coiled Again!
      Thanks, but Application is running within a windows frame utilizing some Java SunAwtCanvas... anything within it is not visible to me from Perl. only graphically. Found the Win32::ActAcc module, here is the Perl code I used to detect any "lasting change" over a 2 second period... It appears very handy for working with other applications...
      use Strict; use Win32::OLE; use Win32::ActAcc; use Win32::GuiTest qw(:ALL :SW); my @win; my %Wnm; my %VW; Win32::OLE->Initialize(); while ( 1 ) { @win = (); @win = FindWindowLike(); #*# report any "lost" windows: for $win ( @win ) { delete $Wnm{$win}; } if ( scalar keys %Wnm) { print "Lost:\n"; my @Lost = sort keys %Wnm; for (@Lost) { print "$Wnm{$_}\n"; delete $Wnm{$_}; } print "\n"; } for $win ( @win ) { dumpwin($win); } print "\n----\n"; sleep(2); } exit; sub dumpwin { my $win = shift; print "Null handle\n", return unless ($win); my $w_text = $win . ' ' . GetWindowText($win); $w_text .= " class=" . GetClassName($win); my $w_state = ' V=' . IsWindowVisible($win) . ' E='; $w_state .= IsWindowEnabled($win); $Wnm{$win} = $w_text . ' ' . $w_state; my $ao = Win32::ActAcc::AccessibleObjectFromWindow($win); my $aatxt = ''; $aatxt = $ao->describe() if defined $ao; $w_state .= ' ' . $aatxt; if ( exists $VW{$win} ) { return if ( $VW{$win} eq $w_state ); } $VW{$win} = $w_state; print $win, GetWindowText($win); print " class=", GetClassName($win); print " vis=", IsWindowVisible($win); print " en=", IsWindowEnabled($win); print "\n ",$aatxt, "\n"; }
Re: GUI Automation - locate image
by bageler (Hermit) on Mar 08, 2004 at 21:15 UTC
    after google search, I found this tidbit:
    This problem is called "image registration" or "image stitching" or "image mosaicing". There are plently of papers written on the subject, most of which don't use AI techniques. The most widely used method is getting the Fourier transform of both images and comparing them; but this only works if there is no change in rotation between the images. I, personally, have written a paper to do just that using Zernike moments. Many other approaches exist, each with it's ups and downs.
Re: GUI Automation - locate image
by Juerd (Abbot) on Mar 08, 2004 at 21:23 UTC

    One ugly and fun way would be to use the regex engine. 1024*786 is less than 1 MB so it could be fast even. (Assuming 8 bpp)

    Just insert .{ screen dump width - expected image width } after every expected image width characters (but not at the end).

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: GUI Automation - locate image
by halley (Prior) on Mar 09, 2004 at 15:16 UTC
    Image searching is a great automated testing method for verifying that DRAWING code is working correctly. It's not a good method for pretty much anything else in the GUI space.

    For real image searching, there are a lot of interesting tests. Juerd mentioned using the regex engine, which has its merits. There are other sparse comparisons which help find exact pixel matches of various swatches. Another poster mentioned image mosaicing methods like least squared errors, but those are better for situations where the alignment, rotation, scale, coloring of two images are not identical.

    Otherwise, please please please dig through the window manager to verify text strings, not pixels. Any change in the test user's Appearance preferences, or operating system version, or even a different video driver, would totally blow all your tests.

    --
    [ e d @ h a l l e y . c c ]

Re: GUI Automation - locate image
by zakzebrowski (Curate) on Mar 09, 2004 at 21:05 UTC
    Not sure if it will help, but look at the Win32::Clipboard module to progromatically do the clipboard capture of the image... good luck.


    ----
    Zak - the office

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://334919]
Approved by Popcorn Dave
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (7)
As of 2024-04-23 15:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found