Paulie Posted April 20, 2009 Share Posted April 20, 2009 Hey guys,Basically, I'm trying to calculate the average color value of a JPG/JPEG image.I'm having the most difficulty with the JPEG format, since I don't really know how to derive color data from it, however, also, I'm still trying to figure out how to find the average of all the colors. For example: 0xFF0000 = Red0x0000FF = BlueAdded, they would equal 0xFF00FFDivide that by two, and i get 0x7F807FShouldn't it be somewhere between Red and Blue?Wish I understood this code here..http://www.empiregpservices.com/blog/post....lor-of-an-image Link to comment Share on other sites More sharing options...
monoceres Posted April 20, 2009 Share Posted April 20, 2009 The color data in jpeg files are compressed so you cannot just read it directly. Easiest way to do what you want would be to use _GDIPlus_BitmapLockBits(), do a search there are good examples floating around As for the avarage color calculation, the code on the page you linked used this: this.averageColor = r «« 16 | g «« 8 | b; Which would be equal to: $avarageColor = BitOR(BitShift($red, -16), BitShift($green, -8), $blue) In autoit Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
weaponx Posted April 20, 2009 Share Posted April 20, 2009 This reminds me of the new taskbar in Windows 7. When you hover over an icon the most frequent color is found to create a glowing background. Do you want the average color or the most frequent? Link to comment Share on other sites More sharing options...
Paulie Posted April 20, 2009 Author Share Posted April 20, 2009 This reminds me of the new taskbar in Windows 7. When you hover over an icon the most frequent color is found to create a glowing background. Do you want the average color or the most frequent?Probably Average.My goal is to do something basically similar to what that page I linked to did. Find a good color to use as an accent to a desktop image.My concern now, it that will it take very long to do that with all the pixels in a 1280x1024 pixel image? Link to comment Share on other sites More sharing options...
monoceres Posted April 20, 2009 Share Posted April 20, 2009 My concern now, it that will it take very long to do that with all the pixels in a 1280x1024 pixel image?Yes it will be very slow in autoit. But it's not like you need to use all pixels, skip every fifth pixel or so, I would be surprised if the result would be much different. Broken link? PM me and I'll send you the file! Link to comment Share on other sites More sharing options...
weaponx Posted April 20, 2009 Share Posted April 20, 2009 (edited) I was looking for a way to do this using ImageMagick and found this:PHP Example using Imagick:http://valokuva.org/?p=72This means you can do this from PHP, C++, or install the ImageMagick COM object and use AutoIt. Edited April 20, 2009 by weaponx Link to comment Share on other sites More sharing options...
KaFu Posted April 20, 2009 Share Posted April 20, 2009 (edited) Found this snippet a while ago to create an "eye-friendly" contrast... Func _CalcContrastColor($crBg) ; http://www.codeproject.com/KB/tips/JbColorContrast.aspx Local Const $TOLERANCE = 30 If ( _ Abs(BitAND($crBg, 0xFF) - 0x80) <= $TOLERANCE And _ Abs(BitAND(BitShift($crBg, 8), 0xFF) - 0x80) <= $TOLERANCE And _ Abs(BitAND(BitShift($crBg, 16), 0xFF) - 0x80) <= $TOLERANCE _ ) Then Return BitAND((0x7F7F7F + $crBg), 0xFFFFFF); Return BitXOR($crBg, 0xFFFFFF); EndFunc ;==>_CalcContrastColor Edit: Ups, a little of topic , would also recommend to try with ImageMagick... Edited April 20, 2009 by KaFu OS: Win10-22H2 - 64bit - German, AutoIt Version: 3.3.16.1, AutoIt Editor: SciTE, Website: https://funk.eu AMT - Auto-Movie-Thumbnailer (2022-Nov-26) BIC - Batch-Image-Cropper (2023-Apr-01) COP - Color Picker (2009-May-21) DCS - Dynamic Cursor Selector (2024-Feb-16) HMW - Hide my Windows (2018-Sep-16) HRC - HotKey Resolution Changer (2012-May-16) ICU - Icon Configuration Utility (2018-Sep-16) SMF - Search my Files (2023-Jun-03) - THE file info and duplicates search tool SSD - Set Sound Device (2017-Sep-16) Link to comment Share on other sites More sharing options...
weaponx Posted April 20, 2009 Share Posted April 20, 2009 Found this snippet a while ago to create an "eye-friendly" contrast...Well the entire image must be analyzed so this isn't quite enough. Link to comment Share on other sites More sharing options...
Paulie Posted April 20, 2009 Author Share Posted April 20, 2009 (edited) Ok I think i got it to work, but i'm not sure if there is a better way to do this... I don't really fully understand what the GDI+ functions are doing But i think it turned out fairly well with a small test image. However there is one problem and that is that it doesn't work on images 1280x1024 Heres what I got, I'm sure it can be optomized expandcollapse popup#include <GDIPlus.au3> #include <Array.au3> #include <Color.au3> _GDIPlus_Startup() $fname1 = FileOpenDialog("First image", "", "All images(*.bmp;*.jpg;*.png;)") If $fname1 = "" Then Exit $bm1 = _GDIPlus_ImageLoadFromFile($fname1) $Result = AverageColor($bm1) MsgBox(0, "", $Result) GUICreate("") GUISetBkColor(Number($Result)) GUISetState() While 1 If GUIGetMsg() = -3 Then Exit WEnd _GDIPlus_ImageDispose($bm1) _GDIPlus_Shutdown() Func AverageColor($bm1) $Width = _GDIPlus_ImageGetWidth($bm1) $Height = _GDIPlus_ImageGetHeight($bm1) $Count = $Width * $Height $BitmapData1 = _GDIPlus_BitmapLockBits($bm1, 0, 0, $Width, $Height, $GDIP_ILMREAD, $GDIP_PXF32RGB) $Stride = DllStructGetData($BitmapData1, "Stride") $Scan0 = DllStructGetData($BitmapData1, "Scan0") Dim $Color[$Width][$Height], $i = 0 For $row = 0 To $Width - 1 For $col = 0 To $Height - 1 $i += 1 ConsoleWrite($i & "/" & $Count & @CRLF) $pixel = DllStructCreate("dword", $Scan0 + $row * $Stride + $col * 4) $Color[$row][$col] = Hex(DllStructGetData($pixel, 1), 6) Next Next ;_ArrayDisplay($Color) Dim $SumRed = 0, $SumGreen = 0, $SumBlue = 0 For $x = 0 To $Width - 1 For $y = 0 To $Height - 1 $SumRed += _ColorGetRed($Color[$x][$y]) $SumGreen += _ColorGetGreen($Color[$x][$y]) $SumBlue += _ColorGetBlue($Color[$x][$y]) Next Next $NewR = $SumRed / $Count $NewG = $SumGreen / $Count $NewB = $SumBlue / $Count $new = BitOR(BitShift($NewR, -16), BitShift($NewG, -8), $NewB) _GDIPlus_BitmapUnlockBits($bm1, $BitmapData1) Return "0x" & $new EndFunc ;==>AverageColor Edited April 20, 2009 by Paulie Link to comment Share on other sites More sharing options...
Malkey Posted April 21, 2009 Share Posted April 21, 2009 Hey guys, Basically, I'm trying to calculate the average color value of a JPG/JPEG image. I'm having the most difficulty with the JPEG format, since I don't really know how to derive color data from it, however, also, I'm still trying to figure out how to find the average of all the colors. For example: 0xFF0000 = Red 0x0000FF = Blue Added, they would equal 0xFF00FF Divide that by two, and i get 0x7F807F Shouldn't it be somewhere between Red and Blue? Wish I understood this code here.. http://www.empiregpservices.com/blog/post....lor-of-an-imageI agree. Make use of _GDIPlus_BitmapLockBits(). I played around with an existing example script. http://www.autoitscript.com/forum/index.ph...st&p=663576 Added average colour. At line #50, is the command:- $hImage2 = _ImageColorRegExpReplace($hImage, "av", "FF0000FF"); Change Average colour to blue in BBGGRRAA hex colour format. The "av" in the search colour parameter enabled the average colour routine. Added range so that colours close to average colour will change to the new colour entered. It looks like you have solved your problem, almost. I hope this helps. expandcollapse popup; #include <GuiConstantsEx.au3> #include <GDIPlus.au3> #include <ScreenCapture.au3> #include <Misc.au3> ; http://www.autoitscript.com/forum/index.php?s=&showtopic=91755&view=findpost&p=663576 Opt('MustDeclareVars', 1) Global $width, $height, $hGUI1, $hGUI2, $hImage, $hImage2, $hGraphic1, $hGraphic2, $iX, $iY Local $PathFile = FileOpenDialog("Choose a File", @ScriptDir & "\", "Images (*.jpg;*.bmp;*.png;*.gif)|All Files (*.*)", 3) If Not @error Then _Main($PathFile) Func _Main($PathFile) ; Capture top left corner of the screen ;_ScreenCapture_Capture(@MyDocumentsDir & "\GDIPlus_Image.png", 0, 0, 400, 300) _GDIPlus_Startup() $hImage = _GDIPlus_ImageLoadFromFile($PathFile) ;$hImage = _GDIPlus_ImageLoadFromFile(@MyDocumentsDir & "\GDIPlus_Image.png") $iX = _GDIPlus_ImageGetWidth($hImage) $iY = _GDIPlus_ImageGetHeight($hImage) ; Create a GUI for the original image $hGUI1 = GUICreate("Original", $iX, $iY, 0, 0) GUISetState() ; Create a GUI for the zoomed image $hGUI2 = GUICreate("Ctrl + Left click to save image", $iX, $iY, 0, $iY + 30) GUISetState() GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3) ; Initialize GDI+ library and load image _GDIPlus_Startup() ; Draw original image $hGraphic1 = _GDIPlus_GraphicsCreateFromHWND($hGUI1) _GDIPlus_GraphicsDrawImage($hGraphic1, $hImage, 0, 0) ; ====== Examples calling _ImageColorRegExpReplace() ========================= ; Note colour format hex 0xBBGGRRAA - Blue, Green, Red, Alpha (transparency) ;$hImage2 = _ImageColorRegExpReplace($hImage, "(000000FF)" , "FFFFFFFF" ); Change black to white ;$hImage2 = _ImageColorRegExpReplace($hImage, "(FFFFFFFF)" , "FFFFFF00" ); Change white to transparent ;$hImage2 = _ImageColorRegExpReplace($hImage, "(([E-F][0-9A-F]){3})(FF)" , "${1}00" ); Change near to white to transparent ;$hImage2 = _ImageColorRegExpReplace($hImage, "(FF0000FF|0000AAFF|FFFFFFFF)", "000000FF"); Change blue, off red, white to black ;Swap red and blue channels on half the image. Image is 400x300 = 120,000 pixels. Number of pixels to replace is 60,000. ;$hImage2 = _ImageColorRegExpReplace($hImage, "([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})(FF)", "${3}${2}${1}${4}", 60000) ;$hImage2 = _ImageColorRegExpReplace($hImage, "(([0-9E-F]){6})(FF)", "0000FFFF"); Change near to white to red $hImage2 = _ImageColorRegExpReplace($hImage, "av", "FF0000FF"); Change Average colour to blue in BBGGRRAA hex colour format. ;============================================================================================== ; Draw RegExpReplace image $hGraphic2 = _GDIPlus_GraphicsCreateFromHWND($hGUI2) _GDIPlus_GraphicsDrawImage($hGraphic2, $hImage2, 0, 0) ;$hImage3 = _GDIPlus_BitmapCreateFromHBITMAP ($hImage2) ConsoleWrite("$hImage2 " & $hImage2 & @CRLF) ; Clean up screen shot file FileDelete(@MyDocumentsDir & "\GDIPlus_Image.jpg") ; Loop until user exits Do If _IsPressed("01") And _IsPressed("11") Then ;Left click + Ctrl key to save image Do Until Not _IsPressed("01") Local $PathFile1 = FileSaveDialog("Choose a name.", @ScriptDir & "\", _ "Images (*.bmp;*.jpg;*.png;*.gif)|All files (*.*)", 16, "ColourModify.jpg") If Not @error Then _GDIPlus_ImageSaveToFile($hImage2, $PathFile1) ShellExecute($PathFile1) EndIf EndIf Sleep(10) Until GUIGetMsg() = $GUI_EVENT_CLOSE ; Release resources _GDIPlus_GraphicsDispose($hGraphic1) _GDIPlus_GraphicsDispose($hGraphic2) _GDIPlus_ImageDispose($hImage) _GDIPlus_ImageDispose($hImage2) _GDIPlus_Shutdown() EndFunc ;==>_Main ; ========= _ImageColorRegExpReplace($hImage, $iColSrch, $iColNew,$iCount = 0) ===================== ;Paramerers:- ; $hImage - Handle to a Bitmap object ; $iColSrch - A regular expression pattern to compare the colours to in 0xBBGGRRAA hex colour format. ; $iColNew - The colour which will replace the regular expression matching colour.Also in 0xBBGGRRAA hex colour format. ; $iCount - [optional] The number of times to execute the replacement in the image. The default is 0. Use 0 for global replacement. ; Note :- Colour format in hex 0xBBGGRRAA ; Func _ImageColorRegExpReplace($hImage, $iColSrch, $iColNew, $iCount = 0) Local $Reslt, $stride, $format, $Scan0, $iIW, $iIH, $hBitmap1 Local $v_BufferA, $AllPixels, $sREResult1, $sResult $iIW = _GDIPlus_ImageGetWidth($hImage) $iIH = _GDIPlus_ImageGetHeight($hImage) $hBitmap1 = _GDIPlus_BitmapCloneArea($hImage, 0, 0, $iIW, $iIH, $GDIP_PXF32ARGB) ; Locks a portion of a bitmap for reading or writing $Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $iIW, $iIH, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB) ;Get the returned values of _GDIPlus_BitmapLockBits () $width = DllStructGetData($Reslt, "width") $height = DllStructGetData($Reslt, "height") $stride = DllStructGetData($Reslt, "stride") $format = DllStructGetData($Reslt, "format") $Scan0 = DllStructGetData($Reslt, "Scan0") $v_BufferA = DllStructCreate("byte[" & $height * $width * 4 & "]", $Scan0) ; Create DLL structure for all pixels $AllPixels = DllStructGetData($v_BufferA, 1) ;ConsoleWrite("$AllPixels, raw data, first 9 colours = " & StringRegExpReplace($AllPixels, "(.{98})(.*)", "\1") & @CRLF) ; Searches on this string - $sREResult1 whch has the prefix "0x" removed and a space put between pixels 8 characters long. $sREResult1 = StringRegExpReplace(StringTrimLeft($AllPixels, 2), "(.{8})", "\1 ") ;ConsoleWrite("$sREResult1 first 9 colours = " & StringRegExpReplace($sREResult1, "(.{81})(.*)", "\1") & @CRLF) ;====================== Average colour =============================== If StringInStr($iColSrch, "av") > 0 Then Local $iBlue, $iGreen, $iRed, $iAlpha, $avBlue, $avGreen, $avRed, $aviAlpha For $x = 1 To StringLen($sREResult1) Step 9 $iBlue += Dec(Hex("0x" & StringMid($sREResult1, $x, 2))) $iGreen += Dec(Hex("0x" & StringMid($sREResult1, $x + 2, 2))) $iRed += Dec(Hex("0x" & StringMid($sREResult1, $x + 4, 2))) $iAlpha += Dec(Hex("0x" & StringMid($sREResult1, $x + 6, 2))) ;MsgBox(0,"","0x" & Hex($iAlpha,2) & Hex($iRed,2) & Hex($iGreen,2) & Hex($iBlue,2) ) Next $avBlue = Hex(Round($iBlue / ($height * $width), 0), 2) $avGreen = Hex(Round($iGreen / ($height * $width), 0), 2) $avRed = Hex(Round($iRed / ($height * $width), 0), 2) $aviAlpha = Hex(Round($iAlpha / ($height * $width), 0), 2) MsgBox(0, "", "$width = " & $width & @CRLF & _ "$height = " & $height & @CRLF & _ "Blue = " & $avBlue & @CRLF & _ "$iGreen = " & $avGreen & @CRLF & _ "$iRed = " & $avRed & @CRLF & _ "$iAlpha = " & $aviAlpha & @CRLF & _ "Av.Col ARGB = " & "0x" & $aviAlpha & $avRed & $avGreen & $avBlue) Local $iRnge = 30 ; Range 30 is plus or minus 15 for each colour channel, max 0xFF and min 0x00. $iColSrch = StringRERange("0x" & $avBlue, $iRnge) & StringRERange("0x" & $avGreen, $iRnge) & _ StringRERange("0x" & $avRed, $iRnge) & StringRERange("0x" & $aviAlpha, $iRnge) ;ConsoleWrite("$iColSrch " & $iColSrch & @CRLF) EndIf ;=================> End of Average colour =============================== If StringInStr($iColNew, "0x") > 0 Then $iColNew = StringReplace($iColNew, "0x", ""); Remove "0x" not needed ; StringRegExpReplace performed and white spaces removed $sResult = StringStripWS(StringRegExpReplace($sREResult1, $iColSrch, $iColNew, $iCount), 8) ; Replace "0x" prefix and set modified data back to DLL structure, $v_BufferA DllStructSetData($v_BufferA, 1, "0x" & $sResult) _GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt) ; releases the locked region Return $hBitmap1 EndFunc ;==>_ImageColorRegExpReplace Func MY_PAINT($hWnd, $msg, $wParam, $lParam) If $hWnd = $hGUI1 Then _GDIPlus_GraphicsDrawImageRect($hGraphic1, $hImage, 0, 0, $width, $height) If $hWnd = $hGUI2 Then _GDIPlus_GraphicsDrawImageRect($hGraphic2, $hImage2, 0, 0, $width, $height) Return $GUI_RUNDEFMSG EndFunc ;==>MY_PAINT Func StringRERange($iColSrch, $iRnge) Local $str = "(", $iColSrchMin, $iColSrchMax $iColSrchMin = "0x" & Hex((Dec(Hex($iColSrch)) - $iRnge) * ((Dec(Hex($iColSrch)) - $iRnge) > 0), 2) $iColSrchMax = "0x" & Hex((Dec(Hex($iColSrch)) + $iRnge) * ((Dec(Hex($iColSrch)) + $iRnge) < 255) + 255, 2) For $n = $iColSrchMin To $iColSrchMax $str &= Hex($n, 2) & "|" Next $str = StringTrimRight($str, 1) & ")" Return $str EndFunc ;==>StringRERange ; 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