Jump to content

Pixel Counter


Go to solution Solved by Nine,

Recommended Posts

9 hours ago, Dexter1993 said:

PixelCount ??? :D

Not a beauty, but may be sufficient ;).

EDIT : new version

#include <Timers.au3>
#include <MsgBoxConstants.au3>

HotKeySet("{ESC}", "_Terminate")
HotKeySet("+!1", "_PixelCount1") ; Shift-Alt-1 ==> start search using PixelGetColor
HotKeySet("+!2", "_PixelCount2") ; Shift-Alt-2 ==> start search using PixelSearch

Global $iLeft, $iTop, $iRight, $iBottom ; coordinates of a rectangle
Global $sColor, $iVariation, $iChecked, $iFound
; set values :
$iLeft      = 0
$iTop       = 0
$iRight     = 200
$iBottom    = 200
$sColor     = "FFFF00" ; color you are looking for
$iVariation = 0
$iChecked   = 0 ; Pixels checked
$iFound     = 0 ; Pixels found

While True
    Sleep(100)
WEnd

; 1. using PixelGetColor :
Func _PixelCount1()
    Local $iMsgID
    Local $hStarttime = _Timer_Init()

    ConsoleWrite("Process running ..." & @CRLF)
    $iChecked   = 0
    $iFound     = 0
    For $x = $iLeft To $iRight
        For $y = $iTop To $iBottom
            If (Hex(PixelGetColor($x, $y), 6)) = $sColor Then
                $iChecked += 1
                $iFound   += 1
            Else
                $iChecked += 1
            EndIf
        Next
    Next

    ConsoleWrite("Process finished" & @CRLF)
    $iMsgID = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION, $MB_RETRYCANCEL), _
                                      "PixelGetColor Result :", _
                                      "Pixels checked : " & @CRLF & $iChecked & @CRLF & _
                                      "Pixels found   : " & @CRLF & $iFound   & @CRLF & @CRLF & _
                                      "Time           : " & @CRLF & _Timer_Diff($hStarttime) & " ms" & @CRLF)
    If $iMsgID = $IDCANCEL Then Exit
EndFunc

; 2. using PixelSearch :
Func _PixelCount2()
    Local $iMsgID, $xColor
    Local $hStarttime = _Timer_Init()

    ConsoleWrite("Process running ..." & @CRLF)
    $iChecked   = 0
    $iFound     = 0
    For $x = $iLeft To $iRight
        For $y = $iTop To $iBottom
            PixelSearch($x, $y, $x, $y, Dec($sColor), $iVariation)
            If @error Then
                $iChecked += 1
            Else
                $iFound   += 1
                $iChecked += 1
            EndIf
        Next
    Next

    ConsoleWrite("Process finished" & @CRLF)
    $iMsgID = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION, $MB_RETRYCANCEL), _
                                      "PixelSearch Result :", _
                                      "Pixels checked : " & @CRLF & $iChecked & @CRLF & _
                                      "Pixels found   : " & @CRLF & $iFound   & @CRLF & @CRLF & _
                                      "Time           : " & @CRLF & _Timer_Diff($hStarttime) & " ms" & @CRLF)
    If $iMsgID = $IDCANCEL Then Exit
EndFunc


Func _Terminate()
    MsgBox(BitOR(4096, 64), "Message :", "Script terminated" & @CRLF)
    Exit
EndFunc

 

Edited by Musashi
new version

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

  • Solution
8 minutes ago, Dexter1993 said:

Very nice UDF!

Thank you.  The simplest way would be to use @Musashi 1st example but instead of calling PixelGetColor, you would use _GetScreen_GetPixel.

For an even faster way, you can also use _GetScreen_SearchArea repeatedly with the start information set at each loop until you get an error.

Put a script together and if you have issues, I will be glad to help you out.

Link to comment
Share on other sites

hm... i dont know bro :( i test it the last 2 hours. My desktop is full of tests :D

 

#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include "GetScreen.au3"
#include <Array.au3>

HotKeySet("{ESC}", "_PixelCount1")

Global $iLeft, $iTop, $iRight, $iBottom ; coordinates of a rectangle
Global $sColor, $iVariation, $iChecked, $iFound
; set values :
$iLeft      = 0
$iTop       = 0
$iRight     = 600
$iBottom    = 600
$sColor     = 0xD05E5E ; color you are looking for
$iVariation = 0
$iChecked   = 0 ; Pixels checked
$iFound     = 0 ; Pixels found

_PixelCount1()

Func _PixelCount1()

    $iChecked   = 0
    $iFound     = 0
    For $x = $iLeft To $iRight
        For $y = $iTop To $iBottom
            If (Hex(_GetScreen_GetPixel($x, $y), 6)) = $sColor Then
                $iChecked += 1
                $iFound   += 1
            Else
                $iChecked += 1
            EndIf
        Next
    Next

    MsgBox (1,"","Pixels checked :" & $iChecked & " Pixel found: " & $iFound)

EndFunc

I test it with a red point.
Unbenannt.png.08b02282154bda8d93041707cdb934cb.png

Edited by Dexter1993
Link to comment
Share on other sites

Look at examples in the UDF.  You need to initialize the buffer and then read the screen.  You are not doing it properly.  Take a moment to understand what you are doing...

Link to comment
Share on other sites

1 hour ago, Dexter1993 said:

hm... i dont know bro :( i test it the last 2 hours. My desktop is full of tests :D

Try :

#include <Timers.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include "GetScreen.au3"
#include <Array.au3>
Opt("MustDeclareVars", True)

HotKeySet("{ESC}", "_Terminate")
HotKeySet("+!1", "_PixelCount1") ; Shift-Alt-1 ==> start search with _GetScreen_GetPixel

Global $iLeft, $iTop, $iRight, $iBottom ; coordinates of a rectangle
Global $sColor, $iFound
; set values :
$iLeft      = 0
$iTop       = 0
$iRight     = 600
$iBottom    = 600
$sColor     = "D05E5E" ; color you are looking for
$iFound     = 0 ; Pixels found

While True
    Sleep(100)
WEnd

Func _PixelCount1()
    Local $iMsgID
    Local $hStarttime = _Timer_Init()
    $iFound  = 0

    _GetScreen_Initialize(($iRight - $iLeft), ($iBottom - $iTop))
    _GetScreen_GetScreen()
    For $x = $iLeft To $iRight
        For $y = $iTop To $iBottom
            If (Hex(_GetScreen_GetPixel($x, $y), 6)) = $sColor Then
                $iFound   += 1
            EndIf
        Next
    Next

    $iMsgID = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION, $MB_RETRYCANCEL), _
                                      "PixelSearch Result :", _
                                      "Pixels checked : " & @CRLF & ($iRight-$iLeft)*($iBottom-$iTop) & @CRLF & _
                                      "Pixels found   : " & @CRLF & $iFound   & @CRLF & @CRLF & _
                                      "Time           : " & @CRLF & _Timer_Diff($hStarttime) & " ms" & @CRLF)
    If $iMsgID = $IDCANCEL Then Exit
EndFunc

Func _Terminate()
    MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION), "Message :", "Script terminated" & @CRLF)
    Exit
EndFunc

EDIT :

As already explained by @Nine : "You need to initialize the buffer and then read the screen."

Edited by Musashi

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

The UDF always starts at 0,0 from the top left, you can reduce the read to a lower right bottom but it will save only micro secs.  Better read the whole screen. Then you can search for specific area.

Link to comment
Share on other sites

7 minutes ago, Musashi said:

Besides, a nice UDF

Thanks.  I am using it a lot, and I know it is working very well.  Sometimes, you need pixel driven script to ease the complexity of a tool.

Link to comment
Share on other sites

THX guys! Very Helpfull.
I have now adapted it the way I need it

thx @Nine !!!!

thx @Musashi

#include "GetScreen.au3"

MsgBox (1,"Founded pixel",_PixelCountInArea(0,0,500,500,"D05E5E"))

Func _PixelCountInArea($left,$top,$right,$bottom,$color)

    $founded  = 0

    _GetScreen_Initialize(($right - $left), ($bottom - $top))
    _GetScreen_GetScreen()

    For $x = $left To $right
        For $y = $top To $bottom
            If (Hex(_GetScreen_GetPixel($x, $y), 6)) = $color Then
                $founded += 1
            EndIf
        Next
    Next

    Return $founded
EndFunc

 

Link to comment
Share on other sites

Initialize should say right and bottom, as I said the UDF always starts at 0,0

So code should be :

#include "GetScreen.au3"

MsgBox (1,"Founded pixel",_PixelCountInArea(0,0,500,500,"D05E5E"))

Func _PixelCountInArea($left,$top,$right,$bottom,$color)

    $founded  = 0

    _GetScreen_Initialize($right, $bottom)
    _GetScreen_GetScreen()

    For $x = $left To $right
        For $y = $top To $bottom
            If _GetScreen_GetPixel($x, $y) = $color Then  $founded += 1
         Next
    Next
    Return $founded
EndFunc

 

Link to comment
Share on other sites

I have one more question:
 

i Creat a while and check my red point. 

I am shown 566 pixels. If I now move a window in front of the point, there are considerably more pixels.

How can that be?

#include "GetScreen.au3"

While 1

    ToolTip (_PixelCountInArea(1131, 460,1406, 750,"D05E5E"),600,500)
    Sleep (100)

WEnd


Func _PixelCountInArea($left,$top,$right,$bottom,$color)

    $founded  = 0

    _GetScreen_Initialize($right, $bottom)
    _GetScreen_GetScreen()

    For $x = $left To $right
        For $y = $top To $bottom
            If _GetScreen_GetPixel($x, $y) = $color Then
                $founded += 1
            EndIf
         Next
    Next
    Return $founded
EndFunc

 

image.thumb.png.ee20c111973b4eb86c8a5764fd3780e8.pngimage.thumb.png.a6751ea61bb6a9db11fefc8ab98b7759.png

Link to comment
Share on other sites

Here's a fast (and small) C DLL version (attached, or compile with TCC)

Takes a file, change it to screencap yourself if needed.

#include <GDIPlus.au3>

Global Static $CountColorDll = DllOpen("CountColor.dll")
Global $hImage, $iLeft = 0, $iTop = 0, $iRight = 1100, $iBottom = 600, $hPixels, $Count = 0, $Color = 0xFFd05e5e

_GDIPlus_Startup()
$hImage = _GDIPlus_BitmapCreateFromFile("image.png")

$Count = _CountColor($hImage, $Color)

_GDIPlus_Shutdown()
ConsoleWrite("Amount of " & Hex($Color, 8) & " = " & $Count & @crlf)

Func _CountColor(ByRef $hImage, $Color)
    $Pixels = _GDIPlus_BitmapLockBits($hImage, $iLeft, $iTop, $iRight, $iBottom, $GDIP_ILMREAD, $GDIP_PXF32ARGB)
    $aRet = DllCall($CountColorDLL, "int:cdecl", "CountColor", "ptr", $Pixels.Scan0, "int", ($iRight-$iLeft)*($iBottom-$iTop), "int", $Color)
    _GDIPlus_BitmapUnlockBits($hImage, $Pixels)
    _GDIPlus_BitmapDispose($hImage)
    Return $aRet[0]
 EndFunc

#cs
===================================================================================================
C code for the DLL, compile with 'Tiny C Compiler' (TCC) https://bellard.org/tcc/

tcc -shared CountColor.c
===================================================================================================
#include <stdlib.h>

__declspec(dllexport) int CountColor(int* pixel, int len, int color) {
    int i, count = 0;
    for(i=0;i<len;i++){if(pixel[i]==color){count+=1;}}
return count;}
===================================================================================================
#ce

Btw, there are WAY more than 566 pixels that have color d05e5e, I count 28661 of them (and the edge of the circle is antialiased so they dont count)

CountColor.dll

Edited by Werty

Some guy's script + some other guy's script = my script!

Link to comment
Share on other sites

1 hour ago, Werty said:

Btw, there are WAY more than 566 pixels that have color d05e5e, I count 28661 of them

True !

For width and height I have given the complete screen (for trial purposes). I still use _GetScreen_GetPixel.

Screenshot without overlaying the area (the red dot) opened with Irfanview ==> 22291 Pixels found

Screenshot with overlaying the area (the red dot) opened with Irfanview ==> 6706 Pixels found

#include <Timers.au3>
#include <MsgBoxConstants.au3>
#include <Constants.au3>
#include "GetScreen.au3"
#include <Array.au3>
Opt("MustDeclareVars", True)

HotKeySet("{ESC}", "_Terminate")
HotKeySet("+!1", "_PixelCount1") ; Shift-Alt-1 ==> start search with _GetScreen_GetPixel

Global $iWidth, $iHeight, $sColor, $iFound
; set values :
$iWidth     = @DesktopWidth  ; Width of the primary display in pixels
$iHeight    = @DesktopHeight ; Height of the primary display in pixels
$sColor     = "D05E5E" ; color you are looking for
$iFound     = 0 ; Pixels found

While True
    Sleep(100)
WEnd

Func _PixelCount1()
    Local $iMsgID
    Local $hStarttime = _Timer_Init()
    $iFound  = 0

    _GetScreen_Initialize($iWidth, $iHeight)
    _GetScreen_GetScreen()
    For $x = 0 To $iWidth
        For $y = 0 To $iHeight
            If (Hex(_GetScreen_GetPixel($x, $y), 6)) = $sColor Then
                $iFound   += 1
            EndIf
        Next
    Next

    $iMsgID = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION, $MB_RETRYCANCEL), _
                                      "PixelSearch Result :", _
                                      "Pixels checked : " & @CRLF & ($iWidth * $iHeight) & @CRLF & _
                                      "Pixels found   : " & @CRLF & $iFound   & @CRLF & @CRLF & _
                                      "Time           : " & @CRLF & _Timer_Diff($hStarttime) & " ms" & @CRLF)
    If $iMsgID = $IDCANCEL Then Exit
EndFunc

Func _Terminate()
    MsgBox(BitOR($MB_SYSTEMMODAL, $MB_ICONINFORMATION), "Message :", "Script terminated" & @CRLF)
    Exit
EndFunc

 

Musashi-C64.png

"In the beginning the Universe was created. This has made a lot of people very angry and been widely regarded as a bad move."

Link to comment
Share on other sites

The red dot is only a test. I dont want to scan image files.

So it's not possible to scan an area in a repeat loop and count the pixels?
And if the number of employees changes, the new number of employees should be output live.

 

@Nine Can't you do a magic trick? :D


 

#include "GetScreen.au3"

While 1

    ToolTip (_PixelCountInArea(1131, 460,1406, 750,"D05E5E"),600,500)
    Sleep (100)

WEnd

Func _PixelCountInArea($left,$top,$right,$bottom,$color)

    $founded  = 0

    _GetScreen_Initialize($right, $bottom)
    _GetScreen_GetScreen()

    For $x = $left To $right
        For $y = $top To $bottom
            If _GetScreen_GetPixel($x, $y) = $color Then
                $founded += 1
            EndIf
         Next
    Next
    Return $founded
EndFunc

 

Edited by Dexter1993
Link to comment
Share on other sites

20 minutes ago, Dexter1993 said:

So it's not possible to scan an area in a repeat loop and count the pixels?

Of course it is possible.  Btw do not initialize repeatedly if the size of the screen does not change. Just do it once at the beginning of the script and only read the screen when you want to count the pixels.

#include "..\GetScreen\GetScreen.au3"

Local $hWnd = WinActivate("[CLASS:YourWindowClassHere]")
If Not $hWnd Then Exit MsgBox($MB_SYSTEMMODAL, "Error", "Unable to find window")
_GetScreen_Initialize(@DesktopWidth, @DesktopHeight)

While True
  ToolTip(_PixelCountInArea(700, 460, 800, 750, "D05E5E"), 600, 500)
  Sleep(100)
WEnd

Func _PixelCountInArea($left, $top, $right, $bottom, $color)
  Local $founded = 0
  _GetScreen_GetScreen()

  For $x = $left To $right
    For $y = $top To $bottom
      If Hex(_GetScreen_GetPixel($x, $y), 6) = $color Then $founded += 1
    Next
  Next
  Return $founded
EndFunc   ;==>_PixelCountInArea

 

Edited by Nine
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...