Jump to content

Compare 2 hbitmap objects


Recommended Posts

Hi,

I'm looking for a fast way to compare 2 hbitmap objects that are being returned by _ScreenCapture_Capture.

All I need is a function with 2 input variables (the 2 hbitmaps) that returns a number that indictates the difference in the images.

I've seen some examples of bitblt and prospeed but most is either image search or the input is vastly different than what I'm looking for.

To be honest dll calls are a bit over my head.

Can anyone point me in the right direction to either find/create a function like the one stated above?

Thanks in advance

[font="Impact"] I always thought dogs laid eggs, and I learned something today. [/font]
Link to comment
Share on other sites

As for the return type:

I'm happy with any numeric value. I would determine a 'threshold' by trial and error and I would compare future images to ensure that they are over the threshold.

[font="Impact"] I always thought dogs laid eggs, and I learned something today. [/font]
Link to comment
Share on other sites

Using modified code from the page linked by junkew, I have the following code:

#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <ScreenCapture.au3>

; quick and dirty....
Global $stride, $ptr, $pixeldata
global $bitmapfile1, $width1, $height1, $stride1, $pbitmap1
global $bitmapfile2, $width2, $height2, $stride2, $pbitmap2
local  $numberdiff  = 0

_ScreenCapture_SetJPGQuality(20)

$pic1 = _ScreenCapture_Capture()
Sleep(1000)
$pic2 =_ScreenCapture_Capture()

$timer = TimerInit()

_GDIPlus_Startup()
$pixelstruct1   = getbmpdata($pic1, $width1, $height1, $stride1, $pbitmap1)
$pixelstruct2   = getbmpdata($pic2, $width2, $height2, $stride2, $pbitmap2)
$length         = DllStructGetSize($pixelstruct1)


for $i=1 to $length
    $diff=dllstructgetdata($pixelstruct1,1,$i)-dllstructgetdata($pixelstruct2,1,$i)
    if $diff<>0 Then $numberdiff+=1
next

ConsoleWrite(@CRLF & "Timer Diff: " & TimerDiff($timer)/1000 & " seconds." & @CRLF & "Difference: " & $numberdiff & @CRLF)

_GDIPlus_Shutdown()


Func getbmpdata($bmpfile, ByRef $width, ByRef $height, ByRef $stride, Byref $pbitmap) ;returns a struct with the data of the pixel
    $pbitmap = _GDIPlus_BitmapCreateFromHBITMAP($bmpfile)
    $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.
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    $pixeldata = DllStructCreate("ubyte[" & (Abs($stride) * ($height)) & "]", $Scan0)
    $BMPData = DllStructGetData($pixeldata, 1)
    _WinAPI_DeleteObject($pbitmap)
    _GDIPlus_BitmapUnlockBits($pBitmap, $BmpData)
    return $pixeldata
EndFunc   ;==>getbmpdata

Unfortunately this takes 14 seconds for a full-screen screenshot. I know I can reduce this by adding a 'Step' in the for loop, however I'd like to exhaust all other options before I do this.

Basically, I'm looking to only save a screenshot if it is different from the last. Perhaps I'm looking at this the wrong way? Rather than comparing images maybe ignore images taken when windows is not doing any kind of window redraws? Anyone have any ideas?

[font="Impact"] I always thought dogs laid eggs, and I learned something today. [/font]
Link to comment
Share on other sites

I edited only a few adding some time checks... Theres no takes 14 seconds to take the screenshot it takes 14 seconds in compare the info data... also you forget_WinAPI_DeleteObject() to delete the HBITMAP Objects from the screenshots(i read that from the screenshot help)

#include <GDIPlus.au3>
#include <GDIPlusConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <ScreenCapture.au3>

; quick and dirty....
Global $stride, $ptr, $pixeldata
global $bitmapfile1, $width1, $height1, $stride1, $pbitmap1
global $bitmapfile2, $width2, $height2, $stride2, $pbitmap2
local  $numberdiff  = 0
$timer = TimerInit()
_ScreenCapture_SetJPGQuality(20)

$pic1 = _ScreenCapture_Capture()
Sleep(1000)
$pic2 =_ScreenCapture_Capture()

ConsoleWrite(@CRLF & "Timer Diff: " & TimerDiff($timer)/1000 & " seconds." & @CRLF)

_GDIPlus_Startup()
$pixelstruct1   = getbmpdata($pic1, $width1, $height1, $stride1, $pbitmap1)
ConsoleWrite(@CRLF & "Timer Diff: " & TimerDiff($timer)/1000 & " seconds." & @CRLF)
$pixelstruct2   = getbmpdata($pic2, $width2, $height2, $stride2, $pbitmap2)
ConsoleWrite(@CRLF & "Timer Diff: " & TimerDiff($timer)/1000 & " seconds." & @CRLF)
$length         = DllStructGetSize($pixelstruct1)


for $i=1 to $length
    $diff=dllstructgetdata($pixelstruct1,1,$i)-dllstructgetdata($pixelstruct2,1,$i)
    if $diff<>0 Then $numberdiff+=1
next

ConsoleWrite(@CRLF & "Timer Diff: " & TimerDiff($timer)/1000 & " seconds." & @CRLF & "Difference: " & $numberdiff & @CRLF)


_WinAPI_DeleteObject($pic1)
_WinAPI_DeleteObject($pic2)
_GDIPlus_Shutdown()
Func getbmpdata($bmpfile, ByRef $width, ByRef $height, ByRef $stride, Byref $pbitmap) ;returns a struct with the data of the pixel
    $pbitmap = _GDIPlus_BitmapCreateFromHBITMAP($bmpfile)
    $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.
    $Scan0 = DllStructGetData($BitmapData, "Scan0");Scan0 - Pointer to the first (index 0) scan line of the bitmap.
    $pixeldata = DllStructCreate("ubyte[" & (Abs($stride) * ($height)) & "]", $Scan0)
    $BMPData = DllStructGetData($pixeldata, 1)
    _WinAPI_DeleteObject($pbitmap)
    _GDIPlus_BitmapUnlockBits($pBitmap, $BmpData)
    return $pixeldata
EndFunc   ;==>getbmpdata

PD: If You anyway want more speed in pixel function, maybe you would try this UDF

Edited by monoscout999
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...