Delta Posted December 31, 2009 Share Posted December 31, 2009 (edited) I have a function that searches an image file for a specific pixel color. It works great but it's EXTREMELY slow. Does anyone know of a way to optimize it? I'd even settle for a whole new function. Please ignore the indenting the AutoIt code tags are a bit weird.expandcollapse popup; (Image file location, Pixel color, Tolerance) Func ImageGetPP($image, $pColor, $pTolerance) Local $hImage, $iWidth, $iHeight, $hBitmap, $iBitmap, $stride, $Scan0, $v_Buffer, $v_Value, $Pos[2] $hImage = _GDIPlus_ImageLoadFromFile($image) $iWidth = _GDIPlus_ImageGetWidth($hImage) $iHeight = _GDIPlus_ImageGetHeight($hImage) $hBitmap = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iWidth, $iHeight, $GDIP_PXF32ARGB) $iBitmap = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB) $R = _ColorGetRed($pColor) $G = _ColorGetGreen($pColor) $B = _ColorGetBlue($pColor) $stride = DllStructGetData($iBitmap, "stride") $Scan0 = DllStructGetData($iBitmap, "Scan0") For $i = 0 To $iWidth - 1 For $j = 0 To $iHeight - 1 $v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4)) $v_Value = DllStructGetData($v_Buffer, 1) $CPR = _ColorGetRed($v_Value) $CPG = _ColorGetGreen($v_Value) $CPB = _ColorGetBlue($v_Value) If $CPR + $pTolerance >= $R And $CPG + $pTolerance >= $G And $CPB + $pTolerance >= $B Then If $CPR - $pTolerance <= $R And $CPG - $pTolerance <= $G And $CPB - $pTolerance <= $B Then $Pos[0] = $i $Pos[1] = $j _GDIPlus_BitmapUnlockBits($hBitmap, $iBitmap) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_ImageDispose($hImage) Return $Pos EndIf EndIf Next Next _GDIPlus_BitmapUnlockBits($hBitmap, $iBitmap) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_ImageDispose($hImage) Return 0 EndFunc Edited December 31, 2009 by Deltaforce229 [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
MvGulik Posted January 1, 2010 Share Posted January 1, 2010 suggestion: with "$v_Buffer = DllStructCreate ..." your buffering only a single pixel. You might speed things up by buffering a single line, or the whole image. "Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions.""The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014) "Believing what you know ain't so" ... Knock Knock ... Link to comment Share on other sites More sharing options...
Zedna Posted January 1, 2010 Share Posted January 1, 2010 Also maybe Prospeed DLL/UDF can help youhttp://www.autoitscript.com/forum/index.php?showtopic=38549 Resources UDF ResourcesEx UDF AutoIt Forum Search Link to comment Share on other sites More sharing options...
AndyG Posted January 2, 2010 Share Posted January 2, 2010 (edited) maybe this solves your problem.... expandcollapse popup#include <GUIConstantsEx.au3> #include <WinAPI.au3> #include <GDIPlus.au3> #include <GDIPlusConstants.au3> #include <StructureConstants.au3> #include <Array.au3> $bitmapfile = "test.bmp" ;works with JPG too... If FileExists(@ScriptDir & "\prospeed.dll") Then global $Prospeedflag = True global $prospeed_dll = DllOpen(@ScriptDir & "\ProSpeed.dll") Else global $prospeedflag= false endif $t = TimerInit() $aCoord = _findpixelinbmpfile($bitmapfile, 0xFFAABB) ;only 24bpp, color in RGB $m = TimerDiff($t) If IsArray($aCoord) Then MsgBox(0, "col / row", $aCoord[0] & " / " & $aCoord[1] & @CRLF & $m) Else MsgBox(0, 0, "pixel not found " & $m) EndIf _GDIPlus_Shutdown() Func _findpixelinbmpfile($bmpfile, $color) ;only 24bpp, returns 0 if miss, returns array with x- and y-koordinates $t=timerinit() Dim $Coord[2] _GDIPlus_Startup() $pBitmap = _GDIPlus_BitmapCreateFromFile($bmpfile) If @error Then MsgBox(0, "", "Error BitmapCreateFromFile") $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB) If @error Then MsgBox(0, "", "Error locking region " & @error) $stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. if $prospeedflag=True then $struct = DllStructCreate("byte[3]") ;for the color DllStructSetData($struct, 1, $color) ;writes the 3-byte colour into the struct $ptr = DllStructGetPtr($struct) $i = FindBytes( $Scan0, 0, (Abs($stride) * ($Height)), $ptr, 3) + 1 Else $pixeldata = DllStructCreate("byte[" & (Abs($stride) * ($Height)) & "]", $Scan0) $BMPData = BinaryToString(DllStructGetData($pixeldata, 1)) $bincol = StringTrimRight(BinaryToString($color), 1) ;string of the color $i = StringInStr($BMPData, $bincol) ;first position of the 3 color-bytes EndIf While $i <> 0 $r = Mod($i, $stride) + 2 If Mod($r, 3) = 0 Then ;only if the 3 color-bytes are in one pixel $Coord[0] = $r / 3 $Coord[1] = Int($i / $stride) + 1 _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _GDIPlus_Shutdown() Return $Coord Else If $Prospeedflag Then $i = FindBytes( $Scan0, $i + 1, (Abs($stride) * ($Height))-$i, $ptr, 3) + 1 Else $i = StringInStr($BMPData, $bincol, 0, 1, $i + 1) ;start an letzter position EndIf EndIf WEnd _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _GDIPlus_Shutdown() Return 0 EndFunc ;==>_findpixelinbmpfile Func FindBytes( $b, $O, $a, $S, $l) ;needed if prospeed.dll is used Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _ "long", $b, _ "long", $O, _ "long", $a, _ "long", $S, _ "long", $l) Return $S_FindBytes[0] EndFunc ;==>FindBytesIf the prospeed.dll is in the scriptdirectory, then the dll is used automatically. If not, AutoIt stringinstr() (which is very fast with not very long strings) finds the pixelposition. /EDIT/ opendll outside the function speeds up multiple use of the function Edited January 6, 2010 by AndyG Link to comment Share on other sites More sharing options...
Delta Posted January 2, 2010 Author Share Posted January 2, 2010 (edited) Thanks guys prospeed did the trick. AndyG thanks for the code it works like a dream. I have one gripe though and that's that I needed the pixel tolerance portion of the code. Edit: I think I got it figured out though. If it turns out I'm wrong I'll post back. Thanks again. Edited January 2, 2010 by Deltaforce229 [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
Delta Posted January 2, 2010 Author Share Posted January 2, 2010 Alright so I didn't figure out how to add tolerance to it and prospeed seems to be causing AutoIt to crash with "autoit3.exe has encountered a problem and needs to close. We are sorry for the inconvenience." when it finds the color. If it helps I'm using the script to track a colored target on my camera. [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
AndyG Posted January 3, 2010 Share Posted January 3, 2010 Hi, because you did´nt post your script i don´t know exactly what you are looking for. Searching for a "tolerance" is nothing but vary the colors. The color is 0xRRGGBB so if you are looking for a color with a tolerance of 10 you could vary RR+-10, GG+-10, BB+-10.$tolerance = 10 $color = 0xAABBCC $Red = BitAND(BitShift($color, 16), 0xFF) ;red $Green = BitAND(BitShift($color, 8), 0xFF) ;green $Blue = BitAND($color, 0xFF) ;blue For $vary_Red = $Red - $tolerance To $Red + $tolerance ;red from AA-10 to AA+10 For $vary_Green = $Green - $tolerance To $Green + $tolerance ;green from BB-10 to BB+10 For $vary_blue = $Blue To $Blue + $tolerance $color = $vary_blue + 256 * $vary_Green + 256 * 256 * $vary_Red ConsoleWrite( hex($color,6) & @CRLF ) Next Next Next Link to comment Share on other sites More sharing options...
MvGulik Posted January 3, 2010 Share Posted January 3, 2010 The color is 0xRRGGBB so if you are looking for a color with a tolerance of 10 you could vary RR+-10, GG+-10, BB+-10.That sound like a major speed bump, a tolerance of 10 give a whopping 9261 variations.I wounder how much faster ProSpeed is compared to a optimized version of the original posted principal when it comes to just scanning for a particular pixel-color. ... "Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions.""The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014) "Believing what you know ain't so" ... Knock Knock ... Link to comment Share on other sites More sharing options...
AndyG Posted January 3, 2010 Share Posted January 3, 2010 That sound like a major speed bump, a tolerance of 10 give a whopping 9261 variations. In prospeed.dll, there is the "comparebytes" function, which is able to compare two bytes (or bunch of bytes, or files) with a tolerance. This is much more faster if you can use it in your application. Link to comment Share on other sites More sharing options...
Delta Posted January 3, 2010 Author Share Posted January 3, 2010 (edited) That sound like a major speed bump, a tolerance of 10 give a whopping 9261 variations. I wounder how much faster ProSpeed is compared to a optimized version of the original posted principal when it comes to just scanning for a particular pixel-color. ... In prospeed.dll, there is the "comparebytes" function, which is able to compare two bytes (or bunch of bytes, or files) with a tolerance. This is much more faster if you can use it in your application. It seems to be faster but when you add a tolerance it's not as fast. Unfortunatly I can't give you a direct answer because as soon as the "While $i <> 0" loop kicks in prospeed causes AutoIt to crash. It was working fine when I first tried it out then I modded the code (I just stripped out the none prospeed stuff AndyG posted.) a bit and it crashed. So I reverted it back and it still crashes. It's driving me up the wall. Edit: Since you need it to more accurately help me here's the full of what I'm doing. expandcollapse popup;========================= ; Configuration Options ;========================= $W = 320 $H = 240 $Color = 0xFFFFFF $Tolerance = 10 ;========================= ; Main Script ;========================= #include <GUIConstants.au3> #include <WindowsConstants.au3> #include <StaticConstants.au3> #include <Color.au3> #include <GDIPlus.au3> #include <Webcam.au3> Opt("GUIOnEventMode", 1) $CTGui = GUICreate("CamTracker", $W, $H + 25, -1, -1, BitOR($WS_MINIMIZEBOX, $WS_SYSMENU, $WS_CAPTION, $WS_POPUP, $WS_POPUPWINDOW, $WS_GROUP, $WS_BORDER)) $CTS = GUICtrlCreateLabel("Starting CamTracker...", 0, $H + 5, $W, 20, $SS_CENTER) GUICtrlSetFont(-1, 10, 800) GUISetState() $CTGGui = GUICreate("Tracking Grid", $W + 4, $H + 4, -1, -1, BitOR($WS_CAPTION, $WS_POPUP, $WS_BORDER, $WS_CLIPSIBLINGS), 0, $CTGui) GUISetState() _Reposition("CamTracker", "Tracking Grid") GUISetOnEvent($GUI_EVENT_CLOSE, "GuiEvent", $CTGui) GUISetOnEvent($GUI_EVENT_MINIMIZE, "GuiEvent", $CTGui) GUISetOnEvent($GUI_EVENT_RESTORE, "GuiEvent", $CTGui) If FileExists(@ScriptDir & "\prospeed.dll") Then Global $prospeed_dll = DllOpen(@ScriptDir & "\ProSpeed.dll") Else MsgBox(48, "Missing DLL", "Missing ProSpeed.dll") Exit EndIf _GDIPlus_Startup() $hWnd = WinGetHandle("Tracking Grid") $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWnd) $hBrush = _GDIPlus_BrushCreateSolid(0xFFFF0000) $hPen = _GDIPlus_PenCreate(0x00000000, 1) _DrawGrid($hGraphic, $hPen, 1, 1, $W, $H, 10) $CTCid = _WebcamOpen($CTGui, 0, 0, $W, $H) Dim $lX, $lY, $lState = True, $Found = False While 1 _Reposition("CamTracker", "Tracking Grid") $Snap = _WebcamSnap($CTCid, "snap.bmp") $Red = BitAND(BitShift($Color, 16), 0xFF) ;red $Green = BitAND(BitShift($Color, 8), 0xFF) ;green $Blue = BitAND($Color, 0xFF) ;blue $Found = False $Count = 0 $Timer = TimerInit() For $vary_Red = $Red - $Tolerance To $Red + $Tolerance ;red from AA-10 to AA+10 For $vary_Green = $Green - $Tolerance To $Green + $Tolerance ;green from BB-10 to BB+10 For $vary_blue = $Blue To $Blue + $Tolerance $Count = $Count + 1 GUICtrlSetData($CTS, "Searching("&$Count&")") $Color = $vary_blue + 256 * $vary_Green + 256 * 256 * $vary_Red $PixelPos = _findpixelinbmpfile("snap.bmp", Hex($Color, 6)) If IsArray($PixelPos) Then $Found = True ExitLoop(3) EndIf Next Next Next ConsoleWrite(TimerDiff($Timer)) If $Found = True Then If $PixelPos[0] <> $lX And $PixelPos[1] <> $lY Then $lState = True GUICtrlSetData($CTS, "Target found at " & $PixelPos[0] & ":" & $PixelPos[1]) _GDIPlus_GraphicsClear($hGraphic, 0xFFD4D0C8) _DrawGrid($hGraphic, $hPen, 1, 1, $W, $H, 10) _GDIPlus_GraphicsFillEllipse($hGraphic, $PixelPos[0] + 1, $PixelPos[1] + 1, 5, 5, $hBrush) EndIf Else If $lState = True Then $lState = False GUICtrlSetData($CTS, "Target not found!") _GDIPlus_GraphicsClear($hGraphic, 0xFFD4D0C8) _DrawGrid($hGraphic, $hPen, 1, 1, $W, $H, 10) EndIf EndIf Sleep(100) WEnd ;========================= ; Functions ;========================= Func GuiEvent() Select Case @GUI_CtrlId = $GUI_EVENT_CLOSE _WebcamClose($CTCid) _GDIPlus_PenDispose($hPen) _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGraphic) _GDIPlus_Shutdown() DllClose($prospeed_dll) Exit Case @GUI_CtrlId = $GUI_EVENT_RESTORE _DrawGrid($hGraphic, $hPen, 1, 1, $W, $H, 10) EndSelect EndFunc ;==>GuiEvent Func _findpixelinbmpfile($bmpfile, $Color) ;only 24bpp, returns 0 if miss, returns array with x- and y-koordinates Dim $Coord[2] $pBitmap = _GDIPlus_BitmapCreateFromFile($bmpfile) If @error Then MsgBox(0, "", "Error BitmapCreateFromFile") $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB) If @error Then MsgBox(0, "", "Error locking region " & @error) $stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. $struct = DllStructCreate("byte[3]") ;for the color DllStructSetData($struct, 1, $Color) ;writes the 3-byte colour into the struct $ptr = DllStructGetPtr($struct) $i = FindBytes($Scan0, 0, (Abs($stride) * ($Height)), $ptr, 3) + 1 While $i <> 0 ConsoleWrite("$i <> 0") $r = Mod($i, $stride) + 2 If Mod($r, 3) = 0 Then ;only if the 3 color-bytes are in one pixel $Coord[0] = $r / 3 $Coord[1] = Int($i / $stride) + 1 _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) Return $Coord Else $i = FindBytes($Scan0, $i + 1, (Abs($stride) * ($Height)), $ptr, 3) + 1 EndIf WEnd _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) Return 0 EndFunc ;==>_findpixelinbmpfile Func FindBytes($b, $O, $a, $S, $l) Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _ "long", $b, _ "long", $O, _ "long", $a, _ "long", $S, _ "long", $l) Return $S_FindBytes[0] EndFunc ;==>FindBytes Func _Reposition($Master, $Slave) Global $gui_pos_check_left, $gui_pos_check_top, $gui_pos_check_right, $gui_pos_check_bottom $Pos = WinGetHandle($Master) $Pos = _WinAPI_GetWindowRect($Pos) If $gui_pos_check_left <> DllStructGetData($Pos, "Left") Or _ $gui_pos_check_top <> DllStructGetData($Pos, "Top") Or _ $gui_pos_check_right <> DllStructGetData($Pos, "Right") Or _ $gui_pos_check_bottom <> DllStructGetData($Pos, "Bottom") Then $gui_pos_check_left = DllStructGetData($Pos, "Left") $gui_pos_check_top = DllStructGetData($Pos, "Top") $gui_pos_check_right = DllStructGetData($Pos, "Right") $gui_pos_check_bottom = DllStructGetData($Pos, "Bottom") $MainWindowPos = WinGetPos($Master) WinMove($Slave, "", $MainWindowPos[0] + $MainWindowPos[2], $MainWindowPos[1]) EndIf EndFunc ;==>_Reposition Func _DrawGrid($gHandel, $pHandel, $StartX, $StartY, $EndX, $EndY, $Space) $Width = $EndX - $StartX $Height = $EndY - $StartY $HCount = Round($Width / $Space) $VCount = Round($Height / $Space) ; H Lines _GDIPlus_GraphicsDrawLine($gHandel, $StartX, $StartY, $EndX, $StartY) For $i = $StartX To $VCount _GDIPlus_GraphicsDrawLine($gHandel, $StartY, ($i * $Space) + $StartX, $EndX, ($i * $Space) + $StartX) Next ; V Lines _GDIPlus_GraphicsDrawLine($gHandel, $StartY, $StartX, $StartX, $EndY) For $i = $StartY To $HCount _GDIPlus_GraphicsDrawLine($gHandel, ($i * $Space) + $StartX, $StartY, ($i * $Space) + $StartY, $EndY) Next EndFunc ;==>_DrawGrid Edited January 3, 2010 by Deltaforce229 [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
AndyG Posted January 4, 2010 Share Posted January 4, 2010 $PixelPos = _findpixelinbmpfile("snap.bmp", Hex($Color, 6))the "color"-Parameter should be an integer, not a string! So try $PixelPos = _findpixelinbmpfile("snap.bmp", $Color) Link to comment Share on other sites More sharing options...
MvGulik Posted January 4, 2010 Share Posted January 4, 2010 Profided I did not mesh up somewhere, A general compare between a pure Autoit(scan) versus ProSpeed(find) comes down to about 1/400, so no contest. When AutoIt crashed on me was because I fed ProSpeed a zero image pointer. Imagine it could do the same with other inconsistent input data. "Straight_and_Crooked_Thinking" : A "classic guide to ferreting out untruths, half-truths, and other distortions of facts in political and social discussions.""The Secrets of Quantum Physics" : New and excellent 2 part documentary on Quantum Physics by Jim Al-Khalili. (Dec 2014) "Believing what you know ain't so" ... Knock Knock ... Link to comment Share on other sites More sharing options...
Delta Posted January 4, 2010 Author Share Posted January 4, 2010 $PixelPos = _findpixelinbmpfile("snap.bmp", Hex($Color, 6))the "color"-Parameter should be an integer, not a string! So try $PixelPos = _findpixelinbmpfile("snap.bmp", $Color) That hex code was what you gave me and is correct, sort of. The color should be in the format 0xFFFFFF. Hex($Color, 6) gives FFFFFF without the 0x. [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
AndyG Posted January 4, 2010 Share Posted January 4, 2010 Hex($Color, 6) gives FFFFFF without the 0x....and this is not correct in the function call findpixelinbmpfile() !0xFFAABB is an other spelling of the number 16755387, HEX(0xFFAABB) is not the same.... Link to comment Share on other sites More sharing options...
Delta Posted January 5, 2010 Author Share Posted January 5, 2010 ...and this is not correct in the function call findpixelinbmpfile() !0xFFAABB is an other spelling of the number 16755387, HEX(0xFFAABB) is not the same....I'm getting very confused now and unfortunately very angry.0xFFAABB IS NOT BEING HEXED! The value for $Color after it has gone through "$Color = $vary_blue + 256 * $vary_Green + 256 * 256 * $vary_Red" is.At that point $Color = 16755387.Then the Hex part changes it to FFAABB.Your code as you first posted it requires 0xFFAABB not 16755387 and not FFAABB so why has it suddenly magically changed to an integer value now? [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
AndyG Posted January 5, 2010 Share Posted January 5, 2010 (edited) Your code as you first posted it requires 0xFFAABB not 16755387 and not FFAABB so why has it suddenly magically changed to an integer value now?nothing changed^^ Run this script, have a look at it and i hope you will see the difference...expandcollapse popup$a = 11189196 ;this is a number, right? But if this is a color, no one can "see" the part ;which represents the red, green, blue part of the color $b = 0xAABBCC ;this is an other spelling of the number 11189196, but its still a number, only difference to $a is, ;you can "see" that red is AA, green is BB and blue is CC $c = "AABBCC" ;This is a string, a bunch of some letters ;ok, lets play around... $d = Hex($a,6) ;This is the same as $c, Hex() converts a NUMBER to a STRING $e = Dec("AABBCC") ;DEC() converts a STRING to a NUMBER ;Lets eleminate the whole green part of a colorNUMBER, how would you do this? ;The first solution could be to convert the colorNUMBER to a string, replace the green part ;with 0, and convert the string to a number... ;Second solution: take the number, extract the "red and blue part" with some bitoperations ;and store this without to consider the "green part" ; ;Lets start with our first solution: msgbox(0,"","First solution....",1) $colorstring = hex($a,6) ;converts a number to a string, you could also take hex($b,6), it´s the same!!!!! Msgbox(0,"convert the number "& $b &" to a string", _ "number $a= " &$a & @CRLF & _ "number $b= " &$b & " which is 0xAABBCC"& @CRLF & _ "string $colorstring= "&$colorstring) $RED_string = stringmid($colorstring,1,2) ;part reperesenting the red color as a string $GREEN_string = stringmid($colorstring,3,2) ;part reperesenting the green color as a string $BLUE_string = stringmid($colorstring,5,2) ;part reperesenting the blue color as a string ;lets make numbers $RED_number = Dec($RED_string) ;the number of the red color $GREEN_number = Dec($GREEN_string) ;the number of the green color $BLUE_number = Dec($BLUE_string) ;the number of the blue color msgbox(0,"show the parts of the color "&$a, _ "RED : " & $RED_string &" "&$RED_number & @CRLF & _ "GREEN : " & $GREEN_string&" "&$GREEN_number & @CRLF & _ "BLUE : " & $BLUE_string &" "&$BLUE_number) $GREEN_string = "00" ;we work with strings, so convert the green part to 0 $colorstring1 = $RED_string & $GREEN_string & $BLUE_string ;put the strings together $colornumber1 = Dec($colorstring1) ;convert the string to a number msgbox(0,"We have eliminated the green part of the color...", _ "$colorstring = "&$colorstring1 & @CRLF & _ "$colornumber = "&$colornumber1) ;second solution.... msgbox(0,"","Second solution....",1) $RED_part = bitand($a,0xFF0000) ;extract only the RR-part from the number $RED_part = bitand($a,16711680) ;extract only the RR-part from the number, 16711680=0xFF0000 , ;but nobody can "SEE" what will happens with this number...all clear now? ;o) $GREEN_part = bitand($a,0x00FF00) ;we write 0x00FF00 to "SEE" what we will do... $BLUE_part = bitand($a,0x0000FF) ;we write 0x0000FF to "SEE" what we will do... $colornumber2 = $RED_part + $BLUE_part;add red and blue part, remember that green part is 0, we have finished here... $colorstring2 = Hex($colornumber2,6) ;convert the number to a string to show it in the msgbox msgbox(0,"We have eliminated the green part of the color...", _ "$colorstring = "&$colorstring2 & @CRLF & _ "$colornumber = "&$colornumber2) ;we could play around with the parts...converting $RED_part to $RED_number $RED_number = bitshift($RED_part,16) ;transform 0xRR0000 to 0x0000RR, the same as divide with (256*256=65536) $GREEN_number = bitshift($GREEN_part,8) ;transform 0x00GG00 to 0x0000GG, the same as divide with 256 $BLUE_number = $BLUE_part ;we dont need to transform, because 0x0000BB = 0x0000BB $RED_string = Hex($RED_number,2) ;we want to show it in the msgbox $GREEN_string = Hex($GREEN_number,2) ;we want to show it in the msgbox $BLUE_string = Hex($BLUE_number,2) ;we want to show it in the msgbox msgbox(0,"show the parts of the color "&$a, _ "RED : " & $RED_string &" "&$RED_number & @CRLF & _ "GREEN : " & $GREEN_string&" "&$GREEN_number & @CRLF & _ "BLUE : " & $BLUE_string &" "&$BLUE_number) ;I hope that I have eliminated all clarity for now... :o) /EDIT/ edit copypaste errors... Edited January 5, 2010 by AndyG Link to comment Share on other sites More sharing options...
AndyG Posted January 5, 2010 Share Posted January 5, 2010 it requires 0xFFAABB not 16755387what is the difference? $a=0xFFAABB $b=16755387 msgbox(0,$a,$b) Link to comment Share on other sites More sharing options...
jvanegmond Posted January 5, 2010 Share Posted January 5, 2010 (edited) Deltaforce, instead of creating the struct over and over in the loop, reuse it. Try with DllStructGetData and DllStructSetData, use it like you would a variable. P.S. Are you sure you even need it? Edited January 5, 2010 by Manadar github.com/jvanegmond Link to comment Share on other sites More sharing options...
AndyG Posted January 5, 2010 Share Posted January 5, 2010 (edited) Hi, @deltaforce, your script (Post#1) is very fast, the higher the tolerance is! I´ve modified it a little bit so it is 2-3 times faster nowexpandcollapse popup#include <Color.au3> #include <GDIPlus.au3> #include <GDIPlusConstants.au3> _GDIPlus_Startup() $image = "mona-lisa.jpg" $pcolor = 0x688950 $ptolerance = 0 $t = TimerInit() $acoord = Imagegetpp($image, $pcolor, $ptolerance) $m = TimerDiff($t) If IsArray($acoord) Then MsgBox(0, "col / row", $acoord[0] & " / " & $acoord[1] & @CRLF & $m) Else MsgBox(0, 0, "pixel not found " & $m) EndIf ; (Image file location, Pixel color, Tolerance) Func ImageGetPP($image, $pcolor, $ptolerance) Local $hImage, $iWidth, $iHeight, $hBitmap, $iBitmap, $stride, $Scan0, $v_Buffer, $v_Value, $Pos[2] $hImage = _GDIPlus_ImageLoadFromFile($image) $iWidth = _GDIPlus_ImageGetWidth($hImage) $iHeight = _GDIPlus_ImageGetHeight($hImage) $hBitmap = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iWidth, $iHeight, $GDIP_PXF24RGB) $iBitmap = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF24RGB) $R = _ColorGetRed($pcolor) $G = _ColorGetGreen($pcolor) $B = _ColorGetBlue($pcolor) $stride = DllStructGetData($iBitmap, "stride") $Scan0 = DllStructGetData($iBitmap, "Scan0") $v_Buffer = DllStructCreate("byte[" & $stride * $iHeight & "]", $Scan0) For $j = 0 To $iHeight - 1 For $i = 0 To $iWidth - 1 $cpr = DllStructGetData($v_Buffer, 1, ($j * $stride) + ($i * 3) + 3) ;red If $cpr + $ptolerance >= $R And $cpr - $ptolerance <= $R Then $cpg = DllStructGetData($v_Buffer, 1, ($j * $stride) + ($i * 3) + 2) ;green If $cpg + $ptolerance >= $G And $cpg - $ptolerance <= $G Then $cpb = DllStructGetData($v_Buffer, 1, ($j * $stride) + ($i * 3) + 1) ;blue If $cpb + $ptolerance >= $B And $cpb - $ptolerance <= $B Then ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $CPR = ' & $cpr & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $CPG = ' & $cpg & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $CPB = ' & $cpb & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $Pos[0] = $i + 1 $Pos[1] = $j + 1 _GDIPlus_BitmapUnlockBits($hBitmap, $iBitmap) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_ImageDispose($hImage) Return $Pos EndIf EndIf EndIf Next Next _GDIPlus_BitmapUnlockBits($hBitmap, $iBitmap) _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_ImageDispose($hImage) Return 0 EndFunc ;==>ImageGetPP I have tested a version with prospeed "comparebytes"-function, but the overhead calling the dll made the script slower than your version in post #1 Here is my version with prospeed/stringinstr. It´s very fast finding the exact color and it will be slower and slower with higher toleranceexpandcollapse popup#include <GUIConstantsEx.au3> #include <WinAPI.au3> #include <GDIPlus.au3> #include <GDIPlusConstants.au3> #include <StructureConstants.au3> #include <Array.au3> $bitmapfile = "mona-lisa.jpg" $tolerance = 0 $color = 0x688950 If FileExists(@ScriptDir & "\prospeed.dll") Then Global $Prospeedflag = True Global $prospeed_dll = DllOpen(@ScriptDir & "\ProSpeed.dll") Else Global $Prospeedflag = False EndIf $t = TimerInit() $aCoord = _findpixelinbmpfile($bitmapfile, $color, $tolerance) ;only 24bpp, color in RGB $m = TimerDiff($t) If IsArray($aCoord) Then MsgBox(0, "col / row", $aCoord[0] & " / " & $aCoord[1] & @CRLF & $m) Else MsgBox(0, 0, "pixel not found " & $m) EndIf Func _findpixelinbmpfile($bmpfile, $color, $tolerance = 0) ;only 24bpp, returns 0 if miss, returns array with x- and y-koordinates $t = TimerInit() Dim $Coord[2] _GDIPlus_Startup() $pBitmap = _GDIPlus_BitmapCreateFromFile($bmpfile) If @error Then MsgBox(0, "", "Error BitmapCreateFromFile") $BitmapData = _GDIPlus_BitmapLockBits($pBitmap, 0, 0, _GDIPlus_ImageGetWidth($pBitmap), _GDIPlus_ImageGetHeight($pBitmap), $GDIP_ILMREAD, $GDIP_PXF24RGB) If @error Then MsgBox(0, "", "Error locking region " & @error) $stride = DllStructGetData($BitmapData, "Stride");Stride - Offset, in bytes, between consecutive scan lines of the bitmap. If the stride is positive, the bitmap is top-down. If the stride is negative, the bitmap is bottom-up. $Width = DllStructGetData($BitmapData, "Width");Image width - Number of pixels in one scan line of the bitmap. $Height = DllStructGetData($BitmapData, "Height");Image height - Number of scan lines in the bitmap. $pixelFormat = DllStructGetData($BitmapData, "PixelFormat");Pixel format - Integer that specifies the pixel format of the bitmap $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap. $m = TimerDiff($t) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $m = ' & $m & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $Red = BitAND(BitShift($color, 16), 0xFF) ;red $Green = BitAND(BitShift($color, 8), 0xFF) ;green $Blue = BitAND($color, 0xFF) ;blue For $vary_Red = $Red - $tolerance To $Red + $tolerance ;red from AA-10 to AA+10 For $vary_Green = $Green - $tolerance To $Green + $tolerance ;green from BB-10 to BB+10 For $vary_blue = $Blue To $Blue + $tolerance $color = $vary_blue + 256 * $vary_Green + 256 * 256 * $vary_Red ConsoleWrite(Hex($color, 6) & @CRLF) If $Prospeedflag = True Then $struct = DllStructCreate("byte[3]") ;for the color DllStructSetData($struct, 1, $color) ;writes the 3-byte colour into the struct $ptr = DllStructGetPtr($struct) $i = FindBytes($Scan0, 0, (Abs($stride) * ($Height)), $ptr, 3) + 1 Else $pixeldata = DllStructCreate("byte[" & (Abs($stride) * ($Height)) & "]", $Scan0) $BMPData = BinaryToString(DllStructGetData($pixeldata, 1)) $bincol = StringTrimRight(BinaryToString($color), 1) ;string of the color $i = StringInStr($BMPData, $bincol) ;first position of the 3 color-bytes EndIf While $i <> 0 $r = Mod($i, $stride) + 2 If Mod($r, 3) = 0 Then ;only if the 3 color-bytes are in one pixel $Coord[0] = $r / 3 $Coord[1] = Int($i / $stride) + 1 _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _GDIPlus_Shutdown() Return $Coord Else If $Prospeedflag Then $i = FindBytes($Scan0, $i + 1, (Abs($stride) * ($Height))-$i, $ptr, 3) + 1 Else $i = StringInStr($BMPData, $bincol, 0, 1, $i + 1) ;start an letzter position EndIf EndIf WEnd Next Next Next _GDIPlus_BitmapUnlockBits($pBitmap, $BitmapData) _GDIPlus_ImageDispose($pBitmap) _GDIPlus_Shutdown() Return 0 EndFunc ;==>_findpixelinbmpfile Func FindBytes($b, $O, $a, $S, $l) ;needed if prospeed.dll is used Local $S_FindBytes = DllCall($prospeed_dll, "long", "FindBytes", _ "long", $b, _ "long", $O, _ "long", $a, _ "long", $S, _ "long", $l) Return $S_FindBytes[0] EndFunc ;==>FindBytes Edited January 6, 2010 by AndyG Link to comment Share on other sites More sharing options...
Delta Posted January 6, 2010 Author Share Posted January 6, 2010 Alright it works and I thank you for helping me even though I was being a bit of an arse. I used your modification of my first post since I'm still getting weird crashes from prospeed. for some reason AutoIt + DLLs + My computer = Crash. Adding tolerances produces weird effects though nothing that's really a problem. If you have an image with only black and white pixels in it and you add a tolerance greater than 0 the pixel in row 1 column 1 is always going to be selected. Once again thank's and sorry for being an arse. @Manadar maybe you could explain structs and such to me on steam sometime. Right now I need to take a step back from all this right now since it was just a hobby project and nothing more. [size="1"]Please stop confusing "how to" with "how do"[/size] Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now