Jardz Posted January 24, 2013 Share Posted January 24, 2013 Hi all,I'm trying to better understand the excellent GDIP UDF by AuthenticitySo I set myself a simple project to try and create a tonal histogram of an image; I use this in Photoshop a lot.I started with an old example by Toady at the below link (Thank you Toady for getting me started)Unfortunately 'PixelGetColor' seems very slow, so I wanted to see how fast GdipGetPixel would be.So, starting with Toady's example, and using GdipGetPixel function by Vossen and ImageScale and Greyscale functions by Uez (Thank you to all) I have the script below...expandcollapse popup#include <GDIP.au3> #include <Array.au3> #include <GUIConstants.au3> Global $iSampleRate = 20000 ; Number of pixels read for histogram, the higher the more accurate but slower. Global $histos, $histo $gui = GUICreate("Histogram",278,200,-1,-1) $pen = GuiCtrlCreateGraphic(10,10, 258, 150) GUICtrlSetBkColor(-1,0xFFFFFF) GUICtrlCreateLabel("Sample Rate:",20,160) $sample = GUICtrlCreateInput($iSampleRate,20,175,70,20) ;GUICtrlSetState(-1, $GUI_DISABLE) $BtnOpen= GUICtrlCreateButton("Open", 180, 165, 78, 30) GUISetState() While 1 Switch GUIGetMsg() Case $BtnOpen _main() Case $GUI_EVENT_CLOSE _GDIPlus_ShutDown() Exit EndSwitch WEnd Func _main() Local $tmp $iSampleRate = GUICtrlRead($sample) If $tmp < 1 and $tmp > 99999999 Then GUICtrlSetData($sample,10000) $iSampleRate = 10000 EndIf Local $sFile = FileOpenDialog("Open File", @WorkingDir, "All Picture Files (*.bmp;*.gif;*.jpg;*.jpeg;*.tif;*.tiff;*.png)", 3) Local $t = TimerInit() $aArrayHist = _Histogram($sFile, $iSampleRate) Local $d = Round(TimerDiff($t)/1000,2) ConsoleWrite("Time to build histogram = " & $d & @CRLF) RenderHistogram($aArrayHist) Local $d = Round(TimerDiff($t)/1000,2) ConsoleWrite("Total Time = " & $d & @CRLF) EndFunc Func RenderHistogram($a) Local $max = _ArrayMax($a,1,1) GuiCtrlDelete($pen) $pen=GuiCtrlCreateGraphic(10,10, 258, 150) GUICtrlSetBkColor(-1,0xFFFFFF) GUICtrlSetState(-1, $GUI_DISABLE) For $i = 1 To UBound($a)-1 GUICtrlSetGraphic($pen,$GUI_GR_MOVE, $i,150) GUICtrlSetGraphic($pen,$GUI_GR_LINE, $i,150 - Round(140*($a[$i]/$max),0)) Next GUICtrlSetColor(-1,0x000000) EndFunc Func _Histogram($fImage, $iSampleRate) If $fImage = "" Then Return SetError(1, 0, 0) If Not FileExists($fImage) Then Return SetError(2, 0, 0) Local $fName = StringRegExpReplace($fImage, ".*\\(.*).{4}", "$1") Local $declared = True If Not $ghGDIPDll Then _GDIPlus_Startup() $declared = False EndIf Local $hImageFromFile = _GDIPlus_ImageLoadFromFile($fImage) Local $iWidth = _GDIPlus_ImageGetWidth($hImageFromFile) Local $iHeight = _GDIPlus_ImageGetHeight($hImageFromFile) Local $ratio If $iWidth*$iHeight > $iSampleRate Then $ratio = $iWidth/$iHeight $iW = Int(Sqrt($iSampleRate*$ratio)) $iH = Int(sqrt($iSampleRate/$ratio)) Else $iW = $iWidth $iH = $iHeight EndIf Local $hImageThumbnail = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iW, "int", $iH, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0) If @error Then Return SetError(3, 0, 0) $hImageThumbnail = $hImageThumbnail[6] Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hImageThumbnail) DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "handle", $hBmpCtxt, "int", 7) _GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImageFromFile, 0, 0, $iW, $iH) _GDIPlus_ImageDispose($hImageFromFile) _GDIPlus_GraphicsDispose($hBmpCtxt) ; If you don't want to transfer to greyscale then comment out below ;#CS $hImageContext = _GDIPlus_ImageGetGraphicsContext($hImageThumbnail) Local $tNegMatrix, $pNegMatrix $tNegMatrix = _GDIPlus_ColorMatrixCreateGrayScale() $pNegMatrix = DllStructGetPtr($tNegMatrix) $hIA = _GDIPlus_ImageAttributesCreate() _GDIPlus_ImageAttributesSetColorMatrix($hIA, 0, True, $pNegMatrix) _GDIPlus_GraphicsDrawImageRectRectIA($hImageContext, $hImageThumbnail, 0, 0, $iW, $iH, 0, 0, $iW, $iH, $hIA) _GDIPlus_ImageAttributesDispose($hIA) _GDIPlus_GraphicsDispose($hImageContext) ;#CE $aHist = _BuildHistogramArray($hImageThumbnail) _GDIPlus_ImageDispose($hImageThumbnail) _GDIPlus_Shutdown() Return $aHist EndFunc Func _BuildHistogramArray($hBitmap) Local $tArgb, $pArgb, $aRet, $blue, $red, $green, $w, $h $tArgb = DllStructCreate("dword Argb") $pArgb = DllStructGetPtr($tArgb) Local $Hist[257] For $i = 0 To UBound($Hist) - 1 $Hist[$i] = 0 Next $w = _GDIPlus_ImageGetWidth($hBitmap) $h = _GDIPlus_ImageGetHeight($hBitmap) ConsoleWrite("Thumbnail W = " & $w & @CRLF & "Thumbnail H = " & $h & @CRLF) ;-------------Use the following if you've changed the bitmap thumbnail to greyscale otherwise comment out and use the next one---------- For $i = 1 To $h For $j = 1 To $w $aRet = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $j, "int", $i, "ptr", $pArgb) $Hist[Dec(Hex(DllStructGetData($tArgb, "Argb"),2))+1] +=1 $Hist[0] += 1 Next Next ;-------------If you're keeping bitmap as RGB and not Greyscale then use below to build Array for Histogram------------------------------ #cs For $i = 1 To $h For $j = 1 To $w $aRet = DllCall($ghGDIPDll, "int", "GdipBitmapGetPixel", "hwnd", $hBitmap, "int", $j, "int", $i, "ptr", $pArgb) $color_hex = "0x" & Hex(DllStructGetData($tArgb, "Argb") ,6) $Hist[Round((BitAND($color_hex,255) + BitShift(BitAND($color_hex,65280),0x08) + BitShift(BitAND($color_hex,16711680),0x10))/3,0)+1] += 1 $Hist[0] += 1 Next Next #ce $Hist[2] = ($Hist[1] + $Hist[3])/2 ConsoleWrite("Total Count = " & $Hist[0] & @CRLF) Return $Hist EndFunc Func ScaleImage($hImage, $iScaleW, $iScaleH, $iInterpolationMode = 7) ;coded by UEZ 2012 Local $iWidth = _GDIPlus_ImageGetWidth($hImage) * $iScaleW Local $iHeight = _GDIPlus_ImageGetHeight($hImage) * $iScaleH Local $hBitmap = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", 0, "int", 0x0026200A, "ptr", 0, "int*", 0) If @error Then Return SetError(3, 0, 0) $hBitmap = $hBitmap[6] Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap) DllCall($ghGDIPDll, "uint", "GdipSetInterpolationMode", "handle", $hBmpCtxt, "int", $iInterpolationMode) _GDIPlus_GraphicsDrawImageRect($hBmpCtxt, $hImage, 0, 0, $iWidth, $iHeight) _GDIPlus_ImageDispose($hImage) _GDIPlus_GraphicsDispose($hBmpCtxt) Return $hBitmap EndFuncHowever, the reason I'm posting in General Help and Support is I found two functions within GDIP v1.1 (Vista and above?) that may be exactly what I want.two dllcalls instead of 2000GdipBitmapGetHistogramSize and GdipBitmapGetHistogramhttp://msdn.microsoft.com/en-us/library/windows/desktop/ms536307(v=vs.85).aspxI know nothing about dllcalls but I've tried altering various examples in GDIP.au3 to see if I can get these to work.After hours of trying on the 'GdipBitmapGetHistogramSize' I've realized I have no hope without a better understanding; I keep getting '0' as a result.I would greatly appreciate anyone who comes across this post with the knowledge and time to show me how to call these functions.Many thanksJardz Link to comment Share on other sites More sharing options...
UEZ Posted January 26, 2013 Share Posted January 26, 2013 (edited) Do you mean something like that here? expandcollapse popup#include <GDIPlus.au3> Global Enum $HistogramFormatARGB = 0, $HistogramFormatPARGB, $HistogramFormatRGB, $HistogramFormatGray, _ $HistogramFormatB, $HistogramFormatG, $HistogramFormatR, $HistogramFormatA ;http://msdn.microsoft.com/en-us/library/windows/desktop/ms534136(v=vs.85).aspx Global Const $ImageFlagsNone = 0 Global Const $ImageFlagsScalable = 0x0001 Global Const $ImageFlagsHasAlpha = 0x0002 Global Const $ImageFlagsHasTranslucent = 0x0004 Global Const $ImageFlagsPartiallyScalable = 0x0008 Global Const $ImageFlagsColorSpaceRGB = 0x0010 Global Const $ImageFlagsColorSpaceCMYK = 0x0020 Global Const $ImageFlagsColorSpaceGRAY = 0x0040 Global Const $ImageFlagsColorSpaceYCBCR = 0x0080 Global Const $ImageFlagsColorSpaceYCCK = 0x0100 Global Const $ImageFlagsHasRealDPI = 0x1000 Global Const $ImageFlagsHasRealPixelSize = 0x2000 Global Const $ImageFlagsReadOnly = 0x00010000 Global Const $ImageFlagsCaching = 0x00020000 Global $file = FileOpenDialog("Select Image", "", "Images (*.jpg;*.png;*.bmp;*.gif)") If @error Then Exit _GDIPlus_Startup() Global $hBitmap = _GDIPlus_BitmapCreateFromFile($file) Global $iHistogramFormat = $HistogramFormatRGB, $bAlpha = False Global $aRes = DllCall($ghGDIPDll, "int", "GdipGetImageFlags", "handle", $hBitmap, "uint*", 0) If BitAND($aRes[2], $ImageFlagsHasAlpha) Then $iHistogramFormat = $HistogramFormatARGB $bAlpha = True EndIf Global Const $iGetHistogramSize = _GDIPlus_BitmapGetHistogramSize($iHistogramFormat) Global $tStructChannel0 = DllStructCreate("uint channel0[" & $iGetHistogramSize & "]") Global $pStructChannel0 = DllStructGetPtr($tStructChannel0) Global $tStructChannel1 = DllStructCreate("uint channel1[" & $iGetHistogramSize & "]") Global $pStructChannel1 = DllStructGetPtr($tStructChannel1) Global $tStructChannel2 = DllStructCreate("uint channel2[" & $iGetHistogramSize & "]") Global $pStructChannel2 = DllStructGetPtr($tStructChannel2) Global $tStructChannel3 = DllStructCreate("uint channel3[" & $iGetHistogramSize & "]") Global $pStructChannel3 = 0 If $bAlpha Then $pStructChannel3 = DllStructGetPtr($tStructChannel3) $r = _GDIPlus_BitmapGetHistogram($hBitmap, $iHistogramFormat, $iGetHistogramSize, $pStructChannel0, $pStructChannel1, $pStructChannel2, $pStructChannel3) Global $a = 0, $r, $g, $b For $i = 1 To $iGetHistogramSize If $bAlpha Then $a = DllStructGetData($tStructChannel0, "channel0", $i) $r = DllStructGetData($tStructChannel1, "channel1", $i) $g = DllStructGetData($tStructChannel2, "channel2", $i) $b = DllStructGetData($tStructChannel3, "channel3", $i) Else $r = DllStructGetData($tStructChannel0, "channel0", $i) $g = DllStructGetData($tStructChannel1, "channel1", $i) $b = DllStructGetData($tStructChannel2, "channel2", $i) EndIf ConsoleWrite("Alpha: " & @TAB & $a & @TAB & "R: " & $r & @TAB & @TAB & "G: " & $g & @TAB & @TAB & "B: " & $B & @LF) Next _GDIPlus_BitmapDispose($hBitmap) _GDIPlus_Shutdown() Exit ;http://msdn.microsoft.com/en-us/library/windows/desktop/ms536307(v=vs.85).aspx Func _GDIPlus_BitmapGetHistogram($hBitmap, $iFormat, $iGetHistogramSize, $pStructChannel0, $pStructChannel1, $pStructChannel2, $pStructChannel3) Local $aRes = DllCall($ghGDIPDll, "bool", "GdipBitmapGetHistogram", "handle", $hBitmap, "uint", $iFormat, "uint", $iGetHistogramSize, "struct*", $pStructChannel0, "struct*", $pStructChannel1, "struct*", $pStructChannel2, "struct*", $pStructChannel3) If @error Then Return SetError(1, @error, 0) Return 1 EndFunc ;http://msdn.microsoft.com/en-us/library/windows/desktop/ms536308(v=vs.85).aspx Func _GDIPlus_BitmapGetHistogramSize($iFormat) Local $aRes = DllCall($ghGDIPDll, "int", "GdipBitmapGetHistogramSize", "uint", $iFormat, "dword*", 0) If @error Then Return SetError(1, @error, 0) Return $aRes[2] EndFunc For an example have a look here: http://www.autoitscript.com/forum/index.php?showtopic=147777 Br, UEZ Edited February 10, 2013 by UEZ Please don't send me any personal message and ask for support! I will not reply! Selection of finest graphical examples at Codepen.io The own fart smells best! ✌Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!¯\_(ツ)_/¯ ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ Link to comment Share on other sites More sharing options...
Jardz Posted January 26, 2013 Author Share Posted January 26, 2013 That's Genius! Thank you very much UEZ. Looking at how you've done this I realise my own efforts were nowhere close and never going to work . I have a lot to learn... Again, thank you! 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