how do I Average colors in a 3x3 pixel nest.

Recommended Posts

Ok, this sounds strange, but I've been working on this in two directions, on with hex (what a mess) and one with in Dec. here is what I have currently. I attempt to average the colors in Dec. and come up with an odd skew' to my color average. I believe i need to work in hex and average each RGB segment and rebuild it. But I'm lost on how to even start to do that.

- Navajo

```; attempt to average colors across a 3x3 area within AutoIT

#include <Color.au3>

\$basepoint_x = 41
\$basepoint_y = 256

AutoItSetOption("PixelCoordMode", 2)

run("c:\Program Files\Internet Explorer\iexplore.exe http://www.kondrashov.org/color.print.test.page.jpg")

sleep(100)

WinWaitActive("http://www.kondrashov.org/")

sleep(100)

Global \$a[4][4]

\$a[1][1] = PixelGetColor(\$basepoint_x -1, \$basepoint_y -1)
\$a[1][2] = PixelGetColor(\$basepoint_x -1, \$basepoint_y)
\$a[1][3] = PixelGetColor(\$basepoint_x -1, \$basepoint_y +1)
\$a[2][1] = PixelGetColor(\$basepoint_x, \$basepoint_y -1)
\$a[2][2] = PixelGetColor(\$basepoint_x, \$basepoint_y)
\$a[2][3] = PixelGetColor(\$basepoint_x, \$basepoint_y +1)
\$a[3][1] = PixelGetColor(\$basepoint_x +1, \$basepoint_y -1)
\$a[3][2] = PixelGetColor(\$basepoint_x +1, \$basepoint_y)
\$a[3][3] = PixelGetColor(\$basepoint_x +1, \$basepoint_y +1)

; Get average

\$c = 0

\$string = " our string is:" & @CRLF

for \$x = 1 to 3
for \$y = 1 to 3
\$string = \$string & " [" & \$x & "]" & "[" & \$y & "] = " & \$a[\$x][\$y] & " " & Hex(\$a[\$x][\$y]) & @CRLF
\$c = \$c + \$a[\$x][\$y]
Next
Next

\$a[0][0] = Round(\$c / 9 )

\$string2 = "Color average is: " & \$a[0][0]

MsgBox(1, "color average", \$string & \$string2 & Hex(\$a[0][0]))```
Edited by navajo

Share on other sites

why do you need this? isn't that exactly what pixelchecksum does?

Share on other sites

Currently I'm working on a test bed system that has problems with color pallets, I would like to grab an areas around a set point and pull in the averages around that point. Not the checksum. As the manual says.

`A checksum only allows you to see if "something" has changed in a region - it does not tell you exactly what has changed.`

and this is not an average. I need a ratio across the pixel, not a checksum.

Edited by navajo

Share on other sites

So um... basically are you trying to blend the colors together? I did a few tests and yours is close, but the tint is off pretty bad

```; attempt to average colors across a 3x3 area within AutoIT

#include <Color.au3>
#include <GUIConstants.au3>
#include <IE.au3>

\$basepoint_x = 41
\$basepoint_y = 256

AutoItSetOption("PixelCoordMode", 2)

\$ie = _IECreate("http://www.kondrashov.org/color.print.test.page.jpg")
sleep(100)

WinWaitActive("http://www.kondrashov.org/")

sleep(100)

Global \$a[4][4]

\$a[1][1] = PixelGetColor(\$basepoint_x -1, \$basepoint_y -1)
\$a[1][2] = PixelGetColor(\$basepoint_x -1, \$basepoint_y)
\$a[1][3] = PixelGetColor(\$basepoint_x -1, \$basepoint_y +1)
\$a[2][1] = PixelGetColor(\$basepoint_x, \$basepoint_y -1)
\$a[2][2] = PixelGetColor(\$basepoint_x, \$basepoint_y)
\$a[2][3] = PixelGetColor(\$basepoint_x, \$basepoint_y +1)
\$a[3][1] = PixelGetColor(\$basepoint_x +1, \$basepoint_y -1)
\$a[3][2] = PixelGetColor(\$basepoint_x +1, \$basepoint_y)
\$a[3][3] = PixelGetColor(\$basepoint_x +1, \$basepoint_y +1)

; Get average

\$c = 0

\$string = " our string is:" & @CRLF

for \$x = 1 to 3
for \$y = 1 to 3
\$string = \$string & " [" & \$x & "]" & "[" & \$y & "] = " & \$a[\$x][\$y] & " " & Hex(\$a[\$x][\$y]) & @CRLF
\$c = \$c + \$a[\$x][\$y]
Next
Next

\$a[0][0] = Round(\$c / 9 )

\$string2 = "Color average is: " & \$a[0][0]

MsgBox(1, "color average", \$string & \$string2 &@CRLF& Hex(\$a[0][0]) &@CRLF&"0x" & StringTrimLeft(Hex(\$a[0][0]),2))
GUICreate("test")
For \$i = 1 To 3
For \$ii = 1 to 3
GUICtrlCreateLabel("",\$i*30-30,\$ii*30-30,30,30)
GUICtrlSetBkColor(-1,\$a[\$i][\$ii])
Next
Next
GUICtrlCreateLabel("",90,0,90,90)
GUICtrlSetBkColor(-1,"0x" & StringTrimLeft(Hex(\$a[0][0]),2))
GUISetState()
While 1
\$msg = GUIGetMsg()
If \$msg = \$GUI_EVENT_CLOSE Then Exit
Wend```

Labels can help you with visualizing it rather than using math for it all lol

Share on other sites

So um... basically are you trying to blend the colors together? I did a few tests and yours is close, but the tint is off pretty bad

```; attempt to average colors across a 3x3 area within AutoIT

#include <Color.au3>
#include <GUIConstants.au3>
#include <IE.au3>
\$basepoint_x = 41
\$basepoint_y = 256

AutoItSetOption("PixelCoordMode", 2)

\$ie = _IECreate("http://www.kondrashov.org/color.print.test.page.jpg")
sleep(100)

WinWaitActive("http://www.kondrashov.org/")

sleep(100)
Global \$a[4][4]
\$a[1][1] = PixelGetColor(\$basepoint_x -1, \$basepoint_y -1)
\$a[1][2] = PixelGetColor(\$basepoint_x -1, \$basepoint_y)
\$a[1][3] = PixelGetColor(\$basepoint_x -1, \$basepoint_y +1)
\$a[2][1] = PixelGetColor(\$basepoint_x, \$basepoint_y -1)
\$a[2][2] = PixelGetColor(\$basepoint_x, \$basepoint_y)
\$a[2][3] = PixelGetColor(\$basepoint_x, \$basepoint_y +1)
\$a[3][1] = PixelGetColor(\$basepoint_x +1, \$basepoint_y -1)
\$a[3][2] = PixelGetColor(\$basepoint_x +1, \$basepoint_y)
\$a[3][3] = PixelGetColor(\$basepoint_x +1, \$basepoint_y +1)

; Get average

\$c = 0

\$string = " our string is:" & @CRLF

for \$x = 1 to 3
for \$y = 1 to 3
\$string = \$string & " [" & \$x & "]" & "[" & \$y & "] = " & \$a[\$x][\$y] & " " & Hex(\$a[\$x][\$y]) & @CRLF
\$c = \$c + \$a[\$x][\$y]
Next
Next

\$a[0][0] = Round(\$c / 9 )

\$string2 = "Color average is: " & \$a[0][0]

MsgBox(1, "color average", \$string & \$string2 &@CRLF& Hex(\$a[0][0]) &@CRLF&"0x" & StringTrimLeft(Hex(\$a[0][0]),2))
GUICreate("test")
For \$i = 1 To 3
For \$ii = 1 to 3
GUICtrlCreateLabel("",\$i*30-30,\$ii*30-30,30,30)
GUICtrlSetBkColor(-1,\$a[\$i][\$ii])
Next
Next
GUICtrlCreateLabel("",90,0,90,90)
GUICtrlSetBkColor(-1,"0x" & StringTrimLeft(Hex(\$a[0][0]),2))
GUISetState()
While 1
\$msg = GUIGetMsg()
If \$msg = \$GUI_EVENT_CLOSE Then Exit
Wend```

Labels can help you with visualizing it rather than using math for it all lol

I'm not sure I understand the problem, but here is an untested function that should give you the pixel color average of a 3x3 block, centered around the given x/y coordinate:

```; =======================
; Function _PixelAvg(\$x, \$y)
;     Reads 3x3 pixel block centered around \$x/\$y
;     Returns average color in 0xRRGGBB format
;     Returns 0 and sets @error = 1 if invalid coordinates
; =======================
Func _PixelAvg(\$x, \$y)
Local \$row, \$col, \$color, \$avgR = 0, \$avgG = 0, \$avgB = 0
For \$col = -1 To 1
For \$row = -1 To 1
\$color = PixelGetColor(\$x + \$col, \$y + \$row)
If \$color = -1 Then Return SetError(1, 0, 0)
\$avgR += BitShift(BitAnd(\$color, 0xFF0000), 16)
\$avgG += BitShift(BitAnd(\$color, 0x00FF00), 8)
\$avgB += BitAnd(\$color, 0xFF)
Next
Next
\$color = BitAnd(BitShift(Round(\$avgR / 9), -16), BitShift(Round(\$avgG / 9), -8), Round(\$avgB / 9))
Return \$color
EndFunc```

Hope that helps!

Edit: Tweak typo in code...

Edit2: Doh! Another typo... mixed up RGB to RBG

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share on other sites

Hmm... Got a chance to test it and the mask/shift ops don't produce expected results, don't know why. So I changed it to the following, which tested OK:

```\$Xcoord = 100
\$Ycoord = 100
\$Result = _PixelAvg(\$Xcoord, \$Ycoord)
MsgBox(64, "Test", "Avg at " & \$Xcoord & "/" & \$Ycoord & " is: " & Hex(\$Result) & "  @error = " & @error)

; =======================
; Function _PixelAvg(\$x, \$y)
;     Reads 3x3 pixel block centered around \$x/\$y
;     Returns average color in 0xRRGGBB format
;     Returns 0 and sets @error = 1 if invalid coordinates
; =======================
Func _PixelAvg(\$x, \$y)
Local \$row, \$col, \$color, \$avgR = 0, \$avgG = 0, \$avgB = 0
For \$col = -1 To 1
For \$row = -1 To 1
\$color = PixelGetColor(\$x + \$col, \$y + \$row)
If \$color = -1 Then Return SetError(1, 0, 0)
\$avgR += BitShift(BitAND(\$color, 0xFF0000), 16)
\$avgG += BitShift(BitAND(\$color, 0x00FF00), 8)
\$avgB += BitAND(\$color, 0xFF)
Next
Next
\$avgR = Round(\$avgR / 9)
\$avgG = Round(\$avgG / 9)
\$avgB = Round(\$avgB / 9)
\$color = (\$avgR * 256 * 256) + (\$avgG * 256) + \$avgB
Return \$color
EndFunc   ;==>_PixelAvg```

Edited by PsaltyDS

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share on other sites

so you're trying to add the red green and blue values of a pixel and then divide by three right? that will give you a grey-ish color, though of doing a similar thing in my greyscale filter, but found a better algorithim

what is the purpose of this?

Share on other sites

so you're trying to add the red green and blue values of a pixel and then divide by three right? that will give you a grey-ish color, though of doing a similar thing in my greyscale filter, but found a better algorithim

what is the purpose of this?

That wasn't my impression of what was desired. I think he wants to break out the R, G, and B portion of the color, get the average of each primary color, and reassemble that to an average color for the 3x3 grid. This is what my function is attempting to do, anyway.

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share on other sites

That wasn't my impression of what was desired. I think he wants to break out the R, G, and B portion of the color, get the average of each primary color, and reassemble that to an average color for the 3x3 grid. This is what my function is attempting to do, anyway.

Okay, now I'm REALLY confused

Is he looking for

_ColorGetRed()

_ColorGetGreen()

_ColorGetBlue()

the "Average" color for ANY RGB value is going to be either black, grey, or white

look at The interactive flash thing HERE for proof

set those sliders to any numbers you want, the average the decimal values, and set them to the result, and you will see that it turns out gray

Share on other sites

Okay, now I'm REALLY confused

Is he looking for

_ColorGetRed()

_ColorGetGreen()

_ColorGetBlue()

the "Average" color for ANY RGB value is going to be either black, grey, or white

look at The interactive flash thing HERE for proof

set those sliders to any numbers you want, the average the decimal values, and set them to the result, and you will see that it turns out gray

Well, we need to hear from navajo to see if I've misunderstood him, but...

Assume a block of 9 pixels (3x3) that are the following colors coordinates are relative to the center pixel:

-1,-1 = 0xFF0000 ; Red

0, -1 = 0x00FF00 ; Green

1, -1 = 0xFFFF00 ; Red/Green

-1,0 = 0xFF0000 ; Red

0, 0 = 0x00FF00 ; Green

1, 0 = 0xFFFF00 ; Red/Green

-1,1 = 0xFF0000 ; Red

0, 1 = 0x00FF00 ; Green

1, 1 = 0xFFFF00 ; Red/Green

My script breaks each pixel's color into R, G, and B values and adds all the Reds together, all the Greens together, and all the Blues together. Then it divides each by 9, giving the average redness, average greeness, and average blueness. Lastly those three averaged tints are recombined into a single average RGB color.

-1,-1 = 0xFF0000 ; Red = FF, 00, 00

0, -1 = 0x00FF00 ; Green = 00, FF, 00

1, -1 = 0xFFFF00 ; Red/Green = FF, FF, 00

-1,0 = 0xFF0000 ; Red = FF, 00, 00

0, 0 = 0x00FF00 ; Green = 00, FF, 00

1, 0 = 0xFFFF00 ; Red/Green = FF, FF, 00

-1,1 = 0xFF0000 ; Red = FF, 00, 00

0, 1 = 0x00FF00 ; Green = 00, FF, 00

1, 1 = 0xFFFF00 ; Red/Green = FF, FF, 00

Add up the Reds:

FF + 00 + FF + 00 + FF + 00 + FF + 00 + FF = 0x4FB

Add up the Greens:

00 + FF + 00 + FF + 00 + FF + 00 + FF + 00 = 0x3FC

Add up the Blues:

0 + 0 + 0+ 0 + 0+ 0 + 0+ 0 + 0 = 0

Average each color (separately):

0x4FB / 9 = 0x8D ; Average redness

0x3FC / 9 = 0x71 ; Average greeness

0 / 9 = 0 ; Average blueness

Assemble the average component colors into a single average color:

RGB = 8D, 71, 00 = 0x8D7100

So the average color of those 9 pixels is 0x8D7100. At least, as I understand it, and my code above calculates it. What are the other theories?

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share on other sites

Well, we need to hear from navajo to see if I've misunderstood him, but...

Assume a block of 9 pixels (3x3) that are the following colors coordinates are relative to the center pixel:

-1,-1 = 0xFF0000 ; Red

0, -1 = 0x00FF00 ; Green

1, -1 = 0xFFFF00 ; Red/Green

-1,0 = 0xFF0000 ; Red

0, 0 = 0x00FF00 ; Green

1, 0 = 0xFFFF00 ; Red/Green

-1,1 = 0xFF0000 ; Red

0, 1 = 0x00FF00 ; Green

1, 1 = 0xFFFF00 ; Red/Green

My script breaks each pixel's color into R, G, and B values and adds all the Reds together, all the Greens together, and all the Blues together. Then it divides each by 9, giving the average redness, average greeness, and average blueness. Lastly those three averaged tints are recombined into a single average RGB color.

-1,-1 = 0xFF0000 ; Red = FF, 00, 00

0, -1 = 0x00FF00 ; Green = 00, FF, 00

1, -1 = 0xFFFF00 ; Red/Green = FF, FF, 00

-1,0 = 0xFF0000 ; Red = FF, 00, 00

0, 0 = 0x00FF00 ; Green = 00, FF, 00

1, 0 = 0xFFFF00 ; Red/Green = FF, FF, 00

-1,1 = 0xFF0000 ; Red = FF, 00, 00

0, 1 = 0x00FF00 ; Green = 00, FF, 00

1, 1 = 0xFFFF00 ; Red/Green = FF, FF, 00

Add up the Reds:

FF + 00 + FF + 00 + FF + 00 + FF + 00 + FF = 0x4FB

Add up the Greens:

00 + FF + 00 + FF + 00 + FF + 00 + FF + 00 = 0x3FC

Add up the Blues:

0 + 0 + 0+ 0 + 0+ 0 + 0+ 0 + 0 = 0

Average each color (separately):

0x4FB / 9 = 0x8D ; Average redness

0x3FC / 9 = 0x71 ; Average greeness

0 / 9 = 0 ; Average blueness

Assemble the average component colors into a single average color:

RGB = 8D, 71, 00 = 0x8D7100

So the average color of those 9 pixels is 0x8D7100. At least, as I understand it, and my code above calculates it. What are the other theories?

OHHH, thats a pretty nifty idea

that makes sense, but i don't see whats wrong in your code

Share on other sites

OHHH, thats a pretty nifty idea

that makes sense, but i don't see whats wrong in your code

Nothing at all wrong with the code in my post #6 in this thread. We just haven't heard from navajo if it answers his question or not...

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share on other sites

Yes, thats exactly what I was looking to do, I just could not figure out how to pull out the colors, thank you!

That wasn't my impression of what was desired. I think he wants to break out the R, G, and B portion of the color, get the average of each primary color, and reassemble that to an average color for the 3x3 grid. This is what my function is attempting to do, anyway.

Share on other sites

Nothing at all wrong with the code in my post #6 in this thread. We just haven't heard from navajo if it answers his question or not...

Oh... i misread, I saw the "...masks/shifts didn't produce expected results..." and jump too conclusions without finishing the sentance

EDIT:

@Navajo-

Glad all worked out for you

Edited by Paulie

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