Jump to content
joshtp

PixelSearch on an image file? (JPG, GIF, BMP)

Recommended Posts

joshtp

I'm in the process of writing a "Rain Notifier", where the user selects a region on a map, then periodically downloads the radar data from the National Weather Service and checks the selected area for the presence of rain, indicated by a certain set of colors. What I'm doing now is displaying the GIF after using GUICtrlCreatePic, and then using PixelSearch on that using the handle gotten by GuiCtrlGetHandle.

However, what I'd like to do is use PixelSearch on an image file, specifically a GIF in this case, instead of having to display the radar data on screen and then use PixelSearch. I've tried using some WinApi and GDIPlus code to do this, but I'm not familiar enough with those APIs to do this.

Anyone have any suggestions how to do this?

Thanks,

-Josh

Share this post


Link to post
Share on other sites
joshtp

I'm in the process of writing a "Rain Notifier", where the user selects a region on a map, then periodically downloads the radar data from the National Weather Service and checks the selected area for the presence of rain, indicated by a certain set of colors. What I'm doing now is displaying the GIF after using GUICtrlCreatePic, and then using PixelSearch on that using the handle gotten by GuiCtrlGetHandle.

However, what I'd like to do is use PixelSearch on an image file, specifically a GIF in this case, instead of having to display the radar data on screen and then use PixelSearch. I've tried using some WinApi and GDIPlus code to do this, but I'm not familiar enough with those APIs to do this.

Anyone have any suggestions how to do this?

Thanks,

-Josh

If AutoIt cannot do this natively, is there some standalone binary that can do this for me that I can integrate into my script? Thank you

Share this post


Link to post
Share on other sites
joshtp

It appears that there is no possible way to do this natively in AutoIt, other than reading in the BMP using _GDIPlus_BitmapCreateFromFile and then recreating the PixelSearch functionality again. Somone please correct me if I'm wrong. Thank you.

Share this post


Link to post
Share on other sites
joshtp

Okay, this isn't working but it seems very close. Can someone please take a look at it and tell me if I'm on the right track? The image I'm using is:

(from Wikimedia )

#include <GDIPlus.au3>

$imageFile=@TempDir&"\image.gif"
InetGet("http://upload.wikimedia.org/wikibooks/en/7/70/Editing.gif",$imageFile,1)

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile ($imageFile)
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap ($hImage)
$width = _GDIPlus_ImageGetWidth($hImage)
$height = _GDIPlus_ImageGetHeight($hImage)

$array=PixelSearch(0,0,$width-1,$height-1,0x000000,0,1,$hBitmap)
If @error Then
    MsgBox(0,"","Not found")
Else
    MsgBox(0,"",$array[0]&","&$array[1])
EndIf

_GDIPlus_ImageDispose ($hImage)
_WinAPI_DeleteObject ($hBitmap)
_GDIPlus_Shutdown()

Thank you all in advance for any input!

Share this post


Link to post
Share on other sites
Nat_H

Hi :)

It feels wrong to drag up something from 2008, but this is exactly what i'm trying to do. :) Unfortunately, i'm kinda struggling too. Did anyone manage to make this (or similar) work? 

Just to be clear, I would like to be able to use PixelSearch against an Image file rather than the screen, and it feels like the example above shouldn't be far off? 

I suppose I'd ask why too, I guess, so here's what I'm doing:

i have created a service which takes a snapshot of a website on a regular basis. It uses PhantomJS to render the page directly to a PNG file. 

The arrangement of the website changes regularly, but there is an area I want to capture as an image which always starts with an identifiable colour block. This crop needs to be saved as an image so that it can be incorporated in another service.

I currently open the PNG in full screen and use PixelSearch to locate the start of the colour block, then use the XY coordinates returned to crop the image using calls to ImageProcessor.  The process works well, but at the moment the use of PixelSearch mandates that this process runs in a console so that the image can be opened and searched.  If there were a way to use PixelSearch against an image file, the whole thing could be neatly wrapped into a scheduled task that wouldn't require the console to be logged on. 

Any advice gratefully received :)

Nat

Share this post


Link to post
Share on other sites
careca

i've seen that, it analises the image file's bytes, searches for a hex pattern. I think i was called something like "image search alternative" or something like it.

On a side note, you could retrieve the image from the site with IE functions.

 

Edited by careca

Spoiler

Paster - Main function is to paste text, but has more functions. (No longer mantained, switched to String Trigger)

Renamer - Rename files and folders, remove portions of text from the filename etc.

GPO Tool - Export/Import Group policy settings.

MirrorDir - Synchronize/Backup/Mirror Folders

BeatsPlayer - Music player.

Params Tool - Right click an exe to see it's parameters or execute them.

String Trigger - Triggers pasting text or applications or internet links on specific strings.

Inconspicuous - Hide files in plain sight, not fully encrypted.

Regedit Control - Registry browsing history, quickly jump into any saved key.

Time4Shutdown - Write the time for shutdown in minutes.

Power Profiles Tool - Set a profile as active, delete, duplicate, export and import.

Firefox Profile Backup - Backup/restore previously saved profile.

Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes.

NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s.

IUIAutomation - Topic with framework and examples

Au3Record.exe

Share this post


Link to post
Share on other sites
BatMan22

If you're willing to use a BMP instead I would look at the links below. I just used his script and gutted it a bit, works great.

 

 

Share this post


Link to post
Share on other sites
Nat_H

Thanks very much for the suggestions guys, they helped me find a way to do what I wanted to do :D

Unfortunately, I really needed the "tolerance" feature of PixelSearch as the colour of the area i'm searching for changes with the weather. Because of this, using the FindBMP style searches wouldn't quite do what I wanted. There are some brilliant solutions for searching live windows, or finding BMPs within BMPs, or BMPs on the desktop! They just didn't quite work for my purpose (and I accept that my purpose is a lost cause, but I really wanted a *pretty* weather panel on my ActionTiles dashboard >.> It only supports displaying an external Image, not a web part.) 

Another hurdle was that the section of the site I wanted to capture is a composite weather report (https://www.bbc.co.uk/weather/0/2650225 for example), not a single image, and it's scripted to boot, so not easy to just fetch. To use it, I had to capture it as an image first, then crop to the bit I want.  

In the end, I did this to search for the coloured bar under the place name. It's ugly, and most likely not the correct way to do such a thing, but in case anyone else was (foolishly) trying to do the same thing as me, here's how I managed a PixelSearch with tolerance on an Image File.  (if there are any glaring mistakes, feel free to point them out !)

Thanks again all :)

 

#include <GDIPlus.au3>
#include <Color.au3>

;Details of the image we are about to search
$webShotPath="C:\Scripts\weather-shot\Shots\httpswww.bbc.co.uk.png" 

_GDIPlus_Startup()

;All of this shiz gets an image file into memory somewhere, in a way it can be queried by GetPixel
$hImage = _GDIPlus_ImageLoadFromFile ($imageFile)
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap ($hImage)
$DeskDC = _WinAPI_GetDC(0)
$UseDC = _WinAPI_CreateCompatibleDC($DeskDC)
_WinAPI_ReleaseDC(0, $DeskDC)
_WinAPI_SelectObject($UseDC,$hBitmap)

;Now we have something we can work with, lets go search. This only looks down 1 column of pixels. You could easily modify this to reapeat for a search area
$xStatic = 160
$yMax = 300
$xMax = 200

;And for which colours?
local $arrColours[7] = [0,"0x9ecb86", "0xfcc90d", "0xd0d73e", "0xafd251", "0xffda01","0xAAD6AE"]
local $arrCNames[7] = [0,"#Minty", "#GoldenYellow", "#Mustard", "#PeaSoup", "#yellow","#Known"]
$iTolerance = 20

$foundY=0
$foundX=0
$foundColour=0

for $a=1 to UBound($arrColours)-1 step 1

   $iTestColour = $arrColours[$a]
   ConsoleWrite("Setting colour to " & $arrCNames[$a] & @CRLF)

   for $y = 0 to $yMax step 1
      Local $Color = DLLCall("gdi32.dll","int","GetPixel","int",$UseDC ,"int",$xStatic,"int",$y)
      
      ;For some reason, Hex($Color[0],6) returns BlueGreenRed, not RedGreenBlue. Dirty way to flip to RGB for comparrison     
      Local $aArray = StringRegExp(Hex($Color[0],6), "(.)", 3)
      $var = "0x"&$aArray[4]&$aArray[5]&$aArray[2]&$aArray[3]&$aArray[0]&$aArray[1]
      
      If (Abs(_ColorGetRed($var) - _ColorGetRed($iTestColour)) <=  $iTolerance) _
         And (Abs(_ColorGetBlue($var) - _ColorGetBlue($iTestColour)) <=  $iTolerance) _
         And (Abs(_ColorGetGreen($var) - _ColorGetGreen($iTestColour)) <=  $iTolerance) Then

         $foundY=$y
         $foundColour=$a
         ExitLoop
      EndIf
   Next

   if $foundY > 0 then
      ConsoleWrite("Found Y at "&$foundY&@CRLF)
      ExitLoop
   EndIf
Next

if $foundColour > 0 then
   ;We found Y, so lets find X.
   ConsoleWrite("Attempting to find X"&@CRLF)

   for $x = 0 to $xMax step 1
      Local $Color = DLLCall("gdi32.dll","int","GetPixel","int",$UseDC ,"int",$x,"int",$foundY)

      ;For some reason, Hex($Color[0],6) returns BlueGreenRed, not RedGreenBlue. Dirty way to flip to RGB for comparrison     
      Local $aArray = StringRegExp(Hex($Color[0],6), "(.)", 3)
      $var = "0x"&$aArray[4]&$aArray[5]&$aArray[2]&$aArray[3]&$aArray[0]&$aArray[1]

      If (Abs(_ColorGetRed($var) - _ColorGetRed($iTestColour)) <=  $iTolerance) _
         And (Abs(_ColorGetBlue($var) - _ColorGetBlue($iTestColour)) <=  $iTolerance) _
         And (Abs(_ColorGetGreen($var) - _ColorGetGreen($iTestColour)) <=  $iTolerance) Then

         $foundX=$x
         ExitLoop
      EndIf
   Next

   ConsoleWrite("Found! at "&$foundX&","&$foundY&" in "&$arrCNames[$foundColour]&@CRLF)
   RegWrite("HKEY_CURRENT_USER\Foxes\WeatherCrop", "xy", "REG_SZ", $foundX&","&$foundY)

Else
   ConsoleWrite("Nope, Couldnt find a match. :("&@CRLF)
EndIf

_WinAPI_DeleteDC($UseDC)
_GDIPlus_ImageDispose ($hImage)
_WinAPI_DeleteObject ($hBitmap)
_GDIPlus_Shutdown()

 

Edited by Nat_H

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×